diff --git a/modules/wrsw_txtsu/Manifest.py b/modules/wrsw_txtsu/Manifest.py new file mode 100644 index 0000000000000000000000000000000000000000..4fd0e54eb661c418142977533abcc49beab0773a --- /dev/null +++ b/modules/wrsw_txtsu/Manifest.py @@ -0,0 +1,3 @@ +files = ["xwrsw_txtsu.vhd", + "wrsw_txtsu_wb.vhd", + "wrsw_txtsu_pkg.vhd"] diff --git a/modules/wrsw_txtsu/wrsw_txtsu.wb b/modules/wrsw_txtsu/wrsw_txtsu.wb new file mode 100644 index 0000000000000000000000000000000000000000..a9587a84e9993973fe7c88dd4f859387380da4c6 --- /dev/null +++ b/modules/wrsw_txtsu/wrsw_txtsu.wb @@ -0,0 +1,72 @@ +-- -*- Mode: LUA; tab-width: 2 -*- + +peripheral { + name = "Shared TX Timestamping Unit (TXTSU)"; + prefix="txtsu"; + + hdl_entity="wrsw_txtsu_wb"; + +-- TXTSU shared FIFO + + fifo_reg { + size = 256; -- or more. We'll see :) + direction = CORE_TO_BUS; + prefix = "tsf"; + name = "Timestamp FIFO"; + description = "This FIFO holds the TX packet timestamps gathered from all switch endpoints. Each entry contains a single timestamp value consisting of 2 numbers:\ + - VAL_R - the timestamp taken at rising clock edge. This is the main timestamp value\ + - VAL_F - few LSBs of timestamp taken at falling clock edge. It's used in conjunction with VAL_R to determine if the timestamp has been taken\ + properly (there was no metastability/setup/hold violation)\ + Entries also contain information required to identify the endpoint and frame for which the timestamp was taken:\ + - FID - Frame identifier assigned by the NIC\ + - PID - TXTSU port ID to which came the timestamp. Used to distinguish the timestamps for broadcast/multicast frames"; + + flags_bus = {FIFO_FULL, FIFO_EMPTY, FIFO_COUNT}; + flags_dev = {FIFO_FULL, FIFO_EMPTY}; + + field { + name = "Rising edge timestamp"; + descritpion = "Timestamp value taken on rising clock edge (full word)"; + prefix = "val_r"; + type = SLV; + size = 28; + }; + + field { + name = "Falling edge timestamp"; + description = "Timestamp value taken on falling clock edge (few LSBs)"; + prefix = "val_f"; + type = SLV; + size = 4; + }; + + + field { + name ="Physical port ID"; + description = "Identifier of the TXTSU port to which came the timestamp. There may be multiple timestamps sharing the same FID value for broadcast/multicast packets."; + prefix = "pid"; + type = SLV; + size = 5; + align= 16; + }; + + + field { + name = "Frame ID"; + description = "OOB Frame Identifier. Used to associate the timestamp value with transmitted packet."; + prefix = "fid"; + type = SLV; + size = 16; + align = 16; + }; + }; + +-- TXTSU interrupts + irq { + name = "TXTSU fifo not-empty"; + description = "Interrupt active when TXTSU shared FIFO contains any timestamps."; + prefix = "nempty"; + trigger = LEVEL_1; + }; + +}; \ No newline at end of file diff --git a/modules/wrsw_txtsu/wrsw_txtsu_pkg.vhd b/modules/wrsw_txtsu/wrsw_txtsu_pkg.vhd new file mode 100644 index 0000000000000000000000000000000000000000..985dc63fdfd4bf2a808adc007a09589b891cc52e --- /dev/null +++ b/modules/wrsw_txtsu/wrsw_txtsu_pkg.vhd @@ -0,0 +1,15 @@ +library ieee; +use ieee.std_logic_1164.all; + +package wrsw_txtsu_pkg is + + type t_txtsu_timestamp is record + valid: std_logic; + tsval : std_logic_vector(31 downto 0); + port_id: std_logic_vector(5 downto 0); + frame_id: std_logic_vector(15 downto 0); + end record; + + type t_txtsu_timestamp_array is array(integer range <>) of t_txtsu_timestamp; + +end wrsw_txtsu_pkg; diff --git a/modules/wrsw_txtsu/wrsw_txtsu_wb.vhd b/modules/wrsw_txtsu/wrsw_txtsu_wb.vhd new file mode 100644 index 0000000000000000000000000000000000000000..97fae79120f0ee22f38682e97df75db5db6743c0 --- /dev/null +++ b/modules/wrsw_txtsu/wrsw_txtsu_wb.vhd @@ -0,0 +1,441 @@ +--------------------------------------------------------------------------------------- +-- Title : Wishbone slave core for Shared TX Timestamping Unit (TXTSU) +--------------------------------------------------------------------------------------- +-- File : wrsw_txtsu_wb.vhd +-- Author : auto-generated by wbgen2 from wrsw_txtsu.wb +-- Created : Wed Mar 16 15:27:30 2011 +-- Standard : VHDL'87 +--------------------------------------------------------------------------------------- +-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE wrsw_txtsu.wb +-- DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY! +--------------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.wbgen2_pkg.all; + +entity wrsw_txtsu_wb is + port ( + rst_n_i : in std_logic; + wb_clk_i : in std_logic; + wb_addr_i : in std_logic_vector(2 downto 0); + wb_data_i : in std_logic_vector(31 downto 0); + wb_data_o : out std_logic_vector(31 downto 0); + wb_cyc_i : in std_logic; + wb_sel_i : in std_logic_vector(3 downto 0); + wb_stb_i : in std_logic; + wb_we_i : in std_logic; + wb_ack_o : out std_logic; + wb_irq_o : out std_logic; +-- FIFO write request + txtsu_tsf_wr_req_i : in std_logic; +-- FIFO full flag + txtsu_tsf_wr_full_o : out std_logic; +-- FIFO empty flag + txtsu_tsf_wr_empty_o : out std_logic; + txtsu_tsf_val_r_i : in std_logic_vector(27 downto 0); + txtsu_tsf_val_f_i : in std_logic_vector(3 downto 0); + txtsu_tsf_pid_i : in std_logic_vector(4 downto 0); + txtsu_tsf_fid_i : in std_logic_vector(15 downto 0); + irq_nempty_i : in std_logic + ); +end wrsw_txtsu_wb; + +architecture syn of wrsw_txtsu_wb is + +signal txtsu_tsf_in_int : std_logic_vector(52 downto 0); +signal txtsu_tsf_out_int : std_logic_vector(52 downto 0); +signal txtsu_tsf_rdreq_int : std_logic ; +signal txtsu_tsf_rdreq_int_d0 : std_logic ; +signal eic_idr_int : std_logic_vector(0 downto 0); +signal eic_idr_write_int : std_logic ; +signal eic_ier_int : std_logic_vector(0 downto 0); +signal eic_ier_write_int : std_logic ; +signal eic_imr_int : std_logic_vector(0 downto 0); +signal eic_isr_clear_int : std_logic_vector(0 downto 0); +signal eic_isr_status_int : std_logic_vector(0 downto 0); +signal eic_irq_ack_int : std_logic_vector(0 downto 0); +signal eic_isr_write_int : std_logic ; +signal txtsu_tsf_full_int : std_logic ; +signal txtsu_tsf_empty_int : std_logic ; +signal txtsu_tsf_usedw_int : std_logic_vector(7 downto 0); +signal irq_inputs_vector_int : std_logic_vector(0 downto 0); +signal ack_sreg : std_logic_vector(9 downto 0); +signal rddata_reg : std_logic_vector(31 downto 0); +signal wrdata_reg : std_logic_vector(31 downto 0); +signal bwsel_reg : std_logic_vector(3 downto 0); +signal rwaddr_reg : std_logic_vector(2 downto 0); +signal ack_in_progress : std_logic ; +signal wr_int : std_logic ; +signal rd_int : std_logic ; +signal bus_clock_int : std_logic ; +signal allones : std_logic_vector(31 downto 0); +signal allzeros : std_logic_vector(31 downto 0); + +begin +-- Some internal signals assignments. For (foreseen) compatibility with other bus standards. + wrdata_reg <= wb_data_i; + bwsel_reg <= wb_sel_i; + bus_clock_int <= wb_clk_i; + rd_int <= wb_cyc_i and (wb_stb_i and (not wb_we_i)); + wr_int <= wb_cyc_i and (wb_stb_i and wb_we_i); + allones <= (others => '1'); + allzeros <= (others => '0'); +-- +-- Main register bank access process. + process (bus_clock_int, rst_n_i) + begin + if (rst_n_i = '0') then + ack_sreg <= "0000000000"; + ack_in_progress <= '0'; + rddata_reg <= "00000000000000000000000000000000"; + eic_idr_write_int <= '0'; + eic_ier_write_int <= '0'; + eic_isr_write_int <= '0'; + txtsu_tsf_rdreq_int <= '0'; + elsif rising_edge(bus_clock_int) then +-- advance the ACK generator shift register + ack_sreg(8 downto 0) <= ack_sreg(9 downto 1); + ack_sreg(9) <= '0'; + if (ack_in_progress = '1') then + if (ack_sreg(0) = '1') then + eic_idr_write_int <= '0'; + eic_ier_write_int <= '0'; + eic_isr_write_int <= '0'; + ack_in_progress <= '0'; + else + end if; + else + if ((wb_cyc_i = '1') and (wb_stb_i = '1')) then + case rwaddr_reg(2 downto 0) is + when "000" => + if (wb_we_i = '1') then + eic_idr_write_int <= '1'; + else + rddata_reg(0) <= 'X'; + rddata_reg(1) <= 'X'; + rddata_reg(2) <= 'X'; + rddata_reg(3) <= 'X'; + rddata_reg(4) <= 'X'; + rddata_reg(5) <= 'X'; + rddata_reg(6) <= 'X'; + rddata_reg(7) <= 'X'; + rddata_reg(8) <= 'X'; + rddata_reg(9) <= 'X'; + rddata_reg(10) <= 'X'; + rddata_reg(11) <= 'X'; + rddata_reg(12) <= 'X'; + rddata_reg(13) <= 'X'; + rddata_reg(14) <= 'X'; + rddata_reg(15) <= 'X'; + rddata_reg(16) <= 'X'; + rddata_reg(17) <= 'X'; + rddata_reg(18) <= 'X'; + rddata_reg(19) <= 'X'; + rddata_reg(20) <= 'X'; + rddata_reg(21) <= 'X'; + rddata_reg(22) <= 'X'; + rddata_reg(23) <= 'X'; + rddata_reg(24) <= 'X'; + rddata_reg(25) <= 'X'; + rddata_reg(26) <= 'X'; + rddata_reg(27) <= 'X'; + rddata_reg(28) <= 'X'; + rddata_reg(29) <= 'X'; + rddata_reg(30) <= 'X'; + rddata_reg(31) <= 'X'; + end if; + ack_sreg(0) <= '1'; + ack_in_progress <= '1'; + when "001" => + if (wb_we_i = '1') then + eic_ier_write_int <= '1'; + else + rddata_reg(0) <= 'X'; + rddata_reg(1) <= 'X'; + rddata_reg(2) <= 'X'; + rddata_reg(3) <= 'X'; + rddata_reg(4) <= 'X'; + rddata_reg(5) <= 'X'; + rddata_reg(6) <= 'X'; + rddata_reg(7) <= 'X'; + rddata_reg(8) <= 'X'; + rddata_reg(9) <= 'X'; + rddata_reg(10) <= 'X'; + rddata_reg(11) <= 'X'; + rddata_reg(12) <= 'X'; + rddata_reg(13) <= 'X'; + rddata_reg(14) <= 'X'; + rddata_reg(15) <= 'X'; + rddata_reg(16) <= 'X'; + rddata_reg(17) <= 'X'; + rddata_reg(18) <= 'X'; + rddata_reg(19) <= 'X'; + rddata_reg(20) <= 'X'; + rddata_reg(21) <= 'X'; + rddata_reg(22) <= 'X'; + rddata_reg(23) <= 'X'; + rddata_reg(24) <= 'X'; + rddata_reg(25) <= 'X'; + rddata_reg(26) <= 'X'; + rddata_reg(27) <= 'X'; + rddata_reg(28) <= 'X'; + rddata_reg(29) <= 'X'; + rddata_reg(30) <= 'X'; + rddata_reg(31) <= 'X'; + end if; + ack_sreg(0) <= '1'; + ack_in_progress <= '1'; + when "010" => + if (wb_we_i = '1') then + else + rddata_reg(0) <= eic_imr_int(0); + rddata_reg(1) <= 'X'; + rddata_reg(2) <= 'X'; + rddata_reg(3) <= 'X'; + rddata_reg(4) <= 'X'; + rddata_reg(5) <= 'X'; + rddata_reg(6) <= 'X'; + rddata_reg(7) <= 'X'; + rddata_reg(8) <= 'X'; + rddata_reg(9) <= 'X'; + rddata_reg(10) <= 'X'; + rddata_reg(11) <= 'X'; + rddata_reg(12) <= 'X'; + rddata_reg(13) <= 'X'; + rddata_reg(14) <= 'X'; + rddata_reg(15) <= 'X'; + rddata_reg(16) <= 'X'; + rddata_reg(17) <= 'X'; + rddata_reg(18) <= 'X'; + rddata_reg(19) <= 'X'; + rddata_reg(20) <= 'X'; + rddata_reg(21) <= 'X'; + rddata_reg(22) <= 'X'; + rddata_reg(23) <= 'X'; + rddata_reg(24) <= 'X'; + rddata_reg(25) <= 'X'; + rddata_reg(26) <= 'X'; + rddata_reg(27) <= 'X'; + rddata_reg(28) <= 'X'; + rddata_reg(29) <= 'X'; + rddata_reg(30) <= 'X'; + rddata_reg(31) <= 'X'; + end if; + ack_sreg(0) <= '1'; + ack_in_progress <= '1'; + when "011" => + if (wb_we_i = '1') then + eic_isr_write_int <= '1'; + else + rddata_reg(0) <= eic_isr_status_int(0); + rddata_reg(1) <= 'X'; + rddata_reg(2) <= 'X'; + rddata_reg(3) <= 'X'; + rddata_reg(4) <= 'X'; + rddata_reg(5) <= 'X'; + rddata_reg(6) <= 'X'; + rddata_reg(7) <= 'X'; + rddata_reg(8) <= 'X'; + rddata_reg(9) <= 'X'; + rddata_reg(10) <= 'X'; + rddata_reg(11) <= 'X'; + rddata_reg(12) <= 'X'; + rddata_reg(13) <= 'X'; + rddata_reg(14) <= 'X'; + rddata_reg(15) <= 'X'; + rddata_reg(16) <= 'X'; + rddata_reg(17) <= 'X'; + rddata_reg(18) <= 'X'; + rddata_reg(19) <= 'X'; + rddata_reg(20) <= 'X'; + rddata_reg(21) <= 'X'; + rddata_reg(22) <= 'X'; + rddata_reg(23) <= 'X'; + rddata_reg(24) <= 'X'; + rddata_reg(25) <= 'X'; + rddata_reg(26) <= 'X'; + rddata_reg(27) <= 'X'; + rddata_reg(28) <= 'X'; + rddata_reg(29) <= 'X'; + rddata_reg(30) <= 'X'; + rddata_reg(31) <= 'X'; + end if; + ack_sreg(0) <= '1'; + ack_in_progress <= '1'; + when "100" => + if (wb_we_i = '1') then + else + if (txtsu_tsf_rdreq_int_d0 = '0') then + txtsu_tsf_rdreq_int <= not txtsu_tsf_rdreq_int; + else + rddata_reg(27 downto 0) <= txtsu_tsf_out_int(27 downto 0); + rddata_reg(31 downto 28) <= txtsu_tsf_out_int(31 downto 28); + ack_in_progress <= '1'; + ack_sreg(0) <= '1'; + end if; + end if; + when "101" => + if (wb_we_i = '1') then + else + rddata_reg(4 downto 0) <= txtsu_tsf_out_int(36 downto 32); + rddata_reg(31 downto 16) <= txtsu_tsf_out_int(52 downto 37); + rddata_reg(5) <= 'X'; + rddata_reg(6) <= 'X'; + rddata_reg(7) <= 'X'; + rddata_reg(8) <= 'X'; + rddata_reg(9) <= 'X'; + rddata_reg(10) <= 'X'; + rddata_reg(11) <= 'X'; + rddata_reg(12) <= 'X'; + rddata_reg(13) <= 'X'; + rddata_reg(14) <= 'X'; + rddata_reg(15) <= 'X'; + end if; + ack_sreg(0) <= '1'; + ack_in_progress <= '1'; + when "110" => + if (wb_we_i = '1') then + else + rddata_reg(16) <= txtsu_tsf_full_int; + rddata_reg(17) <= txtsu_tsf_empty_int; + rddata_reg(7 downto 0) <= txtsu_tsf_usedw_int; + rddata_reg(8) <= 'X'; + rddata_reg(9) <= 'X'; + rddata_reg(10) <= 'X'; + rddata_reg(11) <= 'X'; + rddata_reg(12) <= 'X'; + rddata_reg(13) <= 'X'; + rddata_reg(14) <= 'X'; + rddata_reg(15) <= 'X'; + rddata_reg(18) <= 'X'; + rddata_reg(19) <= 'X'; + rddata_reg(20) <= 'X'; + rddata_reg(21) <= 'X'; + rddata_reg(22) <= 'X'; + rddata_reg(23) <= 'X'; + rddata_reg(24) <= 'X'; + rddata_reg(25) <= 'X'; + rddata_reg(26) <= 'X'; + rddata_reg(27) <= 'X'; + rddata_reg(28) <= 'X'; + rddata_reg(29) <= 'X'; + rddata_reg(30) <= 'X'; + rddata_reg(31) <= 'X'; + end if; + ack_sreg(0) <= '1'; + ack_in_progress <= '1'; + when others => +-- prevent the slave from hanging the bus on invalid address + ack_in_progress <= '1'; + ack_sreg(0) <= '1'; + end case; + end if; + end if; + end if; + end process; + + +-- Drive the data output bus + wb_data_o <= rddata_reg; +-- extra code for reg/fifo/mem: Timestamp FIFO + txtsu_tsf_in_int(27 downto 0) <= txtsu_tsf_val_r_i; + txtsu_tsf_in_int(31 downto 28) <= txtsu_tsf_val_f_i; + txtsu_tsf_in_int(36 downto 32) <= txtsu_tsf_pid_i; + txtsu_tsf_in_int(52 downto 37) <= txtsu_tsf_fid_i; + txtsu_tsf_INST : wbgen2_fifo_sync + generic map ( + g_size => 256, + g_width => 53, + g_usedw_size => 8 + ) + port map ( + wr_req_i => txtsu_tsf_wr_req_i, + wr_full_o => txtsu_tsf_wr_full_o, + wr_empty_o => txtsu_tsf_wr_empty_o, + rd_full_o => txtsu_tsf_full_int, + rd_empty_o => txtsu_tsf_empty_int, + rd_usedw_o => txtsu_tsf_usedw_int, + rd_req_i => txtsu_tsf_rdreq_int, + clk_i => bus_clock_int, + wr_data_i => txtsu_tsf_in_int, + rd_data_o => txtsu_tsf_out_int + ); + +-- extra code for reg/fifo/mem: Interrupt disable register + eic_idr_int(0) <= wrdata_reg(0); +-- extra code for reg/fifo/mem: Interrupt enable register + eic_ier_int(0) <= wrdata_reg(0); +-- extra code for reg/fifo/mem: Interrupt status register + eic_isr_clear_int(0) <= wrdata_reg(0); +-- extra code for reg/fifo/mem: IRQ_CONTROLLER + eic_irq_controller_inst : wbgen2_eic + generic map ( + g_num_interrupts => 1, + g_irq00_mode => 3, + g_irq01_mode => 0, + g_irq02_mode => 0, + g_irq03_mode => 0, + g_irq04_mode => 0, + g_irq05_mode => 0, + g_irq06_mode => 0, + g_irq07_mode => 0, + g_irq08_mode => 0, + g_irq09_mode => 0, + g_irq0a_mode => 0, + g_irq0b_mode => 0, + g_irq0c_mode => 0, + g_irq0d_mode => 0, + g_irq0e_mode => 0, + g_irq0f_mode => 0, + g_irq10_mode => 0, + g_irq11_mode => 0, + g_irq12_mode => 0, + g_irq13_mode => 0, + g_irq14_mode => 0, + g_irq15_mode => 0, + g_irq16_mode => 0, + g_irq17_mode => 0, + g_irq18_mode => 0, + g_irq19_mode => 0, + g_irq1a_mode => 0, + g_irq1b_mode => 0, + g_irq1c_mode => 0, + g_irq1d_mode => 0, + g_irq1e_mode => 0, + g_irq1f_mode => 0 + ) + port map ( + clk_i => bus_clock_int, + rst_n_i => rst_n_i, + irq_i => irq_inputs_vector_int, + irq_ack_o => eic_irq_ack_int, + reg_imr_o => eic_imr_int, + reg_ier_i => eic_ier_int, + reg_ier_wr_stb_i => eic_ier_write_int, + reg_idr_i => eic_idr_int, + reg_idr_wr_stb_i => eic_idr_write_int, + reg_isr_o => eic_isr_status_int, + reg_isr_i => eic_isr_clear_int, + reg_isr_wr_stb_i => eic_isr_write_int, + wb_irq_o => wb_irq_o + ); + + irq_inputs_vector_int(0) <= irq_nempty_i; +-- extra code for reg/fifo/mem: FIFO 'Timestamp FIFO' data output register 0 + process (bus_clock_int, rst_n_i) + begin + if (rst_n_i = '0') then + txtsu_tsf_rdreq_int_d0 <= '0'; + elsif rising_edge(bus_clock_int) then + txtsu_tsf_rdreq_int_d0 <= txtsu_tsf_rdreq_int; + end if; + end process; + + +-- extra code for reg/fifo/mem: FIFO 'Timestamp FIFO' data output register 1 + rwaddr_reg <= wb_addr_i; +-- ACK signal generation. Just pass the LSB of ACK counter. + wb_ack_o <= ack_sreg(0); +end syn; diff --git a/modules/wrsw_txtsu/xwrsw_txtsu.vhd b/modules/wrsw_txtsu/xwrsw_txtsu.vhd new file mode 100644 index 0000000000000000000000000000000000000000..1b6a0a7920d8aa8746336feae643523d80f7ffcf --- /dev/null +++ b/modules/wrsw_txtsu/xwrsw_txtsu.vhd @@ -0,0 +1,223 @@ +------------------------------------------------------------------------------- +-- Title : TX Timestamping Unit +-- Project : White Rabbit Switch +------------------------------------------------------------------------------- +-- File : xwrsw_txtsu.vhd +-- Author : Tomasz Wlostowski +-- Company : CERN BE-Co-HT +-- Created : 2010-04-26 +-- Last update: 2012-01-18 +-- Platform : FPGA-generic +-- Standard : VHDL +------------------------------------------------------------------------------- +-- Description: Shared timestamping unit for all switch endpoints. It collects +-- TX timestamps with associated frame identifiers and puts them (along +-- with the identifier of requesting port) in a shared FIFO. Each FIFO entry +-- contains: +-- - Frame ID value (from OOB field of transmitted frame) +-- - Timestamp value (from the endpoint) +-- - Port ID value (ID of the TXTSU port to which the timstamp+frame id came). +-- FIFO is accessible from the Wishbone bus. An IRQ (level-active) is triggered +-- when the FIFO is not empty. The driver reads TX timestamps (with associated +-- port and frame identifiers) and passes them to PTP daemon. + +------------------------------------------------------------------------------- +-- Copyright (c) 2010 Tomasz Wlostowski +------------------------------------------------------------------------------- +-- Revisions : +-- Date Version Author Description +-- 2010-04-26 1.0 twlostow Created +------------------------------------------------------------------------------- + + + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; + +use work.wishbone_pkg.all; +use work.wrsw_txtsu_pkg.all; + +entity xwrsw_tx_tsu is + + generic ( + g_num_ports : integer := 10; + g_interface_mode : t_wishbone_interface_mode := CLASSIC; + g_address_granularity : t_wishbone_address_granularity := WORD); + + port ( +-- reference clock / 2 (62.5 MHz). All signals below are synchronous to this clock + clk_sys_i : in std_logic; + +-- sync reset, active LO + rst_n_i : in std_logic; + +------------------------------------------------------------------------------- +-- TX timestamp interface (from endpoints) +------------------------------------------------------------------------------- + +-- frame identifier inputs (separate for each port) + timestamps_i : in t_txtsu_timestamp_array(g_num_ports-1 downto 0); + timestamps_ack_o : out std_logic_vector(g_num_ports -1 downto 0); + +------------------------------------------------------------------------------- +-- Wishbone bus +------------------------------------------------------------------------------- + + wb_i: in t_wishbone_slave_in; + wb_o: out t_wishbone_slave_out + ); + + + +end xwrsw_tx_tsu; + + +architecture syn of xwrsw_tx_tsu is + + component wrsw_txtsu_wb + port ( + rst_n_i : in std_logic; + wb_clk_i : in std_logic; + wb_addr_i : in std_logic_vector(2 downto 0); + wb_data_i : in std_logic_vector(31 downto 0); + wb_data_o : out std_logic_vector(31 downto 0); + wb_cyc_i : in std_logic; + wb_sel_i : in std_logic_vector(3 downto 0); + wb_stb_i : in std_logic; + wb_we_i : in std_logic; + wb_ack_o : out std_logic; + wb_irq_o : out std_logic; + txtsu_tsf_wr_req_i : in std_logic; + txtsu_tsf_wr_full_o : out std_logic; + txtsu_tsf_wr_empty_o : out std_logic; + txtsu_tsf_val_r_i : in std_logic_vector(27 downto 0); + txtsu_tsf_val_f_i : in std_logic_vector(3 downto 0); + txtsu_tsf_pid_i : in std_logic_vector(4 downto 0); + txtsu_tsf_fid_i : in std_logic_vector(15 downto 0); + irq_nempty_i : in std_logic); + end component; + + + signal txtsu_tsf_wr_req : std_logic; + signal txtsu_tsf_wr_full : std_logic; + signal txtsu_tsf_wr_empty : std_logic; + signal txtsu_tsf_val_r : std_logic_vector(27 downto 0); + signal txtsu_tsf_val_f : std_logic_vector(3 downto 0); + signal txtsu_tsf_pid : std_logic_vector(4 downto 0); + signal txtsu_tsf_fid : std_logic_vector(15 downto 0); + + signal irq_nempty : std_logic; + + + signal scan_cntr : unsigned(4 downto 0); + + type t_txtsu_state is (TSU_SCAN, TSU_ACK); + + signal state : t_txtsu_state; + + signal ep_valid : std_logic_vector(g_num_ports-1 downto 0); + signal ep_ack : std_logic_vector(g_num_ports-1 downto 0); + + signal cur_ep : integer; + + signal wb_out : t_wishbone_slave_out; + signal wb_in : t_wishbone_slave_in; + +begin -- syn + + U_Adapter : wb_slave_adapter + generic map ( + g_master_use_struct => true, + g_master_mode => CLASSIC, + g_master_granularity => WORD, + g_slave_use_struct => true, + g_slave_mode => g_interface_mode, + g_slave_granularity => g_address_granularity) + port map ( + clk_sys_i => clk_sys_i, + rst_n_i => rst_n_i, + master_i => wb_out, + master_o => wb_in, + slave_i => wb_i, + slave_o => wb_o); + + + cur_ep <= to_integer(scan_cntr); + + process(clk_sys_i, rst_n_i) + begin + if rising_edge(clk_sys_i) then + if rst_n_i = '0' then + + state <= TSU_SCAN; + scan_cntr <= (others => '0'); + txtsu_tsf_wr_req <= '0'; + + timestamps_ack_o <= (others => '0'); + + else + case state is + when TSU_SCAN => + + if(ep_valid(cur_ep) = '1') then + ep_ack(cur_ep) <= '1'; + state <= TSU_ACK; + + if(txtsu_tsf_wr_full = '0') then + txtsu_tsf_pid <= timestamps_i(cur_ep).port_id(4 downto 0); + txtsu_tsf_fid <= timestamps_i(cur_ep).frame_id; + txtsu_tsf_val_f <= timestamps_i(cur_ep).tsval(31 downto 28); + txtsu_tsf_val_r <= timestamps_i(cur_ep).tsval(27 downto 0); + txtsu_tsf_wr_req <= '1'; + end if; + else + if(scan_cntr = g_num_ports-1)then + scan_cntr <= (others => '0'); + else + scan_cntr <= scan_cntr + 1; + end if; + end if; + when TSU_ACK => + timestamps_ack_o(cur_ep) <= '0'; + txtsu_tsf_wr_req <= '0'; + state <= TSU_SCAN; + if(scan_cntr = g_num_ports-1)then + scan_cntr <= (others => '0'); + else + scan_cntr <= scan_cntr + 1; + end if; + when others => null; + end case; + end if; + end if; + end process; + + + U_WB_SLAVE : wrsw_txtsu_wb + port map ( + rst_n_i => rst_n_i, + wb_clk_i => clk_sys_i, + wb_addr_i => wb_in.adr(2 downto 0), + wb_data_i => wb_in.dat, + wb_data_o => wb_out.dat, + wb_cyc_i => wb_in.cyc, + wb_sel_i => wb_in.sel, + wb_stb_i => wb_in.stb, + wb_we_i => wb_in.we, + wb_ack_o => wb_out.ack, + wb_irq_o => wb_out.int, + txtsu_tsf_wr_req_i => txtsu_tsf_wr_req, + txtsu_tsf_wr_full_o => txtsu_tsf_wr_full, + txtsu_tsf_wr_empty_o => txtsu_tsf_wr_empty, + txtsu_tsf_val_r_i => txtsu_tsf_val_r, + txtsu_tsf_val_f_i => txtsu_tsf_val_f, + txtsu_tsf_pid_i => txtsu_tsf_pid, + txtsu_tsf_fid_i => txtsu_tsf_fid, + irq_nempty_i => irq_nempty); + + irq_nempty <= not txtsu_tsf_wr_empty; + +end syn;