Commit a762d226 authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

wrsw_nic: adapted SVN version to pipelined WB fabric

parent 7b7a5d65
files = [ "nic_constants_pkg.vhd" ,
"nic_descriptors_pkg.vhd" ,
"nic_wishbone_slave.vhd" ,
"nic_descriptor_manager.vhd" ,
"nic_rx_fsm.vhd" ,
"nic_tx_fsm.vhd" ,
"nic_buffer.vhd" ,
"nic_elastic_buffer.vhd",
"nic_wbgen2_pkg.vhd",
"xwrsw_nic.vhd",
"wrsw_nic.vhd"];
#!/bin/bash
mkdir -p doc
wbgen2 -D ./doc/wrsw_nic.html -V nic_wishbone_slave.vhd --cstyle defines --lang vhdl -K ../../sim/regs/nic_regs.vh -p nic_wbgen2_pkg.vhd --hstyle record wr_nic.wb
-------------------------------------------------------------------------------
-- Title : Mini Embedded DMA Network Interface Controller
-- Project : WhiteRabbit Core
-------------------------------------------------------------------------------
-- File : nic_buffer.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-Co-HT
-- Created : 2010-07-26
-- Last update: 2011-03-15
-- Platform : FPGA-generic
-- Standard : VHDL
-------------------------------------------------------------------------------
-- Description: RAM-based packet buffer for the NIC
-------------------------------------------------------------------------------
-- Copyright (c) 2010 Tomasz Wlostowski
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-07-26 1.0 twlostow Created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use work.genram_pkg.all;
entity nic_buffer is
generic (
g_memsize_log2 : integer := 14);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
addr_i : in std_logic_vector(g_memsize_log2-1 downto 0);
data_i : in std_logic_vector(31 downto 0);
wr_i : in std_logic;
data_o : out std_logic_vector(31 downto 0);
wb_data_i : in std_logic_vector(31 downto 0);
wb_data_o : out std_logic_vector(31 downto 0);
wb_addr_i : in std_logic_vector(g_memsize_log2-1 downto 0);
wb_cyc_i : in std_logic;
wb_stb_i : in std_logic;
wb_we_i : in std_logic;
wb_ack_o : out std_logic
);
end nic_buffer;
architecture syn of nic_buffer is
signal host_we : std_logic;
signal host_ack : std_logic;
begin -- syn
ack_gen : process(clk_sys_i, rst_n_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
host_ack <= '0';
else
host_ack <= (wb_cyc_i and wb_stb_i) and (not host_ack);
end if;
end if;
end process;
wb_ack_o <= host_ack;
host_we <= wb_cyc_i and wb_stb_i and (wb_we_i and not host_ack);
RAM : generic_dpram
generic map (
g_data_width => 32,
g_size => 2**g_memsize_log2,
g_dual_clock => false)
port map (
-- host port
rst_n_i => rst_n_i,
clka_i => clk_sys_i,
clkb_i => clk_sys_i,
wea_i => host_we,
bwea_i => x"0",
aa_i => wb_addr_i,
da_i => wb_data_i,
qa_o => wb_data_o,
web_i => wr_i,
bweb_i => x"f",
ab_i => addr_i,
db_i => data_i,
qb_o => data_o);
end syn;
-------------------------------------------------------------------------------
-- Title : WR NIC - constants package
-- Project : WhiteRabbit Switch
-------------------------------------------------------------------------------
-- File : nic_constants_pkg.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-Co-HT
-- Created : 2010-11-24
-- Last update: 2010-11-27
-- Platform : FPGA-generic
-- Standard : VHDL
-------------------------------------------------------------------------------
-- Description: Package with global NIC constants
-------------------------------------------------------------------------------
-- Copyright (c) 2010 Tomasz Wlostowski
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-11-24 1.0 twlostow Created
-------------------------------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
package nic_constants_pkg is
-- number of TX descriptors. Must be a power of 2.
constant c_nic_num_tx_descriptors : integer := 8;
-- log2(c_nic_num_tx_descriptors)
constant c_nic_num_tx_descriptors_log2 : integer := 3;
-- number of RX descriptors. Must be a power of 2.
constant c_nic_num_rx_descriptors : integer := 8;
-- log2(c_nic_num_rx_descriptors)
constant c_nic_num_rx_descriptors_log2 : integer := 3;
-- endianess of the packet buffer
constant c_nic_buf_little_endian : boolean := true;
-- log2(size of the packet buffer)
constant c_nic_buf_size_log2 : integer := 15;
end package nic_constants_pkg;
-------------------------------------------------------------------------------
-- Title : WR NIC - RX descriptor management unit
-- Project : WhiteRabbit Switch
-------------------------------------------------------------------------------
-- File : nic_descriptor_manager.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-Co-HT
-- Created : 2010-11-24
-- Last update: 2012-01-13
-- Platform : FPGA-generic
-- Standard : VHDL
-------------------------------------------------------------------------------
-- Description:
-------------------------------------------------------------------------------
-- Copyright (c) 2010 Tomasz Wlostowski
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-11-24 1.0 twlostow Created
-- 2010-11-27 1.0 twlostow Unified RX and TX descriptor mgmt
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.NUMERIC_STD.all;
library work;
use work.nic_constants_pkg.all;
use work.nic_descriptors_pkg.all;
entity nic_descriptor_manager is
generic (
g_desc_mode : string := "tx";
g_num_descriptors : integer;
g_num_descriptors_log2 : integer);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
enable_i : in std_logic;
bna_o : out std_logic;
bna_clear_i : in std_logic;
cur_desc_idx_o : out std_logic_vector(g_num_descriptors_log2-1 downto 0);
-------------------------------------------------------------------------------
-- Descriptor RAM interface
-------------------------------------------------------------------------------
dtbl_addr_o : out std_logic_vector(g_num_descriptors_log2+1 downto 0);
dtbl_data_i : in std_logic_vector(31 downto 0);
dtbl_rd_o : out std_logic;
dtbl_data_o : out std_logic_vector(31 downto 0);
dtbl_wr_o : out std_logic;
-------------------------------------------------------------------------------
-- RX/TX FSM Interface
-------------------------------------------------------------------------------
desc_reload_current_i : in std_logic;
desc_request_next_i : in std_logic;
desc_grant_o : out std_logic;
rxdesc_current_o : out t_rx_descriptor;
rxdesc_new_i : in t_rx_descriptor;
txdesc_current_o : out t_tx_descriptor;
txdesc_new_i : in t_tx_descriptor;
desc_write_i : in std_logic;
desc_write_done_o : out std_logic
);
end nic_descriptor_manager;
architecture behavioral of nic_descriptor_manager is
type t_desc_arb_state is (ARB_DISABLED, ARB_START_SCAN, ARB_CHECK_EMPTY, ARB_FETCH, ARB_GRANT, ARB_UPDATE, ARB_WRITE_DESC);
signal state : t_desc_arb_state;
signal granted_desc_tx : t_tx_descriptor;
signal granted_desc_rx : t_rx_descriptor;
signal granted_desc_idx : unsigned(g_num_descriptors_log2-1 downto 0);
signal desc_idx_d0 : unsigned(g_num_descriptors_log2-1 downto 0);
signal desc_idx : unsigned(g_num_descriptors_log2-1 downto 0);
signal desc_subreg : unsigned(1 downto 0);
signal cntr : unsigned(1 downto 0);
signal check_count : unsigned(g_num_descriptors_log2 downto 0);
signal stupid_hack : std_logic;
impure function f_write_marshalling(index : integer)
return std_logic_vector is
begin
if(g_desc_mode = "rx") then
return f_marshall_rx_descriptor(granted_desc_rx, index);
elsif (g_desc_mode = "tx") then
return f_marshall_tx_descriptor(granted_desc_tx, index);
end if;
end function;
begin -- behavioral
dtbl_addr_o <= std_logic_vector(desc_idx & desc_subreg);
dtbl_rd_o <= '1';
cur_desc_idx_o <= std_logic_vector(desc_idx);
p_rxdesc_arbiter : process(clk_sys_i, rst_n_i)
variable tmp_desc_rx : t_rx_descriptor;
variable tmp_desc_tx : t_tx_descriptor;
-- variable l:line ;
begin
if rising_edge(clk_sys_i) then
if(rst_n_i = '0') then
desc_write_done_o <= '0';
desc_grant_o <= '0';
state <= ARB_DISABLED;
desc_idx <= (others => '0');
desc_subreg <= (others => '0');
dtbl_wr_o <= '0';
-- dtbl_rd_o <= '0';
dtbl_data_o <= (others => '0');
else
case state is
when ARB_DISABLED =>
desc_idx <= (others => '0');
desc_subreg <= (others => '0');
if(enable_i = '1') then
-- dtbl_rd_o <= '1';
state <= ARB_START_SCAN;
desc_idx <= (others => '0');
check_count <= (others => '0');
end if;
when ARB_START_SCAN =>
if(enable_i = '0') then
state <= ARB_DISABLED;
else
-- wait until the current descriptor is read from the memorry
state <= ARB_CHECK_EMPTY;
-- dtbl_rd_o <='1';
dtbl_wr_o <= '0';
end if;
when ARB_CHECK_EMPTY =>
p_unmarshall_rx_descriptor(dtbl_data_i, 1, tmp_desc_rx);
p_unmarshall_tx_descriptor(dtbl_data_i, 1, tmp_desc_tx);
if((tmp_desc_rx.empty = '1' and g_desc_mode = "rx") or (tmp_desc_tx.ready = '1' and g_desc_mode = "tx")) then
granted_desc_tx <= tmp_desc_tx;
granted_desc_rx <= tmp_desc_rx;
desc_subreg <= "01";
state <= ARB_FETCH;
bna_o <= '0';
else
bna_o <= '1';
end if;
when ARB_FETCH =>
case desc_subreg is
when "10" => -- ignore the timestamps for RX
-- descriptors (they're
-- write-only by the NIC)
p_unmarshall_tx_descriptor(dtbl_data_i, 2, tmp_desc_tx);
granted_desc_tx.len <= tmp_desc_tx.len;
granted_desc_tx.offset <= tmp_desc_tx.offset;
when "11" =>
p_unmarshall_tx_descriptor(dtbl_data_i, 3, tmp_desc_tx); -- TX
granted_desc_tx.dpm <= tmp_desc_tx.dpm;
p_unmarshall_rx_descriptor(dtbl_data_i, 3, tmp_desc_rx); -- RX
granted_desc_rx.len <= tmp_desc_rx.len;
granted_desc_rx.offset <= tmp_desc_rx.offset;
state <= ARB_GRANT;
when others => null;
end case;
desc_subreg <= desc_subreg + 1;
when ARB_GRANT =>
if(desc_request_next_i = '1') then
desc_grant_o <= '1';
if(g_desc_mode = "tx") then
txdesc_current_o <= granted_desc_tx;
elsif (g_desc_mode = "rx") then
rxdesc_current_o <= granted_desc_rx;
end if;
state <= ARB_UPDATE;
end if;
desc_write_done_o <= '0';
when ARB_UPDATE =>
desc_grant_o <= '0';
if(desc_write_i = '1') then
if(g_desc_mode = "rx") then
granted_desc_rx <= rxdesc_new_i;
elsif(g_desc_mode = "tx") then
granted_desc_tx <= txdesc_new_i;
end if;
desc_subreg <= (others => '0');
-- dtbl_rd_o <= '0';
state <= ARB_WRITE_DESC;
cntr <= "00";
end if;
when ARB_WRITE_DESC =>
cntr <= cntr + 1;
-- fprint(output,l, "WriteDesc %b %b\n",fo(cntr),fo(f_write_marshalling(1)));
case cntr is
when "00" =>
desc_subreg <= "00";
dtbl_data_o <= f_write_marshalling(1);
dtbl_wr_o <= '1';
when "01" =>
desc_subreg <= "01";
dtbl_data_o <= f_write_marshalling(2);
dtbl_wr_o <= '1';
when "10" =>
desc_subreg <= "10";
dtbl_data_o <= f_write_marshalling(3);
dtbl_wr_o <= '1';
when "11" =>
dtbl_wr_o <= '0';
desc_subreg <= (others => '0');
state <= ARB_START_SCAN;
if(desc_reload_current_i = '0') then
desc_idx <= desc_idx + 1;
end if;
desc_write_done_o <= '1';
when others => null;
end case;
when others => null;
end case;
end if;
end if;
end process;
end behavioral;
-------------------------------------------------------------------------------
-- Title : WR NIC - descriptors package
-- Project : WhiteRabbit Switch
-------------------------------------------------------------------------------
-- File : nic_descriptors_pkg.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-Co-HT
-- Created : 2010-11-24
-- Last update: 2010-12-01
-- Platform : FPGA-generic
-- Standard : VHDL
-------------------------------------------------------------------------------
-- Description: Package declares RX/TX descriptor data types and functions for
-- marshalling/unmarshalling the descriptors to/from SLVs
-------------------------------------------------------------------------------
-- Copyright (c) 2010 Tomasz Wlostowski
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-11-24 1.0 twlostow Created
-------------------------------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
library work;
use work.nic_constants_pkg.all;
package nic_descriptors_pkg is
type t_tx_descriptor is record
ts_id : std_logic_vector(15 downto 0); -- OOB frame id (for TX timestamping)
pad_e : std_logic; -- padding enable
ts_e : std_logic; -- timestamp enable
error : std_logic; -- TX error indication
ready : std_logic; -- Descriptor ready for transmission flag
len : std_logic_vector(c_nic_buf_size_log2-1 downto 0); -- Length of the packet
offset : std_logic_vector(c_nic_buf_size_log2-1 downto 0); -- Offset of the packet in the buffer
dpm : std_logic_vector(31 downto 0); -- Destination port mask
end record;
type t_rx_descriptor is record
empty : std_logic; -- Descriptor empty (ready for
-- reception) flag
error : std_logic; -- RX error indication
port_id : std_logic_vector(5 downto 0); -- Packet source port ID
got_ts : std_logic; -- Got a timestamp?
ts_r : std_logic_vector(27 downto 0); -- Rising edge timestamp
ts_f : std_logic_vector(3 downto 0); -- Falling edge timestamp
len : std_logic_vector(c_nic_buf_size_log2-1 downto 0); -- Length of the allocated buffer
-- (or length of the received
-- packet when the desc is not empty)
offset : std_logic_vector(c_nic_buf_size_log2-1 downto 0); -- Address of the buffer;
end record;
function f_marshall_tx_descriptor(desc : t_tx_descriptor;
regnum : integer) return std_logic_vector;
function f_marshall_rx_descriptor(desc : t_rx_descriptor;
regnum : integer) return std_logic_vector;
procedure p_unmarshall_tx_descriptor(mem_input : in std_logic_vector(31 downto 0);
regnum : in integer;
desc : inout t_tx_descriptor);
procedure p_unmarshall_rx_descriptor(mem_input : in std_logic_vector(31 downto 0);
regnum : in integer;
desc : inout t_rx_descriptor);
function f_resize_slv(x : std_logic_vector;
newsize : integer) return std_logic_vector;
end NIC_descriptors_pkg;
package body NIC_descriptors_pkg is
function f_resize_slv(x : std_logic_vector; newsize : integer) return std_logic_vector is
variable tmp:std_logic_vector(newsize-1 downto 0);
begin
tmp(x'length-1 downto 0) := x;
tmp(newsize-1 downto x'length) := (others => '0');
return tmp;
end f_resize_slv;
function f_marshall_tx_descriptor(desc : t_tx_descriptor; regnum : integer) return std_logic_vector is
variable tmp : std_logic_vector(31 downto 0);
begin
case regnum is
when 1 => tmp := desc.ts_id & x"000" & desc.pad_e & desc.ts_e & desc.error & desc.ready;
when 2 => tmp := f_resize_slv(desc.len, 16) & f_resize_slv(desc.offset, 16);
when 3 => tmp := desc.dpm;
when others => null;
end case;
return tmp;
end f_marshall_tx_descriptor;
function f_marshall_rx_descriptor(desc : t_rx_descriptor; regnum : integer) return std_logic_vector is
variable tmp : std_logic_vector(31 downto 0);
begin
case regnum is
when 1 => tmp := "00000000000000000" & desc.got_ts & desc.port_id & "000000" & desc.error & desc.empty;
when 2 => tmp := desc.ts_f & desc.ts_r;
when 3 => tmp := f_resize_slv(desc.len, 16) & f_resize_slv(desc.offset, 16);
when others => null;
end case;
return tmp;
end f_marshall_rx_descriptor;
procedure p_unmarshall_tx_descriptor(mem_input : in std_logic_vector(31 downto 0);
regnum : in integer;
desc : inout t_tx_descriptor) is
begin
case regnum is
when 1 =>
desc.ts_id := mem_input(31 downto 16);
desc.pad_e := mem_input(3);
desc.ts_e := mem_input(2);
desc.error := mem_input(1);
desc.ready := mem_input(0);
when 2 =>
desc.len := mem_input(16+c_nic_buf_size_log2-1 downto 16);
desc.offset := mem_input(c_nic_buf_size_log2-1 downto 0);
when 3 =>
desc.dpm := mem_input;
when others => null;
end case;
end p_unmarshall_tx_descriptor;
procedure p_unmarshall_rx_descriptor(mem_input : in std_logic_vector(31 downto 0);
regnum : in integer;
desc : inout t_rx_descriptor) is
begin
case regnum is
when 1 =>
desc.empty := mem_input(0);
desc.error := mem_input(1);
desc.port_id := mem_input(13 downto 8);
desc.got_ts := mem_input(14);
when 2 =>
desc.ts_f := mem_input(31 downto 28);
desc.ts_r := mem_input(27 downto 0);
when 3 =>
desc.len := mem_input(16+c_nic_buf_size_log2-1 downto 16);
desc.offset := mem_input(c_nic_buf_size_log2-1 downto 0);
when others => null;
end case;
end p_unmarshall_rx_descriptor;
end package body;
library ieee;
use ieee.std_logic_1164.all;
use ieee.NUMERIC_STD.all;
library work;
use work.endpoint_private_pkg.all; -- dirty hack, again
use work.genram_pkg.all;
use work.wr_fabric_pkg.all;
entity nic_elastic_buffer is
generic (
g_depth : integer := 64);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
snk_i : in t_wrf_sink_in;
snk_o : out t_wrf_sink_out;
fab_o : out t_ep_internal_fabric;
dreq_i : in std_logic
);
end nic_elastic_buffer;
architecture rtl of nic_elastic_buffer is
function log2 (A : natural) return natural is
begin
for I in 1 to 64 loop -- Works for up to 32 bits
if (2**I > A) then
return(I-1);
end if;
end loop;
return(63);
end function log2;
constant c_fifo_width : integer := 16 + 2 + 5;
signal fifo_write : std_logic;
signal fifo_read : std_logic;
signal fifo_in_ser : std_logic_vector(c_fifo_width-1 downto 0);
signal fifo_out_ser : std_logic_vector(c_fifo_width-1 downto 0);
signal fifo_full : std_logic;
signal fifo_empty : std_logic;
signal fifo_usedw : std_logic_vector(log2(g_depth)-1 downto 0);
signal output_valid : std_logic;
signal got_empty : std_logic;
signal cyc_d0 : std_logic;
signal fifo_in : t_ep_internal_fabric;
signal fifo_out : t_ep_internal_fabric;
signal snk_out : t_wrf_sink_out;
signal stall_int : std_logic;
begin -- rtl
p_delay_cyc : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
cyc_d0 <= '0';
else
cyc_d0 <= snk_i.cyc;
end if;
end if;
end process;
snk_o <= snk_out;
snk_out.err <= fifo_full and snk_i.cyc and snk_i.stb;
snk_out.rty <= '0';
p_gen_ack : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
snk_out.ack <= '0';
else
snk_out.ack <= snk_i.cyc and snk_i.stb and not snk_out.stall;
end if;
end if;
end process;
fifo_in.sof <= not cyc_d0 and snk_i.cyc;
fifo_in.eof <= cyc_d0 and not snk_i.cyc;
fifo_in.data <= snk_i.dat;
fifo_in.dvalid <= snk_i.stb and snk_i.cyc and not snk_out.stall;
fifo_in.addr <= snk_i.adr;
fifo_in.error <= '1' when (fifo_in.dvalid = '1') and
snk_i.adr = c_WRF_STATUS and
(f_unmarshall_wrf_status(snk_i.dat).error = '1') else '0';
fifo_in.bytesel <= not snk_i.sel(0);
fifo_write <= fifo_in.sof or fifo_in.eof or fifo_in.dvalid or fifo_in.error;
fifo_in_ser <= fifo_in.bytesel & fifo_in.sof & fifo_in.eof & fifo_in.dvalid & fifo_in.error & fifo_in.addr & fifo_in.data;
p_gen_stall : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
stall_int <= '0';
else
if (unsigned(fifo_usedw) < g_depth/2) then
stall_int <= '0';
elsif (unsigned(fifo_usedw) > g_depth-5) then
stall_int <= '1';
end if;
end if;
end if;
end process;
snk_out.stall <= fifo_in.sof or stall_int;
fifo_read <= not fifo_empty and dreq_i;
p_gen_valid_flag : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
output_valid <= '0';
else
output_valid <= fifo_read;
end if;
end if;
end process;
U_fifo : generic_sync_fifo
generic map (
g_data_width => c_fifo_width,
g_size => g_depth,
g_with_count => true)
port map (
rst_n_i => rst_n_i,
clk_i => clk_sys_i,
we_i => fifo_write,
d_i => fifo_in_ser,
rd_i => fifo_read,
q_o => fifo_out_ser,
empty_o => fifo_empty,
full_o => fifo_full,
count_o => fifo_usedw
);
fab_o.data <= fifo_out_ser(15 downto 0);
fab_o.addr <= fifo_out_ser(17 downto 16);
fab_o.error <= fifo_out_ser(18) and output_valid;
fab_o.dvalid <= fifo_out_ser(19) and output_valid;
fab_o.eof <= fifo_out_ser(20) and output_valid;
fab_o.sof <= fifo_out_ser(21) and output_valid;
fab_o.bytesel <= fifo_out_ser(22);
end rtl;
-------------------------------------------------------------------------------
-- Title : WRF Interface reception logic for WR NIC
-- Project : WhiteRabbit Switch
-------------------------------------------------------------------------------
-- File : nic_rx_fsm.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-Co-HT
-- Created : 2010-11-24
-- Last update: 2012-01-19
-- Platform : FPGA-generic
-- Standard : VHDL
-------------------------------------------------------------------------------
-- Description: The NIC receive path state machine. Takes the packets coming to
-- the WRF sink, requests RX descriptors from RX descriptor manager and writes
-- the packet data and OOB into at specified addresses in the buffer.
-------------------------------------------------------------------------------
-- Copyright (c) 2010 Tomasz Wlostowski
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-11-24 1.0 twlostow Created
-------------------------------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.NUMERIC_STD.all;
use work.nic_constants_pkg.all;
use work.nic_descriptors_pkg.all;
use work.wr_fabric_pkg.all;
use work.nic_wbgen2_pkg.all;
use work.endpoint_private_pkg.all;
entity nic_rx_fsm is
port (clk_sys_i : in std_logic;
rst_n_i : in std_logic;
-------------------------------------------------------------------------------
-- WRF sink
-------------------------------------------------------------------------------
snk_i : in t_wrf_sink_in;
snk_o : out t_wrf_sink_out;
-------------------------------------------------------------------------------
-- Wishbone regs
-------------------------------------------------------------------------------
regs_i : in t_nic_out_registers;
regs_o : out t_nic_in_registers;
irq_rcomp_o : out std_logic;
irq_rcomp_ack_i : in std_logic;
-------------------------------------------------------------------------------
-- RX Descriptor Manager I/F
-------------------------------------------------------------------------------
-- 1 requests next available (empty) RX descriptor
rxdesc_request_next_o : out std_logic;
-- 1 indicates that an empty descriptor has been granted and it's available
-- on rxdesc_current_i
rxdesc_grant_i : in std_logic;
-- currently granted RX descriptor
rxdesc_current_i : in t_rx_descriptor;
-- updated RX descriptor (with new length, error flags, timestamp, etc.)
rxdesc_new_o : out t_rx_descriptor;
-- 1 requests an update of the current RX descriptor with the values
-- given on rxdesc_new_o output
rxdesc_write_o : out std_logic;
-- 1 indicates that the RX descriptor update is done
rxdesc_write_done_i : in std_logic;
-------------------------------------------------------------------------------
-- Packet buffer RAM
-------------------------------------------------------------------------------
-- 1 indicates that we'll have the memory access in the following clock
-- cycle
buf_grant_i : in std_logic;
-- buffer address, data and write enable lines.
buf_addr_o : out std_logic_vector(c_nic_buf_size_log2-3 downto 0);
buf_wr_o : out std_logic;
buf_data_o : out std_logic_vector(31 downto 0)
);
end nic_rx_fsm;
architecture behavioral of NIC_RX_FSM is
component nic_elastic_buffer
generic (
g_depth : integer);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
snk_i : in t_wrf_sink_in;
snk_o : out t_wrf_sink_out;
fab_o : out t_ep_internal_fabric;
dreq_i : in std_logic);
end component;
type t_rx_fsm_state is (RX_DISABLED, RX_WAIT_SOF, RX_REQUEST_DESCRIPTOR, RX_DATA, RX_UPDATE_DESC, RX_MEM_RESYNC, RX_MEM_FLUSH);
signal cur_rx_desc : t_rx_descriptor;
signal state : t_rx_fsm_state;
signal rx_avail : unsigned(c_nic_buf_size_log2-1 downto 0);
signal rx_length : unsigned(c_nic_buf_size_log2-1 downto 0);
signal rx_dreq_mask : std_logic;
signal rx_rdreg_toggle : std_logic;
signal rx_buf_addr : unsigned(c_nic_buf_size_log2-3 downto 0);
signal rx_buf_data : std_logic_vector(31 downto 0);
signal rx_is_payload : std_logic;
signal rx_newpacket : std_logic;
signal rx_newpacket_d0 : std_logic;
signal wrf_is_payload : std_logic;
signal wrf_terminate : std_logic;
signal wrf_is_oob : std_logic;
signal oob_sreg : std_logic_vector(2 downto 0);
signal increase_addr : std_logic;
signal fab_in : t_ep_internal_fabric;
signal fab_dreq : std_logic;
begin
U_Buffer : nic_elastic_buffer
generic map (
g_depth => 64)
port map (
clk_sys_i => clk_sys_i,
rst_n_i => rst_n_i,
snk_i => snk_i,
snk_o => snk_o,
fab_o => fab_in,
dreq_i => fab_dreq);
-- stupid VHDL type conversions
buf_addr_o <= std_logic_vector(rx_buf_addr);
buf_data_o <= rx_buf_data; -- so we can avoid "buffer" I/Os
rxdesc_new_o <= cur_rx_desc;
-- some combinatorial helpers to minimize conditions in IFs.
wrf_is_payload <= '1' when (fab_in.addr = c_WRF_DATA) else '0';
wrf_is_oob <= '1' when (fab_in.addr = c_WRF_OOB) else '0';
wrf_terminate <= '1' when (fab_in.eof = '1' or fab_in.error = '1') else '0';
-- process produces the RCOMP interrupt each time a packet has been received
p_handle_rx_interrupt : process(clk_sys_i, rst_n_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
irq_rcomp_o <= '0';
rx_newpacket_d0 <= '0';
else
rx_newpacket_d0 <= rx_newpacket;
-- we've got another packet? Trigger the IRQ
if (rx_newpacket_d0 = '0' and rx_newpacket = '1') then
irq_rcomp_o <= '1';
-- host acked the interrupt?
elsif (irq_rcomp_ack_i = '1') then
irq_rcomp_o <= '0';
end if;
end if;
end if;
end process;
-- process produces the REC field in SR register
p_handle_status_rec : process(clk_sys_i, rst_n_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
regs_o.sr_rec_i <= '0';
else
-- we've got a packet? Set REC to 1
if (rx_newpacket_d0 = '0' and rx_newpacket = '1') then
regs_o.sr_rec_i <= '1';
-- host wrote 1 to REC bit? Clear!
elsif (regs_i.sr_rec_o = '1' and regs_i.sr_rec_load_o = '1') then
regs_o.sr_rec_i <= '0';
end if;
end if;
end if;
end process;
-- the big beast
p_main_fsm : process(clk_sys_i, rst_n_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
state <= RX_DISABLED;
rxdesc_request_next_o <= '0';
rxdesc_write_o <= '0';
rx_newpacket <= '0';
rx_dreq_mask <= '0';
rx_buf_addr <= (others => '0');
rx_avail <= (others => '0');
buf_wr_o <= '0';
increase_addr <= '0';
else
case state is
-------------------------------------------------------------------------------
-- State DISABLED: packet reception is OFF, all incoming traffic is dropped
-------------------------------------------------------------------------------
when RX_DISABLED =>
rxdesc_request_next_o <= '0';
rx_rdreg_toggle <= '0';
if(regs_i.cr_rx_en_o = '1') then -- check if the user has re-enabled
-- the reception
state <= RX_REQUEST_DESCRIPTOR;
rx_dreq_mask <= '0';
else
rx_dreq_mask <= '1'; -- enable RX, but everything goes to
-- /dev/null
end if;
-------------------------------------------------------------------------------
-- State REQUEST_DESCRIPTOR: take a next empty RX descriptor and have it ready
-- for the incoming packet
-------------------------------------------------------------------------------
when RX_REQUEST_DESCRIPTOR =>
rxdesc_request_next_o <= '1'; -- tell the RX desc manager that we
-- need a descriptor
if(rxdesc_grant_i = '1') then -- RX manager assigned us a desc?
cur_rx_desc <= rxdesc_current_i; -- save a local copy
rxdesc_request_next_o <= '0';
rx_dreq_mask <= '1'; -- enable packet flow on WRF
state <= RX_WAIT_SOF; -- and start waiting for
-- incoming traffic
else
rx_dreq_mask <= '0'; -- disable RX (/dev/null)
end if;
-------------------------------------------------------------------------------
-- State WAIT_SOF: Wait for incoming packets and initiate the reception
-------------------------------------------------------------------------------
when RX_WAIT_SOF =>
-- this guy controls the memory write order. As the fabric is 16-bit and
-- the memory is 32-bit wide, we have to write the data to the buffer
-- with every two received words. The data is committed to the mem
-- when rx_rdreg_toggle = 1, so if we initialize it to 1 before
-- receiving the frame, we'll get a 2-byte gap at the beginning of
-- the buffer (cheers, Alessandro :)
rx_rdreg_toggle <= '1';
-- rx_buf_addr is in 32-bit word, but the offsets and lengths in
-- the descriptors are in bytes to make driver developer's life
-- easier.
rx_buf_addr <= unsigned(cur_rx_desc.offset(c_nic_buf_size_log2-1 downto 2));
rx_avail <= unsigned(cur_rx_desc.len);
rx_length <= (others => '0');
oob_sreg <= "001";
rx_newpacket <= '0';
if(fab_in.sof = '1') then -- got a packet on WRF sink?
state <= RX_DATA; -- then start receiving it!
end if;
-------------------------------------------------------------------------------
-- State RX_DATA: enormously big, messy and complicated data reception logic.
-- Does everything needed to put the received packet into the right place in
-- the buffer
-------------------------------------------------------------------------------
when RX_DATA =>
-- increase the address 1 cycle after committing the data to the memory
if(increase_addr = '1') then
rx_buf_addr <= rx_buf_addr + 1;
increase_addr <= '0';
end if;
-- check if we still have enough space in the buffer
if(fab_in.dvalid = '1' and rx_avail(rx_avail'length-1 downto 1) = to_unsigned(0, rx_avail'length-1)) then
-- no space? drop an error
cur_rx_desc.error <= '1';
buf_wr_o <= '0';
state <= RX_UPDATE_DESC;
end if;
-- got an abort/error/end-of-frame?
if(wrf_terminate = '1') then
-- check if the ends with an error and eventually indicate it.
-- For the NIC, there's no difference between an abort and an RX
-- error.
cur_rx_desc.error <= fab_in.error;
-- make sure the remaining packet data is written into the buffer
state <= RX_MEM_FLUSH;
-- disable the WRF sink data flow, so we won't get another
-- packet before we are done with the memory flush and RX descriptor update
rx_dreq_mask <= '0';
end if;
-- got a valid payload word?
if(fab_in.dvalid = '1' and wrf_is_payload = '1') then
-- check if it's a byte or a word transfer and update the length
-- and buffer space counters accordingly
if(fab_in.bytesel = '1') then
rx_avail <= rx_avail - 1;
rx_length <= rx_length + 1;
else
rx_avail <= rx_avail - 2;
rx_length <= rx_length + 2;
end if;
-- pack two 16-bit words received from the fabric I/F into one
-- 32-bit buffer word
if(c_nic_buf_little_endian = false) then
-- CPU is big-endian
if(rx_rdreg_toggle = '0') then
-- 1st word
rx_buf_data(31 downto 16) <= fab_in.data;
else
-- 2nd word
rx_buf_data(15 downto 0) <= fab_in.data;
end if;
else
-- CPU is little endian
if(rx_rdreg_toggle = '0') then
-- 1st word
rx_buf_data(15 downto 8) <= fab_in.data(7 downto 0);
rx_buf_data(7 downto 0) <= fab_in.data(15 downto 8);
else
-- 2nd word
rx_buf_data(31 downto 24) <= fab_in.data(7 downto 0);
rx_buf_data(23 downto 16) <= fab_in.data(15 downto 8);
end if;
end if;
-- toggle the current word
rx_rdreg_toggle <= not rx_rdreg_toggle;
end if;
-- got a valid OOB word?
if(fab_in.dvalid = '1' and wrf_is_oob = '1') then
-- oob_sreg is a shift register, where each bit represents one of
-- 3 RX OOB words
oob_sreg <= oob_sreg(oob_sreg'length-2 downto 0) & '0';
-- check which word we've just received and put its contents into
-- the descriptor
if(oob_sreg (0) = '1') then -- 1st OOB word
cur_rx_desc.port_id <= '0' & fab_in.data(15 downto 11);
end if;
if(oob_sreg (1) = '1') then -- 2nd OOB word
cur_rx_desc.ts_f <= fab_in.data(15 downto 12);
cur_rx_desc.ts_r (27 downto 16) <= fab_in.data(11 downto 0);
end if;
if(oob_sreg (2) = '1') then -- 3rd OOB word
cur_rx_desc.ts_r(15 downto 0) <= fab_in.data;
cur_rx_desc.got_ts <= '1';
end if;
end if;
-- we've got 2 valid word of the payload in rx_buf_data, write them to the
-- memory
if(rx_rdreg_toggle = '1' and fab_in.dvalid = '1' and ( wrf_is_oob = '1' or wrf_is_payload = '1') and wrf_terminate = '0') then
increase_addr <= '1';
buf_wr_o <= '1';
-- check if we are synchronized with the memory write arbiter,
-- which grants us the memory acces every 2 clock cycles.
-- If we're out of the "beat" (for example when the RX traffic
-- was throttled by the WRF source), we need to resynchronize ourselves.
if(buf_grant_i = '1') then
state <= RX_MEM_RESYNC;
end if;
else
-- nothing to write
buf_wr_o <= '0';
end if;
-------------------------------------------------------------------------------
-- State "Memory resync": a "wait state" entered when the NIC tries to write the RX
-- payload, but the memory access is given for the TX path at the moment.
-------------------------------------------------------------------------------
when RX_MEM_RESYNC =>
-- check for error/abort conditions, they may appear even when
-- the fabric is not accepting the data (tx_dreq_o = 0)
if(fab_in.error = '1') then
cur_rx_desc.error <= '1';
state <= RX_MEM_FLUSH;
rx_dreq_mask <= '0';
else
state <= RX_DATA;
end if;
-------------------------------------------------------------------------------
-- State "Memory flush": flushes the remaining contents of RX data register
-- into the packet buffer after end-of-packet/error/abort
-------------------------------------------------------------------------------
when RX_MEM_FLUSH =>
buf_wr_o <= '1';
-- make sure the data has been written
if(buf_grant_i = '0') then
state <= RX_UPDATE_DESC;
end if;
-------------------------------------------------------------------------------
-- State "Update Descriptor": writes new length, timestamps, port ID, flags and
-- marks the descriptor as non-empty.
-------------------------------------------------------------------------------
when RX_UPDATE_DESC =>
buf_wr_o <= '0';
cur_rx_desc.len <= std_logic_vector(rx_length);
cur_rx_desc.empty <= '0';
rxdesc_write_o <= '1'; -- request descriptor update
-- update done?
if(rxdesc_write_done_i = '1') then
rxdesc_write_o <= '0';
rx_newpacket <= '1';
-- check the RX_EN bit and eventually disable the reception.
-- we can do that only here (disabling RX in the middle of
-- received packet can corrupt the descriptor table).
if(regs_i.cr_rx_en_o = '0') then
state <= RX_DISABLED;
else
-- we're done - prepare another descriptor for the next
-- incoming packet
state <= RX_REQUEST_DESCRIPTOR;
end if;
end if;
when others => null;
end case;
end if;
end if;
end process;
-------------------------------------------------------------------------------
-- helper process for producing the RX fabric data request signal (combinatorial)
-------------------------------------------------------------------------------
gen_rx_dreq : process(rx_dreq_mask, buf_grant_i, rx_rdreg_toggle, fab_in, regs_i)
begin
-- make sure we don't have any incoming data when the reception is masked (e.g.
-- the NIC is updating the descriptors of finishing the memory write.
if(regs_i.cr_rx_en_o = '0' and state = RX_DISABLED) then
fab_dreq <= '1'; -- /dev/null
elsif(fab_in.eof = '1' or fab_in.sof = '1' or rx_dreq_mask = '0') then
fab_dreq <= '0';
-- the condition below forces the RX FSM to go into RX_MEM_RESYNC state. Don't
-- receive anything during the RESYNC cycle.
elsif(rx_rdreg_toggle = '1' and buf_grant_i = '1' and state /= RX_WAIT_SOF) then
fab_dreq <= '0';
else
fab_dreq <= '1';
end if;
end process;
end architecture;
-------------------------------------------------------------------------------
-- Title : WRF Interface transmission logic for WR NIC
-- Project : WhiteRabbit Switch
-------------------------------------------------------------------------------
-- File : nic_tx_fsm.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-Co-HT
-- Created : 2010-11-24
-- Last update: 2012-01-12
-- Platform : FPGA-generic
-- Standard : VHDL
-------------------------------------------------------------------------------
-- Description: The NIC transmit FSM
-------------------------------------------------------------------------------
-- Copyright (c) 2010 Tomasz Wlostowski
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-11-24 1.0 twlostow Created
-------------------------------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.NUMERIC_STD.all;
use work.nic_constants_pkg.all;
use work.nic_descriptors_pkg.all;
use work.wr_fabric_pkg.all;
use work.endpoint_private_pkg.all; -- dirty hack
use work.nic_wbgen2_pkg.all;
entity nic_tx_fsm is
port (clk_sys_i : in std_logic;
rst_n_i : in std_logic;
-------------------------------------------------------------------------------
-- WRF source
-------------------------------------------------------------------------------
src_o : out t_wrf_source_out;
src_i : in t_wrf_source_in;
-------------------------------------------------------------------------------
-- "Fake" RTU interface
-------------------------------------------------------------------------------
rtu_dst_port_mask_o : out std_logic_vector(31 downto 0);
rtu_prio_o : out std_logic_vector(2 downto 0);
rtu_drop_o : out std_logic;
rtu_rsp_valid_o : out std_logic;
rtu_rsp_ack_i : in std_logic;
-------------------------------------------------------------------------------
-- Wishbone regs & IRQs
-------------------------------------------------------------------------------
regs_i : in t_nic_out_registers;
regs_o : out t_nic_in_registers;
irq_tcomp_o : out std_logic;
irq_tcomp_ack_i : in std_logic;
irq_tcomp_mask_i : in std_logic;
irq_txerr_o : out std_logic;
irq_txerr_ack_i : in std_logic;
irq_txerr_mask_i : in std_logic;
-------------------------------------------------------------------------------
-- TX Descriptor Manager I/F
-------------------------------------------------------------------------------
txdesc_reload_current_o : out std_logic;
-- 1 requests next available (empty) TX descriptor
txdesc_request_next_o : out std_logic;
-- 1 indicates that an empty descriptor has been granted and it's available
-- on rxdesc_current_i
txdesc_grant_i : in std_logic;
-- currently granted TX descriptor
txdesc_current_i : in t_tx_descriptor;
-- updated RX descriptor (with new length, error flags, timestamp, etc.)
txdesc_new_o : out t_tx_descriptor;
-- 1 requests an update of the current TX descriptor with the values
-- given on rxdesc_new_o output
txdesc_write_o : out std_logic;
-- 1 indicates that the TX descriptor update is done
txdesc_write_done_i : in std_logic;
bna_i : in std_logic;
-------------------------------------------------------------------------------
-- Packet buffer RAM
-------------------------------------------------------------------------------
-- 1 indicates that we'll have the memory access in the following clock
-- cycle
buf_grant_i : in std_logic;
-- buffer address, data and write enable lines.
buf_addr_o : out std_logic_vector(c_nic_buf_size_log2-3 downto 0);
buf_data_i : in std_logic_vector(31 downto 0)
);
end nic_tx_fsm;
architecture behavioral of nic_tx_fsm is
type t_tx_fsm_state is (TX_DISABLED, TX_REQUEST_DESCRIPTOR, TX_MEM_FETCH, TX_START_PACKET, TX_HWORD, TX_LWORD, TX_END_PACKET, TX_OOB1, TX_OOB2, TX_PAD, TX_UPDATE_DESCRIPTOR, TX_ERROR);
signal cur_tx_desc : t_tx_descriptor;
component ep_rx_wb_master
generic (
g_ignore_ack : boolean);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
snk_fab_i : in t_ep_internal_fabric;
snk_dreq_o : out std_logic;
src_wb_i : in t_wrf_source_in;
src_wb_o : out t_wrf_source_out);
end component;
function f_buf_swap_endian_32
(
data : std_logic_vector(31 downto 0)
) return std_logic_vector is
begin
if(c_nic_buf_little_endian = true) then
return data(7 downto 0) & data(15 downto 8) & data(23 downto 16) & data(31 downto 24);
else
return data;
end if;
end function f_buf_swap_endian_32;
signal state : t_tx_fsm_state;
signal tx_remaining : unsigned(c_nic_buf_size_log2-2 downto 0);
signal odd_length : std_logic;
signal tx_buf_addr : unsigned(c_nic_buf_size_log2-3 downto 0);
signal tx_start_delayed : std_logic;
signal tx_data_reg : std_logic_vector(31 downto 0);
signal tx_done : std_logic;
signal ignore_first_hword : std_logic;
signal tx_cntr_expired : std_logic;
signal is_runt_frame : std_logic;
signal needs_padding : std_logic;
signal padding_size : unsigned(7 downto 0);
signal rtu_valid_int : std_logic;
signal rtu_valid_int_d0 : std_logic;
signal fab_dreq : std_logic;
signal fab_out : t_ep_internal_fabric;
signal tx_err : std_logic;
begin -- behavioral
tx_err <= src_i.err or src_i.rty;
buf_addr_o <= std_logic_vector(tx_buf_addr);
is_runt_frame <= '1' when (to_integer(unsigned(cur_tx_desc.len)) < 60) else '0';
tx_cntr_expired <= '1' when (tx_remaining = 0) else '0';
txdesc_new_o <= cur_tx_desc;
U_WB_Master : ep_rx_wb_master
generic map(
g_ignore_ack => true)
port map (
clk_sys_i => clk_sys_i,
rst_n_i => rst_n_i,
snk_fab_i => fab_out,
snk_dreq_o => fab_dreq,
src_wb_i => src_i,
src_wb_o => src_o);
p_gen_tcomp_irq : process(clk_sys_i, rst_n_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
irq_tcomp_o <= '0';
else
if(irq_tcomp_ack_i = '1') then
irq_tcomp_o <= '0';
else
if(tx_done = '1' and irq_tcomp_mask_i = '1') then
irq_tcomp_o <= '1';
end if;
end if;
end if;
end if;
end process;
p_gen_sr_tx_done : process(clk_sys_i, rst_n_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
regs_o.sr_tx_done_i <= '0';
else
if(regs_i.sr_tx_done_load_o = '1' and regs_i.sr_tx_done_o = '1') then
regs_o.sr_tx_done_i <= '0';
else
if(tx_done = '1' and bna_i = '1') then
regs_o.sr_tx_done_i <= '1';
end if;
end if;
end if;
end if;
end process;
p_fsm : process(clk_sys_i, rst_n_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
state <= TX_DISABLED;
irq_txerr_o <= '0';
txdesc_request_next_o <= '0';
txdesc_write_o <= '0';
txdesc_reload_current_o <= '0';
fab_out.sof <= '0';
fab_out.eof <= '0';
fab_out.dvalid <= '0';
fab_out.bytesel <= '0';
fab_out.data <= (others => '0');
fab_out.addr <= (others => '0');
fab_out.error <= '0';
tx_done <= '0';
rtu_valid_int <= '0';
irq_txerr_o <= '0';
regs_o.sr_tx_error_i <= '0';
else
case state is
when TX_DISABLED =>
regs_o.sr_tx_error_i <= '0';
irq_txerr_o <= '0';
txdesc_request_next_o <= '0';
if(regs_i.cr_tx_en_o = '1') then
state <= TX_REQUEST_DESCRIPTOR;
end if;
when TX_REQUEST_DESCRIPTOR =>
tx_done <= '0';
txdesc_request_next_o <= '1';
if(txdesc_grant_i = '1') then
cur_tx_desc <= txdesc_current_i;
txdesc_request_next_o <= '0';
state <= TX_START_PACKET;
tx_buf_addr <= resize(unsigned(txdesc_current_i.offset(tx_buf_addr'length+1 downto 2)), tx_buf_addr'length);
tx_remaining <= unsigned(txdesc_current_i.len(tx_remaining'length downto 1));
state <= TX_MEM_FETCH;
end if;
-- 1 wait cycle to make sure the 1st TX word has been successfully
-- read from the buffer
when TX_MEM_FETCH =>
if(txdesc_current_i.len(0) = '1') then
tx_remaining <= tx_remaining + 1;
end if;
state <= TX_START_PACKET;
when TX_START_PACKET =>
regs_o.sr_tx_error_i <= '0';
rtu_prio_o <= (others => '0');
rtu_dst_port_mask_o <= cur_tx_desc.dpm;
rtu_drop_o <= '0';
rtu_valid_int <= '1';
-- check if the memory is ready, read the 1st word of the payload
if(fab_dreq = '1' and buf_grant_i = '0') then
tx_data_reg <= buf_data_i;
fab_out.sof <= '1';
tx_buf_addr <= tx_buf_addr + 1;
ignore_first_hword <= '1';
state <= TX_HWORD;
if(is_runt_frame = '1' and cur_tx_desc.pad_e = '1') then
odd_length <= '0';
needs_padding <= '1';
if(cur_tx_desc.len(0) = '1') then
padding_size <= 29 - unsigned(cur_tx_desc.len(padding_size'length downto 1));
else
padding_size <= 30 - unsigned(cur_tx_desc.len(padding_size'length downto 1));
end if;
else
odd_length <= cur_tx_desc.len(0);
needs_padding <= '0';
end if;
tx_data_reg <= f_buf_swap_endian_32(buf_data_i);
end if;
when TX_HWORD =>
rtu_valid_int <= '0';
-- generate the control value depending on the packet type, OOB and the current
-- transmission offset.
fab_out.addr <= c_WRF_DATA;
fab_out.data <= tx_data_reg(31 downto 16);
if(tx_err = '1') then
state <= TX_UPDATE_DESCRIPTOR;
cur_tx_desc.error <= '1';
elsif(fab_dreq = '1') then
if(tx_cntr_expired = '1') then
fab_out.bytesel <= odd_length and (not needs_padding);
if(needs_padding = '1' and padding_size /= 0) then
state <= TX_PAD;
elsif(cur_tx_desc.ts_e = '1') then
state <= TX_OOB1;
else
state <= TX_END_PACKET;
end if;
fab_out.dvalid <= '1';
else
if(ignore_first_hword = '1') then
ignore_first_hword <= '0';
fab_out.dvalid <= '0';
tx_remaining <= tx_remaining - 1;
else
fab_out.dvalid <= '1';
tx_remaining <= tx_remaining - 1;
end if;
state <= TX_LWORD;
end if;
else
fab_out.dvalid <= '0';
end if;
fab_out.sof <= '0';
-- check for errors
when TX_LWORD =>
fab_out.addr <= c_WRF_DATA;
fab_out.data <= tx_data_reg (15 downto 0);
-- the TX fabric is ready, the memory is ready and we haven't reached the end
-- of the packet yet:
if(tx_err = '1') then
state <= TX_UPDATE_DESCRIPTOR;
cur_tx_desc.error <= '1';
elsif(fab_dreq = '1' and buf_grant_i = '0') then
if(tx_cntr_expired = '0') then
fab_out.dvalid <= '1';
tx_data_reg <= f_buf_swap_endian_32(buf_data_i);
tx_remaining <= tx_remaining - 1;
tx_buf_addr <= tx_buf_addr + 1;
state <= TX_HWORD;
-- We're at the end of the packet. Generate an end-of-packet condition on the
-- fabric I/F
else
fab_out.bytesel <= odd_length and (not needs_padding);
fab_out.dvalid <= '1';
if(needs_padding = '1' and padding_size /= 0) then
state <= TX_PAD;
elsif(cur_tx_desc.ts_e = '1') then
state <= TX_OOB1;
else
state <= TX_END_PACKET;
fab_out.eof <= '0';
end if;
end if;
else
-- the fabric is not ready, don't send anything
fab_out.dvalid <= '0';
end if;
when TX_PAD =>
if(tx_err = '1') then
state <= TX_UPDATE_DESCRIPTOR;
cur_tx_desc.error <= '1';
elsif(fab_dreq = '1') then
fab_out.data <= x"0000";
fab_out.addr <= c_WRF_DATA;
fab_out.dvalid <= '1';
padding_size <= padding_size - 1;
if(padding_size = 0) then
fab_out.dvalid <= '0';
if(cur_tx_desc.ts_e = '1')then
state <= TX_OOB1;
else
fab_out.eof <= '0';
state <= TX_END_PACKET;
end if;
end if;
else
fab_out.dvalid <= '0';
end if;
when TX_OOB1 =>
fab_out.bytesel <= '0';
if(fab_dreq = '1') then
fab_out.data <= c_WRF_OOB_TYPE_TX & x"000";
fab_out.addr <= c_WRF_OOB;
fab_out.dvalid <= '1';
fab_out.eof <= '0';
state <= TX_OOB2;
end if;
when TX_OOB2 =>
fab_out.bytesel <= '0';
if(fab_dreq = '1') then
fab_out.data <= cur_tx_desc.ts_id;
fab_out.addr <= c_WRF_OOB;
fab_out.dvalid <= '1';
fab_out.eof <= '0';
state <= TX_END_PACKET;
end if;
when TX_END_PACKET =>
fab_out.dvalid <= '0';
fab_out.bytesel <= '0';
if(fab_dreq = '1') then
fab_out.eof <= '1';
state <= TX_UPDATE_DESCRIPTOR;
end if;
when TX_UPDATE_DESCRIPTOR =>
fab_out.eof <= '0';
txdesc_write_o <= '1';
txdesc_reload_current_o <= cur_tx_desc.error;
cur_tx_desc.ready <= '0';
if(txdesc_write_done_i = '1') then
txdesc_write_o <= '0';
if(cur_tx_desc.error = '1') then
state <= TX_ERROR;
else
tx_done <= '1';
state <= TX_REQUEST_DESCRIPTOR;
end if;
end if;
when TX_ERROR =>
if(irq_txerr_mask_i = '1') then -- clear the error status in
-- interrupt-driver mode
irq_txerr_o <= '1';
if(irq_txerr_ack_i = '1') then
irq_txerr_o <= '0';
state <= TX_REQUEST_DESCRIPTOR;
end if;
end if;
regs_o.sr_tx_error_i <= '1';
if(regs_i.sr_tx_error_o = '1' and regs_i.sr_tx_error_load_o = '1') then --
-- or in status register mode
irq_txerr_o <= '0';
state <= TX_REQUEST_DESCRIPTOR;
end if;
end case;
end if;
end if;
end process;
gen_rtu_valid : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
rtu_rsp_valid_o <= '0';
rtu_valid_int_d0 <= '0';
else
rtu_valid_int_d0 <= rtu_valid_int;
if(rtu_rsp_ack_i = '1') then
rtu_rsp_valid_o <= '0';
elsif(rtu_valid_int = '1' and rtu_valid_int_d0 = '0') then
rtu_rsp_valid_o <= '1';
end if;
end if;
end if;
end process;
end behavioral;
---------------------------------------------------------------------------------------
-- Title : Wishbone slave core for White Rabbit Switch NIC's spec
---------------------------------------------------------------------------------------
-- File : nic_wbgen2_pkg.vhd
-- Author : auto-generated by wbgen2 from wr_nic.wb
-- Created : Thu Jan 12 17:37:53 2012
-- Standard : VHDL'87
---------------------------------------------------------------------------------------
-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE wr_nic.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;
package nic_wbgen2_pkg is
-- Input registers (user design -> WB slave)
type t_nic_in_registers is record
sr_bna_i : std_logic;
sr_rec_i : std_logic;
sr_tx_done_i : std_logic;
sr_tx_error_i : std_logic;
sr_cur_tx_desc_i : std_logic_vector(2 downto 0);
sr_cur_rx_desc_i : std_logic_vector(2 downto 0);
end record;
constant c_nic_in_registers_init_value: t_nic_in_registers := (
sr_bna_i => '0',
sr_rec_i => '0',
sr_tx_done_i => '0',
sr_tx_error_i => '0',
sr_cur_tx_desc_i => (others => '0'),
sr_cur_rx_desc_i => (others => '0')
);
-- Output registers (WB slave -> user design)
type t_nic_out_registers is record
cr_rx_en_o : std_logic;
cr_tx_en_o : std_logic;
sr_rec_o : std_logic;
sr_rec_load_o : std_logic;
sr_tx_done_o : std_logic;
sr_tx_done_load_o : std_logic;
sr_tx_error_o : std_logic;
sr_tx_error_load_o : std_logic;
reset_o : std_logic_vector(31 downto 0);
reset_wr_o : std_logic;
end record;
constant c_nic_out_registers_init_value: t_nic_out_registers := (
cr_rx_en_o => '0',
cr_tx_en_o => '0',
sr_rec_o => '0',
sr_rec_load_o => '0',
sr_tx_done_o => '0',
sr_tx_done_load_o => '0',
sr_tx_error_o => '0',
sr_tx_error_load_o => '0',
reset_o => (others => '0'),
reset_wr_o => '0'
);
function "or" (left, right: t_nic_in_registers) return t_nic_in_registers;
function f_x_to_zero (x:std_logic) return std_logic;
end package;
package body nic_wbgen2_pkg is
function f_x_to_zero (x:std_logic) return std_logic is
begin
if(x = 'X' or x = 'U') then
return '0';
else
return x;
end if;
end function;
function "or" (left, right: t_nic_in_registers) return t_nic_in_registers is
variable tmp: t_nic_in_registers;
begin
tmp.sr_bna_i := left.sr_bna_i or right.sr_bna_i;
tmp.sr_rec_i := left.sr_rec_i or right.sr_rec_i;
tmp.sr_tx_done_i := left.sr_tx_done_i or right.sr_tx_done_i;
tmp.sr_tx_error_i := left.sr_tx_error_i or right.sr_tx_error_i;
tmp.sr_cur_tx_desc_i := left.sr_cur_tx_desc_i or right.sr_cur_tx_desc_i;
tmp.sr_cur_rx_desc_i := left.sr_cur_rx_desc_i or right.sr_cur_rx_desc_i;
return tmp;
end function;
end package body;
---------------------------------------------------------------------------------------
-- Title : Wishbone slave core for White Rabbit Switch NIC's spec
---------------------------------------------------------------------------------------
-- File : nic_wishbone_slave.vhd
-- Author : auto-generated by wbgen2 from wr_nic.wb
-- Created : Thu Jan 12 17:37:53 2012
-- Standard : VHDL'87
---------------------------------------------------------------------------------------
-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE wr_nic.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;
use work.nic_wbgen2_pkg.all;
entity nic_wishbone_slave is
port (
rst_n_i : in std_logic;
wb_clk_i : in std_logic;
wb_addr_i : in std_logic_vector(6 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;
irq_rcomp_i : in std_logic;
irq_rcomp_ack_o : out std_logic;
irq_tcomp_i : in std_logic;
irq_tcomp_ack_o : out std_logic;
irq_tcomp_mask_o : out std_logic;
irq_txerr_i : in std_logic;
irq_txerr_ack_o : out std_logic;
irq_txerr_mask_o : out std_logic;
-- Ports for RAM: TX descriptors mem
nic_dtx_addr_i : in std_logic_vector(4 downto 0);
-- Read data output
nic_dtx_data_o : out std_logic_vector(31 downto 0);
-- Read strobe input (active high)
nic_dtx_rd_i : in std_logic;
-- Write data input
nic_dtx_data_i : in std_logic_vector(31 downto 0);
-- Write strobe (active high)
nic_dtx_wr_i : in std_logic;
-- Ports for RAM: RX descriptors mem
nic_drx_addr_i : in std_logic_vector(4 downto 0);
-- Read data output
nic_drx_data_o : out std_logic_vector(31 downto 0);
-- Read strobe input (active high)
nic_drx_rd_i : in std_logic;
-- Write data input
nic_drx_data_i : in std_logic_vector(31 downto 0);
-- Write strobe (active high)
nic_drx_wr_i : in std_logic;
regs_i : in t_nic_in_registers;
regs_o : out t_nic_out_registers
);
end nic_wishbone_slave;
architecture syn of nic_wishbone_slave is
signal nic_cr_rx_en_int : std_logic ;
signal nic_cr_tx_en_int : std_logic ;
signal nic_dtx_rddata_int : std_logic_vector(31 downto 0);
signal nic_dtx_rd_int : std_logic ;
signal nic_dtx_wr_int : std_logic ;
signal nic_drx_rddata_int : std_logic_vector(31 downto 0);
signal nic_drx_rd_int : std_logic ;
signal nic_drx_wr_int : std_logic ;
signal eic_idr_int : std_logic_vector(2 downto 0);
signal eic_idr_write_int : std_logic ;
signal eic_ier_int : std_logic_vector(2 downto 0);
signal eic_ier_write_int : std_logic ;
signal eic_imr_int : std_logic_vector(2 downto 0);
signal eic_isr_clear_int : std_logic_vector(2 downto 0);
signal eic_isr_status_int : std_logic_vector(2 downto 0);
signal eic_irq_ack_int : std_logic_vector(2 downto 0);
signal eic_isr_write_int : std_logic ;
signal irq_inputs_vector_int : std_logic_vector(2 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(6 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 (wb_clk_i, rst_n_i)
begin
if (rst_n_i = '0') then
ack_sreg <= "0000000000";
ack_in_progress <= '0';
rddata_reg <= "00000000000000000000000000000000";
nic_cr_rx_en_int <= '0';
nic_cr_tx_en_int <= '0';
regs_o.sr_rec_load_o <= '0';
regs_o.sr_tx_done_load_o <= '0';
regs_o.sr_tx_error_load_o <= '0';
regs_o.reset_wr_o <= '0';
eic_idr_write_int <= '0';
eic_ier_write_int <= '0';
eic_isr_write_int <= '0';
elsif rising_edge(wb_clk_i) 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
regs_o.sr_rec_load_o <= '0';
regs_o.sr_tx_done_load_o <= '0';
regs_o.sr_tx_error_load_o <= '0';
regs_o.reset_wr_o <= '0';
eic_idr_write_int <= '0';
eic_ier_write_int <= '0';
eic_isr_write_int <= '0';
ack_in_progress <= '0';
else
regs_o.sr_rec_load_o <= '0';
regs_o.sr_tx_done_load_o <= '0';
regs_o.sr_tx_error_load_o <= '0';
regs_o.reset_wr_o <= '0';
end if;
else
if ((wb_cyc_i = '1') and (wb_stb_i = '1')) then
case rwaddr_reg(6 downto 5) is
when "00" =>
case rwaddr_reg(3 downto 0) is
when "0000" =>
if (wb_we_i = '1') then
rddata_reg(0) <= 'X';
nic_cr_rx_en_int <= wrdata_reg(0);
rddata_reg(1) <= 'X';
nic_cr_tx_en_int <= wrdata_reg(1);
else
rddata_reg(0) <= nic_cr_rx_en_int;
rddata_reg(1) <= nic_cr_tx_en_int;
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 "0001" =>
if (wb_we_i = '1') then
rddata_reg(0) <= 'X';
rddata_reg(1) <= 'X';
regs_o.sr_rec_load_o <= '1';
rddata_reg(2) <= 'X';
regs_o.sr_tx_done_load_o <= '1';
rddata_reg(3) <= 'X';
regs_o.sr_tx_error_load_o <= '1';
else
rddata_reg(0) <= regs_i.sr_bna_i;
rddata_reg(1) <= regs_i.sr_rec_i;
rddata_reg(2) <= regs_i.sr_tx_done_i;
rddata_reg(3) <= regs_i.sr_tx_error_i;
rddata_reg(10 downto 8) <= regs_i.sr_cur_tx_desc_i;
rddata_reg(18 downto 16) <= regs_i.sr_cur_rx_desc_i;
rddata_reg(4) <= 'X';
rddata_reg(5) <= 'X';
rddata_reg(6) <= 'X';
rddata_reg(7) <= 'X';
rddata_reg(11) <= 'X';
rddata_reg(12) <= 'X';
rddata_reg(13) <= 'X';
rddata_reg(14) <= 'X';
rddata_reg(15) <= '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 "0010" =>
if (wb_we_i = '1') then
regs_o.reset_wr_o <= '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 "1000" =>
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 "1001" =>
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 "1010" =>
if (wb_we_i = '1') then
else
rddata_reg(2 downto 0) <= eic_imr_int(2 downto 0);
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 "1011" =>
if (wb_we_i = '1') then
eic_isr_write_int <= '1';
else
rddata_reg(2 downto 0) <= eic_isr_status_int(2 downto 0);
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 others =>
-- prevent the slave from hanging the bus on invalid address
ack_in_progress <= '1';
ack_sreg(0) <= '1';
end case;
when "01" =>
if (rd_int = '1') then
ack_sreg(0) <= '1';
else
ack_sreg(0) <= '1';
end if;
ack_in_progress <= '1';
when "10" =>
if (rd_int = '1') then
ack_sreg(0) <= '1';
else
ack_sreg(0) <= '1';
end if;
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;
-- Data output multiplexer process
process (rddata_reg, rwaddr_reg, nic_dtx_rddata_int, nic_drx_rddata_int, wb_addr_i )
begin
case rwaddr_reg(6 downto 5) is
when "01" =>
wb_data_o(31 downto 0) <= nic_dtx_rddata_int;
when "10" =>
wb_data_o(31 downto 0) <= nic_drx_rddata_int;
when others =>
wb_data_o <= rddata_reg;
end case;
end process;
-- Read & write lines decoder for RAMs
process (wb_addr_i, rd_int, wr_int )
begin
if (wb_addr_i(6 downto 5) = "01") then
nic_dtx_rd_int <= rd_int;
nic_dtx_wr_int <= wr_int;
else
nic_dtx_wr_int <= '0';
nic_dtx_rd_int <= '0';
end if;
if (wb_addr_i(6 downto 5) = "10") then
nic_drx_rd_int <= rd_int;
nic_drx_wr_int <= wr_int;
else
nic_drx_wr_int <= '0';
nic_drx_rd_int <= '0';
end if;
end process;
-- Receive enable
regs_o.cr_rx_en_o <= nic_cr_rx_en_int;
-- Transmit enable
regs_o.cr_tx_en_o <= nic_cr_tx_en_int;
-- Buffer Not Available
-- Frame Received
regs_o.sr_rec_o <= wrdata_reg(1);
-- Transmission done
regs_o.sr_tx_done_o <= wrdata_reg(2);
-- Transmission error
regs_o.sr_tx_error_o <= wrdata_reg(3);
-- Current TX descriptor
-- Current RX descriptor
-- Software reset
-- pass-through field: Software reset in register: SW_Reset
regs_o.reset_o <= wrdata_reg(31 downto 0);
-- extra code for reg/fifo/mem: TX descriptors mem
-- RAM block instantiation for memory: TX descriptors mem
nic_dtx_raminst : wbgen2_dpssram
generic map (
g_data_width => 32,
g_size => 32,
g_addr_width => 5,
g_dual_clock => false,
g_use_bwsel => false
)
port map (
clk_a_i => wb_clk_i,
clk_b_i => wb_clk_i,
addr_b_i => nic_dtx_addr_i,
addr_a_i => rwaddr_reg(4 downto 0),
data_b_o => nic_dtx_data_o,
rd_b_i => nic_dtx_rd_i,
data_b_i => nic_dtx_data_i,
wr_b_i => nic_dtx_wr_i,
bwsel_b_i => allones(3 downto 0),
data_a_o => nic_dtx_rddata_int(31 downto 0),
rd_a_i => nic_dtx_rd_int,
data_a_i => wrdata_reg(31 downto 0),
wr_a_i => nic_dtx_wr_int,
bwsel_a_i => allones(3 downto 0)
);
-- extra code for reg/fifo/mem: RX descriptors mem
-- RAM block instantiation for memory: RX descriptors mem
nic_drx_raminst : wbgen2_dpssram
generic map (
g_data_width => 32,
g_size => 32,
g_addr_width => 5,
g_dual_clock => false,
g_use_bwsel => false
)
port map (
clk_a_i => wb_clk_i,
clk_b_i => wb_clk_i,
addr_b_i => nic_drx_addr_i,
addr_a_i => rwaddr_reg(4 downto 0),
data_b_o => nic_drx_data_o,
rd_b_i => nic_drx_rd_i,
data_b_i => nic_drx_data_i,
wr_b_i => nic_drx_wr_i,
bwsel_b_i => allones(3 downto 0),
data_a_o => nic_drx_rddata_int(31 downto 0),
rd_a_i => nic_drx_rd_int,
data_a_i => wrdata_reg(31 downto 0),
wr_a_i => nic_drx_wr_int,
bwsel_a_i => allones(3 downto 0)
);
-- extra code for reg/fifo/mem: Interrupt disable register
eic_idr_int(2 downto 0) <= wrdata_reg(2 downto 0);
-- extra code for reg/fifo/mem: Interrupt enable register
eic_ier_int(2 downto 0) <= wrdata_reg(2 downto 0);
-- extra code for reg/fifo/mem: Interrupt status register
eic_isr_clear_int(2 downto 0) <= wrdata_reg(2 downto 0);
-- extra code for reg/fifo/mem: IRQ_CONTROLLER
eic_irq_controller_inst : wbgen2_eic
generic map (
g_num_interrupts => 3,
g_irq00_mode => 3,
g_irq01_mode => 3,
g_irq02_mode => 3,
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 => wb_clk_i,
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_rcomp_i;
irq_rcomp_ack_o <= eic_irq_ack_int(0);
irq_inputs_vector_int(1) <= irq_tcomp_i;
irq_tcomp_ack_o <= eic_irq_ack_int(1);
irq_tcomp_mask_o <= eic_imr_int(1);
irq_inputs_vector_int(2) <= irq_txerr_i;
irq_txerr_ack_o <= eic_irq_ack_int(2);
irq_txerr_mask_o <= eic_imr_int(2);
rwaddr_reg <= wb_addr_i;
-- ACK signal generation. Just pass the LSB of ACK counter.
wb_ack_o <= ack_sreg(0);
end syn;
-- -*- Mode: LUA; tab-width: 2 -*-
-- White-Rabbit NIC spec
-- author: Emilio G. Cota <cota@braap.org>
-- updated by: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
--
-- Use wbgen2 to generate code, documentation and more.
-- wbgen2 is available at:
-- http://www.ohwr.org/projects/wishbone-gen
--
top = peripheral {
name = "White Rabbit Switch NIC's spec",
description = "This NIC is in between the endpoints and the on-board Linux CPU of the White Rabbit Switch.\
\
Operation \
~~~~~~~ \
* There's a pool of n TX descriptors and a pool of n RX descriptors. \
* In fact, we should have n for TX and m for RX since 32K / 1536 = 21.3. Anyway, to make things simple, first let's do n and n; we can fine-tune later on. \
* Software keeps track of which buffers are marked to be used with the READY/EMPTY flags. \
* Interrupts are useed by software to update the state, e.g. when frames are received or when a frame has been sent. \
* Endianness: all multi-byte registers are Little Endian \
\
Frame transmission \
~~~~~~~~~~~~~~~ \
* Enable Transmission in the Control Register \
* Store the frame in memory \
* Fill in the corresponding descriptor from the TX pool \
* Set READY bit to 1 \
* Interrupt arrives--if enabled-- and software updates stats reading the descriptor (READY has been set to 0 by the NIC). \
\
Frame reception \
~~~~~~~~~~~~~ \
* Enable Reception in the Control Register \
* Initialize a descriptor from the RX descriptors pool. Mark it as EMPTY \
* A frame is received and, if enabled, the NIC raises an interrupt \
* With EMPTY set to 0, the frame can now be copied from the NIC's memory and stats can be updated \
* Set READY bit to 1 \
\
Todo \
~~~~ \
* Descriptors in RAM, not as registers. wbgen2 doesn't support this yet. Working on it. \
Known issues \
~~~~~~~~~~~ \
* Only 32-bit aligned addresses are supported";
hdl_entity = "nic_wishbone_slave";
prefix = "nic";
reg {
name = "NIC Control Register";
prefix = "CR";
field {
name = "Receive enable";
description = "Enables the NIC to receive data";
prefix = "rx_en";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Transmit enable";
description = "Enables the NIC to transmit data. When reset, the internal transmit pointer points to the first entry in the TX descriptor pool";
prefix = "tx_en";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
reg {
name = "NIC Status Register";
prefix = "SR";
field {
name = "Buffer Not Available";
prefix = "bna";
description = "No buffers were available when receiving a packet.";
type = BIT;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
load = LOAD_EXT;
};
field {
name = "Frame Received";
prefix = "rec";
description = "One or more frames have been received.\
Cleared by writing a one to this bit";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
load = LOAD_EXT;
};
field {
name = "Transmission done";
prefix = "tx_done";
description = "read 1: All non-empty TX descriptors have been transmitted\
read 0: Transmission in progress\
write 1: Clears the flag\
write 0: No effect";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
load = LOAD_EXT;
};
field {
name = "Transmission error";
prefix = "tx_error";
description = "read 1: A TX error occured and the transmission was stopped. CUR_TX_DESC is pointing the TX descriptor for which the error occured\
read 0: No TX error\
write 1: Clears the flag\
write 0: No effect";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
load = LOAD_EXT;
};
field {
align = 8;
name = "Current TX descriptor";
size = 3;
prefix = "cur_TX_Desc";
description = "Index of the currently handled TX descriptor";
type = SLV;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
field {
align = 8;
name = "Current RX descriptor";
size = 3;
prefix = "cur_RX_DESC";
description = "Index of the currently handled RX descriptor";
type = SLV;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
};
reg {
name = "SW_Reset";
description = "Writing to this register resets the NIC, zeroing all registers and resetting the state of the module";
prefix = "reset";
field {
name = "Software reset";
type = PASS_THROUGH;
size = 32;
};
};
irq {
name = "Receive Complete";
prefix = "rcomp";
ack_line = true;
description = "A frame has been stored in memory.";
trigger = LEVEL_1;
};
irq {
name = "Transmit Complete";
prefix = "tcomp";
ack_line = true;
mask_line = true;
description = "Frame successfully transmitted";
trigger = LEVEL_1;
};
irq {
name = "Transmit Error";
prefix = "txerr";
ack_line = true;
mask_line = true;
trigger = LEVEL_1;
};
ram {
name = "TX descriptors mem";
prefix = "dtx";
size = 32;
width = 32;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
};
ram {
name = "RX descriptors mem";
prefix = "drx";
size = 32;
width = 32;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
};
-- ram {
-- name = "TX/RX Buffers";
-- prefix = "mem";
-- -- 8192 * 32 = 32Kb
-- size = 8192;
-- width = 32;
-- access_bus = READ_WRITE;
-- access_dev = READ_WRITE;
-- };
};
TX_desc_template =
{
reg {
name = "TX Descriptor %d register 1";
description = "1st part of TX descriptor header. ";
prefix = "tx%d_d1";
align = 4;
field {
name = "Ready";
prefix = "ready";
description = "0 - The descriptor and buffer can be manipulated. \
1 - The device owns the descriptor and will set the bit to 0 after transmission";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
load = LOAD_EXT;
};
field {
name = "Error";
prefix = "error";
description = "1 - an error occured during transmission of this descriptor.\
0 - transmission was successful";
type = BIT;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
field {
name = "Timestamp Enable";
description = "Set to 1 if the frame has to be timestamped by the endpoint. The NIC will then generate a TX OOB block on its WRF source, containing the value of TS_ID from the descriptor. ";
prefix = "ts_e";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
},
field {
name = "Pad Enable";
prefix = "pad_e";
description = "When set, short frames (< 60 bytes) are padded with zeros to 60 bytes. This doesn't include the CRC field (so the final frame length will be 64 bytes)";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
},
-- todo: Errors: add some more, e.g. Retry Count, Retry Limit exceeded...
field {
name = "Timestamp Frame Identifier";
prefix = "ts_id";
description = "Frame Identifier - a 16-bit value which must be unique in reasonably long time period. It's used to match the TX timestamps coming from different physical ports with the timestamped packets.";
type = SLV;
size = 16;
align = 16;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
reg {
name = "TX Descriptor %d register 2";
prefix = "tx%d_d2";
field {
name = "offset in RAM--in bytes, must be aligned to 32-bit boundary";
prefix = "offset";
type = SLV;
size = 13;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Length of buffer--in bytes. Least significant bit must always be 0 (the packet size must be divisible by 2)";
prefix = "len";
type = SLV;
size = 13;
align = 16;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
reg {
name = "TX Descriptor %d register 3";
prefix = "tx%d_d3";
field {
prefix = "DPM";
name = "Destination Port Mask: 0x00000001 means the packet will be sent to port 0, 0x00000002 - port 1, etc. 0xffffffff means broadcast. 0x0 doesn't make any sense yet.";
type = SLV;
size = 32;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
};
RX_desc_template = {
reg {
align=4;
name = "RX Descriptor %d register 1";
description = "Descriptor of an RX frame buffer";
prefix = "rx%d_d1";
field {
name = "Empty";
prefix = "empty";
description = "0 - Reception (or failure) has occurred on this buffer. The NIC cannot operate on the until this bit is set to 1. \
1 - The buffer is ready to be filled in with data by the NIC";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
load = LOAD_EXT;
};
field {
name = "Error";
prefix = "error";
description = "Set when the the received frame contains an error (an error was indicated by the remote WRF source)";
type = BIT;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
field {
name = "Port number of the receiving endpoint--0 to n-1. Indicated in RX OOB block.";
prefix = "port";
type = SLV;
size = 6;
align = 8;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
field {
name = "Got RX Timestamp";
prefix = "GOT_TS";
description = "1 - there is a valid RX timestamp present in the TS field,\
0 - no RX timestamp";
type = BIT;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
};
reg {
name = "RX Descriptor %d register 2";
prefix = "rx%d_d2";
field {
name = "RX_TS_R";
description = "Value of the RX timestamp (rising edge bits)";
size = 28;
type = SLV;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
field {
name = "RX_TS_F";
description = "Value of the RX timestamp (falling edge bits)";
size = 4;
type = SLV;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
};
reg {
name = "RX Descriptor %d register 3";
prefix = "rx%d_d3";
field {
name = "Offset in packet RAM (in bytes, 32-bit aligned)";
prefix = "offset";
type = SLV;
size = 13;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
},
field {
name = "Length of buffer in bytes. After reception of the packet, it's updated with the length of the received packet.";
prefix = "len";
type = SLV;
size = 13;
align = 16;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
load = LOAD_EXT;
};
};
};
function generate_descriptors(n)
local i;
for i=1,n do
local T=deepcopy(TX_desc_template);
foreach_reg({TYPE_REG}, function(r)
r.name = string.format(r.name, i);
r.prefix = string.format(r.prefix, i);
print(r.name)
end, T);
table_join(periph, T);
end
for i=1,n do
local T=deepcopy(RX_desc_template);
foreach_reg({TYPE_REG}, function(r)
r.name = string.format(r.name, i);
r.prefix = string.format(r.prefix, i);
end, T);
table_join(periph, T);
end
end
--generate_descriptors(8);
library ieee;
use ieee.std_logic_1164.all;
library work;
use work.wishbone_pkg.all;
use work.wr_fabric_pkg.all;
entity wrsw_nic is
generic
(
g_interface_mode : t_wishbone_interface_mode := CLASSIC;
g_address_granularity : t_wishbone_address_granularity := WORD
);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
-------------------------------------------------------------------------------
-- Pipelined Wishbone interface
-------------------------------------------------------------------------------
-- WBP Master (TX)
src_dat_o : out std_logic_vector(15 downto 0);
src_adr_o : out std_logic_vector(1 downto 0);
src_sel_o : out std_logic_vector(1 downto 0);
src_cyc_o : out std_logic;
src_stb_o : out std_logic;
src_we_o : out std_logic;
src_stall_i : in std_logic;
src_err_i : in std_logic;
src_ack_i : in std_logic;
-- WBP Slave (RX)
snk_dat_i : in std_logic_vector(15 downto 0);
snk_adr_i : in std_logic_vector(1 downto 0);
snk_sel_i : in std_logic_vector(1 downto 0);
snk_cyc_i : in std_logic;
snk_stb_i : in std_logic;
snk_we_i : in std_logic;
snk_stall_o : out std_logic;
snk_err_o : out std_logic;
snk_ack_o : out std_logic;
-------------------------------------------------------------------------------
-- "Fake" RTU interface
-------------------------------------------------------------------------------
rtu_dst_port_mask_o : out std_logic_vector(31 downto 0);
rtu_prio_o : out std_logic_vector(2 downto 0);
rtu_drop_o : out std_logic;
rtu_rsp_valid_o : out std_logic;
rtu_rsp_ack_i : in std_logic;
-------------------------------------------------------------------------------
-- Wishbone bus
-------------------------------------------------------------------------------
wb_cyc_i : in std_logic;
wb_stb_i : in std_logic;
wb_we_i : in std_logic;
wb_sel_i : in std_logic_vector(c_wishbone_data_width/8-1 downto 0);
wb_adr_i : in std_logic_vector(c_wishbone_address_width-1 downto 0);
wb_dat_i : in std_logic_vector(c_wishbone_data_width-1 downto 0);
wb_dat_o : out std_logic_vector(c_wishbone_data_width-1 downto 0);
wb_ack_o : out std_logic;
wb_stall_o : out std_logic;
wb_irq_o : out std_logic
);
end wrsw_nic;
architecture rtl of wrsw_nic is
component xwrsw_nic
generic (
g_interface_mode : t_wishbone_interface_mode;
g_address_granularity : t_wishbone_address_granularity);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
snk_i : in t_wrf_sink_in;
snk_o : out t_wrf_sink_out;
src_i : in t_wrf_source_in;
src_o : out t_wrf_source_out;
rtu_dst_port_mask_o : out std_logic_vector(31 downto 0);
rtu_prio_o : out std_logic_vector(2 downto 0);
rtu_drop_o : out std_logic;
rtu_rsp_valid_o : out std_logic;
rtu_rsp_ack_i : in std_logic;
wb_i : in t_wishbone_slave_in;
wb_o : out t_wishbone_slave_out);
end component;
signal snk_out : t_wrf_sink_out;
signal snk_in : t_wrf_sink_in;
signal src_out : t_wrf_source_out;
signal src_in : t_wrf_source_in;
signal wb_out : t_wishbone_slave_out;
signal wb_in : t_wishbone_slave_in;
begin
U_Wrapped_NIC : xwrsw_nic
generic map (
g_interface_mode => g_interface_mode,
g_address_granularity => g_address_granularity)
port map (
clk_sys_i => clk_sys_i,
rst_n_i => rst_n_i,
snk_i => snk_in,
snk_o => snk_out,
src_i => src_in,
src_o => src_out,
rtu_dst_port_mask_o => rtu_dst_port_mask_o,
rtu_prio_o => rtu_prio_o,
rtu_drop_o => rtu_drop_o,
rtu_rsp_valid_o => rtu_rsp_valid_o,
rtu_rsp_ack_i => rtu_rsp_ack_i,
wb_i => wb_in,
wb_o => wb_out);
-- WBP Master (TX)
src_dat_o <= src_out.dat;
src_adr_o <= src_out.adr;
src_sel_o <= src_out.sel;
src_cyc_o <= src_out.cyc;
src_stb_o <= src_out.stb;
src_we_o <= src_out.we;
src_in.stall <= src_stall_i;
src_in.err <= src_err_i;
src_in.ack <= src_ack_i;
-- WBP Slave (RX)
snk_in.dat <= snk_dat_i;
snk_in.adr <= snk_adr_i;
snk_in.sel <= snk_sel_i;
snk_in.cyc <= snk_cyc_i;
snk_in.stb <= snk_stb_i;
snk_in.we <= snk_we_i;
snk_stall_o <= snk_out.stall;
snk_err_o <= snk_out.err;
snk_ack_o <= snk_out.ack;
wb_in.cyc <= wb_cyc_i;
wb_in.stb <= wb_stb_i;
wb_in.we <= wb_we_i;
wb_in.sel <= wb_sel_i;
wb_in.adr <= wb_adr_i;
wb_in.dat <= wb_dat_i;
wb_dat_o <= wb_out.dat;
wb_ack_o <= wb_out.ack;
wb_stall_o <= wb_out.stall;
wb_irq_o <= wb_out.int;
end rtl;
library ieee;
use ieee.std_logic_1164.all;
library work;
use work.nic_constants_pkg.all;
use work.nic_descriptors_pkg.all;
use work.wishbone_pkg.all;
use work.wr_fabric_pkg.all;
use work.nic_wbgen2_pkg.all;
entity xwrsw_nic is
generic
(
g_interface_mode : t_wishbone_interface_mode := CLASSIC;
g_address_granularity : t_wishbone_address_granularity := WORD
);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
-------------------------------------------------------------------------------
-- WRF sink
-------------------------------------------------------------------------------
snk_i : in t_wrf_sink_in;
snk_o : out t_wrf_sink_out;
src_i : in t_wrf_source_in;
src_o : out t_wrf_source_out;
-------------------------------------------------------------------------------
-- "Fake" RTU interface
-------------------------------------------------------------------------------
rtu_dst_port_mask_o : out std_logic_vector(31 downto 0);
rtu_prio_o : out std_logic_vector(2 downto 0);
rtu_drop_o : out std_logic;
rtu_rsp_valid_o : out std_logic;
rtu_rsp_ack_i : in std_logic;
-------------------------------------------------------------------------------
-- Wishbone bus
-------------------------------------------------------------------------------
wb_i : in t_wishbone_slave_in;
wb_o : out t_wishbone_slave_out
);
end xwrsw_nic;
architecture rtl of xwrsw_nic is
component nic_descriptor_manager
generic (
g_desc_mode : string;
g_num_descriptors : integer;
g_num_descriptors_log2 : integer);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
enable_i : in std_logic;
bna_o : out std_logic;
bna_clear_i : in std_logic;
cur_desc_idx_o : out std_logic_vector(g_num_descriptors_log2-1 downto 0);
dtbl_addr_o : out std_logic_vector(g_num_descriptors_log2+1 downto 0);
dtbl_data_i : in std_logic_vector(31 downto 0);
dtbl_rd_o : out std_logic;
dtbl_data_o : out std_logic_vector(31 downto 0);
dtbl_wr_o : out std_logic;
desc_reload_current_i : in std_logic;
desc_request_next_i : in std_logic;
desc_grant_o : out std_logic;
rxdesc_current_o : out t_rx_descriptor;
rxdesc_new_i : in t_rx_descriptor;
txdesc_current_o : out t_tx_descriptor;
txdesc_new_i : in t_tx_descriptor;
desc_write_i : in std_logic;
desc_write_done_o : out std_logic);
end component;
component nic_rx_fsm
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
snk_i : in t_wrf_sink_in;
snk_o : out t_wrf_sink_out;
regs_i : in t_nic_out_registers;
regs_o : out t_nic_in_registers;
irq_rcomp_o : out std_logic;
irq_rcomp_ack_i : in std_logic;
rxdesc_request_next_o : out std_logic;
rxdesc_grant_i : in std_logic;
rxdesc_current_i : in t_rx_descriptor;
rxdesc_new_o : out t_rx_descriptor;
rxdesc_write_o : out std_logic;
rxdesc_write_done_i : in std_logic;
buf_grant_i : in std_logic;
buf_addr_o : out std_logic_vector(c_nic_buf_size_log2-3 downto 0);
buf_wr_o : out std_logic;
buf_data_o : out std_logic_vector(31 downto 0));
end component;
component nic_buffer
generic (
g_memsize_log2 : integer);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
addr_i : in std_logic_vector(g_memsize_log2-1 downto 0);
data_i : in std_logic_vector(31 downto 0);
wr_i : in std_logic;
data_o : out std_logic_vector(31 downto 0);
wb_data_i : in std_logic_vector(31 downto 0);
wb_data_o : out std_logic_vector(31 downto 0);
wb_addr_i : in std_logic_vector(g_memsize_log2-1 downto 0);
wb_cyc_i : in std_logic;
wb_stb_i : in std_logic;
wb_we_i : in std_logic;
wb_ack_o : out std_logic);
end component;
component nic_wishbone_slave
port (
rst_n_i : in std_logic;
wb_clk_i : in std_logic;
wb_addr_i : in std_logic_vector(6 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;
irq_rcomp_i : in std_logic;
irq_rcomp_ack_o : out std_logic;
irq_tcomp_i : in std_logic;
irq_tcomp_ack_o : out std_logic;
irq_tcomp_mask_o : out std_logic;
irq_txerr_i : in std_logic;
irq_txerr_ack_o : out std_logic;
irq_txerr_mask_o : out std_logic;
nic_dtx_addr_i : in std_logic_vector(4 downto 0);
nic_dtx_data_o : out std_logic_vector(31 downto 0);
nic_dtx_rd_i : in std_logic;
nic_dtx_data_i : in std_logic_vector(31 downto 0);
nic_dtx_wr_i : in std_logic;
nic_drx_addr_i : in std_logic_vector(4 downto 0);
nic_drx_data_o : out std_logic_vector(31 downto 0);
nic_drx_rd_i : in std_logic;
nic_drx_data_i : in std_logic_vector(31 downto 0);
nic_drx_wr_i : in std_logic;
regs_i : in t_nic_in_registers;
regs_o : out t_nic_out_registers);
end component;
component nic_tx_fsm
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
src_o : out t_wrf_source_out;
src_i : in t_wrf_source_in;
rtu_dst_port_mask_o : out std_logic_vector(31 downto 0);
rtu_prio_o : out std_logic_vector(2 downto 0);
rtu_drop_o : out std_logic;
rtu_rsp_valid_o : out std_logic;
rtu_rsp_ack_i : in std_logic;
regs_i : in t_nic_out_registers;
regs_o : out t_nic_in_registers;
irq_tcomp_o : out std_logic;
irq_tcomp_ack_i : in std_logic;
irq_tcomp_mask_i : in std_logic;
irq_txerr_o : out std_logic;
irq_txerr_ack_i : in std_logic;
irq_txerr_mask_i : in std_logic;
txdesc_reload_current_o : out std_logic;
txdesc_request_next_o : out std_logic;
txdesc_grant_i : in std_logic;
txdesc_current_i : in t_tx_descriptor;
txdesc_new_o : out t_tx_descriptor;
txdesc_write_o : out std_logic;
txdesc_write_done_i : in std_logic;
bna_i : in std_logic;
buf_grant_i : in std_logic;
buf_addr_o : out std_logic_vector(c_nic_buf_size_log2-3 downto 0);
buf_data_i : in std_logic_vector(31 downto 0));
end component;
signal rxdesc_request_next : std_logic;
signal rxdesc_grant : std_logic;
signal rxdesc_current : t_rx_descriptor;
signal rxdesc_new : t_rx_descriptor;
signal rxdesc_write : std_logic;
signal rxdesc_write_done : std_logic;
signal txdesc_reload_current : std_logic;
signal txdesc_request_next : std_logic;
signal txdesc_grant : std_logic;
signal txdesc_current : t_tx_descriptor;
signal txdesc_new : t_tx_descriptor;
signal txdesc_write : std_logic;
signal txdesc_write_done : std_logic;
signal regs_fromwb : t_nic_out_registers;
signal regs_towb_main, regs_towb_rx, regs_towb_tx, regs_towb : t_nic_in_registers;
signal irq_rcomp : std_logic;
signal irq_rcomp_ack : std_logic;
signal irq_tcomp : std_logic;
signal irq_tcomp_ack : std_logic;
signal irq_tcomp_mask : std_logic;
signal irq_txerr : std_logic;
signal irq_txerr_ack : std_logic;
signal irq_txerr_mask : std_logic;
signal nic_dtx_addr : std_logic_vector(4 downto 0);
signal nic_dtx_wr_data : std_logic_vector(31 downto 0);
signal nic_dtx_rd : std_logic;
signal nic_dtx_rd_data : std_logic_vector(31 downto 0);
signal nic_dtx_wr : std_logic;
signal nic_drx_addr : std_logic_vector(4 downto 0);
signal nic_drx_wr_data : std_logic_vector(31 downto 0);
signal nic_drx_rd : std_logic;
signal nic_drx_rd_data : std_logic_vector(31 downto 0);
signal nic_drx_wr : std_logic;
signal nic_mem_addr : std_logic_vector(12 downto 0);
signal nic_mem_wr_data : std_logic_vector(31 downto 0);
signal nic_mem_rd : std_logic;
signal nic_mem_rd_data : std_logic_vector(31 downto 0);
signal nic_mem_wr : std_logic;
signal mem_grant_rx : std_logic;
signal mem_grant_tx : std_logic;
signal mem_addr_tx : std_logic_vector(c_nic_buf_size_log2-3 downto 0);
signal mem_addr_rx : std_logic_vector(c_nic_buf_size_log2-3 downto 0);
signal mem_wr_rx : std_logic;
signal mem_wr_data_rx : std_logic_vector(31 downto 0);
signal tx_bna : std_logic;
signal nic_reset_n : std_logic;
signal dummy_rx_desc : t_rx_descriptor; -- stupid VHDL
signal dummy_tx_desc : t_tx_descriptor;
signal wb_cyc_slave : std_logic;
signal wb_cyc_buf : std_logic;
signal wb_ack_slave : std_logic;
signal wb_ack_buf : std_logic;
signal wb_rdata_slave : std_logic_vector(31 downto 0);
signal wb_rdata_buf : std_logic_vector(31 downto 0);
signal wb_in : t_wishbone_master_out;
signal wb_out : t_wishbone_master_in;
begin -- rtl
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,
slave_i => wb_i,
slave_o => wb_o,
master_i => wb_out,
master_o => wb_in);
nic_reset_n <= rst_n_i and (not regs_fromwb.reset_wr_o);
regs_towb <= regs_towb_tx or regs_towb_rx or regs_towb_main;
U_WB_SLAVE : nic_wishbone_slave
port map (
rst_n_i => rst_n_i,
wb_clk_i => clk_sys_i,
wb_addr_i => wb_in.adr(6 downto 0),
wb_data_i => wb_in.dat,
wb_data_o => wb_rdata_slave,
wb_cyc_i => wb_cyc_slave,
wb_sel_i => wb_in.sel,
wb_stb_i => wb_in.stb,
wb_we_i => wb_in.we,
wb_ack_o => wb_ack_slave,
wb_irq_o => wb_out.int,
regs_o => regs_fromwb,
regs_i => regs_towb,
irq_rcomp_i => irq_rcomp,
irq_rcomp_ack_o => irq_rcomp_ack,
irq_tcomp_i => irq_tcomp,
irq_tcomp_ack_o => irq_tcomp_ack,
irq_tcomp_mask_o => irq_tcomp_mask,
irq_txerr_i => irq_txerr,
irq_txerr_ack_o => irq_txerr_ack,
irq_txerr_mask_o => irq_txerr_mask,
nic_dtx_addr_i => nic_dtx_addr,
nic_dtx_data_o => nic_dtx_rd_data,
nic_dtx_rd_i => nic_dtx_rd,
nic_dtx_data_i => nic_dtx_wr_data,
nic_dtx_wr_i => nic_dtx_wr,
nic_drx_addr_i => nic_drx_addr,
nic_drx_data_o => nic_drx_rd_data,
nic_drx_rd_i => nic_drx_rd,
nic_drx_data_i => nic_drx_wr_data,
nic_drx_wr_i => nic_drx_wr);
U_BUFFER : nic_buffer
generic map (
g_memsize_log2 => c_nic_buf_size_log2 - 2)
port map (
clk_sys_i => clk_sys_i,
rst_n_i => nic_reset_n,
addr_i => nic_mem_addr,
data_i => nic_mem_wr_data,
wr_i => nic_mem_wr,
data_o => nic_mem_rd_data,
wb_data_i => wb_in.dat,
wb_data_o => wb_rdata_buf,
wb_addr_i => wb_in.adr(c_nic_buf_size_log2 - 3 downto 0),
wb_cyc_i => wb_cyc_buf,
wb_stb_i => wb_in.stb,
wb_we_i => wb_in.we,
wb_ack_o => wb_ack_buf);
wb_cyc_slave <= wb_in.cyc when wb_in.adr(13) = '0' else '0';
wb_cyc_buf <= wb_in.cyc when wb_in.adr(13) = '1' else '0';
wb_out.ack <= wb_ack_buf or wb_ack_slave;
wb_out.dat <= wb_rdata_slave when (wb_in.adr(13) = '0')
else wb_rdata_buf;
p_buffer_arb : process(clk_sys_i, nic_reset_n)
begin
if rising_edge(clk_sys_i) then
if(nic_reset_n = '0') then
mem_grant_rx <= '0';
else
mem_grant_rx <= not mem_grant_rx; -- round-robin
end if;
end if;
end process;
mem_grant_tx <= not mem_grant_rx;
p_mux_buffer_addr : process(mem_grant_rx, mem_addr_tx, mem_addr_rx)
begin
if(mem_grant_rx = '0') then
nic_mem_addr <= mem_addr_tx;
else
nic_mem_addr <= mem_addr_rx;
end if;
end process;
nic_mem_wr_data <= mem_wr_data_rx;
nic_mem_wr <= mem_wr_rx when mem_grant_rx = '1' else '0';
--mem_addr_tx <= (others => '0');
nic_mem_rd <= '1';
-- bna_clear_rx <= nic_sr_bna_out and nic_sr_bna_load;
-------------------------------------------------------------------------------
-- RX Path
-------------------------------------------------------------------------------
U_RX_DESC_MANAGER : nic_descriptor_manager
generic map (
g_desc_mode => "rx",
g_num_descriptors => c_nic_num_rx_descriptors,
g_num_descriptors_log2 => c_nic_num_rx_descriptors_log2)
port map (
clk_sys_i => clk_sys_i,
rst_n_i => nic_reset_n,
enable_i => regs_fromwb.cr_rx_en_o,
bna_o => regs_towb_main.sr_bna_i,
bna_clear_i => '1',
cur_desc_idx_o => regs_towb_main.sr_cur_rx_desc_i,
dtbl_addr_o => nic_drx_addr,
dtbl_data_i => nic_drx_rd_data,
dtbl_rd_o => nic_drx_rd,
dtbl_data_o => nic_drx_wr_data,
dtbl_wr_o => nic_drx_wr,
desc_reload_current_i => '0',
desc_request_next_i => rxdesc_request_next,
desc_grant_o => rxdesc_grant,
desc_write_i => rxdesc_write,
desc_write_done_o => rxdesc_write_done,
rxdesc_current_o => rxdesc_current,
rxdesc_new_i => rxdesc_new,
txdesc_current_o => open,
txdesc_new_i => dummy_tx_desc
);
U_RX_FSM : nic_rx_fsm
port map (
clk_sys_i => clk_sys_i,
rst_n_i => nic_reset_n,
snk_i => snk_i,
snk_o => snk_o,
regs_i => regs_fromwb,
regs_o => regs_towb_rx,
irq_rcomp_o => irq_rcomp,
irq_rcomp_ack_i => irq_rcomp_ack,
rxdesc_request_next_o => rxdesc_request_next,
rxdesc_grant_i => rxdesc_grant,
rxdesc_current_i => rxdesc_current,
rxdesc_new_o => rxdesc_new,
rxdesc_write_o => rxdesc_write,
rxdesc_write_done_i => rxdesc_write_done,
buf_grant_i => mem_grant_rx,
buf_addr_o => mem_addr_rx,
buf_wr_o => mem_wr_rx,
buf_data_o => mem_wr_data_rx);
-------------------------------------------------------------------------------
-- TX Path
-------------------------------------------------------------------------------
U_TX_DESC_MANAGER : nic_descriptor_manager
generic map (
g_desc_mode => "tx",
g_num_descriptors => c_nic_num_tx_descriptors,
g_num_descriptors_log2 => c_nic_num_tx_descriptors_log2)
port map (
clk_sys_i => clk_sys_i,
rst_n_i => nic_reset_n,
enable_i => regs_fromwb.cr_tx_en_o,
bna_o => tx_bna,
bna_clear_i => '0',
cur_desc_idx_o => regs_towb_main.sr_cur_tx_desc_i,
dtbl_addr_o => nic_dtx_addr,
dtbl_data_i => nic_dtx_rd_data,
dtbl_rd_o => nic_dtx_rd,
dtbl_data_o => nic_dtx_wr_data,
dtbl_wr_o => nic_dtx_wr,
desc_reload_current_i => txdesc_reload_current,
desc_request_next_i => txdesc_request_next,
desc_grant_o => txdesc_grant,
rxdesc_current_o => open,
rxdesc_new_i => dummy_rx_desc,
txdesc_current_o => txdesc_current,
txdesc_new_i => txdesc_new,
desc_write_i => txdesc_write,
desc_write_done_o => txdesc_write_done);
U_TX_FSM : nic_tx_fsm
port map (
clk_sys_i => clk_sys_i,
rst_n_i => nic_reset_n,
src_o => src_o,
src_i => src_i,
rtu_dst_port_mask_o => rtu_dst_port_mask_o,
rtu_prio_o => rtu_prio_o,
rtu_drop_o => rtu_drop_o,
rtu_rsp_valid_o => rtu_rsp_valid_o,
rtu_rsp_ack_i => rtu_rsp_ack_i,
regs_i => regs_fromwb,
regs_o => regs_towb_tx,
irq_tcomp_o => irq_tcomp,
irq_tcomp_ack_i => irq_tcomp_ack,
irq_tcomp_mask_i => irq_tcomp_mask,
irq_txerr_o => irq_txerr,
irq_txerr_ack_i => irq_txerr_ack,
irq_txerr_mask_i => irq_txerr_mask,
txdesc_reload_current_o => txdesc_reload_current,
txdesc_request_next_o => txdesc_request_next,
txdesc_grant_i => txdesc_grant,
txdesc_current_i => txdesc_current,
txdesc_new_o => txdesc_new,
txdesc_write_o => txdesc_write,
txdesc_write_done_i => txdesc_write_done,
bna_i => tx_bna,
buf_grant_i => mem_grant_tx,
buf_addr_o => mem_addr_tx,
buf_data_i => nic_mem_rd_data);
end rtl;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment