From 779cd73e8d9bcfa84deca63c6d2ab43578688b42 Mon Sep 17 00:00:00 2001 From: Greek Date: Sun, 26 Apr 2020 11:35:46 +0200 Subject: [PATCH] * Moved config/constants to central package * Made cap of addsub selectable via signal * Added debug reporting - MAX ADC Input 1 - MAX ADC Input 2 - MAX Scaler output - MAX DAC Output * Added Async FIFO * Added Simple Dual Port RAM * Added Feedback Controller * Added Xillybus Link * Moved testbenches to seperate directory --- src/UNUSED/memory_mapped_registers.vhd | 213 ++++++++++++++++++++++++ src/addsub.vhd | 17 +- src/async_fifo.vhd | 90 +++++++++++ src/clockgen.vhd | 14 +- src/delay_line.vhd | 30 ++-- src/dual_port_ram.vhd | 75 +++++++++ src/feedback_controller.vhd | 124 ++++++++++++++ src/feedback_loop.vhd | 139 +++++++++++----- src/open_loop.vhd | 26 +-- src/pmod_ad1_ctrl.vhd | 14 +- src/pmod_da3_ctrl.vhd | 16 +- src/{ => sim}/open_loop_tb.vhd | 0 src/{ => sim}/pmod_ad1_ctrl_tb.vhd | 0 src/{ => sim}/pmod_da3_ctrl_tb.vhd | 0 src/single_port_ram.vhd | 13 +- src/top.vhd | 2 +- src/typedef_package.vhd | 65 ++++++++ src/xillybus_link.vhd | 214 +++++++++++++++++++++++++ 18 files changed, 950 insertions(+), 102 deletions(-) create mode 100644 src/UNUSED/memory_mapped_registers.vhd create mode 100644 src/async_fifo.vhd create mode 100644 src/dual_port_ram.vhd create mode 100644 src/feedback_controller.vhd rename src/{ => sim}/open_loop_tb.vhd (100%) rename src/{ => sim}/pmod_ad1_ctrl_tb.vhd (100%) rename src/{ => sim}/pmod_da3_ctrl_tb.vhd (100%) create mode 100644 src/typedef_package.vhd create mode 100644 src/xillybus_link.vhd diff --git a/src/UNUSED/memory_mapped_registers.vhd b/src/UNUSED/memory_mapped_registers.vhd new file mode 100644 index 0000000..cfe6706 --- /dev/null +++ b/src/UNUSED/memory_mapped_registers.vhd @@ -0,0 +1,213 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity memory_mapped_registers is + port ( + clk : in std_logic; + reset : in std_logic; + + --***AXI4-LITE INTERFACE*** + -- WRITE ADDRESS CHANNEL + AWVALID : in std_logic; + AWREADY : out std_logic; + AWADDR : in std_logic_vector(1 downto 0); + AWPROT : in std_logic_vector(2 downto 0); + -- WRITE DATA CHANNEL + WVALID : in std_logic; + WREADY : out std_logic; + WDATA : in std_logic_vector(31 downto 0); + WSTRB : in std_logic_vector(3 downto 0); + -- WRITE RESPONSE CHANNEL + BVALID : out std_logic; + BREADY : in std_logic; + BRESP : out std_logic_vector(1 downto 0); + -- READ ADDRESS CHANNEL + ARVALID : in std_logic; + ARREADY : out std_logic; + ARADDR : in std_logic_vector(1 downto 0); + ARPROT : in std_logic_vector(2 downto 0); + -- READ DATA CHANNEL + RVALID : out std_logic; + RREADY : in std_logic; + RDATA : out std_logic_vector(31 downto 0); + RRESP : out std_logic_vector(1 downto 0); + + -- DEBUG + reset_debug : out std_logic; + adc_data1_max : in std_logic_vector(11 downto 0); + adc_data2_max : in std_logic_vector(11 downto 0); + scaler_max : in std_logic_vector(15 downto 0); + dac_max : in std_logic_vector(15 downto 0) + + -- DYNAMIC CONFIGURATION + addsub_mode : out std_logic; + delay : out std_logic_vector(7 downto 0); + factor : out std_logic_vector(3 downto 0); + ); +end entity; + +architecture arch of memory_mapped_registers is + + --*****TYPE DECLARATION***** + type WRITE_STAGE_TYPE is (WRITE_ADDR, WRITE_DATA, WRITE_RESP); + type READ_STAGE_TYPE is (READ_ADDR, READ_DATA); + + --*****SIGNAL DECLARATION***** + signal read_stage, read_stage_next : READ_STAGE_TYPE := READ_ADDR; + signal write_stage, write_stage_next : WRITE_STAGE_TYPE := WRITE_ADDR; + signal arready_next, arready, addsub_mode_next, rvalid, rvalid_next : std_logic := '0'; + signal awready, awready_next, wready, wready_next, bvalid, bvalid_next : std_logic := '0'; + signal rdata, rdata_next : std_logic_vector(31 downto 0) := (others => '0'); + signal factor_next : std_logic_vector(3 downto 0) := (others => '0'); + signal delay_next : std_logic_vector(7 downto 0) := (others => '0'); + signal awaddr, awaddr_next : std_logic_vector(1 downto 0) := (others => '0'); + signal reset_debug : std_logic := '0'; + +begin + + BRESP <= (others => '0'); + RRESP <= (others => '0'); + AWREADY <= awready; + AWADDR <= awaddr; + WREADY <= wready; + BVALID <= bvalid; + ARREADY <= arready; + RVALID <= rvalid; + + read_ctrl : process(all) + begin + --DEFAULT VALUES + read_stage_next <= read_stage; + arready_next <= arready; + rdata_next <= rdata; + rvalid_next <= rvalid; + + case(read_stage) + when READ_ADDR => + arready_next <= '1'; + rvalid_next <= '0'; + if (ARVALID = '1') then + case(to_integer(unsigned(ARADDR))) + when 0 => + rdata_next <= (others => '0'); + rdata_next(30) <= addsub_mode_next; + rdata_next(19 downto 16) <= factor_next; + rdata_next(7 downto 0) <= delay_next; + when 1 => + rdata_next <= (others => '0'); + rdata_next(11 downto 0) <= adc_data1_max; + rdata_next(27 downto 16)<= adc_data2_max; + when 2 => + rdata_next <= (others => '0'); + rdata_next(15 downto 0) <= dac_max; + rdata_next(31 downto 16)<= scaler_max; + when others => + rdata_next <= (others => '0'); + end case; + arready_next <= '0'; + rvalid_next <= '1'; + read_stage_next <= READ_DATA; + end if; + when READ_DATA => + arready_next <= '0'; + rvalid_next <= '1'; + if (RREADY = '1') then + arready_next <= '1'; + rvalid_next <= '0'; + read_stage_next <= READ_ADDR; + end if; + end case; + end process; + + read_ctrl : process(all) + begin + --DEFAULT VALUES + write_stage_next <= write_stage; + awready_next <= awready; + awaddr_next <= awaddr; + wready_next <= wready; + bvalid_next <= bvalid; + reset_debug_next <= '0'; + + case(write_stage) + when WRITE_ADDR => + awready_next <= '1'; + wready_next <= '0'; + bvalid <= '0'; + if (AWVALID = '1') then + awaddr_next <= AWADDR; + awready_next <= '0'; + wready_next <= '1'; + write_stage_next <= WRITE_DATA; + end if; + when WRITE_DATA => + awready_next <= '0'; + wready_next <= '1'; + bvalid <= '0'; + if (WVALID = '1') then + case(to_integer(unsigned(awaddr))) + when 0 => + reset_debug_next <= WDATA(31); + addsub_mode_next <= WDATA(30); + factor_next <= WDATA(19 downto 16); + delay_next <= WDATA(7 downto 0); + when others => + null; + end case; + wready_next <= '0'; + bvalid_next <= '1'; + write_stage_next <= WRITE_RESP; + end if; + when WRITE_RESP => + awready_next <= '0'; + wready_next <= '0'; + bvalid_next <= '1'; + if (BREADY = '1') then + bvalid_next <= '0'; + awready_next <= '1'; + write_stage_next <= WRITE_ADDR; + end if; + end case; + end process; + + sync : process(clk) + begin + if (rising_edge(clk)) then + if (reset = '1') then + awready <= '0'; + awaddr <= (others => '0'); + wready <= '0'; + bvalid <= '0'; + arready <= '0'; + rvalid <= '0'; + + read_stage <= READ_ADDR; + write_stage <= WRITE_ADDR; + + addsub_mode <= '0'; + factor <= (others => '0'); + delay <= (others => '0'); + + rdata <= (others => '0'); + else + awready <= awready_next; + awaddr <= awaddr_next; + wready <= wready_next; + bvalid <= bvalid_next; + arready <= arready_next; + rvalid <= rvalid_next; + + read_stage <= read_stage_next; + write_stage <= write_stage_next; + + addsub_mode <= addsub_mode_next; + factor <= factor_next; + delay <= delay_next; + + rdata <= rdata_next; + end if; + end if; + end process; + +end architecture; \ No newline at end of file diff --git a/src/addsub.vhd b/src/addsub.vhd index ab608c9..a742738 100644 --- a/src/addsub.vhd +++ b/src/addsub.vhd @@ -10,7 +10,7 @@ use UNIMACRO.vcomponents.all; -- Add/Sub -- This entity adds or subtracts inputs 'A' and 'B', depending on 'mode' (1 = add, 0 = sub). --- NOTE: In Overfolw/Underflow conditions the result is capped at max/min value. +-- If 'cap' is high, on Overfolw/Underflow conditions the result is capped at max/min value. entity addsub is generic ( @@ -18,12 +18,13 @@ entity addsub is DATA_WIDTH : integer := 16 ); port ( - clk : std_logic; - reset : std_logic; - mode : std_logic; - A : std_logic_vector(DATA_WIDTH-1 downto 0); - B : std_logic_vector(DATA_WIDTH-1 downto 0); - RES : std_logic_vector(DATA_WIDTH-1 downto 0) + clk : in std_logic; + reset : in std_logic; + mode : in std_logic; + cap : in std_logic; + A : in std_logic_vector(DATA_WIDTH-1 downto 0); + B : in std_logic_vector(DATA_WIDTH-1 downto 0); + RES : out std_logic_vector(DATA_WIDTH-1 downto 0) ); end entity; @@ -59,7 +60,7 @@ begin RES <= result; --Overflow/Underflow - if(carry = '1') then + if(carry = '1' and cap = '1') then --ADD if(mode = '1') then --CAP AT MAX VALUE diff --git a/src/async_fifo.vhd b/src/async_fifo.vhd new file mode 100644 index 0000000..dd139ff --- /dev/null +++ b/src/async_fifo.vhd @@ -0,0 +1,90 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +Library xpm; +use xpm.vcomponents.all; + +-- Read and Write requests are ignored while the FIFO is in a reset state (reset busy signal high) + +entity async_fifo is + generic ( + DATA_WIDTH : integer := 32; + FIFO_DEPTH : integer := 16; -- (16 - 4194304) + PROG_EMPTY : integer := 3; -- MIN:3 MAX:(FIFO_DEPTH-3) + PROG_FULL : integer := 13 -- MIN:3+CDC_SYNC_STAGES MAX:(FIFO_DEPTH-3) + ); + port ( + wr_clk : in std_logic; + rd_clk : in std_logic; + reset : in std_logic; --wr_clk synchronous + wen : in std_logic; + ren : in std_logic; + empty : out std_logic; + almost_empty: out std_logic; + prog_empty : out std_logic; + full : out std_logic; + almost_full : out std_logic; + prog_full : out std_logic; + wr_data : in std_logic_vector(DATA_WIDTH-1 downto 0); + rd_data : out std_logic_vector(DATA_WIDTH-1 downto 0) + ); +end entity; + +architecture arch of async_fifo is + + --*****SIGNAL DECLARATION***** + signal rd_busy, wr_busy : std_logic := '0'; + +begin + + xpm_fifo_async_inst : xpm_fifo_async + generic map ( + CDC_SYNC_STAGES => 2, + DOUT_RESET_VALUE => "0", + ECC_MODE => "no_ecc", + FIFO_MEMORY_TYPE => "auto", + FIFO_READ_LATENCY => 1, + FIFO_WRITE_DEPTH => FIFO_DEPTH, + FULL_RESET_VALUE => 1, + PROG_EMPTY_THRESH => PROG_EMPTY, + PROG_FULL_THRESH => PROG_FULL, + RD_DATA_COUNT_WIDTH => 1, + READ_DATA_WIDTH => DATA_WIDTH, + READ_MODE => "std", + RELATED_CLOCKS => 0, + USE_ADV_FEATURES => "0A0A", + WAKEUP_TIME => 0, + WRITE_DATA_WIDTH => DATA_WIDTH, + WR_DATA_COUNT_WIDTH => 1 + ) + port map ( + almost_empty => almost_empty, + almost_full => almost_full, + data_valid => open, + dbiterr => open, + dout => rd_data, + empty => empty, + full => full, + overflow => open, + prog_empty => prog_empty, + prog_full => prog_full, + rd_data_count => open, + rd_rst_busy => rd_busy, + sbiterr => open, + underflow => open, + wr_ack => open, + wr_data_count => open, + wr_rst_busy => wr_busy, + din => wr_data, + injectdbiterr => '0', + injectsbiterr => '0', + rd_clk => rd_clk, + rd_en => ren and (not rd_busy), + rst => reset, + sleep => '0', + wr_clk => wr_clk, + wr_en => wr_en and (not wr_busy) + ); + +end architecture; \ No newline at end of file diff --git a/src/clockgen.vhd b/src/clockgen.vhd index 4914a31..240f38a 100644 --- a/src/clockgen.vhd +++ b/src/clockgen.vhd @@ -6,6 +6,12 @@ library UNISIM; use UNISIM.VCOMPONENTS.ALL; entity clockgen is + generic ( + CLKFBOUT_MULT : integer := 41; + CLKIN1_PERIOD : real := 10.000000; + CLKOUT0_DIVIDE : integer := 41; + DIVCLK_DIVIDE : integer := 5 + ); port ( clk_in : in std_logic; clk_out : out std_logic @@ -29,11 +35,11 @@ begin plle2_adv_inst: unisim.vcomponents.PLLE2_ADV generic map( BANDWIDTH => "OPTIMIZED", - CLKFBOUT_MULT => 41, + CLKFBOUT_MULT => CLKFBOUT_MULT, CLKFBOUT_PHASE => 0.000000, - CLKIN1_PERIOD => 10.000000, + CLKIN1_PERIOD => CLKIN1_PERIOD, CLKIN2_PERIOD => 0.000000, - CLKOUT0_DIVIDE => 41, + CLKOUT0_DIVIDE => CLKOUT0_DIVIDE, CLKOUT0_DUTY_CYCLE => 0.500000, CLKOUT0_PHASE => 0.000000, CLKOUT1_DIVIDE => 1, @@ -52,7 +58,7 @@ begin CLKOUT5_DUTY_CYCLE => 0.500000, CLKOUT5_PHASE => 0.000000, COMPENSATION => "ZHOLD", - DIVCLK_DIVIDE => 5, + DIVCLK_DIVIDE => DIVCLK_DIVIDE, IS_CLKINSEL_INVERTED => '0', IS_PWRDWN_INVERTED => '0', IS_RST_INVERTED => '0', diff --git a/src/delay_line.vhd b/src/delay_line.vhd index 9f4bc67..d7d069a 100644 --- a/src/delay_line.vhd +++ b/src/delay_line.vhd @@ -8,14 +8,14 @@ use ieee.numeric_std.all; -- have effectively a ring buffer that we can vary in size (up to the maximum capacity of the memory). -- NOTE: Changing the 'delay' value may lead to glitches during the first "delay period", due to the -- way the address generation is made. More specifically, these glitches happen when the 'delay' is --- increased (which is unavoidable), and when it is decreased while the counter is the same as the new --- delay [single cycle glitch]. +-- increased (which is unavoidable), and when it is decreased while the momentarily counter value is +-- the same as the new delay value [single cycle glitch]. entity delay_line is generic ( DATA_WIDTH : integer := 12; - DELAY_WIDTH : integer := 8; - MAX_DELAY : integer := 200 + MAX_DELAY : integer := 200; + DELAY_WIDTH : integer := 8 ); port ( clk : in std_logic; @@ -31,16 +31,15 @@ architecture arch of delay_line is component single_port_ram is generic ( ADDR_WIDTH : integer := 8; - DATA_WIDTH : integer := 12; - MEMORY_DEPTH : integer := 200 + DATA_WIDTH : integer := 12 ); port ( clk : in std_logic; addr : in std_logic_vector(ADDR_WIDTH-1 downto 0); wen : in std_logic; ren : in std_logic; - write_data : in std_logic_vector(DATA_WIDTH-1 downto 0); - read_data : out std_logic_vector(DATA_WIDTH-1 downto 0) + wr_data : in std_logic_vector(DATA_WIDTH-1 downto 0); + rd_data : out std_logic_vector(DATA_WIDTH-1 downto 0) ); end component; @@ -54,30 +53,29 @@ begin ram_inst : single_port_ram generic map( ADDR_WIDTH => DELAY_WIDTH, - DATA_WIDTH => DATA_WIDTH, - MEMORY_DEPTH => MAX_DELAY + DATA_WIDTH => DATA_WIDTH ); port map( clk => clk, - addr => cnt, + addr => std_logic_vector(to_unsigned(cnt,DELAY_WIDTH)), wen => '1', ren => '1', - write_data => data_in, - read_data => memory_out + wr_data => data_in, + rd_data => memory_out ); - cntrl : process(all) + ctrl : process(all) begin -- DEFAULT VALUES cnt_next <= cnt; cnt_max_next <= cnt_max; - if(to_integer(unsigned(addr)) = 0) then + if(to_integer(unsigned(delay)) = 0) then data_out <= data_in; else data_out <= memory_out; -- COUNT GENERATION - cnt_max_next <= to_integer(unsigned(addr)) - 1; + cnt_max_next <= to_integer(unsigned(delay)) - 1; if (cnt >= cnt_max) then cnt_next <= 0; else diff --git a/src/dual_port_ram.vhd b/src/dual_port_ram.vhd new file mode 100644 index 0000000..c45471b --- /dev/null +++ b/src/dual_port_ram.vhd @@ -0,0 +1,75 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +Library xpm; +use xpm.vcomponents.all; + +-- NOTE: Simutanous reads and writes to the same addresses have to be prevented by external means! + +entity dual_port_ram is + generic ( + ADDR_WIDTH : integer := 4; + DATA_WIDTH : integer := 16 + ); + port ( + wr_clk : in std_logic; + rd_clk : in std_logic; + rd_addr : in std_logic_vector(ADDR_WIDTH-1 downto 0); + wr_addr : in std_logic_vector(ADDR_WIDTH-1 downto 0); + wen : in std_logic; + ren : in std_logic; + wr_data : in std_logic_vector(DATA_WIDTH-1 downto 0); + rd_data : out std_logic_vector(DATA_WIDTH-1 downto 0) + ); +end entity; + +architecture arch of dual_port_ram is + +begin + + xpm_memory_sdpram_inst : xpm_memory_sdpram + generic map ( + ADDR_WIDTH_A => ADDR_WIDTH, + ADDR_WIDTH_B => ADDR_WIDTH, + AUTO_SLEEP_TIME => 0, + BYTE_WRITE_WIDTH_A => DATA_WIDTH, + CLOCKING_MODE => "independent_clock", + ECC_MODE => "no_ecc", + MEMORY_INIT_FILE => "none", + MEMORY_INIT_PARAM => "0", + MEMORY_OPTIMIZATION => "true", + MEMORY_PRIMITIVE => "auto", + MEMORY_SIZE => DATA_WIDTH*(2**ADDR_WIDTH), + MESSAGE_CONTROL => 0, + READ_DATA_WIDTH_B => DATA_WIDTH, + READ_LATENCY_B => 1, + READ_RESET_VALUE_B => "0", + RST_MODE_A => "SYNC", + RST_MODE_B => "SYNC", + USE_EMBEDDED_CONSTRAINT => 1, --TODO + USE_MEM_INIT => 1, + WAKEUP_TIME => "disable_sleep", + WRITE_DATA_WIDTH_A => DATA_WIDTH, + WRITE_MODE_B => "no_change" + ) + port map ( + dbiterrb => open, + doutb => rd_data, + sbiterrb => open, + addra => wr_addr, + addrb => rd_addr, + clka => wr_clk, + clkb => rd_clk, + dina => wr_data, + ena => wen, + enb => ren, + injectdbiterra => '0', + injectsbiterra => '0', + regceb => '1', + rstb => '0', + sleep => '0', + wea => wen + ); + +end architecture; \ No newline at end of file diff --git a/src/feedback_controller.vhd b/src/feedback_controller.vhd new file mode 100644 index 0000000..f88592d --- /dev/null +++ b/src/feedback_controller.vhd @@ -0,0 +1,124 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +use work.typedef_package.all; + +-- Feedback Controller +-- This entity reads from the config memory and applies the resepctive configuration when the relevant +-- timestamp is reached or exceeded. The timer starts counting when a high level is detected in the 'sync' +-- signal after a reset. +-- NOTE: This entity is continuosly reading from the memory, except when the 'reset' signal is held high. + +-- Config Mapping: +-- mem_data(63) : Slot Enable +-- mem_data(62) : Addsub_mode +-- mem_data(61) : Add_input_mux +-- mem_data(47-40) : delay +-- mem_data(35-32) : factor +-- mem_data(31-0) : timestamp + + +entity feedback_controller is + port ( + clk : in std_logic; + reset : in std_logic; + + sync : in std_logic; + + mem_addr : out std_logic_vector(CONFIG_MEM_ADDR_WIDTH-1 downto 0); + mem_ren : out std_logic; + mem_data : in std_logic_vector(CONFIG_DATA_WIDTH-1 downto 0); + + addsub_mode : out std_logic; + add_input_mux : out std_logic; + delay : out std_logic_vector(DELAY_WIDTH-1 downto 0); + factor : out std_logic_vector(FACTOR_WIDTH-1 downto 0) + ); +end entity; + +architecture arch of feedback_controller is + --*****CONSTANT DECLARATION***** + constant inc : unsigned(CONFIG_MEM_ADDR_WIDTH-1 downto 0) := to_unsigned(1,CONFIG_MEM_ADDR_WIDTH); + + --*****SIGNAL DECLARATION***** + signal slot_nr, slot_nr_next : std_logic_vector(CONFIG_MEM_ADDR_WIDTH-1 downto 0) : (others => '0'); + signal timer : std_logic_vector(TIMESTAMP_WIDTH-1 downto 0) := (others => '0'); + signal sync_arrived : std_logic; + signal addsub_mode_next, addsub_mode_sig, add_input_mux_next, add_input_mux_sig : std_logic := '0'; + signal delay_next, delay_sig : std_logic_vector(DELAY_WIDTH-1 downto 0); := (others => '0'); + signal factor_next, factor_sig : std_logic_vector(FACTOR_WIDTH-1 downto 0) := (others => '0'); + +begin + + --OUTPUT SIGNALS + -- Intermediate "_sig" signals needed because we cannot read from output pins + mem_ren <= not reset; + mem_addr <= slot_nr_next; -- Use 'next' signal to "asynchronously" set addr (Save 1 clock cycle) + addsub_mode <= addsub_mode_sig; + add_input_mux <= add_input_mux_sig; + delay <= delay_sig; + factor <= factor_sig; + + ctrl : process(all) + begin + --DEFAULT + slot_nr_next <= slot_nr; + addsub_mode_next <= addsub_mode_sig; + add_input_mux_next <= add_input_mux_sig; + delay_next <= delay_sig; + factor_next <= factor_sig; + + if(mem_data(CONFIG_DATA_WIDTH-1) = '1') then + -- If timestamp is reached (or exceeded), apply configuration and fetch next configuration + -- slot + if (unsigned(timer) >= unsigned(mem_data(TIMESTAMP_WIDTH-1 downto 0))) then + addsub_mode_next <= mem_data(CONFIG_DATA_WIDTH-2); + add_input_mux_next <= mem_data(CONFIG_DATA_WIDTH-3); + delay_next <= mem_data(CONFIG_DATA_WIDTH-17 downto CONFIG_DATA_WIDTH-16-DELAY_WIDTH); + factor_next <= mem_data(TIMESTAMP_WIDTH+FACTOR_WIDTH-1 downto TIMESTAMP_WIDTH); + + slot_nr_next <= std_logic_vector(unsigned(slot_nr) + inc); + end if; + end if; + end process; + + sync : process(clk) + begin + if rising_edge(clk) then + if (reset = '1') then + slot_nr <= (others => '0'); + addsub_mode_sig <= '0'; + add_input_mux_sig <= '0'; + delay_sig <= (others => '0'); + factor_sig <= (others => '0'); + else + slot_nr <= slot_nr_next; + addsub_mode_sig <= addsub_mode_next; + add_input_mux_sig <= add_input_mux_next; + delay_sig <= delay_next; + factor_sig <= factor_next; + end if; + end if; + end process; + + timer : process(clk) + begin + if rising_edge(clk) then + if (reset = '1') then + timer <= (others => '0'); + sync_arrived <= '0'; + else + if (sync_arrived = '0') then + -- Wait for rising edge of sync pulse + if (sync = '1') then + sync_arrived <= '1'; + end if; + else + timer <= std_logic_vector(unsigned(timer) + inc); + end if; + end if; + end if; + end process; + +end architecture; \ No newline at end of file diff --git a/src/feedback_loop.vhd b/src/feedback_loop.vhd index 3602cb1..7acac64 100644 --- a/src/feedback_loop.vhd +++ b/src/feedback_loop.vhd @@ -2,14 +2,23 @@ library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; +use work.typedef_package.all; + -- Architecture - --- ---------- ------ ------- --- +-- --- ---------- ------ ------- --- --->|ADC|--->|Delay Line|--->|Scaler|--->|ADD/SUB|--->|DAC|---> - --- ---------- ------ ------- --- +-- --- ---------- ------ ------- --- -- ^ - --- ----- | ---->|ADC|---------------------|Latch|-------- - --- ----- +-- --- ----- --- | +--->|ADC|-------------------->|Latch|->| | | +-- --- ----- |MUX|-- +-- GND--->| | +-- --- + +-- Feedback Loop +-- This entity implements the feedback loop as defined above. +-- In addition to that, this entity latches and provides various max values that can be used for debug +-- purposes. entity feedback_loop is port ( @@ -17,20 +26,27 @@ entity feedback_loop is reset : in std_logic; adc_data_in1 : in std_logic; adc_data_in2 : in std_logic; - addsub_mode : in std_logic; - delay : in std_logic_vector(7 downto 0); - factor : in std_logic_vector(3 downto 0); adc_cs_n : out std_logic; dac_data_out : out std_logic; dac_cs_n : out std_logic; - dac_ldac : out std_logic + dac_ldac : out std_logic; + -- DYNAMIC CONFIGURATION + addsub_mode : in std_logic; -- (1=ADD, 0=SUB) + add_input_mux : in std_logic; -- (1=ADC Input 2, 0=GND) + delay : in std_logic_vector(DELAY_WIDTH-1 downto 0); -- unsigned delay clock count + factor : in std_logic_vector(FACTOR_WIDTH-1 downto 0); -- 1Q3 Fixed Point + -- DEBUG + adc_data1_max : out std_logic_vector(ADC_DATA_WIDTH-1 downto 0); + adc_data2_max : out std_logic_vector(ADC_DATA_WIDTH-1 downto 0); + scaler_max : out std_logic_vector(DAC_DATA_WIDTH-1 downto 0); + dac_max : out std_logic_vector(DAC_DATA_WIDTH-1 downto 0) ); end entity; architecture arch of feedback_loop is --*****SIGNAL DECLARATION***** - signal adc_data1, adc_data2 : std_logic_vector(11 downto 0) := (others => '0'); + signal adc_data1, adc_data2 : std_logic_vector(ADC_DATA_WIDTH-1 downto 0) := (others => '0'); signal adc_done : std_logic := '0'; --*****COMPONENT DECLARATION***** @@ -38,7 +54,7 @@ architecture arch of feedback_loop is generic( TRANSFER_CLK_COUNT : integer := 16; DELAY_CLK_CNT : integer := 2; - DATA_BITS : integer := 12 + DATA_WIDTH : integer := 12 ); port ( sclk : in std_logic; -- PMOD-AD1 @@ -47,8 +63,8 @@ architecture arch of feedback_loop is sdata2 : in std_logic; -- PMOD-AD1 enable : in std_logic; cs_n : out std_logic;-- PMOD-AD1 - data1 : out std_logic_vector(DATA_BITS-1 downto 0); - data2 : out std_logic_vector(DATA_BITS-1 downto 0); + data1 : out std_logic_vector(DATA_WIDTH-1 downto 0); + data2 : out std_logic_vector(DATA_WIDTH-1 downto 0); done : out std_logic ); end component; @@ -56,13 +72,13 @@ architecture arch of feedback_loop is component pmod_da3_ctrl is generic( TRANSFER_CLK_COUNT : integer := 16; - DATA_BITS : integer := 16 + DATA_WIDTH : integer := 16 ); port ( sclk : in std_logic; -- PMOD-DA3 reset : in std_logic; start : in std_logic; - data : in std_logic_vector(DATA_BITS-1 downto 0); + data : in std_logic_vector(DATA_WIDTH-1 downto 0); cs_n : out std_logic;-- PMOD-DA3 sdata : out std_logic;-- PMOD-DA3 ldac : out std_logic;-- PMOD-DA3 @@ -90,12 +106,13 @@ architecture arch of feedback_loop is DATA_WIDTH : integer := 16 ); port ( - clk : std_logic; - reset : std_logic; - mode : std_logic; - A : std_logic_vector(DATA_WIDTH-1 downto 0); - B : std_logic_vector(DATA_WIDTH-1 downto 0); - RES : std_logic_vector(DATA_WIDTH-1 downto 0) + clk : in std_logic; + reset : in std_logic; + mode : in std_logic; + cap : in std_logic; + A : in std_logic_vector(DATA_WIDTH-1 downto 0); + B : in std_logic_vector(DATA_WIDTH-1 downto 0); + RES : out std_logic_vector(DATA_WIDTH-1 downto 0) ); end component; @@ -114,18 +131,19 @@ architecture arch of feedback_loop is end component; --*****SIGNAL DECLARATION***** - signal delay_out, latch_out : std_logic_vector(12 downto 0) := (others => '0'); - signal scaler_out, addsub_out : std_logic_vector(15 downto 0) := (others => '0'); + signal delay_out, latch_out : std_logic_vector(ADC_DATA_WIDTH downto 0) := (others => '0'); + signal scaler_out, addsub_out, dac_max, scaler_max, inputA : std_logic_vector(DAC_DATA_WIDTH-1 downto 0) := (others => '0'); signal scaler_done, addsub_done : std_logic := '0'; + signal adc_data1_max, adc_data2_max : std_logic_vector(ADC_DATA_WIDTH-1 downto 0) := (others => '0'); begin --*****STAGE I***** adc_inst : pmod_ad1_ctrl generic map( - TRANSFER_CLK_COUNT => 16, - DELAY_CLK_CNT => 2, - DATA_BITS => 12 + TRANSFER_CLK_COUNT => ADC_TRANSFER_CLK_COUNT, + DELAY_CLK_CNT => ADC_DELAY_CLK_CNT, + DATA_WIDTH => ADC_DATA_WIDTH ) port map( sclk => clk, @@ -142,9 +160,9 @@ begin --*****STAGE II***** delay_line_inst : delay_line generic map( - DATA_WIDTH => 13, - DELAY_WIDTH => 8, - MAX_DELAY => 200 + DATA_WIDTH => ADC_DATA_WIDTH+1, + DELAY_WIDTH => DELAY_WIDTH, + MAX_DELAY => MAX_DELAY ) port map( clk => clk, @@ -156,13 +174,13 @@ begin --*****STAGE III***** scaler_inst : scaler generic map( - DATA_WIDTH => 12, - FACTOR_WIDTH => 4, + DATA_WIDTH => ADC_DATA_WIDTH, + FACTOR_WIDTH => FACTOR_WIDTH, PIPELINE_STAGES => 1 ) port map( clk => clk, - data_in => delay_out(11 downto 0), + data_in => delay_out(ADC_DATA_WIDTH-1 downto 0), factor => factor, data_out => scaler_out ); @@ -171,9 +189,9 @@ begin begin if (rising_edge(clk)) then if (reset = '1') then - scaler_done <= (others => '0'); + scaler_done <= '0'; else - scaler_done <= delay_out(12); + scaler_done <= delay_out(ADC_DATA_WIDTH); end if; end if; end process; @@ -190,17 +208,28 @@ begin end process; --*****STAGE IV***** + + mux: process(all) + begin + if (input_mux = '1') then + inputA <= latch_out & "0000"; + else + inputA <= (others => '0'); + end if; + end process; + addsub_inst : addsub generic map( PIPELINE_STAGES => 1, - DATA_WIDTH => 16 + DATA_WIDTH => DAC_DATA_WIDTH ) port map( clk => clk, reset => reset, mode => addsub_mode, - A => scaler_out, - B => latch_out & "0000", + cap => input_mux, + A => inputA, + B => scaler_out, RES => addsub_out ); @@ -218,8 +247,8 @@ begin --*****STAGE V***** dac_inst : pmod_da3_ctrl generic map( - TRANSFER_CLK_COUNT => 16, - DATA_BITS => 16 + TRANSFER_CLK_COUNT => DAC_TRANSFER_CLK_COUNT, + DATA_WIDTH => DAC_DATA_WIDTH ) port map( sclk => clk, @@ -232,4 +261,36 @@ begin done => open ); + --*****DEBUG***** + process(clk) + begin + if (rising_edge(clk)) then + if (reset = '1' or reset_debug = '1') then + adc_data1_max <= (others => '0'); + adc_data2_max <= (others => '0'); + dac_max <= (others => '0'); + scaler_max <= (others => '0'); + -- ADC MAX VALUES + elsif (adc_done = '1') then + if (to_integer(unsigned(adc_data1)) >= to_integer(unsigned(adc_data1_max))) then + adc_data1_max <= adc_data1; + elsif (to_integer(unsigned(adc_data2)) >= to_integer(unsigned(adc_data2_max))) then + adc_data2_max <= adc_data2; + end if; + -- DAC MAX VALUES + elsif (addsub_done = '1') then + if (to_integer(unsigned(addsub_out)) >= to_integer(unsigned(dac_max))) then + dac_max <= addsub_out; + end if; + -- SCALER MAX VALUES + elsif (scaler_done = '1') then + if (to_integer(unsigned(scaler_out)) >= to_integer(unsigned(scaler_max))) then + scaler_max <= scaler_out; + end if; + end if; + end if; + end process; + + + end architecture; \ No newline at end of file diff --git a/src/open_loop.vhd b/src/open_loop.vhd index 82c9a68..a7c4235 100644 --- a/src/open_loop.vhd +++ b/src/open_loop.vhd @@ -2,6 +2,8 @@ library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; +use work.typedef_package.all; + entity open_loop is port ( clk : in std_logic; @@ -17,7 +19,7 @@ end entity; architecture arch of open_loop is --*****SIGNAL DECLARATION***** - signal interconnect : std_logic_vector(15 downto 0) := (others => '0'); + signal interconnect : std_logic_vector(DAC_DATA_WIDTH-1 downto 0) := (others => '0'); signal adc_done : std_logic := '0'; --*****COMPONENT DECLARATION***** @@ -25,7 +27,7 @@ architecture arch of open_loop is generic( TRANSFER_CLK_COUNT : integer := 16; DELAY_CLK_CNT : integer := 2; - DATA_BITS : integer := 12 + DATA_WIDTH : integer := 12 ); port ( sclk : in std_logic; -- PMOD-AD1 @@ -34,8 +36,8 @@ architecture arch of open_loop is sdata2 : in std_logic; -- PMOD-AD1 enable : in std_logic; cs_n : out std_logic;-- PMOD-AD1 - data1 : out std_logic_vector(DATA_BITS-1 downto 0); - data2 : out std_logic_vector(DATA_BITS-1 downto 0); + data1 : out std_logic_vector(DATA_WIDTH-1 downto 0); + data2 : out std_logic_vector(DATA_WIDTH-1 downto 0); done : out std_logic ); end component; @@ -43,13 +45,13 @@ architecture arch of open_loop is component pmod_da3_ctrl is generic( TRANSFER_CLK_COUNT : integer := 16; - DATA_BITS : integer := 16 + DATA_WIDTH : integer := 16 ); port ( sclk : in std_logic; -- PMOD-DA3 reset : in std_logic; start : in std_logic; - data : in std_logic_vector(DATA_BITS-1 downto 0); + data : in std_logic_vector(DATA_WIDTH-1 downto 0); cs_n : out std_logic;-- PMOD-DA3 sdata : out std_logic;-- PMOD-DA3 ldac : out std_logic;-- PMOD-DA3 @@ -62,9 +64,9 @@ begin --*****COMPONENT INSTANTIATION***** adc : pmod_ad1_ctrl generic map( - TRANSFER_CLK_COUNT => 16, - DELAY_CLK_CNT => 2, - DATA_BITS => 12 + TRANSFER_CLK_COUNT => ADC_TRANSFER_CLK_COUNT, + DELAY_CLK_CNT => ADC_DELAY_CLK_CNT, + DATA_WIDTH => ADC_DATA_WIDTH ) port map( sclk => clk, @@ -73,15 +75,15 @@ begin sdata2 => '0', enable => '1', cs_n => adc_cs_n, - data1 => interconnect(15 downto 4), + data1 => interconnect(DAC_DATA_WIDTH-1 downto DAC_DATA_WIDTH-ADC_DATA_WIDTH), data2 => open, done => adc_done ); dac : pmod_da3_ctrl generic map( - TRANSFER_CLK_COUNT => 16, - DATA_BITS => 16 + TRANSFER_CLK_COUNT => DAC_TRANSFER_CLK_COUNT, + DATA_WIDTH => DAC_DATA_WIDTH ) port map( sclk => clk, diff --git a/src/pmod_ad1_ctrl.vhd b/src/pmod_ad1_ctrl.vhd index 1bea4a8..e04a348 100644 --- a/src/pmod_ad1_ctrl.vhd +++ b/src/pmod_ad1_ctrl.vhd @@ -14,7 +14,7 @@ entity pmod_ad1_ctrl is generic( TRANSFER_CLK_COUNT : integer := 16; DELAY_CLK_CNT : integer := 2; - DATA_BITS : integer := 12 + DATA_WIDTH : integer := 12 ); port ( sclk : in std_logic; -- PMOD-AD1 @@ -23,8 +23,8 @@ entity pmod_ad1_ctrl is sdata2 : in std_logic; -- PMOD-AD1 enable : in std_logic; cs_n : out std_logic;-- PMOD-AD1 - data1 : out std_logic_vector(DATA_BITS-1 downto 0); - data2 : out std_logic_vector(DATA_BITS-1 downto 0); + data1 : out std_logic_vector(DATA_WIDTH-1 downto 0); + data2 : out std_logic_vector(DATA_WIDTH-1 downto 0); done : out std_logic ); end entity; @@ -35,9 +35,9 @@ architecture arch of pmod_ad1_ctrl is type STAGE_TYPE is (IDLE, TRANSFER, DELAY); --*****SIGNAL DECLARATIONS***** - signal buf1, buf2, buf1_next, buf2_next : std_logic_vector(DATA_BITS-1 downto 0) := (others => '0'); + signal buf1, buf2, buf1_next, buf2_next : std_logic_vector(DATA_WIDTH-1 downto 0) := (others => '0'); signal stage, stage_next : STAGE_TYPE := IDLE; - signal count, count_next : integer range 0 to 16 := 0; + signal count, count_next : integer range 0 to TRANSFER_CLK_COUNT := 0; -- Output Signals signal cs_n_next : std_logic := '1'; signal done_next : std_logic := '0'; @@ -65,8 +65,8 @@ begin -- to shift out the initial zero bits of the tranfer. when TRANSFER => -- Shift Bits into buffer - buf1_next <= buf1(DATA_BITS-2 downto 0) & sdata1; - buf2_next <= buf2(DATA_BITS-2 downto 0) & sdata2; + buf1_next <= buf1(DATA_WIDTH-2 downto 0) & sdata1; + buf2_next <= buf2(DATA_WIDTH-2 downto 0) & sdata2; cs_n_next <= '0'; if (count = TRANSFER_CLK_COUNT) then stage_next <= DELAY; diff --git a/src/pmod_da3_ctrl.vhd b/src/pmod_da3_ctrl.vhd index d322f9c..decf674 100644 --- a/src/pmod_da3_ctrl.vhd +++ b/src/pmod_da3_ctrl.vhd @@ -13,13 +13,13 @@ use ieee.numeric_std.all; entity pmod_da3_ctrl is generic( TRANSFER_CLK_COUNT : integer := 16; - DATA_BITS : integer := 16 + DATA_WIDTH : integer := 16 ); port ( sclk : in std_logic; -- PMOD-DA3 reset : in std_logic; start : in std_logic; - data : in std_logic_vector(DATA_BITS-1 downto 0); + data : in std_logic_vector(DATA_WIDTH-1 downto 0); cs_n : out std_logic;-- PMOD-DA3 sdata : out std_logic;-- PMOD-DA3 ldac : out std_logic;-- PMOD-DA3 @@ -33,9 +33,9 @@ architecture arch of pmod_da3_ctrl is type STAGE_TYPE is (IDLE, TRANSFER); --*****SIGNAL DECLARATIONS***** - signal buf, buf_next : std_logic_vector(DATA_BITS-1 downto 0) := (others => '0'); + signal buf, buf_next : std_logic_vector(DATA_WIDTH-1 downto 0) := (others => '0'); signal stage, stage_next : STAGE_TYPE := IDLE; - signal count, count_next : integer range 0 to 16 := 0; + signal count, count_next : integer range 0 to TRANSFER_CLK_COUNT := 0; -- Output Signals signal cs_n_next : std_logic := '1'; signal sdata_next : std_logic := '0'; @@ -63,13 +63,13 @@ begin cs_n_next <= '0'; count_next <= 1; -- Shift first bit into DAC - buf_next <= data(DATA_BITS-2 downto 0) & '0'; - sdata_next <= data(DATA_BITS-1); + buf_next <= data(DATA_WIDTH-2 downto 0) & '0'; + sdata_next <= data(DATA_WIDTH-1); end if; when TRANSFER => -- Shift Bits into DAC - buf_next <= buf(DATA_BITS-2 downto 0) & '0'; - sdata_next <= buf(DATA_BITS-1); + buf_next <= buf(DATA_WIDTH-2 downto 0) & '0'; + sdata_next <= buf(DATA_WIDTH-1); cs_n_next <= '0'; if (count = TRANSFER_CLK_COUNT) then cs_n_next <= '1'; diff --git a/src/open_loop_tb.vhd b/src/sim/open_loop_tb.vhd similarity index 100% rename from src/open_loop_tb.vhd rename to src/sim/open_loop_tb.vhd diff --git a/src/pmod_ad1_ctrl_tb.vhd b/src/sim/pmod_ad1_ctrl_tb.vhd similarity index 100% rename from src/pmod_ad1_ctrl_tb.vhd rename to src/sim/pmod_ad1_ctrl_tb.vhd diff --git a/src/pmod_da3_ctrl_tb.vhd b/src/sim/pmod_da3_ctrl_tb.vhd similarity index 100% rename from src/pmod_da3_ctrl_tb.vhd rename to src/sim/pmod_da3_ctrl_tb.vhd diff --git a/src/single_port_ram.vhd b/src/single_port_ram.vhd index 85dc69c..e1e4d93 100644 --- a/src/single_port_ram.vhd +++ b/src/single_port_ram.vhd @@ -8,16 +8,15 @@ use xpm.vcomponents.all; entity single_port_ram is generic ( ADDR_WIDTH : integer := 8; - DATA_WIDTH : integer := 12; - MEMORY_DEPTH : integer := 200 + DATA_WIDTH : integer := 12 ); port ( clk : in std_logic; addr : in std_logic_vector(ADDR_WIDTH-1 downto 0); wen : in std_logic; ren : in std_logic; - write_data : in std_logic_vector(DATA_WIDTH-1 downto 0); - read_data : out std_logic_vector(DATA_WIDTH-1 downto 0) + wr_data : in std_logic_vector(DATA_WIDTH-1 downto 0); + rd_data : out std_logic_vector(DATA_WIDTH-1 downto 0) ); end entity; @@ -35,7 +34,7 @@ begin MEMORY_INIT_PARAM => "0", MEMORY_OPTIMIZATION => "true", MEMORY_PRIMITIVE => "auto", - MEMORY_SIZE => DATA_WIDTH*MEMORY_DEPTH, + MEMORY_SIZE => DATA_WIDTH*(2**ADDR_WIDTH), MESSAGE_CONTROL => 0, READ_DATA_WIDTH_A => DATA_WIDTH, READ_LATENCY_A => 1, @@ -48,11 +47,11 @@ begin ) port map ( dbiterra => open, - douta => read_data, + douta => rd_data, sbiterra => open, addra => addr, clka => clk, - dina => write_data, + dina => wr_data, ena => (ren or wen), injectdbiterra => '0', injectsbiterra => '0', diff --git a/src/top.vhd b/src/top.vhd index 9ce3dec..358c4f3 100644 --- a/src/top.vhd +++ b/src/top.vhd @@ -39,7 +39,7 @@ architecture arch of top is ); end component; - --*****DIGNAL DECLARATION***** + --*****SIGNAL DECLARATION***** signal clk_20 : std_logic := '0'; begin diff --git a/src/typedef_package.vhd b/src/typedef_package.vhd new file mode 100644 index 0000000..a129df7 --- /dev/null +++ b/src/typedef_package.vhd @@ -0,0 +1,65 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +package typedef_package is + + --*****CONSTANT DECLARATIONS***** + -- FIXED + constant ADC_DATA_WIDTH : integer := 12;--* + constant DAC_DATA_WIDTH : integer := 16;--* + + --* If these values are changed, the signal mappings in 'xillybus_link' have to be updated. + + constant ADC_TRANSFER_CLK_COUNT : integer := 16; + constant ADC_DELAY_CLK_CNT : integer := 2; + constant DAC_TRANSFER_CLK_COUNT : integer := 16; + + constant MAX_DELAY : integer := 200; + constant DELAY_WIDTH : integer := 8; --at least log2(MAX_DELAY) + constant FACTOR_WIDTH : integer := 4; + + constant TIMESTAMP_WIDTH : integer := 32; + + --XILLYBUS + constant DEBUG_FIFO_DATA_WIDTH : integer := 32; + constant DEBUG_FIFO_DEPTH : integer := 16; + + constant CONFIG_MEM_DATA_WIDTH : integer := 32; + constant CONFIG_DATA_WIDTH : integer := CONFIG_MEM_DATA_WIDTH*2; + constant CONFIG_MEM_ADDR_WIDTH : integer := 15; + + + --***CLOCKGEN SETTINGS*** + --100 MHz IN, 20 MHz OUT + constant CLKFBOUT_MULT : integer := 41; + constant CLKIN1_PERIOD : real := 10.000000; + constant CLKOUT0_DIVIDE : integer := 41; + constant DIVCLK_DIVIDE : integer := 5; + + --TODO: 3-stage sync to delay write-mode 1 clk cycle + + --*****FUNCTION DECLARATIONS***** + function log2c(constant value : in integer) return integer; + +end package; + +package body typedef_package is + + + --*****FUNCTION DEFINITIONS***** + function log2c(constant value : in integer) return integer is + variable ret_value : integer; + variable cur_value : integer; + begin + ret_value := 0; + cur_value := 1; + while cur_value < value loop + ret_value := ret_value + 1; + cur_value := cur_value * 2; + end loop; + return ret_value; + end function log2c; + + +end package body; diff --git a/src/xillybus_link.vhd b/src/xillybus_link.vhd new file mode 100644 index 0000000..4074c40 --- /dev/null +++ b/src/xillybus_link.vhd @@ -0,0 +1,214 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +use work.typedef_package.all; + +-- Xillybus Link +-- This entity is the link between the xillybus IP core, and the rest of the FPGA logic. +-- This entity contains asynchronous FIFOs and RAMs handling the clock domain crossing between +-- the xillybus and the FPGA logic. + +-- The current xillybus IP core is configured for a 32-bit FPGA-to-HOST FIFO used for sending debug +-- stats to the host every "DEBUG_SEND_INTERVAL" clock cycles, and 32-bit HOST-to-FPGA 16-bit address +-- memory for configuration. The 32-bit wide 16-bit address interface is converted into 2 32-bit wide +-- 15-bit address RAMs, effectively increasing the internal config to 64-bits. + +-- NOTE: It has to be made sure that the read and write port to not access the smae address at the same +-- time + +entity xillybus_link is + generic ( + DEBUG_SEND_INTERVAL : integer := 20000000 + ); + port ( + --***XILLYBUS IF*** + xillybus_clk : in std_logic; + -- FIFO + fifo_rd_data : out std_logic_vector(DEBUG_FIFO_DATA_WIDTH-1 downto 0); + fifo_ren : in std_logic; + fifo_empty : out std_logic; + -- RAM + mem_addr : in std_logic_vector(CONFIG_MEM_ADDR_WIDTH downto 0); + mem_wr_data : in std_logic_vector(CONFIG_MEM_DATA_WIDTH-1 downto 0); + mem_wen : in std_logic; + --***FPGA IF*** + fpga_clk : in std_logic; + reset : in std_logic; + -- Dynamic Configuration + config_addr : in std_logic_vector(CONFIG_MEM_ADDR_WIDTH-1 downto 0); + config_ren : in std_logic; + config_data : out std_logic_vector(CONFIG_DATA_WIDTH-1 downto 0); + -- DEBUG + adc_data1_max : in std_logic_vector(ADC_DATA_WIDTH-1 downto 0); + adc_data2_max : in std_logic_vector(ADC_DATA_WIDTH-1 downto 0); + scaler_max : in std_logic_vector(DAC_DATA_WIDTH-1 downto 0); + dac_max : in std_logic_vector(DAC_DATA_WIDTH-1 downto 0) + ); +end entity; + +architecture arch of xillybus_link is + + --*****COMPONENT DECLARATION***** + component dual_port_ram is + generic ( + ADDR_WIDTH : integer := 8; + DATA_WIDTH : integer := 16; + MEMORY_DEPTH : integer := 20 + ); + port ( + wr_clk : in std_logic; + rd_clk : in std_logic; + rd_addr : in std_logic_vector(ADDR_WIDTH-1 downto 0); + wr_addr : in std_logic_vector(ADDR_WIDTH-1 downto 0); + wen : in std_logic; + ren : in std_logic; + wr_data : in std_logic_vector(DATA_WIDTH-1 downto 0); + rd_data : out std_logic_vector(DATA_WIDTH-1 downto 0) + ); + end component; + + component async_fifo is + generic ( + DATA_WIDTH : integer := 32; + FIFO_DEPTH : integer := 16; -- (16 - 4194304) + PROG_EMPTY : integer := 3; -- MIN:3 MAX:(FIFO_DEPTH-3) + PROG_FULL : integer := 13 -- MIN:3+CDC_SYNC_STAGES MAX:(FIFO_DEPTH-3) + ); + port ( + wr_clk : in std_logic; + rd_clk : in std_logic; + reset : in std_logic; --wr_clk synchronous + wen : in std_logic; + ren : in std_logic; + empty : out std_logic; + almost_empty: out std_logic; + prog_empty : out std_logic; + full : out std_logic; + almost_full : out std_logic; + prog_full : out std_logic; + wr_data : in std_logic_vector(DATA_WIDTH-1 downto 0); + rd_data : out std_logic_vector(DATA_WIDTH-1 downto 0) + ); + end component; + + --*****TYPE DEFINITION***** + type STAGE_TYPE is (WAIT_COUNTER, WAIT_FIFO, SEND1, SEND2); + + --*****SIGNAL DEFINITION***** + signal cnt, cnt_next : integer range 0 to DEBUG_SEND_INTERVAL := 0; + signal stage : STAGE_TYPE := WAIT_COUNTER; + signal fifo_almost_full, fifo_wen : std_logic := '0'; + signal fifo_wr_data : std_logic_vector(DEBUG_FIFO_DATA_WIDTH-1 downto 0) := (others => '0'); + +begin + + --*****COMPONENT INSTANTIATION***** + config_mem_high : dual_port_ram + generic map ( + ADDR_WIDTH => CONFIG_MEM_ADDR_WIDTH, + DATA_WIDTH => CONFIG_MEM_DATA_WIDTH + ) + port map ( + wr_clk => xillybus_clk, + rd_clk => fpga_clk, + rd_addr => config_addr, + wr_addr => mem_addr(CONFIG_MEM_ADDR_WIDTH downto 1), + wen => mem_wen and (not mem_addr(0)), -- Only even adresses + ren => config_ren, + wr_data => mem_wr_data, + rd_data => config_data(CONFIG_DATA_WIDTH-1 downto CONFIG_MEM_DATA_WIDTH) + ); + + config_mem_low : dual_port_ram + generic map ( + ADDR_WIDTH => CONFIG_MEM_ADDR_WIDTH, + DATA_WIDTH => CONFIG_MEM_DATA_WIDTH + ) + port map ( + wr_clk => xillybus_clk, + rd_clk => fpga_clk, + rd_addr => config_addr, + wr_addr => mem_addr(CONFIG_MEM_ADDR_WIDTH downto 1), + wen => mem_wen and (mem_addr(0)), -- Only odd adresses + ren => config_ren, + wr_data => mem_wr_data, + rd_data => config_data(CONFIG_MEM_DATA_WIDTH-1 downto 0) + ); + + + debug_fifo : async_fifo + generic map ( + DATA_WIDTH => DEBUG_FIFO_DATA_WIDTH, + FIFO_DEPTH => DEBUG_FIFO_DEPTH + ) + port map( + wr_clk => fpga_clk, + rd_clk => xillybus_clk, + reset => reset, + wen => fifo_wen, + ren => fifo_ren, + empty => fifo_empty, + almost_empty=> open, + prog_empty => open, + full => open, + almost_full => fifo_almost_full, + prog_full => open, + wr_data => fifo_wr_data, + rd_data => fifo_rd_data + ); + + debug_prc : process(all) + begin + -- DEFAULT VALUES + stage_next <= stage; + cnt_next <= cnt; + fifo_wen <= '0'; + fifo_wr_data<= (others => '0'); + + case (stage) + when WAIT_COUNTER => + if(cnt = DEBUG_SEND_INTERVAL) then + if(fifo_almost_full = '1') then + stage_next => WAIT_FIFO; + else + stage_next => SEND1; + end if; + else + cnt_next => cnt + 1; + end if; + when WAIT_FIFO => + if(fifo_almost_full = '0') then + stage_next => SEND1; + end if; + when SEND1 => + fifo_wen <= '1'; + fifo_wr_data(11 downto 0) <= adc_data1_max; + fifo_wr_data(27 downto 16) <= adc_data2_max; + + stage_next <= SEND2; + when SEND2 => + fifo_wen <= '1'; + fifo_wr_data(15 downto 0) <= dac_max; + fifo_wr_data(31 downto 16) <= scaler_max; + + stage_next <= WAIT_COUNTER; + cnt_next <= 0; + end case; + end process; + + + sync : process(fpga_clk) + begin + if rising_edge(fpga_clk) then + if(reset = '1') then + stage <= WAIT_COUNTER; + cnt <= 0; + else + stage <= stage_next; + cnt <= cnt_next; + end if; + end if; + end process; + +end architecture; \ No newline at end of file