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