From 2afadcae205c2e3e694614f14a5c8cf7f406ec43 Mon Sep 17 00:00:00 2001 From: donker <donker@astron.nl> Date: Thu, 5 Mar 2020 08:34:56 +0100 Subject: [PATCH] changed eth1g_master, now with state machine. --- .../src/vhdl/unb2b_arp_ping.vhd | 24 +- libraries/io/eth1g/hdllib.cfg | 3 +- libraries/io/eth1g/src/vhdl/eth1g_master.vhd | 618 +++++++++++++++--- libraries/io/eth1g/src/vhdl/eth1g_mem_pkg.vhd | 299 +++++++++ libraries/technology/tse/tech_tse_pkg.vhd | 8 + 5 files changed, 837 insertions(+), 115 deletions(-) create mode 100644 libraries/io/eth1g/src/vhdl/eth1g_mem_pkg.vhd diff --git a/boards/uniboard2b/designs/unb2b_arp_ping/src/vhdl/unb2b_arp_ping.vhd b/boards/uniboard2b/designs/unb2b_arp_ping/src/vhdl/unb2b_arp_ping.vhd index 57923804c9..a4879bc8fa 100644 --- a/boards/uniboard2b/designs/unb2b_arp_ping/src/vhdl/unb2b_arp_ping.vhd +++ b/boards/uniboard2b/designs/unb2b_arp_ping/src/vhdl/unb2b_arp_ping.vhd @@ -48,7 +48,7 @@ ENTITY unb2b_arp_ping IS g_stamp_date : NATURAL := 0; -- Date (YYYYMMDD) -- set by QSF g_stamp_time : NATURAL := 0; -- Time (HHMMSS) -- set by QSF g_revision_id : STRING := ""; -- revision id -- set by QSF - g_factory_image : BOOLEAN := TRUE; + g_factory_image : BOOLEAN := FALSE; --TRUE; g_protect_addr_range: BOOLEAN := FALSE ); PORT ( @@ -138,7 +138,6 @@ ARCHITECTURE str OF unb2b_arp_ping IS SIGNAL eth1g_reg_interrupt : STD_LOGIC; -- Interrupt SIGNAL eth1g_ram_mosi : t_mem_mosi := c_mem_mosi_rst; -- ETH rx frame and tx frame memory SIGNAL eth1g_ram_miso : t_mem_miso; - SIGNAL eth1g_init_done : STD_LOGIC; -- Init done from eth1g_setup -- EPCS read SIGNAL reg_dpmm_data_mosi : t_mem_mosi := c_mem_mosi_rst; @@ -203,7 +202,7 @@ BEGIN g_aux => c_unb2b_board_aux, g_factory_image => g_factory_image, g_udp_offload => g_sim, -- use g_udp_offload to enable ETH instance in simulation - g_udp_offload_nof_streams => 0, -- use g_udp_offload, but no UDP offload streams + g_udp_offload_nof_streams => 3, -- use g_udp_offload, but no UDP offload streams g_protect_addr_range => g_protect_addr_range ) PORT MAP ( @@ -309,20 +308,24 @@ BEGIN ); -- normaly done by unb_os - p_wdi : PROCESS(st_clk) + p_wdi : PROCESS(mm_clk) BEGIN - IF wdi_cnt = 1000 THEN - pout_wdi <= NOT pout_wdi; - wdi_cnt <= 0; - ELSE - wdi_cnt <= wdi_cnt + 1; + IF rising_edge(mm_clk) THEN + IF wdi_cnt = 5000 THEN + pout_wdi <= NOT pout_wdi; + wdi_cnt <= 0; + ELSE + wdi_cnt <= wdi_cnt + 1; + END IF; END IF; END PROCESS; eth1g_mm_rst <= mm_rst; - u_eth1g_master : ENTITY eth1g_lib.eth1g_master + + --u_eth1g_master : ENTITY eth1g_lib.eth1g_master(beh) + u_eth1g_master : ENTITY eth1g_lib.eth1g_master(rtl) PORT MAP ( mm_rst => mm_rst, mm_clk => mm_clk, @@ -339,6 +342,7 @@ BEGIN src_ip => src_ip ); + u_front_led : ENTITY unb2b_board_lib.unb2b_board_qsfp_leds GENERIC MAP ( g_sim => g_sim, diff --git a/libraries/io/eth1g/hdllib.cfg b/libraries/io/eth1g/hdllib.cfg index 0952012130..6f6ca08b3a 100644 --- a/libraries/io/eth1g/hdllib.cfg +++ b/libraries/io/eth1g/hdllib.cfg @@ -1,11 +1,12 @@ hdl_lib_name = eth1g hdl_library_clause_name = eth1g_lib -hdl_lib_uses_synth = dp common eth +hdl_lib_uses_synth = dp common eth tech_tse hdl_lib_uses_sim = hdl_lib_technology = synth_files = src/vhdl/eth1g.vhd + src/vhdl/eth1g_mem_pkg.vhd src/vhdl/eth1g_master.vhd test_bench_files = diff --git a/libraries/io/eth1g/src/vhdl/eth1g_master.vhd b/libraries/io/eth1g/src/vhdl/eth1g_master.vhd index b74d01c6bd..2a4161c63d 100644 --- a/libraries/io/eth1g/src/vhdl/eth1g_master.vhd +++ b/libraries/io/eth1g/src/vhdl/eth1g_master.vhd @@ -22,8 +22,8 @@ -- -- Author: E. Kooistra/ P. Donker -- Purpose: --- 1) Initial setup eth1g via the MM tse and MM reg port --- 2) Loop control eth1g via MM reg port and reg_interrupt to receive and +-- 1) Initial setup eth1g via the MM tse and MM r port +-- 2) Loop control eth1g via MM r port and reg_interrupt to receive and -- transmit packets via the MM ram port. -- Description: -- @@ -33,18 +33,18 @@ LIBRARY IEEE, common_lib, technology_lib, eth_lib, tech_tse_lib; USE IEEE.std_logic_1164.ALL; USE common_lib.common_pkg.ALL; USE common_lib.common_mem_pkg.ALL; -USE common_lib.tb_common_mem_pkg.ALL; +--USE common_lib.tb_common_mem_pkg.ALL; USE common_lib.common_network_layers_pkg.ALL; USE common_lib.common_network_total_header_pkg.ALL; USE tech_tse_lib.tech_tse_pkg.ALL; -USE tech_tse_lib.tb_tech_tse_pkg.ALL; USE eth_lib.eth_pkg.ALL; USE technology_lib.technology_select_pkg.ALL; +USE work.eth1g_mem_pkg.ALL; ENTITY eth1g_master IS --GENERIC ( - -- g_data_type : NATURAL := c_tb_tech_tse_data_type_ping + -- g_data_type : NATURAL := c_tech_tse_data_type_ping --); PORT ( mm_rst : IN STD_LOGIC; @@ -63,19 +63,23 @@ ENTITY eth1g_master IS ); END eth1g_master; - ARCHITECTURE rtl OF eth1g_master IS -- ETH control - CONSTANT c_reply_payload : BOOLEAN := TRUE; -- TRUE copy rx payload into response payload, else header only (e.g. for ARP) + CONSTANT c_reply_payload : BOOLEAN := FALSE; -- TRUE copy rx payload into response payload, else header only (e.g. for ARP) SIGNAL mm_init : STD_LOGIC := '1'; - SIGNAL eth_init : STD_LOGIC := '1'; -- debug signal to view progress in Wave Window - SIGNAL tse_init : STD_LOGIC := '1'; -- debug signal to view progress in Wave Window SIGNAL tse_psc_access : STD_LOGIC := '0'; -- debug signal to view when PSC registers in TSE are accessed -- TSE constants CONSTANT c_promis_en : BOOLEAN := FALSE; -- FALSE receive only frames for this src_mac and broadcast, TRUE receive all + + -- Test bench supported packet data types + CONSTANT c_tb_tech_tse_data_type_symbols : NATURAL := 0; + CONSTANT c_tb_tech_tse_data_type_counter : NATURAL := 1; + CONSTANT c_tb_tech_tse_data_type_arp : NATURAL := 2; + CONSTANT c_tb_tech_tse_data_type_ping : NATURAL := 3; -- over IP/ICMP + CONSTANT c_tb_tech_tse_data_type_udp : NATURAL := 4; -- over IP -- ETH control CONSTANT c_control_rx_en : NATURAL := 2**c_eth_mm_reg_control_bi.rx_en; @@ -87,20 +91,106 @@ ARCHITECTURE rtl OF eth1g_master IS CONSTANT c_udp_port_st2 : NATURAL := 59; -- ETH demux UDP port 2 CONSTANT c_udp_port_en : NATURAL := 16#10000#; -- ETH demux UDP port enable bit 16 + -- used in eth setup SIGNAL src_mac_hi : STD_LOGIC_VECTOR(c_16-1 DOWNTO 0); SIGNAL src_mac_lo : STD_LOGIC_VECTOR(c_32-1 DOWNTO 0); + -- used in tse setup + SIGNAL src_mac_0 : STD_LOGIC_VECTOR(c_32-1 DOWNTO 0); + SIGNAL src_mac_1 : STD_LOGIC_VECTOR(c_16-1 DOWNTO 0); + -- ETH MM registers interface SIGNAL eth_mm_reg_control : t_eth_mm_reg_control; SIGNAL eth_mm_reg_status : t_eth_mm_reg_status; - SIGNAL data_type : NATURAL := c_tb_tech_tse_data_type_ping; + SIGNAL data_type : NATURAL := c_tech_tse_data_type_ping; + + -- State maschine + SIGNAL ctrl_state : NATURAL := 0; + SIGNAL mm_rd_state : NATURAL := 0; + SIGNAL mm_wt_state : NATURAL := 0; + + -- mem mm bus request + SIGNAL mm_rd_request : STD_LOGIC := '0'; + SIGNAL mm_wr_request : STD_LOGIC := '0'; + + TYPE t_state IS (s_rst, + s_wr_demux_0, s_wr_demux_1, s_wr_demux_2, s_rd_demux_0, s_rd_demux_1, s_rd_demux_2, + s_wr_config_0, s_wr_config_1, s_wr_config_2, s_wr_config_3, s_wr_control_0, + s_rd_tse_rev, s_wr_tse_if_mode, s_wr_tse_control, s_wr_tse_promis_en, s_wr_tse_mac_0, s_wr_tse_mac_1, s_wr_tse_tx_ipg_len, s_wr_tse_frm_len, + s_wr_tse_rx_section_empty, s_wr_tse_rx_section_full, s_wr_tse_tx_section_empty, s_wr_tse_tx_section_full, + s_wr_tse_rx_almost_empty, s_wr_tse_rx_almost_full, s_wr_tse_tx_almost_empty, s_wr_tse_tx_almost_full, + s_wait_interrupt_1, s_wait_interrupt_0, s_rd_payload, s_wr_payload, s_wr_control, s_eth_continue); + + TYPE t_reg IS RECORD + -- outputs + tse_mosi : t_mem_mosi; + reg_mosi : t_mem_mosi; + ram_mosi : t_mem_mosi; + --internals + eth_init : STD_LOGIC; + tse_init : STD_LOGIC; + tse_psc_access : STD_LOGIC; -- debug signal to view when PSC registers in TSE are accessed + ram_offset : NATURAL; + state : t_state; + END RECORD t_reg; + + SIGNAL r : t_reg; + SIGNAL nxt_r : t_reg; + + CONSTANT lat_vec_size : NATURAL := 8; + + SIGNAL lat_reg_rd : STD_LOGIC; + SIGNAL lat_reg_vec : STD_LOGIC_VECTOR(0 TO lat_vec_size-1); + SIGNAL reg_rd_valid : STD_LOGIC; + + SIGNAL lat_ram_rd : STD_LOGIC; + SIGNAL lat_ram_vec : STD_LOGIC_VECTOR(0 TO lat_vec_size-1); + SIGNAL ram_rd_valid : STD_LOGIC; + + + -- Write data to the MM bus + PROCEDURE proc_eth1g_mem_mm_bus_wr(CONSTANT wr_addr : IN NATURAL; + CONSTANT wr_data : IN INTEGER; + VARIABLE mm_mosi : OUT t_mem_mosi) IS + BEGIN + mm_mosi.address := TO_MEM_ADDRESS(wr_addr); + mm_mosi.wrdata := TO_MEM_DATA(wr_data); + mm_mosi.wr := '1'; + END proc_eth1g_mem_mm_bus_wr; + + PROCEDURE proc_eth1g_mem_mm_bus_wr(CONSTANT wr_addr : IN NATURAL; + SIGNAL wr_data : IN STD_LOGIC_VECTOR; + VARIABLE mm_mosi : OUT t_mem_mosi) IS + BEGIN + mm_mosi.address := TO_MEM_ADDRESS(wr_addr); + mm_mosi.wrdata := RESIZE_MEM_DATA(wr_data); + mm_mosi.wr := '1'; + END proc_eth1g_mem_mm_bus_wr; + + PROCEDURE proc_eth1g_mem_mm_bus_rd(CONSTANT wr_addr : IN NATURAL; + VARIABLE mm_mosi : OUT t_mem_mosi) IS + BEGIN + mm_mosi.address := TO_MEM_ADDRESS(wr_addr); + mm_mosi.rd := '1'; + END proc_eth1g_mem_mm_bus_rd; + BEGIN + tse_mosi <= r.tse_mosi; + --r.tse_miso <= tse_miso; + reg_mosi <= r.reg_mosi; + --r.reg_miso <= reg_miso; + ram_mosi <= r.ram_mosi; + --r.ram_miso <= ram_miso; + src_mac_hi <= src_mac(c_48-1 DOWNTO c_32); src_mac_lo <= src_mac(c_32-1 DOWNTO 0); + src_mac_0 <= hton(src_mac(c_48-1 DOWNTO c_16), 4); + src_mac_1 <= hton(src_mac(c_16-1 DOWNTO 0), 2); + --p_mm_init : PROCESS(mm_clk) --BEGIN -- IF rising_edge(mm_clk) THEN @@ -111,105 +201,425 @@ BEGIN --END PROCESS; mm_init <= '0' WHEN rising_edge(mm_clk) AND mm_rst='0'; -- concurrent statement is equivalent to commented p_mm_init - p_eth_control : PROCESS + + p_reg : PROCESS (mm_rst, mm_clk) + BEGIN + IF mm_rst = '1' THEN + r <= (c_mem_mosi_rst, c_mem_mosi_rst, c_mem_mosi_rst, '1', '1', '0', 0, s_rst); -- reset all + ELSIF rising_edge(mm_clk) THEN + r <= nxt_r; + END IF; + END PROCESS p_reg; + + + p_rd_latency : PROCESS (mm_rst, mm_clk) + BEGIN + IF mm_rst = '1' THEN + lat_reg_vec <= (OTHERS => '0'); + lat_ram_vec <= (OTHERS => '0'); + lat_reg_rd <= '0'; + lat_ram_rd <= '0'; + ELSIF rising_edge(mm_clk) THEN + IF nxt_r.reg_mosi.rd = '1' THEN lat_reg_rd <= '1'; ELSIF reg_rd_valid = '1' THEN lat_reg_rd <= '0'; END IF; + IF nxt_r.ram_mosi.rd = '1' THEN lat_ram_rd <= '1'; ELSIF ram_rd_valid = '1' THEN lat_ram_rd <= '0'; END IF; + + IF reg_rd_valid = '1' THEN lat_reg_vec <= (OTHERS => '0'); ELSE lat_reg_vec <= lat_reg_rd & lat_reg_vec(0 TO lat_vec_size-2); END IF; + IF ram_rd_valid = '1' THEN lat_ram_vec <= (OTHERS => '0'); ELSE lat_ram_vec <= lat_ram_rd & lat_ram_vec(0 TO lat_vec_size-2); END IF; + END IF; + END PROCESS p_rd_latency; + + reg_rd_valid <= lat_reg_vec(c_mem_reg_rd_latency); + ram_rd_valid <= lat_ram_vec(c_mem_ram_rd_latency); + + + p_comb : PROCESS (r, reg_miso, ram_miso, tse_miso, reg_interrupt, mm_init, reg_rd_valid, ram_rd_valid) + VARIABLE v : t_reg; VARIABLE v_eth_control_word : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); BEGIN - -- Reset only the control signals in the record, to reduce unnecessary logic usage - tse_mosi.wr <= '0'; - tse_mosi.rd <= '0'; - reg_mosi.wr <= '0'; - reg_mosi.rd <= '0'; - --ram_mosi.wr <= '0'; - --ram_mosi.rd <= '0'; - -- Reset entire record to avoid slv to integer conversion warnings on 'X' - --tse_mosi <= c_mem_mosi_rst; - --reg_mosi <= c_mem_mosi_rst; - ram_mosi <= c_mem_mosi_rst; - - -- Wait for mm_rst release, use mm_init as synchronous equivalent of mm_rst - WAIT UNTIL mm_init='0'; + -- default assignment + v := r; + + v.tse_mosi.wr := '0'; + v.tse_mosi.rd := '0'; + v.reg_mosi.wr := '0'; + v.reg_mosi.rd := '0'; + v.ram_mosi.wr := '0'; + v.ram_mosi.rd := '0'; + + CASE r.state IS + WHEN s_rst => + v := (c_mem_mosi_rst, c_mem_mosi_rst, c_mem_mosi_rst, '1', '1', '0', 0, s_rst); -- reset all + IF mm_init = '0' THEN v.state := s_wr_demux_0; + END IF; + + -- -- start eth setup -- -- + WHEN s_wr_demux_0 => proc_eth1g_mem_mm_bus_wr(c_eth_reg_demux_wi+0, c_udp_port_en+c_udp_port_st0, v.reg_mosi); v.state := s_wr_demux_1; + WHEN s_wr_demux_1 => proc_eth1g_mem_mm_bus_wr(c_eth_reg_demux_wi+1, c_udp_port_en+c_udp_port_st1, v.reg_mosi); v.state := s_wr_demux_2; + WHEN s_wr_demux_2 => proc_eth1g_mem_mm_bus_wr(c_eth_reg_demux_wi+2, c_udp_port_en+c_udp_port_st2, v.reg_mosi); v.state := s_rd_demux_0; + WHEN s_rd_demux_0 => -- read back demux_0 settings + IF lat_reg_rd = '0' THEN proc_eth1g_mem_mm_bus_rd(c_eth_reg_demux_wi+0, v.reg_mosi); + ELSIF reg_rd_valid = '1' THEN v.state := s_rd_demux_1; + END IF; + WHEN s_rd_demux_1 => -- read back demux_1 settings + IF lat_reg_rd = '0' THEN proc_eth1g_mem_mm_bus_rd(c_eth_reg_demux_wi+1, v.reg_mosi); + ELSIF reg_rd_valid = '1' THEN v.state := s_rd_demux_2; + END IF; + WHEN s_rd_demux_2 => -- read back demux_2 settings + IF lat_reg_rd = '0' THEN proc_eth1g_mem_mm_bus_rd(c_eth_reg_demux_wi+2, v.reg_mosi); + ELSIF reg_rd_valid = '1' THEN v.state := s_wr_config_0; + END IF; + WHEN s_wr_config_0 => proc_eth1g_mem_mm_bus_wr(c_eth_reg_config_wi+0, src_mac_lo, v.reg_mosi); v.state := s_wr_config_1; + WHEN s_wr_config_1 => proc_eth1g_mem_mm_bus_wr(c_eth_reg_config_wi+1, src_mac_hi, v.reg_mosi); v.state := s_wr_config_2; + WHEN s_wr_config_2 => proc_eth1g_mem_mm_bus_wr(c_eth_reg_config_wi+2, src_ip, v.reg_mosi); v.state := s_wr_config_3; + WHEN s_wr_config_3 => proc_eth1g_mem_mm_bus_wr(c_eth_reg_config_wi+3, c_udp_port_ctrl, v.reg_mosi); v.state := s_wr_control_0; + WHEN s_wr_control_0 => proc_eth1g_mem_mm_bus_wr(c_eth_reg_control_wi+0, c_control_rx_en, v.reg_mosi); v.state := s_rd_tse_rev; + + -- -- start tse setup -- -- + WHEN s_rd_tse_rev => + + v.eth_init := '0'; + v.tse_psc_access := '1'; + proc_eth1g_mem_mm_bus_rd(func_tech_tse_map_pcs_addr(16#22#), v.tse_mosi); -- REV --> 0x0901 + v.state := s_wr_tse_if_mode; + + WHEN s_wr_tse_if_mode => + IF tse_miso.waitrequest = '1' THEN + v.tse_mosi.rd := '1'; + ELSE + proc_eth1g_mem_mm_bus_wr(func_tech_tse_map_pcs_addr(16#28#), 16#0008#, v.tse_mosi); + v.state := s_wr_tse_control; + END IF; + + WHEN s_wr_tse_control => + IF tse_miso.waitrequest = '1' THEN + v.tse_mosi.wr := '1'; + ELSE + proc_eth1g_mem_mm_bus_wr(func_tech_tse_map_pcs_addr(16#00#), 16#0140#, v.tse_mosi); -- PSC control, Auto negotiate disable + --proc_eth1g_mem_mm_bus_wr(func_tech_tse_map_pcs_addr(16#00#), 16#1140#, v.tse_mosi); -- PSC control, Auto negotiate enable + v.state := s_wr_tse_promis_en; + END IF; + + WHEN s_wr_tse_promis_en => + IF tse_miso.waitrequest = '1' THEN + v.tse_mosi.wr := '1'; + ELSE + v.tse_psc_access := '0'; + IF c_promis_en = FALSE THEN proc_eth1g_mem_mm_bus_wr(16#008#, 16#0100004B#, v.tse_mosi); -- MAC control + ELSE proc_eth1g_mem_mm_bus_wr(16#008#, 16#0100005B#, v.tse_mosi); END IF; + v.state := s_wr_tse_mac_0; + END IF; + + WHEN s_wr_tse_mac_0 => + IF tse_miso.waitrequest = '1' THEN + v.tse_mosi.wr := '1'; + ELSE + proc_eth1g_mem_mm_bus_wr(16#00C#, src_mac_0, v.tse_mosi); -- MAC_0 + v.state := s_wr_tse_mac_1; + END IF; + + WHEN s_wr_tse_mac_1 => + IF tse_miso.waitrequest = '1' THEN + v.tse_mosi.wr := '1'; + ELSE + proc_eth1g_mem_mm_bus_wr(16#010#, src_mac_1, v.tse_mosi); -- MAC_1 <-- SRC_MAC + v.state := s_wr_tse_tx_ipg_len; + END IF; + + WHEN s_wr_tse_tx_ipg_len => + IF tse_miso.waitrequest = '1' THEN + v.tse_mosi.wr := '1'; + ELSE + proc_eth1g_mem_mm_bus_wr(16#05C#, 16#0000000C#, v.tse_mosi); -- TX_IPG_LENGTH <-- interpacket gap = 12 + v.state := s_wr_tse_frm_len; + END IF; + + WHEN s_wr_tse_frm_len => + IF tse_miso.waitrequest = '1' THEN + v.tse_mosi.wr := '1'; + ELSE + --proc_eth1g_mem_mm_bus_wr(16#014#, 16#000005EE#, v.tse_mosi); -- FRM_LENGTH <-- receive max frame length = 1518 + proc_eth1g_mem_mm_bus_wr(16#014#, 16#0000233A#, v.tse_mosi); -- FRM_LENGTH <-- receive max frame length = 9018 + v.state := s_wr_tse_rx_section_empty; + END IF; + + WHEN s_wr_tse_rx_section_empty => + IF tse_miso.waitrequest = '1' THEN + v.tse_mosi.wr := '1'; + ELSE + proc_eth1g_mem_mm_bus_wr(16#01C#, c_tech_tse_rx_fifo_depth-16, v.tse_mosi); -- RX_SECTION_EMPTY <-- default FIFO depth - 16, >3 + v.state := s_wr_tse_rx_section_full; + END IF; + + WHEN s_wr_tse_rx_section_full => + IF tse_miso.waitrequest = '1' THEN + v.tse_mosi.wr := '1'; + ELSE + proc_eth1g_mem_mm_bus_wr(16#020#, 16, v.tse_mosi); -- RX_SECTION_FULL <-- default 16 + v.state := s_wr_tse_tx_section_empty; + END IF; + + WHEN s_wr_tse_tx_section_empty => + IF tse_miso.waitrequest = '1' THEN + v.tse_mosi.wr := '1'; + ELSE + proc_eth1g_mem_mm_bus_wr(16#024#, c_tech_tse_tx_fifo_depth-16, v.tse_mosi); -- TX_SECTION_EMPTY <-- default FIFO depth - 16, >3 + v.state := s_wr_tse_tx_section_full; + END IF; + + WHEN s_wr_tse_tx_section_full => + IF tse_miso.waitrequest = '1' THEN + v.tse_mosi.wr := '1'; + ELSE + proc_eth1g_mem_mm_bus_wr(16#028#, 16, v.tse_mosi); -- TX_SECTION_FULL <-- default 16, >~ 8 otherwise no tx + v.state := s_wr_tse_rx_almost_empty; + END IF; + + WHEN s_wr_tse_rx_almost_empty => + IF tse_miso.waitrequest = '1' THEN + v.tse_mosi.wr := '1'; + ELSE + proc_eth1g_mem_mm_bus_wr(16#02C#, 8, v.tse_mosi); -- RX_ALMOST_EMPTY <-- default 8 + v.state := s_wr_tse_rx_almost_full; + END IF; + + WHEN s_wr_tse_rx_almost_full => + IF tse_miso.waitrequest = '1' THEN + v.tse_mosi.wr := '1'; + ELSE + proc_eth1g_mem_mm_bus_wr(16#030#, 8, v.tse_mosi); -- RX_ALMOST_FULL <-- default 8 + v.state := s_wr_tse_tx_almost_empty; + END IF; + + WHEN s_wr_tse_tx_almost_empty => + IF tse_miso.waitrequest = '1' THEN + v.tse_mosi.wr := '1'; + ELSE + proc_eth1g_mem_mm_bus_wr(16#034#, 8, v.tse_mosi); -- TX_ALMOST_EMPTY <-- default 8 + v.state := s_wr_tse_tx_almost_full; + END IF; + + WHEN s_wr_tse_tx_almost_full => + IF tse_miso.waitrequest = '1' THEN + v.tse_mosi.wr := '1'; + ELSE + proc_eth1g_mem_mm_bus_wr(16#038#, c_tech_tse_tx_ready_latency+3, v.tse_mosi); -- TX_ALMOST_FULL <-- default 3 + v.state := s_wait_interrupt_1; v.tse_init := '0'; + END IF; + + -- -- start control loop -- -- + WHEN s_wait_interrupt_1 => + eth_mm_reg_status <= c_eth_mm_reg_status_rst; + eth_mm_reg_control <= c_eth_mm_reg_control_rst; + IF reg_interrupt = '1' THEN + IF lat_reg_rd = '0' THEN proc_eth1g_mem_mm_bus_rd(c_eth_reg_status_wi+0, v.reg_mosi); -- read status register to read the status + ELSIF reg_rd_valid = '1' THEN + eth_mm_reg_status <= func_eth_mm_reg_status(reg_miso.rddata); + proc_eth1g_mem_mm_bus_wr(c_eth_reg_status_wi+0, 0, v.reg_mosi); -- write status register to acknowledge the interrupt + v.state := s_wait_interrupt_0; + END IF; + END IF; + + WHEN s_wait_interrupt_0 => + IF reg_interrupt = '0' THEN + -- prepare control register for response + IF c_reply_payload=TRUE THEN + eth_mm_reg_control.tx_nof_words <= INCR_UVEC(eth_mm_reg_status.rx_nof_words, -1); -- -1 to skip the CRC word for the response + eth_mm_reg_control.tx_empty <= eth_mm_reg_status.rx_empty; + ELSE + eth_mm_reg_control.tx_nof_words <= TO_UVEC(c_network_total_header_32b_nof_words, c_eth_max_frame_nof_words_w); + eth_mm_reg_control.tx_empty <= TO_UVEC(0, c_eth_empty_w); + END IF; + eth_mm_reg_control.tx_en <= '1'; + eth_mm_reg_control.rx_en <= '1'; + + -- TODO: check for data_type + IF c_reply_payload=TRUE THEN + v.ram_offset := func_tech_tse_header_size(data_type); + v.state := s_rd_payload; + ELSE + v.state := s_wr_control; + END IF; + END IF; + + WHEN s_rd_payload => proc_eth1g_mem_mm_bus_rd(c_eth_ram_rx_offset+v.ram_offset, v.ram_mosi); v.state := s_wr_payload; + WHEN s_wr_payload => + IF ram_rd_valid = '1' THEN + proc_eth1g_mem_mm_bus_wr(c_eth_ram_tx_offset+v.ram_offset, TO_SINT(ram_miso.rddata(c_word_w-1 DOWNTO 0)), v.ram_mosi); + v.ram_offset := v.ram_offset + 1; + IF v.ram_offset = TO_UINT(eth_mm_reg_control.tx_nof_words)-1 THEN v.state := s_wr_control; ELSE v.state := s_rd_payload; END IF; + END IF; + + WHEN s_wr_control => + v_eth_control_word := func_eth_mm_reg_control(eth_mm_reg_control); + proc_eth1g_mem_mm_bus_wr(c_eth_reg_control_wi+0, TO_UINT(v_eth_control_word), v.reg_mosi); v.state := s_eth_continue; + WHEN s_eth_continue => proc_eth1g_mem_mm_bus_wr(c_eth_reg_continue_wi, 0, v.reg_mosi); v.state := s_wait_interrupt_1; -- write continue register to make the ETH module continue + WHEN OTHERS => NULL; + END CASE; + + --lat_rd <= v.reg_mosi.rd OR v.ram_mosi.rd; + nxt_r <= v; + + END PROCESS p_comb; + +END; + + +--ARCHITECTURE beh OF eth1g_master IS + +-- -- ETH control +-- CONSTANT c_reply_payload : BOOLEAN := TRUE; -- TRUE copy rx payload into response payload, else header only (e.g. for ARP) + +-- SIGNAL mm_init : STD_LOGIC := '1'; +-- SIGNAL eth_init : STD_LOGIC := '1'; -- debug signal to view progress in Wave Window +-- SIGNAL tse_init : STD_LOGIC := '1'; -- debug signal to view progress in Wave Window +-- SIGNAL tse_psc_access : STD_LOGIC := '0'; -- debug signal to view when PSC registers in TSE are accessed + +-- -- TSE constants +-- CONSTANT c_promis_en : BOOLEAN := FALSE; -- FALSE receive only frames for this src_mac and broadcast, TRUE receive all + +-- -- Test bench supported packet data types +-- CONSTANT c_tb_tech_tse_data_type_symbols : NATURAL := 0; +-- CONSTANT c_tb_tech_tse_data_type_counter : NATURAL := 1; +-- CONSTANT c_tb_tech_tse_data_type_arp : NATURAL := 2; +-- CONSTANT c_tb_tech_tse_data_type_ping : NATURAL := 3; -- over IP/ICMP +-- CONSTANT c_tb_tech_tse_data_type_udp : NATURAL := 4; -- over IP + +-- -- ETH control +-- CONSTANT c_control_rx_en : NATURAL := 2**c_eth_mm_reg_control_bi.rx_en; + +-- -- . UDP header +-- CONSTANT c_udp_port_ctrl : NATURAL := 11; -- ETH demux UDP for control +-- CONSTANT c_udp_port_st0 : NATURAL := 57; -- ETH demux UDP port 0 +-- CONSTANT c_udp_port_st1 : NATURAL := 58; -- ETH demux UDP port 1 +-- CONSTANT c_udp_port_st2 : NATURAL := 59; -- ETH demux UDP port 2 +-- CONSTANT c_udp_port_en : NATURAL := 16#10000#; -- ETH demux UDP port enable bit 16 + +-- SIGNAL src_mac_hi : STD_LOGIC_VECTOR(c_16-1 DOWNTO 0); +-- SIGNAL src_mac_lo : STD_LOGIC_VECTOR(c_32-1 DOWNTO 0); + +-- -- ETH MM registers interface +-- SIGNAL eth_mm_reg_control : t_eth_mm_reg_control; +-- SIGNAL eth_mm_reg_status : t_eth_mm_reg_status; + +-- SIGNAL data_type : NATURAL := c_tb_tech_tse_data_type_ping; + +--BEGIN + +-- src_mac_hi <= src_mac(c_48-1 DOWNTO c_32); +-- src_mac_lo <= src_mac(c_32-1 DOWNTO 0); + +-- --p_mm_init : PROCESS(mm_clk) +-- --BEGIN +-- -- IF rising_edge(mm_clk) THEN +-- -- IF mm_rst='0' THEN +-- -- mm_init <= '0'; +-- -- END IF; +-- -- END IF; +-- --END PROCESS; +-- mm_init <= '0' WHEN rising_edge(mm_clk) AND mm_rst='0'; -- concurrent statement is equivalent to commented p_mm_init + +-- p_eth_control : PROCESS +-- VARIABLE v_eth_control_word : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); +-- BEGIN +-- -- Reset only the control signals in the record, to reduce unnecessary logic usage +-- tse_mosi.wr <= '0'; +-- tse_mosi.rd <= '0'; +-- reg_mosi.wr <= '0'; +-- reg_mosi.rd <= '0'; +-- --ram_mosi.wr <= '0'; +-- --ram_mosi.rd <= '0'; +-- -- Reset entire record to avoid slv to integer conversion warnings on 'X' +-- --tse_mosi <= c_mem_mosi_rst; +-- --reg_mosi <= c_mem_mosi_rst; +-- ram_mosi <= c_mem_mosi_rst; + +-- -- Wait for mm_rst release, use mm_init as synchronous equivalent of mm_rst +-- WAIT UNTIL mm_init='0'; - --------------------------------------------------------------------------- - -- ETH setup - --------------------------------------------------------------------------- +-- --------------------------------------------------------------------------- +-- -- ETH setup +-- --------------------------------------------------------------------------- - -- Setup the DEMUX UDP - proc_mem_mm_bus_wr(c_eth_reg_demux_wi+0, c_udp_port_en+c_udp_port_st0, mm_clk, reg_miso, reg_mosi); -- UDP port stream 0 - proc_mem_mm_bus_wr(c_eth_reg_demux_wi+1, c_udp_port_en+c_udp_port_st1, mm_clk, reg_miso, reg_mosi); -- UDP port stream 1 - proc_mem_mm_bus_wr(c_eth_reg_demux_wi+2, c_udp_port_en+c_udp_port_st2, mm_clk, reg_miso, reg_mosi); -- UDP port stream 2 - proc_mem_mm_bus_rd(c_eth_reg_demux_wi+0, mm_clk, reg_miso, reg_mosi); - proc_mem_mm_bus_rd(c_eth_reg_demux_wi+1, mm_clk, reg_miso, reg_mosi); - proc_mem_mm_bus_rd(c_eth_reg_demux_wi+2, mm_clk, reg_miso, reg_mosi); +-- -- Setup the DEMUX UDP +-- proc_mem_mm_bus_wr(c_eth_reg_demux_wi+0, c_udp_port_en+c_udp_port_st0, mm_clk, reg_miso, reg_mosi); -- UDP port stream 0 +-- proc_mem_mm_bus_wr(c_eth_reg_demux_wi+1, c_udp_port_en+c_udp_port_st1, mm_clk, reg_miso, reg_mosi); -- UDP port stream 1 +-- proc_mem_mm_bus_wr(c_eth_reg_demux_wi+2, c_udp_port_en+c_udp_port_st2, mm_clk, reg_miso, reg_mosi); -- UDP port stream 2 +-- proc_mem_mm_bus_rd(c_eth_reg_demux_wi+0, mm_clk, reg_miso, reg_mosi); +-- proc_mem_mm_bus_rd(c_eth_reg_demux_wi+1, mm_clk, reg_miso, reg_mosi); +-- proc_mem_mm_bus_rd(c_eth_reg_demux_wi+2, mm_clk, reg_miso, reg_mosi); - -- Setup the RX config - proc_mem_mm_bus_wr(c_eth_reg_config_wi+0, src_mac_lo, mm_clk, reg_miso, reg_mosi); -- control MAC address lo word - proc_mem_mm_bus_wr(c_eth_reg_config_wi+1, src_mac_hi, mm_clk, reg_miso, reg_mosi); -- control MAC address hi halfword - proc_mem_mm_bus_wr(c_eth_reg_config_wi+2, src_ip, mm_clk, reg_miso, reg_mosi); -- control IP address - proc_mem_mm_bus_wr(c_eth_reg_config_wi+3, c_udp_port_ctrl, mm_clk, reg_miso, reg_mosi); -- control UDP port +-- -- Setup the RX config +-- proc_mem_mm_bus_wr(c_eth_reg_config_wi+0, src_mac_lo, mm_clk, reg_miso, reg_mosi); -- control MAC address lo word +-- proc_mem_mm_bus_wr(c_eth_reg_config_wi+1, src_mac_hi, mm_clk, reg_miso, reg_mosi); -- control MAC address hi halfword +-- proc_mem_mm_bus_wr(c_eth_reg_config_wi+2, src_ip, mm_clk, reg_miso, reg_mosi); -- control IP address +-- proc_mem_mm_bus_wr(c_eth_reg_config_wi+3, c_udp_port_ctrl, mm_clk, reg_miso, reg_mosi); -- control UDP port - -- Enable RX - proc_mem_mm_bus_wr(c_eth_reg_control_wi+0, c_control_rx_en, mm_clk, reg_miso, reg_mosi); -- control rx en - eth_init <= '0'; - - --------------------------------------------------------------------------- - -- TSE MAC setup - --------------------------------------------------------------------------- - - proc_tech_tse_setup(c_tech_select_default, - c_promis_en, c_tech_tse_tx_fifo_depth, c_tech_tse_rx_fifo_depth, c_tech_tse_tx_ready_latency, - src_mac, tse_psc_access, - mm_clk, tse_miso, tse_mosi); - tse_init <= '0'; - - --------------------------------------------------------------------------- - -- Ethernet Rx and Tx control - --------------------------------------------------------------------------- +-- -- Enable RX +-- proc_mem_mm_bus_wr(c_eth_reg_control_wi+0, c_control_rx_en, mm_clk, reg_miso, reg_mosi); -- control rx en +-- eth_init <= '0'; + +-- --------------------------------------------------------------------------- +-- -- TSE MAC setup +-- --------------------------------------------------------------------------- + +-- --proc_tech_tse_setup(c_tech_select_default, +-- -- c_promis_en, c_tech_tse_tx_fifo_depth, c_tech_tse_rx_fifo_depth, c_tech_tse_tx_ready_latency, +-- -- src_mac, tse_psc_access, +-- -- mm_clk, tse_miso, tse_mosi); + +-- proc_tech_tse_setup(c_promis_en, c_tech_tse_tx_fifo_depth, c_tech_tse_rx_fifo_depth, c_tech_tse_tx_ready_latency, +-- src_mac, tse_psc_access, +-- mm_clk, tse_miso, tse_mosi); +-- tse_init <= '0'; + +-- --------------------------------------------------------------------------- +-- -- Ethernet Rx and Tx control +-- --------------------------------------------------------------------------- - WHILE TRUE LOOP - eth_mm_reg_status <= c_eth_mm_reg_status_rst; - eth_mm_reg_control <= c_eth_mm_reg_control_rst; - -- wait for rx_avail interrupt - IF reg_interrupt='1' THEN - -- read status register to read the status - proc_mem_mm_bus_rd(c_eth_reg_status_wi+0, mm_clk, reg_miso, reg_mosi); -- read result available in eth_mm_reg_status - proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); - eth_mm_reg_status <= func_eth_mm_reg_status(reg_miso.rddata); - WAIT UNTIL rising_edge(mm_clk); - -- write status register to acknowledge the interrupt - proc_mem_mm_bus_wr(c_eth_reg_status_wi+0, 0, mm_clk, reg_miso, reg_mosi); -- void value - -- prepare control register for response - IF c_reply_payload=TRUE THEN - eth_mm_reg_control.tx_nof_words <= INCR_UVEC(eth_mm_reg_status.rx_nof_words, -1); -- -1 to skip the CRC word for the response - eth_mm_reg_control.tx_empty <= eth_mm_reg_status.rx_empty; - ELSE - eth_mm_reg_control.tx_nof_words <= TO_UVEC(c_network_total_header_32b_nof_words, c_eth_max_frame_nof_words_w); - eth_mm_reg_control.tx_empty <= TO_UVEC(0, c_eth_empty_w); - END IF; - eth_mm_reg_control.tx_en <= '1'; - eth_mm_reg_control.rx_en <= '1'; - WAIT UNTIL rising_edge(mm_clk); - -- wait for interrupt removal due to status register read access - WHILE reg_interrupt='1' LOOP WAIT UNTIL rising_edge(mm_clk); END LOOP; - -- write control register to enable tx - IF c_reply_payload=TRUE THEN - -- . copy the received payload to the response payload (overwrite part of the default response header in case of raw ETH) - FOR I IN func_tech_tse_header_size(data_type) TO TO_UINT(eth_mm_reg_control.tx_nof_words)-1 LOOP - proc_mem_mm_bus_rd(c_eth_ram_rx_offset+I, mm_clk, ram_miso, ram_mosi); - proc_mem_mm_bus_rd_latency(c_mem_ram_rd_latency, mm_clk); - proc_mem_mm_bus_wr(c_eth_ram_tx_offset+I, TO_SINT(ram_miso.rddata(c_word_w-1 DOWNTO 0)), mm_clk, ram_miso, ram_mosi); - END LOOP; - --ELSE - -- . only reply header - END IF; - v_eth_control_word := func_eth_mm_reg_control(eth_mm_reg_control); - proc_mem_mm_bus_wr(c_eth_reg_control_wi+0, TO_UINT(v_eth_control_word), mm_clk, reg_miso, reg_mosi); - -- write continue register to make the ETH module continue - proc_mem_mm_bus_wr(c_eth_reg_continue_wi, 0, mm_clk, reg_miso, reg_mosi); -- void value - END IF; - WAIT UNTIL rising_edge(mm_clk); - END LOOP; +-- WHILE TRUE LOOP +-- eth_mm_reg_status <= c_eth_mm_reg_status_rst; +-- eth_mm_reg_control <= c_eth_mm_reg_control_rst; +-- -- wait for rx_avail interrupt +-- IF reg_interrupt='1' THEN +-- -- read status register to read the status +-- proc_mem_mm_bus_rd(c_eth_reg_status_wi+0, mm_clk, reg_miso, reg_mosi); -- read result available in eth_mm_reg_status +-- proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); +-- eth_mm_reg_status <= func_eth_mm_reg_status(reg_miso.rddata); +-- WAIT UNTIL rising_edge(mm_clk); +-- -- write status register to acknowledge the interrupt +-- proc_mem_mm_bus_wr(c_eth_reg_status_wi+0, 0, mm_clk, reg_miso, reg_mosi); -- void value +-- -- prepare control register for response +-- IF c_reply_payload=TRUE THEN +-- eth_mm_reg_control.tx_nof_words <= INCR_UVEC(eth_mm_reg_status.rx_nof_words, -1); -- -1 to skip the CRC word for the response +-- eth_mm_reg_control.tx_empty <= eth_mm_reg_status.rx_empty; +-- ELSE +-- eth_mm_reg_control.tx_nof_words <= TO_UVEC(c_network_total_header_32b_nof_words, c_eth_max_frame_nof_words_w); +-- eth_mm_reg_control.tx_empty <= TO_UVEC(0, c_eth_empty_w); +-- END IF; +-- eth_mm_reg_control.tx_en <= '1'; +-- eth_mm_reg_control.rx_en <= '1'; +-- WAIT UNTIL rising_edge(mm_clk); +-- -- wait for interrupt removal due to status register read access +-- WHILE reg_interrupt='1' LOOP WAIT UNTIL rising_edge(mm_clk); END LOOP; +-- -- write control register to enable tx +-- IF c_reply_payload=TRUE THEN +-- -- . copy the received payload to the response payload (overwrite part of the default response header in case of raw ETH) +-- FOR I IN func_tech_tse_header_size(data_type) TO TO_UINT(eth_mm_reg_control.tx_nof_words)-1 LOOP +-- proc_mem_mm_bus_rd(c_eth_ram_rx_offset+I, mm_clk, ram_miso, ram_mosi); +-- proc_mem_mm_bus_rd_latency(c_mem_ram_rd_latency, mm_clk); +-- proc_mem_mm_bus_wr(c_eth_ram_tx_offset+I, TO_SINT(ram_miso.rddata(c_word_w-1 DOWNTO 0)), mm_clk, ram_miso, ram_mosi); +-- END LOOP; +-- --ELSE +-- -- . only reply header +-- END IF; +-- v_eth_control_word := func_eth_mm_reg_control(eth_mm_reg_control); +-- proc_mem_mm_bus_wr(c_eth_reg_control_wi+0, TO_UINT(v_eth_control_word), mm_clk, reg_miso, reg_mosi); +-- -- write continue register to make the ETH module continue +-- proc_mem_mm_bus_wr(c_eth_reg_continue_wi, 0, mm_clk, reg_miso, reg_mosi); -- void value +-- END IF; +-- WAIT UNTIL rising_edge(mm_clk); +-- END LOOP; - WAIT; - END PROCESS; - -END; \ No newline at end of file +-- WAIT; +-- END PROCESS; +--END; diff --git a/libraries/io/eth1g/src/vhdl/eth1g_mem_pkg.vhd b/libraries/io/eth1g/src/vhdl/eth1g_mem_pkg.vhd new file mode 100644 index 0000000000..2761578704 --- /dev/null +++ b/libraries/io/eth1g/src/vhdl/eth1g_mem_pkg.vhd @@ -0,0 +1,299 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2020 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +-- +-- Author: - +-- Purpose: +-- 1) Initial setup eth1g via the MM tse and MM reg port +-- 2) Loop control eth1g via MM reg port and reg_interrupt to receive and +-- transmit packets via the MM ram port. +-- Description: +-- +------------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib, tech_tse_lib; +USE IEEE.std_logic_1164.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE common_lib.common_network_layers_pkg.ALL; +USE common_lib.common_network_total_header_pkg.ALL; +USE tech_tse_lib.tech_tse_pkg.ALL; + + +PACKAGE eth1g_mem_pkg IS + ------------------------------------------------------------------------------ + -- MM bus access functions + ------------------------------------------------------------------------------ + + -- The mm_miso input needs to be declared as signal, because otherwise the + -- procedure does not notice a change (also not when the mm_clk is declared + -- as signal). + + -- Write data to the MM bus + PROCEDURE proc_mem_mm_bus_wr(CONSTANT wr_addr : IN NATURAL; -- [31:0] + CONSTANT wr_data : IN INTEGER; -- [31:0] + SIGNAL mm_clk : IN STD_LOGIC; + SIGNAL mm_miso : IN t_mem_miso; -- used for waitrequest + SIGNAL mm_mosi : OUT t_mem_mosi); + + PROCEDURE proc_mem_mm_bus_wr(CONSTANT wr_addr : IN INTEGER; -- [31:0] + SIGNAL wr_data : IN STD_LOGIC_VECTOR; -- [31:0] + SIGNAL mm_clk : IN STD_LOGIC; + SIGNAL mm_miso : IN t_mem_miso; -- used for waitrequest + SIGNAL mm_mosi : OUT t_mem_mosi); + + -- Read data request to the MM bus + PROCEDURE proc_mem_mm_bus_rd(CONSTANT rd_addr : IN NATURAL; -- [31:0] + SIGNAL mm_clk : IN STD_LOGIC; + SIGNAL mm_miso : IN t_mem_miso; -- used for waitrequest + SIGNAL mm_mosi : OUT t_mem_mosi); + + -- Wait for read data valid after read latency mm_clk cycles + PROCEDURE proc_mem_mm_bus_rd_latency(CONSTANT c_rd_latency : IN NATURAL; + SIGNAL mm_clk : IN STD_LOGIC); + +-- supported packet data types + CONSTANT c_tech_tse_data_type_symbols : NATURAL := 0; + CONSTANT c_tech_tse_data_type_counter : NATURAL := 1; + CONSTANT c_tech_tse_data_type_arp : NATURAL := 2; + CONSTANT c_tech_tse_data_type_ping : NATURAL := 3; -- over IP/ICMP + CONSTANT c_tech_tse_data_type_udp : NATURAL := 4; -- over IP + + FUNCTION func_tech_tse_header_size(data_type : NATURAL) RETURN NATURAL; -- raw ethernet: 4 header words, protocol ethernet: 11 header words + + -- Configure the TSE MAC + PROCEDURE proc_tech_tse_setup(CONSTANT c_promis_en : IN BOOLEAN; + CONSTANT c_tse_tx_fifo_depth : IN NATURAL; + CONSTANT c_tse_rx_fifo_depth : IN NATURAL; + CONSTANT c_tx_ready_latency : IN NATURAL; + CONSTANT src_mac : IN STD_LOGIC_VECTOR(c_network_eth_mac_slv'RANGE); + SIGNAL psc_access : OUT STD_LOGIC; + SIGNAL mm_clk : IN STD_LOGIC; + SIGNAL mm_miso : IN t_mem_miso; + SIGNAL mm_mosi : OUT t_mem_mosi); + +END eth1g_mem_pkg; + + +PACKAGE BODY eth1g_mem_pkg IS + ------------------------------------------------------------------------------ + -- Private functions + ------------------------------------------------------------------------------ + + -- Issues a rd or a wr MM access + PROCEDURE proc_mm_access(SIGNAL mm_clk : IN STD_LOGIC; + SIGNAL mm_access : OUT STD_LOGIC) IS + BEGIN + mm_access <= '1'; + IF rising_edge(mm_clk) THEN + mm_access <= '0'; + END IF; + END proc_mm_access; + + + -- Issues a rd or a wr MM access and wait for it to have finished + PROCEDURE proc_mm_access(SIGNAL mm_clk : IN STD_LOGIC; + SIGNAL mm_waitreq : IN STD_LOGIC; + SIGNAL mm_access : OUT STD_LOGIC) IS + BEGIN + mm_access <= '1'; + WAIT UNTIL rising_edge(mm_clk); + WHILE mm_waitreq='1' LOOP + WAIT UNTIL rising_edge(mm_clk); + END LOOP; + mm_access <= '0'; + + END proc_mm_access; + + + FUNCTION func_map_pcs_addr(pcs_addr : NATURAL) RETURN NATURAL IS + BEGIN + RETURN pcs_addr * 2 + c_tech_tse_byte_addr_pcs_offset; + END func_map_pcs_addr; + + ------------------------------------------------------------------------------ + -- Public functions + ------------------------------------------------------------------------------ + + -- Write data to the MM bus + PROCEDURE proc_mem_mm_bus_wr(CONSTANT wr_addr : IN NATURAL; + CONSTANT wr_data : IN INTEGER; + SIGNAL mm_clk : IN STD_LOGIC; + SIGNAL mm_miso : IN t_mem_miso; + SIGNAL mm_mosi : OUT t_mem_mosi) IS + BEGIN + mm_mosi.address <= TO_MEM_ADDRESS(wr_addr); + mm_mosi.wrdata <= TO_MEM_DATA(wr_data); + proc_mm_access(mm_clk, mm_miso.waitrequest, mm_mosi.wr); + + END proc_mem_mm_bus_wr; + + + PROCEDURE proc_mem_mm_bus_wr(CONSTANT wr_addr : IN INTEGER; + SIGNAL wr_data : IN STD_LOGIC_VECTOR; + SIGNAL mm_clk : IN STD_LOGIC; + SIGNAL mm_miso : IN t_mem_miso; + SIGNAL mm_mosi : OUT t_mem_mosi) IS + BEGIN + mm_mosi.address <= TO_MEM_ADDRESS(wr_addr); + mm_mosi.wrdata <= RESIZE_MEM_DATA(wr_data); + proc_mm_access(mm_clk, mm_miso.waitrequest, mm_mosi.wr); + END proc_mem_mm_bus_wr; + + + -- Read data request to the MM bus + -- Use proc_mem_mm_bus_rd_latency() to wait for the MM MISO rd_data signal + -- to show the data after some read latency + PROCEDURE proc_mem_mm_bus_rd(CONSTANT rd_addr : IN NATURAL; + SIGNAL mm_clk : IN STD_LOGIC; + SIGNAL mm_miso : IN t_mem_miso; + SIGNAL mm_mosi : OUT t_mem_mosi) IS + BEGIN + mm_mosi.address <= TO_MEM_ADDRESS(rd_addr); + mm_mosi.rd <= '1'; + proc_mm_access(mm_clk, mm_miso.waitrequest, mm_mosi.rd); + mm_mosi.rd <= '0'; + END proc_mem_mm_bus_rd; + + + -- Wait for read data valid after read latency mm_clk cycles + -- Directly assign mm_miso.rddata to capture the read data + PROCEDURE proc_mem_mm_bus_rd_latency(CONSTANT c_rd_latency : IN NATURAL; + SIGNAL mm_clk : IN STD_LOGIC) IS + BEGIN + FOR I IN 0 TO c_rd_latency-1 LOOP WAIT UNTIL rising_edge(mm_clk); END LOOP; + END proc_mem_mm_bus_rd_latency; + + + FUNCTION func_tech_tse_header_size(data_type : NATURAL) RETURN NATURAL IS + BEGIN + CASE data_type IS + WHEN c_tech_tse_data_type_symbols => RETURN c_network_total_header_32b_eth_nof_words; + WHEN c_tech_tse_data_type_counter => RETURN c_network_total_header_32b_eth_nof_words; + WHEN OTHERS => NULL; + END CASE; + RETURN c_network_total_header_32b_nof_words; + END func_tech_tse_header_size; + + + -- . The src_mac[47:0] = 0x123456789ABC for MAC address 12-34-56-78-9A-BC + PROCEDURE proc_tech_tse_setup(CONSTANT c_promis_en : IN BOOLEAN; + CONSTANT c_tse_tx_fifo_depth : IN NATURAL; + CONSTANT c_tse_rx_fifo_depth : IN NATURAL; + CONSTANT c_tx_ready_latency : IN NATURAL; + CONSTANT src_mac : IN STD_LOGIC_VECTOR(c_network_eth_mac_slv'RANGE); + SIGNAL psc_access : OUT STD_LOGIC; + SIGNAL mm_clk : IN STD_LOGIC; + SIGNAL mm_miso : IN t_mem_miso; + SIGNAL mm_mosi : OUT t_mem_mosi) IS + CONSTANT c_mac0 : INTEGER := TO_SINT(hton(src_mac(47 DOWNTO 16), 4)); + CONSTANT c_mac1 : INTEGER := TO_SINT(hton(src_mac(15 DOWNTO 0), 2)); + BEGIN + -- PSC control + psc_access <= '1'; + proc_mem_mm_bus_rd(func_map_pcs_addr(16#22#), mm_clk, mm_miso, mm_mosi); -- REV --> 0x0901 + proc_mem_mm_bus_wr(func_map_pcs_addr(16#28#), 16#0008#, mm_clk, mm_miso, mm_mosi); -- IF_MODE <-- Force 1GbE, no autonegatiation + proc_mem_mm_bus_rd(func_map_pcs_addr(16#00#), mm_clk, mm_miso, mm_mosi); -- CONTROL --> 0x1140 + proc_mem_mm_bus_rd(func_map_pcs_addr(16#02#), mm_clk, mm_miso, mm_mosi); -- STATUS --> 0x000D + proc_mem_mm_bus_wr(func_map_pcs_addr(16#00#), 16#0140#, mm_clk, mm_miso, mm_mosi); -- CONTROL <-- Auto negotiate disable + --proc_mem_mm_bus_wr(func_map_pcs_addr(16#00#), 16#1140#, mm_clk, mm_miso, mm_mosi); -- CONTROL <-- Auto negotiate enable + psc_access <= '0'; + + -- MAC control + proc_mem_mm_bus_rd(16#000#, mm_clk, mm_miso, mm_mosi); -- REV --> CUST_VERSION & 0x0901 + IF c_promis_en=FALSE THEN + proc_mem_mm_bus_wr(16#008#, 16#0100004B#, mm_clk, mm_miso, mm_mosi); + ELSE + proc_mem_mm_bus_wr(16#008#, 16#0100005B#, mm_clk, mm_miso, mm_mosi); + END IF; + -- COMMAND_CONFIG <-- + -- Only the bits relevant to UniBoard are explained here, others are 0 + -- [ 0] = TX_ENA = 1, enable tx datapath + -- [ 1] = RX_ENA = 1, enable rx datapath + -- [ 2] = XON_GEN = 0 + -- [ 3] = ETH_SPEED = 1, enable 1GbE operation + -- [ 4] = PROMIS_EN = 0, when 1 then receive all frames + -- [ 5] = PAD_EN = 0, when 1 enable receive padding removal (requires ethertype=payload length) + -- [ 6] = CRC_FWD = 1, enable receive CRC forward + -- [ 7] = PAUSE_FWD = 0 + -- [ 8] = PAUSE_IGNORE = 0 + -- [ 9] = TX_ADDR_INS = 0, when 1 then MAX overwrites tx SRC MAC with mac_0,1 or one of the supplemental mac + -- [ 10] = HD_ENA = 0 + -- [ 11] = EXCESS_COL = 0 + -- [ 12] = LATE_COL = 0 + -- [ 13] = SW_RESET = 0, when 1 MAC disables tx and rx, clear statistics and flushes receive FIFO + -- [ 14] = MHAS_SEL = 0, select multicast address resolutions hash-code mode + -- [ 15] = LOOP_ENA = 0 + -- [18-16] = TX_ADDR_SEL[2:0] = 000, TX_ADDR_INS insert mac_0,1 or one of the supplemental mac + -- [ 19] = MAGIC_EN = 0 + -- [ 20] = SLEEP = 0 + -- [ 21] = WAKEUP = 0 + -- [ 22] = XOFF_GEN = 0 + -- [ 23] = CNT_FRM_ENA = 0 + -- [ 24] = NO_LGTH_CHECK = 1, when 0 then check payload length of received frames (requires ethertype=payload length) + -- [ 25] = ENA_10 = 0 + -- [ 26] = RX_ERR_DISC = 0, when 1 then discard erroneous frames (requires store and forward mode, so rx_section_full=0) + -- when 0 then pass on with rx_err[0]=1 + -- [ 27] = DISABLE_RD_TIMEOUT = 0 + -- [30-28] = RSVD = 000 + -- [ 31] = CNT_RESET = 0, when 1 clear statistics + proc_mem_mm_bus_wr(16#00C#, c_mac0, mm_clk, mm_miso, mm_mosi); -- MAC_0 + proc_mem_mm_bus_wr(16#010#, c_mac1, mm_clk, mm_miso, mm_mosi); -- MAC_1 <-- SRC_MAC = 12-34-56-78-9A-BC + proc_mem_mm_bus_wr(16#05C#, 16#0000000C#, mm_clk, mm_miso, mm_mosi); -- TX_IPG_LENGTH <-- interpacket gap = 12 + --proc_mem_mm_bus_wr(16#014#, 16#000005EE#, mm_clk, mm_miso, mm_mosi); -- FRM_LENGTH <-- receive max frame length = 1518 + proc_mem_mm_bus_wr(16#014#, 16#0000233A#, mm_clk, mm_miso, mm_mosi); -- FRM_LENGTH <-- receive max frame length = 9018 + + -- FIFO legenda: + -- . Tx section full = There is enough data in the FIFO to start reading it, when 0 then store and forward. + -- . Rx section full = There is enough data in the FIFO to start reading it, when 0 then store and forward. + -- . Tx section empty = There is not much empty space anymore in the FIFO, warn user via ff_tx_septy + -- . Rx section empty = There is not much empty space anymore in the FIFO, inform remote device via XOFF flow control + -- . Tx almost full = Assert ff_tx_a_full and deassert ff_tx_rdy. Furthermore TX_ALMOST_FULL = c_tx_ready_latency+3, + -- so choose 3 for zero tx ready latency + -- . Rx almost full = Assert ff_rx_a_full and if the user is not ready ff_rx_rdy then: + -- --> break off the reception with an error to avoid FIFO overflow + -- . Tx almost empty = Assert ff_tx_a_empty and if the FIFO does not contain a eop yet then: + -- --> break off the transmission with an error to avoid FIFO underflow + -- . Rx almost empty = Assert ff_rx_a_empty + -- Typical FIFO values: + -- . TX_SECTION_FULL = 16 > 8 = TX_ALMOST_EMPTY + -- . RX_SECTION_FULL = 16 > 8 = RX_ALMOST_EMPTY + -- . TX_SECTION_EMPTY = D-16 < D-3 = Tx FIFO depth - TX_ALMOST_FULL + -- . RX_SECTION_EMPTY = D-16 < D-8 = Rx FIFO depth - RX_ALMOST_FULL + -- . c_tse_tx_fifo_depth = 1 M9K = 256*32b = 1k * 8b is sufficient when the Tx user respects ff_tx_rdy, to store a complete + -- ETH packet would require 1518 byte, so 2 M9K = 2k * 8b + -- . c_tse_rx_fifo_depth = 1 M9K = 256*32b = 1k * 8b is sufficient when the Rx user ff_rx_rdy is sufficiently active + proc_mem_mm_bus_wr(16#01C#, c_tse_rx_fifo_depth-16, mm_clk, mm_miso, mm_mosi); -- RX_SECTION_EMPTY <-- default FIFO depth - 16, >3 + proc_mem_mm_bus_wr(16#020#, 16, mm_clk, mm_miso, mm_mosi); -- RX_SECTION_FULL <-- default 16 + proc_mem_mm_bus_wr(16#024#, c_tse_tx_fifo_depth-16, mm_clk, mm_miso, mm_mosi); -- TX_SECTION_EMPTY <-- default FIFO depth - 16, >3 + proc_mem_mm_bus_wr(16#028#, 16, mm_clk, mm_miso, mm_mosi); -- TX_SECTION_FULL <-- default 16, >~ 8 otherwise no tx + proc_mem_mm_bus_wr(16#02C#, 8, mm_clk, mm_miso, mm_mosi); -- RX_ALMOST_EMPTY <-- default 8 + proc_mem_mm_bus_wr(16#030#, 8, mm_clk, mm_miso, mm_mosi); -- RX_ALMOST_FULL <-- default 8 + proc_mem_mm_bus_wr(16#034#, 8, mm_clk, mm_miso, mm_mosi); -- TX_ALMOST_EMPTY <-- default 8 + proc_mem_mm_bus_wr(16#038#, c_tx_ready_latency+3, mm_clk, mm_miso, mm_mosi); -- TX_ALMOST_FULL <-- default 3 + + proc_mem_mm_bus_rd(16#0E8#, mm_clk, mm_miso, mm_mosi); -- TX_CMD_STAT --> 0x00040000 : [18]=1 TX_SHIFT16, [17]=0 OMIT_CRC + proc_mem_mm_bus_rd(16#0EC#, mm_clk, mm_miso, mm_mosi); -- RX_CMD_STAT --> 0x02000000 : [25]=1 RX_SHIFT16 + + WAIT UNTIL rising_edge(mm_clk); + END proc_tech_tse_setup; + +END eth1g_mem_pkg; \ No newline at end of file diff --git a/libraries/technology/tse/tech_tse_pkg.vhd b/libraries/technology/tse/tech_tse_pkg.vhd index 030e0ea9f5..603b85d225 100644 --- a/libraries/technology/tse/tech_tse_pkg.vhd +++ b/libraries/technology/tse/tech_tse_pkg.vhd @@ -82,8 +82,16 @@ PACKAGE tech_tse_pkg IS col : STD_LOGIC; END RECORD; + FUNCTION func_tech_tse_map_pcs_addr(pcs_addr : NATURAL) RETURN NATURAL; + END tech_tse_pkg; PACKAGE BODY tech_tse_pkg IS + +FUNCTION func_tech_tse_map_pcs_addr(pcs_addr : NATURAL) RETURN NATURAL IS +BEGIN + RETURN pcs_addr * 2 + c_tech_tse_byte_addr_pcs_offset; +END func_tech_tse_map_pcs_addr; + END tech_tse_pkg; -- GitLab