diff --git a/sim/rtps_out_test1.do b/sim/rtps_out_test1.do new file mode 100644 index 0000000..0ac6716 --- /dev/null +++ b/sim/rtps_out_test1.do @@ -0,0 +1,50 @@ +onerror {resume} +quietly WaveActivateNextPane {} 0 +add wave -noupdate -divider SYSTEM +add wave -noupdate /rtps_out_test1/uut/clk +add wave -noupdate /rtps_out_test1/uut/reset +add wave -noupdate -divider TESTBENCH +add wave -noupdate /rtps_out_test1/start +add wave -noupdate /rtps_out_test1/packet_sent +add wave -noupdate -divider INPUT +add wave -noupdate -radix hexadecimal /rtps_out_test1/uut/data_in +add wave -noupdate /rtps_out_test1/uut/last_word_in +add wave -noupdate /rtps_out_test1/uut/rd +add wave -noupdate /rtps_out_test1/uut/empty +add wave -noupdate -divider OUTPUT +add wave -noupdate -radix hexadecimal /rtps_out_test1/uut/data_out +add wave -noupdate /rtps_out_test1/uut/wr +add wave -noupdate /rtps_out_test1/uut/full +add wave -noupdate -divider {INPUT FSM} +add wave -noupdate /rtps_out_test1/uut/input_stage +add wave -noupdate /rtps_out_test1/uut/input_stage_next +add wave -noupdate /rtps_out_test1/uut/in_pntr +add wave -noupdate /rtps_out_test1/uut/selector +add wave -noupdate -radix unsigned /rtps_out_test1/uut/length +add wave -noupdate -divider {OUTPUT FSM} +add wave -noupdate /rtps_out_test1/uut/output_stage +add wave -noupdate /rtps_out_test1/uut/output_stage_next +add wave -noupdate /rtps_out_test1/uut/out_pntr +add wave -noupdate -radix unsigned /rtps_out_test1/uut/packet_end +add wave -noupdate -divider MISC +add wave -noupdate /rtps_out_test1/uut/filled +add wave -noupdate /rtps_out_test1/uut/reset_filled +add wave -noupdate /rtps_out_test1/uut/set_filled +TreeUpdate [SetDefaultTree] +WaveRestoreCursors {Error {2175000 ps} 1} {Cursor {12626 ps} 0} +quietly wave cursor active 1 +configure wave -namecolwidth 150 +configure wave -valuecolwidth 100 +configure wave -justifyvalue left +configure wave -signalnamewidth 1 +configure wave -snapdistance 10 +configure wave -datasetprefix 0 +configure wave -rowmargin 4 +configure wave -childrowmargin 2 +configure wave -gridoffset 0 +configure wave -gridperiod 1 +configure wave -griddelta 40 +configure wave -timeline 0 +configure wave -timelineunits ns +update +WaveRestoreZoom {1663 ns} {2687 ns} diff --git a/src/Tests/Level_0/rtps_out_test1.vhd b/src/Tests/Level_0/rtps_out_test1.vhd new file mode 100644 index 0000000..43482df --- /dev/null +++ b/src/Tests/Level_0/rtps_out_test1.vhd @@ -0,0 +1,349 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library osvvm; -- Utility Library +context osvvm.OsvvmContext; + +use work.rtps_package.all; +use work.user_config.all; +use work.rtps_config_package.all; +use work.rtps_test_package.all; + +-- This testbench tests the general behavior of the rtps_out entity. Following 3 tests are done in sequence: +-- TEST 1 +-- Add 2 random sized packets to random input port t1. After t1 is beginning being processed add 2 random sized packets to a random input port t2 that is after the t1 input port, +-- and add 2 random sized packets to a random input port t3 that is before the t1 input port. The packets should come in order : t1p1, t2p1, t3p1, t1p2, t2p2, t3p2. +-- TEST 2 +-- Add 4 packets with sizes 4-Bytes, 3-Bytes, 2-Bytes, and 1-Bytes respectively to the input port t1. Add a maximum size packet at input port t2, and a oversized (over maximum size) +-- at input port t3. The expected order should be: t1p1, t2p1. +-- Note that during the beginning of this test the UUT should be processing input port t3. +-- TEST 3 +-- Add one random sized packet to each available input port. The expected order is: t1+1p1, t1+2p1,...,t1p1. +-- Note that during the beginning of this test the UUT should be processing input port t1. + +entity rtps_out_test1 is +end entity; + +architecture testbench of rtps_out_test1 is + + -- *COMPONENT DECLARATION* + component rtps_out is + generic ( + MAX_BUFFER_SIZE : natural := 65508/4 + ); + port ( + clk : in std_logic; + reset : in std_logic; + data_in : in RTPS_OUT_DATA_TYPE; + last_word_in: in std_logic_vector(0 to NUM_ENDPOINTS); + rd : out std_logic_vector(0 to NUM_ENDPOINTS); + empty : in std_logic_vector(0 to NUM_ENDPOINTS); + data_out : out std_logic_vector(WORD_WIDTH-1 downto 0); + wr : out std_logic; + full : in std_logic + ); + end component; + + -- *CONSTANT DECLARATION* + constant MAX_SIZE : natural := 20; + + -- *TYPE DECLARATION* + type TEST_STAGE_TYPE is (IDLE, BUSY); + type TEST_PACKET_ARRAY_TYPE is array (0 to NUM_ENDPOINTS) of TEST_PACKET_TYPE; + type TEST_STAGE_ARRAY_TYPE is array (0 to NUM_ENDPOINTS) of TEST_STAGE_TYPE; + type CNT_STIM_ARRAY_TYPE is array (0 to NUM_ENDPOINTS) of natural; + + -- *SIGNAL DECLARATION* + signal clk, wr_sig, full : std_logic := '0'; + signal reset : std_logic := '1'; + signal data_out : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0'); + signal data_in : RTPS_OUT_DATA_TYPE := (others => (others => '0')); + signal last_word_in, rd_sig, empty : std_logic_vector(0 to NUM_ENDPOINTS) := (others => '0'); + + signal stim_stage : TEST_STAGE_ARRAY_TYPE := (others => IDLE); + shared variable reference : TEST_PACKET_TYPE := EMPTY_TEST_PACKET; + shared variable stimulus : TEST_PACKET_ARRAY_TYPE := (others => EMPTY_TEST_PACKET); + + signal packet_sent : std_logic_vector(0 to NUM_ENDPOINTS) := (others => '0'); + + signal cnt_stim : CNT_STIM_ARRAY_TYPE := (others => 0); + signal start : std_logic := '0'; + shared variable SB : osvvm.ScoreBoardPkg_slv.ScoreBoardPType; + signal stim_done, check_done : std_logic := '0'; + + -- *FUNCTION DECLARATION* + procedure push_reference(index : in natural; input : in TEST_PACKET_TYPE) is + variable tmp : natural := 0; + variable header_start : natural := 0; + variable packet_start : natural := input.length; + variable len : natural := 0; + begin + for i in 0 to input.length-1 loop + if (tmp = index) then + SB.Push(input.data(i)); + -- Mark End of Header/Start of Packet + + end if; + if (i = header_start and tmp = index) then + packet_start := header_start+3; + end if; + -- Calculate and Push Length + if (i = packet_start-1) then + -- Count until End of Current Packet + loop + len := len + 1; + if (input.last(len-1+packet_start) = '1') then + exit; + end if; + end loop; + SB.Push(std_logic_vector(to_unsigned(len, WORD_WIDTH))); + end if; + if (input.last(i) = '1') then + tmp := tmp + 1; + header_start := i+1; + end if; + end loop; + end procedure; + +begin + + empty <= packet_sent; + + -- Unit Under Test + uut: rtps_out + generic map ( + MAX_BUFFER_SIZE => MAX_SIZE-3 + ) + port map ( + clk => clk, + reset => reset, + data_in => data_in, + last_word_in=> last_word_in, + rd => rd_sig, + empty => empty, + data_out => data_out, + wr => wr_sig, + full => full + ); + + stimulus_prc : process + variable RV : RandomPType; + variable t1, t2, t3 : natural := 0; + variable tmp : std_logic_vector(0 to NUM_ENDPOINTS) := (others => '0'); + + procedure gen_rand_packet(size : in natural; output : inout TEST_PACKET_TYPE) is + variable tmp : natural := 0; + begin + if (size = 0) then + tmp := RV.RandInt(4, MAX_SIZE-1); + else + tmp := size; + end if; + Log("Packet Size: " & to_string(tmp), DEBUG); + + for i in 0 to tmp-1 loop + output.data(output.length) := RV.RandSlv(WORD_WIDTH); + Log("DATA: " & to_hstring(output.data(output.length)), DEBUG); + output.length := output.length + 1; + end loop; + output.last(output.length-1) := '1'; + end procedure; + + procedure start_test is + begin + start <= '1'; + wait until rising_edge(clk); + start <= '0'; + wait until rising_edge(clk); + end procedure; + begin + assert (NUM_ENDPOINTS >= 2) report "Testbench needs at least 2 Endpoints" severity FAILURE; + assert (MAX_SIZE > 4) report "MAX_SIZE has to be larger than 4" severity FAILURE; + + SetAlertLogName("L0-rtps_out"); + SetAlertEnable(FAILURE, TRUE); + SetAlertEnable(ERROR, TRUE); + SetAlertEnable(WARNING, TRUE); + SetLogEnable(DEBUG, FALSE); + SetLogEnable(PASSED, FALSE); + SetLogEnable(INFO, TRUE); + RV.InitSeed(RV'instance_name); + + -- + + Log("Initiating Test", INFO); + stim_done <= '0'; + start <= '0'; + reset <= '1'; + wait until rising_edge(clk); + wait until rising_edge(clk); + reset <= '0'; + + Log("Begin Test 1", INFO); + t1 := RV.RandInt(1, NUM_ENDPOINTS-1); + Log("T1: " & to_string(t1), DEBUG); + t2 := RV.RandInt(t1+1, NUM_ENDPOINTS); + Log("T2: " & to_string(t2), DEBUG); + t3 := RV.RandInt(0, t1-1); + Log("T3: " & to_string(t3), DEBUG); + -- Generate 2 Packets + gen_rand_packet(0, stimulus(t1)); + gen_rand_packet(0, stimulus(t1)); + -- Push T1 Packet 0 + push_reference(0, stimulus(t1)); + start_test; + -- Wait for UUT do reach t1 + wait until rd_sig(t1) = '1'; + -- Generate 2 Packets for T2 and T3 + gen_rand_packet(0, stimulus(t2)); + gen_rand_packet(0, stimulus(t2)); + gen_rand_packet(0, stimulus(t3)); + gen_rand_packet(0, stimulus(t3)); + -- Push T2 Packet 0 + push_reference(0, stimulus(t2)); + -- Push T3 Packet 0 + push_reference(0, stimulus(t3)); + -- Push T1 Packet 1 + push_reference(1, stimulus(t1)); + -- Push T2 Packet 1 + push_reference(1, stimulus(t2)); + -- Push T3 Packet 1 + push_reference(1, stimulus(t3)); + start_test; + -- Wait until begining of t3 sending + tmp := (t3 => '0', others => '1'); + wait on rd_sig until packet_sent = tmp and rd_sig = not tmp; + + -- Reset Input + stimulus := (t3 => stimulus(t3), others => EMPTY_TEST_PACKET); + Log("Begin Test 2", INFO); + -- Min Valid Packet + gen_rand_packet(4, stimulus(t1)); + push_reference(0, stimulus(t1)); + -- MAX Valid Packet + gen_rand_packet(MAX_SIZE, stimulus(t2)); + push_reference(0, stimulus(t2)); + -- Invalid Packet (Over size) + gen_rand_packet(MAX_SIZE+1, stimulus(t3)); + -- Invalid Packet [Packet too small] + gen_rand_packet(3, stimulus(t1)); + gen_rand_packet(2, stimulus(t1)); + gen_rand_packet(1, stimulus(t1)); + start_test; + -- Wait until all but t1 sent + tmp := (t1 => '0', others => '1'); + wait on rd_sig until packet_sent = tmp and rd_sig = not tmp; + + -- reset Input + stimulus := (t1 => stimulus(t1), others => EMPTY_TEST_PACKET); + Log("Begin Test 3", INFO); + for i in 1 to NUM_ENDPOINTS+1 loop + t3 := (t1+i) mod (NUM_ENDPOINTS+1); + Log("Generate package for input port : " & to_string(t3), DEBUG); + gen_rand_packet(0, stimulus(t3)); + if (t3 = t1) then + -- t1 has 4 Packets in Queue + push_reference(4, stimulus(t3)); + else + push_reference(0, stimulus(t3)); + end if; + end loop; + start_test; + -- Wait until all sent + wait on packet_sent until packet_sent(t1) = '1'; + + + TranscriptOpen(RESULTS_FILE, APPEND_MODE); + SetTranscriptMirror; + stim_done <= '1'; + wait until check_done = '1'; + AlertIf(not SB.empty, "Incomplete test run"); + ReportAlerts; + TranscriptClose; + std.env.stop; + wait; + end process; + + clock_prc : process + begin + clk <= '0'; + wait for 25 ns; + clk <= '1'; + wait for 25 ns; + end process; + + endpoint_full_prc : process + begin + full <= '0'; + wait until wr_sig = '1'; + wait until rising_edge(clk); + full <= '1'; + wait until rising_edge(clk); + end process; + + alert_prc : process(all) + begin + if rising_edge(clk) then + alertif((empty and rd_sig) /= (rd_sig'range => '0'), "Input FIFO read signal high while empty signal high", ERROR); + alertif((full and wr_sig) = '1', "Output FIFO write signal high while full signal high", ERROR); + end if; + end process; + + input_prc_gen : for i in 0 to NUM_ENDPOINTS generate + begin + input_prc : process(all) + begin + data_in(i) <= stimulus(i).data(cnt_stim(i)); + last_word_in(i) <= stimulus(i).last(cnt_stim(i)); + + if rising_edge(clk) then + if (reset = '1') then + cnt_stim(i) <= 0; + stim_stage(i) <= IDLE; + packet_sent(i) <= '1'; + else + case (stim_stage(i)) is + when IDLE => + if (start = '1' and stimulus(i).length /= 0) then + stim_stage(i) <= BUSY; + cnt_stim(i) <= 0; + packet_sent(i) <= '0'; + end if; + when BUSY => + if (rd_sig(i) = '1') then + if (cnt_stim(i) = stimulus(i).length-1) then + stim_stage(i) <= IDLE; + packet_sent(i) <= '1'; + else + cnt_stim(i) <= cnt_stim(i) + 1; + end if; + end if; + end case; + end if; + end if; + end process; + end generate; + + + output_check_prc : process(all) + begin + check_done <= '0'; + if rising_edge(clk) then + if (wr_sig = '1') then + SB.Check(data_out); + end if; + if (stim_done = '1' and SB.empty) then + check_done <= '1'; + end if; + end if; + end process; + + watchdog : process + begin + wait for 5 ms; + Alert("Test timeout", FAILURE); + std.env.stop; + end process; + +end architecture; \ No newline at end of file diff --git a/src/Tests/testbench.pro b/src/Tests/testbench.pro index ca9232b..41876f4 100644 --- a/src/Tests/testbench.pro +++ b/src/Tests/testbench.pro @@ -10,6 +10,7 @@ analyze ../rtps_config_package.vhd analyze ../rtps_test_package.vhd analyze ../rtps_handler.vhd analyze ../rtps_builtin_endpoint.vhd +analyze ../rtps_out.vhd analyze Level_0/rtps_handler_test1.vhd analyze Level_0/rtps_handler_test2.vhd analyze test_ram.vhd @@ -20,11 +21,13 @@ analyze Level_0/rtps_builtin_endpoint_test2.vhd analyze Level_0/rtps_builtin_endpoint_test3.vhd analyze Level_0/rtps_builtin_endpoint_test4.vhd analyze Level_0/rtps_builtin_endpoint_test5.vhd +analyze Level_0/rtps_out_test1.vhd #simulate rtps_handler_test1 -simulate rtps_handler_test2 +#simulate rtps_handler_test2 #simulate rtps_builtin_endpoint_test1 #simulate rtps_builtin_endpoint_test2 #simulate rtps_builtin_endpoint_test3 #simulate rtps_builtin_endpoint_test4 -#simulate rtps_builtin_endpoint_test5 \ No newline at end of file +#simulate rtps_builtin_endpoint_test5 +simulate rtps_out_test1 \ No newline at end of file diff --git a/src/rtps_config_package.vhd b/src/rtps_config_package.vhd index 29a8d77..2e01c56 100644 --- a/src/rtps_config_package.vhd +++ b/src/rtps_config_package.vhd @@ -85,6 +85,8 @@ package rtps_config_package is constant READER_DEFAULT_QOS_MATCH : DEFAULT_QOS_MATCH_TYPE; -- Deferred to Package Body constant WRITER_DEFAULT_QOS_MATCH : DEFAULT_QOS_MATCH_TYPE; -- Deferred to Package Body + type RTPS_OUT_DATA_TYPE is array (0 to NUM_ENDPOINTS) of std_logic_vector(WORD_WIDTH-1 downto 0); + -- Swap "data" to Big Endian representation. function endian_swap(swap : std_logic; data : std_logic_vector) return std_logic_vector; function endian_swap(swap : std_logic; data : unsigned) return unsigned; diff --git a/src/rtps_out.vhd b/src/rtps_out.vhd index 19ac969..a974a8b 100644 --- a/src/rtps_out.vhd +++ b/src/rtps_out.vhd @@ -2,29 +2,310 @@ library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; +use work.rtps_package.all; +use work.user_config.all; +use work.rtps_config_package.all; entity rtps_out is generic ( - PIPELINE_STAGES : integer := 1; - DATA_WIDTH : integer := 16 + MAX_BUFFER_SIZE : natural := 65508/4 ); port ( - 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) + clk : in std_logic; + reset : in std_logic; + data_in : in RTPS_OUT_DATA_TYPE; + last_word_in: in std_logic_vector(0 to NUM_ENDPOINTS); + rd : out std_logic_vector(0 to NUM_ENDPOINTS); + empty : in std_logic_vector(0 to NUM_ENDPOINTS); + data_out : out std_logic_vector(WORD_WIDTH-1 downto 0); + wr : out std_logic; + full : in std_logic ); end entity; architecture arch of rtps_out is + -- *TYPE DECLARATION* + type BUFFER_TYPE is array (0 to MAX_BUFFER_SIZE-1) of std_logic_vector(WORD_WIDTH-1 downto 0); + type INPUT_STAGE_TYPE is (IDLE, SRC_ADDR_HEADER, DEST_ADDR_HEADER, PORT_HEADER, READ, SKIP); + type OUTPUT_STAGE_TYPE is (IDLE, SRC_ADDR_HEADER, DEST_ADDR_HEADER, PORT_HEADER, PACKET_LENGTH, WRITE); + + -- *SIGNAL DECLARATION* + signal selector, selector_next : natural range 0 to NUM_ENDPOINTS := 0; + signal buff, buff_next : BUFFER_TYPE := (others => (others => '0')); + signal in_pntr, in_pntr_next : natural range 0 to MAX_BUFFER_SIZE := MAX_BUFFER_SIZE; + signal out_pntr, out_pntr_next : natural range 0 to MAX_BUFFER_SIZE := MAX_BUFFER_SIZE; + signal length, length_next : unsigned(WORD_WIDTH-1 downto 0) := (others => '0'); + signal packet_end, packet_end_next : unsigned(WORD_WIDTH-1 downto 0) := (others => '0'); + signal input_stage, input_stage_next : INPUT_STAGE_TYPE := IDLE; + signal output_stage, output_stage_next : OUTPUT_STAGE_TYPE := IDLE; + signal filled ,reset_filled, set_filled: std_logic := '0'; + signal src_addr, src_addr_next : std_logic_vector(WORD_WIDTH-1 downto 0 ) := (others => '0'); + signal dest_addr, dest_addr_next : std_logic_vector(WORD_WIDTH-1 downto 0 ) := (others => '0'); + signal ports, ports_next : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0'); begin + in_prc : process (all) + begin + -- DEFAULT + input_stage_next <= input_stage; + selector_next <= selector; + in_pntr_next <= in_pntr; + src_addr_next <= src_addr; + dest_addr_next <= dest_addr; + ports_next <= ports; + buff_next <= buff; + length_next <= length; + rd <= (others => '0'); + set_filled <= '0'; + + case (input_stage) is + when IDLE => + -- Currently Selected Input FIFO is empty + if (empty(selector) = '1') then + -- Select next input FIFO + if (selector = NUM_ENDPOINTS) then + selector_next <= 0; + else + selector_next <= selector + 1; + end if; + else + -- Wait until Output Pointer is beyond the Header + if (filled = '0' and out_pntr /= 0) then + -- Read from input FIFO + input_stage_next <= SRC_ADDR_HEADER; + in_pntr_next <= 0; + end if; + end if; + when SRC_ADDR_HEADER => + -- Input FIFO Guard + if (empty(selector) = '0') then + rd(selector) <= '1'; + src_addr_next <= data_in(selector); + input_stage_next<= DEST_ADDR_HEADER; + + -- SANITY CHECK: Skip Packet if last word in before actual packet + if (last_word_in(selector) = '1') then + -- Skip + input_stage_next <= IDLE; + in_pntr_next <= MAX_BUFFER_SIZE; + -- Select next input FIFO + if (selector = NUM_ENDPOINTS) then + selector_next <= 0; + else + selector_next <= selector + 1; + end if; + end if; + end if; + when DEST_ADDR_HEADER => + -- Input FIFO Guard + if (empty(selector) = '0') then + rd(selector) <= '1'; + dest_addr_next <= data_in(selector); + input_stage_next<= PORT_HEADER; + + -- SANITY CHECK: Skip Packet if last word in before actual packet + if (last_word_in(selector) = '1') then + -- Skip + input_stage_next <= IDLE; + in_pntr_next <= MAX_BUFFER_SIZE; + -- Select next input FIFO + if (selector = NUM_ENDPOINTS) then + selector_next <= 0; + else + selector_next <= selector + 1; + end if; + end if; + end if; + when PORT_HEADER => + -- Input FIFO Guard + if (empty(selector) = '0') then + rd(selector) <= '1'; + ports_next <= data_in(selector); + input_stage_next<= READ; + + -- SANITY CHECK: Skip Packet if last word in before actual packet + if (last_word_in(selector) = '1') then + -- Skip + input_stage_next <= IDLE; + in_pntr_next <= MAX_BUFFER_SIZE; + -- Select next input FIFO + if (selector = NUM_ENDPOINTS) then + selector_next <= 0; + else + selector_next <= selector + 1; + end if; + end if; + end if; + when READ => + -- Output pointer past our point (We can safely read into the Buffer) + if (out_pntr > in_pntr) then + -- Input FIFO Guard + if (empty(selector) = '0') then + rd(selector) <= '1'; + buff_next(in_pntr) <= data_in(selector); + in_pntr_next <= in_pntr + 1; + + -- Last Input Word + if (last_word_in(selector) = '1') then + -- Set Length + length_next <= to_unsigned(in_pntr, WORD_WIDTH); + -- Mark Buffer Ready for Output + set_filled <= '1'; + -- DONE + input_stage_next <= IDLE; + in_pntr_next <= MAX_BUFFER_SIZE; + -- Select next input FIFO + if (selector = NUM_ENDPOINTS) then + selector_next <= 0; + else + selector_next <= selector + 1; + end if; + -- Overflow (Packet larger than buffer) + elsif (in_pntr = MAX_BUFFER_SIZE-1) then + -- SKIP PACKET + input_stage_next <= SKIP; + end if; + end if; + end if; + when SKIP => + -- Input FIFO Guard + if (empty(selector) = '0') then + rd(selector) <= '1'; + + -- Last Input Word + if (last_word_in(selector) = '1') then + -- DONE + input_stage_next <= IDLE; + in_pntr_next <= MAX_BUFFER_SIZE; + -- Select next input FIFO + if (selector = NUM_ENDPOINTS) then + selector_next <= 0; + else + selector_next <= selector + 1; + end if; + end if; + end if; + when others => + null; + end case; + end process; + out_prc : process (all) + begin + -- DEFAULT + output_stage_next <= output_stage; + out_pntr_next <= out_pntr; + wr <= '0'; + data_out <= (others => '0'); + packet_end_next <= packet_end; + reset_filled <= '0'; + + case (output_stage) is + when IDLE => + -- Wait until Buffer is Ready + if (filled = '1') then + output_stage_next <= SRC_ADDR_HEADER; + out_pntr_next <= 0; + -- Mark Buffer as being processed + reset_filled <= '1'; + end if; + when SRC_ADDR_HEADER => + -- Output FIFO Guard + if (full = '0') then + wr <= '1'; + data_out <= src_addr; + output_stage_next <= DEST_ADDR_HEADER; + end if; + when DEST_ADDR_HEADER => + -- Output FIFO Guard + if (full = '0') then + wr <= '1'; + data_out <= dest_addr; + output_stage_next <= PORT_HEADER; + end if; + when PORT_HEADER => + -- Output FIFO Guard + if (full = '0') then + wr <= '1'; + data_out <= ports; + output_stage_next <= PACKET_LENGTH; + end if; + when PACKET_LENGTH => + -- Output FIFO Guard + if (full = '0') then + wr <= '1'; + data_out <= std_logic_vector(length + 1); + packet_end_next <= length; + output_stage_next <= WRITE; + end if; + when WRITE => + -- Output FIFO Guard + if (full = '0') then + wr <= '1'; + out_pntr_next <= out_pntr + 1; + data_out <= buff(out_pntr); + + if (out_pntr = packet_end) then + -- DONE + output_stage_next <= IDLE; + out_pntr_next <= MAX_BUFFER_SIZE; + end if; + end if; + when others => + null; + end case; + end process; + + filled_prc : process (all) + begin + if rising_edge(clk) then + if (reset = '1') then + filled <= '0'; + else + -- NOTE: This condition should not be possible due to the additional bound checks of the input and output processes. + assert(not (reset_filled = '1' and set_filled = '1')) report "Both set and reset Flag set on same clock cycle" severity FAILURE; + + if (reset_filled = '1') then + filled <= '0'; + elsif (set_filled = '1') then + filled <= '1'; + end if; + end if; + end if; + end process; + + sync_prc : process(all) + begin + if rising_edge(clk) then + if (reset = '1') then + input_stage <= IDLE; + output_stage <= IDLE; + selector <= 0; + in_pntr <= MAX_BUFFER_SIZE; + out_pntr <= MAX_BUFFER_SIZE; + src_addr <= (others => '0'); + dest_addr <= (others => '0'); + ports <= (others => '0'); + length <= (others => '0'); + packet_end <= (others => '0'); + buff <= (others => (others => '0')); + else + input_stage <= input_stage_next; + output_stage <= output_stage_next; + selector <= selector_next; + in_pntr <= in_pntr_next; + out_pntr <= out_pntr_next; + src_addr <= src_addr_next; + dest_addr <= dest_addr_next; + ports <= ports_next; + length <= length_next; + packet_end <= packet_end_next; + buff <= buff_next; + end if; + end if; + end process; end architecture; \ No newline at end of file