Commit 5b002c35 authored by Grzegorz Daniluk's avatar Grzegorz Daniluk

Merge branch 'wrsw_nic' into proposed_master

parents e50ffe01 0c08bdb2
......@@ -13,5 +13,6 @@ modules = {
"wr_tlu",
"wrc_core",
"wr_streamers",
"wr_nic",
]
}
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_bw_throttling.vhd",
"nic_wbgen2_pkg.vhd",
"xwr_nic.vhd",
"wr_nic.vhd"];
#!/bin/bash
mkdir -p doc
wbgen2 -D ./doc/wr_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 - 2011 CERN / BE-CO-HT
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
-- 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,
g_with_byte_enable => 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 : Rx bandwidth throttling
-- Project : WhiteRabbit Switch
-------------------------------------------------------------------------------
-- File : nic_bw_throttling.vhd
-- Author : Grzegorz Daniluk
-- Company : CERN BE-Co-HT
-- Created : 2016-07-28
-- Platform : FPGA-generic
-- Standard : VHDL
-------------------------------------------------------------------------------
-- Description:
-- Module implementing Random Early Detection algorithm for throttling the
-- bandwidth of RX traffic on NIC.
-------------------------------------------------------------------------------
--
-- Copyright (c) 2016 CERN / BE-CO-HT
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2016-08-01 1.0 greg.d Created
-------------------------------------------------------------------------------
library IEEE;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.wr_fabric_pkg.all;
entity nic_bw_throttling is
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
pps_p_i : in std_logic;
pps_valid_i : in std_logic;
snk_i : in t_wrf_sink_in;
snk_o : out t_wrf_sink_out;
src_o : out t_wrf_source_out;
src_i : in t_wrf_source_in;
en_i : in std_logic;
new_limit_i : in std_logic;
bwmax_kbps_i : in unsigned(15 downto 0);
bw_bps_o : out std_logic_vector(31 downto 0));
end nic_bw_throttling;
architecture behav of nic_bw_throttling is
signal bw_bps_cnt : unsigned(31 downto 0);
signal is_data : std_logic;
signal src_out : t_wrf_source_out;
signal drop_frame : std_logic;
type t_fwd_fsm is (WAIT_FRAME, FLUSH, PASS, DROP);
signal state_fwd : t_fwd_fsm;
signal wrf_reg : t_wrf_sink_in;
signal rnd_reg : unsigned(7 downto 0);
constant c_LFSR_START : unsigned(7 downto 0) := x"A5";
constant c_DROP_STEP : unsigned(7 downto 0) := x"20"; --32
constant c_DROP_THR_MAX : unsigned(8 downto 0) := to_unsigned(256, 9);
signal drop_thr : unsigned(8 downto 0); -- 1 more bit than rnd_reg
-- so that we can have drop_thr larger than any random number and drop the
-- whole traffic.
signal bwmin_kbps : unsigned(15 downto 0);
signal bwcur_kbps : unsigned(31 downto 0);
signal last_thr_kbps : unsigned(31 downto 0);
signal thr_step_kbps : unsigned(15 downto 0);
begin
-------------------------------------------------
-- Pseudo-random number generation --
-- based on LSFR x^8 + x^6 + x^5 + x^4 + 1 --
-------------------------------------------------
process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
rnd_reg(7 downto 0) <= c_LFSR_START;
else
rnd_reg(0) <= rnd_reg(7) xor rnd_reg(5) xor rnd_reg(4) xor rnd_reg(3);
rnd_reg(7 downto 1) <= rnd_reg(6 downto 0);
end if;
end if;
end process;
-------------------------------------------------
-- Monitoring b/w and generating drop decisions--
-------------------------------------------------
drop_frame <= '1' when (rnd_reg < drop_thr) else
'0';
-- set min b/w from which we start the throttling
-- set it to half of the required max b/w
bwmin_kbps <= shift_right(bwmax_kbps_i, 1);
-- convert current b/w to KBps
-- it's bw_bps_cnt divided by 1024 (2^10)
bwcur_kbps <= shift_right(bw_bps_cnt, 10);
process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' or new_limit_i = '1' then
drop_thr <= (others=>'0');
last_thr_kbps <= x"0000" & bwmin_kbps;
thr_step_kbps <= shift_right(bwmax_kbps_i - bwmin_kbps, 3);
-- both max and min b/w we divide by 8 (because we want 8 steps like with
-- c_DROP_STEP = 64 for range 0-255)
elsif en_i = '1' then
if (bwcur_kbps > last_thr_kbps and drop_thr < c_DROP_THR_MAX) then
-- current b/w is larger than the last crossed threshold
-- we increase the probability of drop
drop_thr <= drop_thr + c_DROP_STEP;
last_thr_kbps <= last_thr_kbps + thr_step_kbps;
elsif (bwcur_kbps + thr_step_kbps < last_thr_kbps and drop_thr > 0) then
-- current b/w has dropped below the last crossed threshold,
-- we decrease the probability of drop
drop_thr <= drop_thr - c_DROP_STEP;
last_thr_kbps <= last_thr_kbps - thr_step_kbps;
end if;
else
-- If the module is disabled, keep drop_thr at 0 so that we don't drop
-- any frames.
drop_thr <= (others=>'0');
end if;
end if;
end process;
-------------------------------------------------
-- Forwarding or dropping frames --
-------------------------------------------------
process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
state_fwd <= WAIT_FRAME;
wrf_reg <= c_dummy_snk_in;
snk_o <= c_dummy_src_in;
src_out <= c_dummy_snk_in;
else
case state_fwd is
when WAIT_FRAME =>
snk_o.ack <= '0';
snk_o.err <= '0';
snk_o.rty <= '0';
src_out <= c_dummy_snk_in;
if (snk_i.cyc='1' and snk_i.stb='1') then
-- new frame is transmitted
snk_o.stall <= '1';
wrf_reg <= snk_i;
if (drop_frame = '0') then
state_fwd <= FLUSH;
elsif (drop_frame = '1') then
state_fwd <= DROP;
end if;
else
snk_o.stall <= '0';
end if;
when FLUSH =>
-- flush wrf_reg stored on stall or in WAIT_FRAME
snk_o <= src_i;
if (src_i.stall = '0') then
src_out <= wrf_reg;
state_fwd <= PASS;
end if;
when PASS =>
snk_o <= src_i;
if (src_i.stall = '0') then
src_out <= snk_i;
if (snk_i.cyc='0' and snk_i.stb='0') then
state_fwd <= WAIT_FRAME;
end if;
else
wrf_reg <= snk_i;
state_fwd <= FLUSH;
end if;
when DROP =>
-- ack everything from SNK, pass nothing to SRC
snk_o.stall <= '0';
snk_o.err <= '0';
snk_o.rty <= '0';
src_out <= c_dummy_snk_in;
if (snk_i.stb='1') then
snk_o.ack <= '1';
else
snk_o.ack <= '0';
end if;
if (snk_i.cyc='0' and snk_i.stb='0') then
state_fwd <= WAIT_FRAME;
end if;
end case;
end if;
end if;
end process;
src_o <= src_out;
-------------------------------------------------
-- Calculating bandwidth actually going to ARM --
-------------------------------------------------
is_data <= '1' when (src_out.adr=c_WRF_DATA and src_out.cyc='1' and src_out.stb='1' and src_i.stall='0') else
'0';
process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' or pps_valid_i = '0' then
bw_bps_cnt <= (others=>'0');
bw_bps_o <= (others=>'0');
elsif pps_p_i = '1' then
bw_bps_cnt <= (others=>'0');
bw_bps_o <= std_logic_vector(bw_bps_cnt);
elsif is_data = '1' then
-- we count incoming bytes here
if src_out.sel(0) = '1' then
-- 16bits carry valid data
bw_bps_cnt <= bw_bps_cnt + 2;
elsif src_out.sel(0) = '0' then
-- only 8bits carry valid data
bw_bps_cnt <= bw_bps_cnt + 1;
end if;
end if;
end if;
end process;
end behav;
-------------------------------------------------------------------------------
-- 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 CERN / BE-CO-HT
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
-- 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 - 2012 CERN / BE-CO-HT
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
-- 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;
g_port_mask_bits : integer := 32); --worth using only in TX mode
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_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 desc_idx : unsigned(g_num_descriptors_log2-1 downto 0);
signal desc_subreg : unsigned(1 downto 0);
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);
--GD can do that, those outputs are validated by desc_grant_o
--and nic_rx_fsm stores it in internal register too
GEN_TXDESC_CUR: if g_desc_mode = "tx" generate
txdesc_current_o <= granted_desc_tx;
end generate;
GEN_RXDESC_CUR: if g_desc_mode = "rx" generate
rxdesc_current_o <= granted_desc_rx;
end generate;
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_START_SCAN;
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_START_SCAN =>
desc_subreg <= (others => '0');
dtbl_wr_o <= '0';
if(enable_i = '1') then
state <= ARB_CHECK_EMPTY;
else
desc_idx <= (others => '0');
end if;
when ARB_CHECK_EMPTY =>
dtbl_wr_o <= '0';
tmp_desc_rx := f_unmarshall_rx_descriptor(dtbl_data_i, 1);
tmp_desc_tx := f_unmarshall_tx_descriptor(dtbl_data_i, 1);
granted_desc_tx <= tmp_desc_tx;
granted_desc_rx <= tmp_desc_rx;
if((tmp_desc_rx.empty = '1' and g_desc_mode = "rx") or (tmp_desc_tx.ready = '1' and g_desc_mode = "tx")) then
desc_subreg <= "01";
state <= ARB_FETCH;
bna_o <= '0';
else
bna_o <= '1';
end if;
when ARB_FETCH =>
dtbl_wr_o <= '0';
case desc_subreg is
when "10" => -- ignore the timestamps for RX
-- descriptors (they're
-- write-only by the NIC)
tmp_desc_tx := f_unmarshall_tx_descriptor(dtbl_data_i, 2);
granted_desc_tx.len <= tmp_desc_tx.len;
granted_desc_tx.offset <= tmp_desc_tx.offset;
when "11" =>
tmp_desc_tx := f_unmarshall_tx_descriptor(dtbl_data_i, 3); -- TX
granted_desc_tx.dpm(g_port_mask_bits-1 downto 0) <= tmp_desc_tx.dpm(g_port_mask_bits-1 downto 0);
tmp_desc_rx := f_unmarshall_rx_descriptor(dtbl_data_i, 3); -- 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 =>
dtbl_wr_o <= '0';
desc_subreg <= "11";
if(desc_request_next_i = '1') then
desc_grant_o <= '1';
state <= ARB_UPDATE;
end if;
desc_write_done_o <= '0';
when ARB_UPDATE =>
dtbl_wr_o <= '0';
desc_grant_o <= '0';
desc_subreg <= "11";
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;
state <= ARB_WRITE_DESC;
end if;
when ARB_WRITE_DESC =>
dtbl_data_o <= f_write_marshalling(to_integer(desc_subreg));
if(desc_subreg = "10") then
dtbl_wr_o <= '0';
desc_subreg <= "00";
state <= ARB_START_SCAN;
if(desc_reload_current_i = '0') then
desc_idx <= desc_idx + 1;
end if;
desc_write_done_o <= '1';
else
dtbl_wr_o <= '1';
desc_subreg <= desc_subreg + 1;
end if;
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: 2012-03-16
-- 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 - 2012 CERN / BE-CO-HT
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
-- 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_incorrect: std_logic; -- 1: Timestamp may be incorrect (generated
-- during time base adjustment)
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;
function f_unmarshall_tx_descriptor(mem_input : std_logic_vector(31 downto 0);
regnum : integer) return t_tx_descriptor;
function f_unmarshall_rx_descriptor(mem_input : std_logic_vector(31 downto 0);
regnum : integer) return 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 3 => tmp := desc.ts_id & x"000" & desc.pad_e & desc.ts_e & desc.error & desc.ready;
when 0 => tmp := f_resize_slv(desc.len, 16) & f_resize_slv(desc.offset, 16);
when 1 => 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 3 => tmp := "0000000000000000" & desc.ts_incorrect & desc.got_ts & desc.port_id & "000000" & desc.error & desc.empty;
when 0 => tmp := desc.ts_f & desc.ts_r;
when 1 => 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;
function f_unmarshall_tx_descriptor(mem_input : std_logic_vector(31 downto 0); regnum : integer)
return t_tx_descriptor is
variable desc : t_tx_descriptor;
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;
return desc;
end f_unmarshall_tx_descriptor;
function f_unmarshall_rx_descriptor(mem_input : std_logic_vector(31 downto 0); regnum : integer)
return t_rx_descriptor is
variable desc : t_rx_descriptor;
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);
desc.ts_incorrect := mem_input(15);
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;
return desc;
end f_unmarshall_rx_descriptor;
end package body;
-------------------------------------------------------------------------------
-- Title : WR NIC - Elastic Buffer
-- Project : White Rabbit Switch
-------------------------------------------------------------------------------
-- File : nic_elastic_buffer.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-CO-HT
-- Created : 2012-01-19
-- Last update: 2013-10-23
-- Platform : FPGA-generic
-- Standard : VHDL
-------------------------------------------------------------------------------
--
-- Copyright (c) 2012 - 2013 CERN / BE-CO-HT
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.NUMERIC_STD.all;
library work;
use work.endpoint_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_almost_empty : std_logic;
signal fifo_almost_full : std_logic;
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' or fifo_almost_empty = '1' then
stall_int <= '0';
elsif fifo_almost_full = '1' then
stall_int <= '1';
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_almost_empty => true,
g_with_almost_full => true,
g_almost_empty_threshold => g_depth/2,
g_almost_full_threshold => g_depth-5,
g_with_count => false)
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,
almost_empty_o => fifo_almost_empty,
almost_full_o => fifo_almost_full
);
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-03-16
-- 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 - 2012 CERN / BE-CO-HT
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
-- 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_pkg.all;
entity nic_rx_fsm is
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
pps_p_i : in std_logic;
pps_valid_i : in std_logic;
-------------------------------------------------------------------------------
-- WRF sink
-------------------------------------------------------------------------------
snk_i : in t_wrf_sink_in;
snk_o : out t_wrf_sink_out;
-------------------------------------------------------------------------------
-- Wishbone regs
-------------------------------------------------------------------------------
bna_i : in std_logic;
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;
component nic_bw_throttling
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
pps_p_i : in std_logic;
pps_valid_i : in std_logic;
snk_i : in t_wrf_sink_in;
snk_o : out t_wrf_sink_out;
src_o : out t_wrf_source_out;
src_i : in t_wrf_source_in;
en_i : in std_logic;
new_limit_i : in std_logic;
bwmax_kbps_i : in unsigned(15 downto 0);
bw_bps_o : out std_logic_vector(31 downto 0));
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_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;
signal bw_src_out : t_wrf_source_out;
signal bw_src_in : t_wrf_source_in;
signal max_bw_reg : std_logic_vector(15 downto 0);
begin
U_Throttling: nic_bw_throttling
port map (
clk_sys_i => clk_sys_i,
rst_n_i => rst_n_i,
pps_p_i => pps_p_i,
pps_valid_i => pps_valid_i,
snk_i => snk_i,
snk_o => snk_o,
src_o => bw_src_out,
src_i => bw_src_in,
en_i => regs_i.cr_rxthr_en_o,
new_limit_i => regs_i.maxrxbw_load_o,
bwmax_kbps_i => unsigned(regs_i.maxrxbw_o),
bw_bps_o => regs_o.rxbw_i);
process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
max_bw_reg <= (others=>'0');
elsif regs_i.maxrxbw_load_o = '1' then
max_bw_reg <= regs_i.maxrxbw_o;
end if;
end if;
end process;
regs_o.maxrxbw_i <= max_bw_reg;
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 => bw_src_out, --snk_i,
snk_o => bw_src_in, --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');
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 <= bna_i; -- enable RX (but to /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_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 =>
buf_wr_o <= '0';
-- 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_length(rx_length'length-1 downto 1) = unsigned(cur_rx_desc.len(rx_length'length-1 downto 1))) then
-- no space? drop an error
cur_rx_desc.error <= '1';
state <= RX_UPDATE_DESC;
else
-- 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_length <= rx_length + 1;
else
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(4 downto 0);
cur_rx_desc.ts_incorrect <= fab_in.data(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;
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, state)
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) and (state /= RX_REQUEST_DESCRIPTOR)) 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-24
-- Platform : FPGA-generic
-- Standard : VHDL
-------------------------------------------------------------------------------
-- Description: The NIC transmit FSM
-------------------------------------------------------------------------------
--
-- Copyright (c) 2010 - 2012 CERN / BE-CO-HT
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
-- 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;
entity nic_tx_fsm is
generic(
g_port_mask_bits : integer := 32;
g_cyc_on_stall : boolean := false;
g_rmon_events_pp : integer := 1);
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(g_port_mask_bits-1 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);
-------------------------------------------------------------------------------
-- RMON events
-------------------------------------------------------------------------------
rmon_events_o : out std_logic_vector(g_port_mask_bits*g_rmon_events_pp-1 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, TX_STATUS);
signal cur_tx_desc : t_tx_descriptor;
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_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 needs_padding : std_logic;
signal padding_size : unsigned(4 downto 0);
signal rtu_valid_int : std_logic;
signal rtu_valid_int_d0 : std_logic;
signal rtu_port_mask : std_logic_vector(g_port_mask_bits-1 downto 0);
signal tx_err : std_logic;
signal default_status_reg : t_wrf_status_reg;
signal ack_count : unsigned(3 downto 0);
signal src_stb_int : std_logic;
signal ackcnt_nrst : std_logic;
begin -- behavioral
default_status_reg.has_smac <= '1';
default_status_reg.has_crc <= '0';
default_status_reg.error <= '0';
default_status_reg.is_hp <= '0';
tx_err <= src_i.err or src_i.rty;
buf_addr_o <= std_logic_vector(tx_buf_addr);
needs_padding <= '1' when (to_integer(unsigned(cur_tx_desc.len)) < 60 and cur_tx_desc.pad_e='1') else '0';
odd_length <= (not needs_padding) and cur_tx_desc.len(0);
tx_cntr_expired <= '1' when (tx_remaining = 0) else '0';
txdesc_new_o <= cur_tx_desc;
src_o.stb <= src_stb_int;
--because it's validated with rtu_rsp_valid_o and sw_core stores it to internal register on rtu_rsp_valid strobe
rtu_port_mask <= cur_tx_desc.dpm(g_port_mask_bits-1 downto 0);
rtu_dst_port_mask_o <= rtu_port_mask;
rtu_prio_o <= (others => '0');
rtu_drop_o <= '0';
count_acks: process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if(rst_n_i='0' or ackcnt_nrst='0') then
ack_count <= (others=>'0');
elsif(src_stb_int = '1' and src_i.stall = '0' and src_i.ack = '0') then
ack_count <= ack_count + 1;
elsif(src_i.ack = '1' and not(src_stb_int = '1' and src_i.stall = '0')) then
ack_count <= ack_count - 1;
end if;
end if;
end process;
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';
src_o.cyc <= '0';
src_stb_int <= '0';
src_o.we <= '1';
src_o.adr <= (others => '0');
src_o.dat <= (others => '0');
src_o.sel <= (others => '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';
ackcnt_nrst <= '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';
ackcnt_nrst <= '0';
if(txdesc_grant_i = '1') then
cur_tx_desc <= txdesc_current_i;
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 =>
txdesc_request_next_o <= '0';
ackcnt_nrst <= '0';
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';
ackcnt_nrst <= '0';
rtu_valid_int <= '1';
ignore_first_hword <= '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;
-- check if the memory is ready, read the 1st word of the payload
if( ( (src_i.stall = '0' and g_cyc_on_stall = false) or g_cyc_on_stall = true)
and buf_grant_i = '0') then
src_o.cyc <= '1';
tx_buf_addr <= tx_buf_addr + 1;
state <= TX_STATUS;
tx_data_reg <= f_buf_swap_endian_32(buf_data_i);
end if;
when TX_STATUS =>
ackcnt_nrst <= '1';
src_o.adr <= c_WRF_STATUS;
src_o.sel <= "11";
src_o.dat <= f_marshall_wrf_status(default_status_reg);
if( src_i.stall = '0' and buf_grant_i = '0') then
src_stb_int <= '1';
state <= TX_HWORD;
else
src_stb_int <= '0';
end if;
when TX_HWORD =>
rtu_valid_int <= '0';
-- generate the control value depending on the packet type, OOB and the current
-- transmission offset.
if(tx_err = '1') then
state <= TX_UPDATE_DESCRIPTOR;
cur_tx_desc.error <= '1';
elsif( src_i.stall = '0' ) then
src_o.adr <= c_WRF_DATA;
src_o.dat <= tx_data_reg(31 downto 16);
ignore_first_hword <= '0';
src_stb_int <= not ignore_first_hword;
if(tx_cntr_expired = '1') then
-- we are at the end of transmitted frame
src_o.sel(1) <= '1';
src_o.sel(0) <= (not odd_length) or needs_padding;
if(needs_padding = '1') then
state <= TX_PAD;
elsif(cur_tx_desc.ts_e = '1') then
state <= TX_OOB1;
else
state <= TX_END_PACKET;
end if;
else
src_o.sel <= "11";
tx_remaining <= tx_remaining - 1;
state <= TX_LWORD;
end if;
end if;
when TX_LWORD =>
-- 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( src_i.stall='0' and buf_grant_i = '0') then
src_o.adr <= c_WRF_DATA;
src_o.dat <= tx_data_reg(15 downto 0);
src_stb_int <= '1';
if(tx_cntr_expired = '0') then
src_o.sel <= "11";
tx_remaining <= tx_remaining - 1;
state <= TX_HWORD;
-- but we also fetch next word from the buffer
tx_data_reg <= f_buf_swap_endian_32(buf_data_i);
tx_buf_addr <= tx_buf_addr + 1;
-- We're at the end of the packet. Generate an end-of-packet condition on the
-- fabric I/F
else
-- (tx_cntr_expired=1) we are at the end of transmitted frame
src_o.sel(1) <= '1';
src_o.sel(0) <= (not odd_length) or needs_padding;
if(needs_padding = '1') then
state <= TX_PAD;
elsif(cur_tx_desc.ts_e = '1') then
state <= TX_OOB1;
else
state <= TX_END_PACKET;
end if;
end if;
elsif( src_i.stall='0' and buf_grant_i = '1') then
--if we wait for buffer then drop stb so that we don't retransmit last data word
src_stb_int <= '0';
end if;
when TX_PAD =>
if(tx_err = '1') then
state <= TX_UPDATE_DESCRIPTOR;
cur_tx_desc.error <= '1';
elsif( src_i.stall='0' ) then
src_o.dat <= x"0000";
src_o.adr <= c_WRF_DATA;
src_o.sel <= "11";
src_stb_int <= '1';
padding_size <= padding_size - 1;
if(padding_size = 0) then
src_stb_int <= '0';
if(cur_tx_desc.ts_e = '1') then
state <= TX_OOB1;
else
state <= TX_END_PACKET;
end if;
end if;
end if;
when TX_OOB1 =>
src_o.sel <= "11";
if( src_i.stall='0' ) then
src_o.dat <= c_WRF_OOB_TYPE_TX & x"000";
src_o.adr <= c_WRF_OOB;
src_stb_int <= '1';
state <= TX_OOB2;
end if;
when TX_OOB2 =>
src_o.sel <= "11";
if( src_i.stall='0' ) then
src_o.dat <= cur_tx_desc.ts_id;
src_o.adr <= c_WRF_OOB;
src_stb_int <= '1';
state <= TX_END_PACKET;
end if;
when TX_END_PACKET =>
src_o.sel <= "11";
if( src_i.stall='0') then
src_stb_int <= '0';
end if;
if( src_i.stall='0' and ack_count = 0) then
state <= TX_UPDATE_DESCRIPTOR;
ackcnt_nrst <= '0';
end if;
when TX_UPDATE_DESCRIPTOR =>
src_o.cyc <= '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;
GEN_RMON: for I in 0 to g_port_mask_bits-1 generate
-- don't need to check if decision is drop, because in NIC, drop is always wired to 0
rmon_events_o(I*g_rmon_events_pp) <= rtu_valid_int and rtu_port_mask(I) and rtu_rsp_ack_i;
end generate;
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 : Mon Aug 1 16:26:56 2016
-- 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);
rxbw_i : std_logic_vector(31 downto 0);
maxrxbw_i : std_logic_vector(15 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'),
rxbw_i => (others => '0'),
maxrxbw_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;
cr_rxthr_en_o : std_logic;
cr_sw_rst_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;
maxrxbw_o : std_logic_vector(15 downto 0);
maxrxbw_load_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',
cr_rxthr_en_o => '0',
cr_sw_rst_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',
maxrxbw_o => (others => '0'),
maxrxbw_load_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;
function f_x_to_zero (x:std_logic_vector) return std_logic_vector;
end package;
package body nic_wbgen2_pkg is
function f_x_to_zero (x:std_logic) return std_logic is
begin
if x = '1' then
return '1';
else
return '0';
end if;
end function;
function f_x_to_zero (x:std_logic_vector) return std_logic_vector is
variable tmp: std_logic_vector(x'length-1 downto 0);
begin
for i in 0 to x'length-1 loop
if x(i) = '1' then
tmp(i):= '1';
else
tmp(i):= '0';
end if;
end loop;
return tmp;
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 := f_x_to_zero(left.sr_bna_i) or f_x_to_zero(right.sr_bna_i);
tmp.sr_rec_i := f_x_to_zero(left.sr_rec_i) or f_x_to_zero(right.sr_rec_i);
tmp.sr_tx_done_i := f_x_to_zero(left.sr_tx_done_i) or f_x_to_zero(right.sr_tx_done_i);
tmp.sr_tx_error_i := f_x_to_zero(left.sr_tx_error_i) or f_x_to_zero(right.sr_tx_error_i);
tmp.sr_cur_tx_desc_i := f_x_to_zero(left.sr_cur_tx_desc_i) or f_x_to_zero(right.sr_cur_tx_desc_i);
tmp.sr_cur_rx_desc_i := f_x_to_zero(left.sr_cur_rx_desc_i) or f_x_to_zero(right.sr_cur_rx_desc_i);
tmp.rxbw_i := f_x_to_zero(left.rxbw_i) or f_x_to_zero(right.rxbw_i);
tmp.maxrxbw_i := f_x_to_zero(left.maxrxbw_i) or f_x_to_zero(right.maxrxbw_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 : Mon Aug 1 16:26:56 2016
-- 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;
clk_sys_i : in std_logic;
wb_adr_i : in std_logic_vector(6 downto 0);
wb_dat_i : in std_logic_vector(31 downto 0);
wb_dat_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_stall_o : out std_logic;
wb_int_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_cr_rxthr_en_int : std_logic ;
signal nic_cr_sw_rst_dly0 : std_logic ;
signal nic_cr_sw_rst_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 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_dat_i;
bwsel_reg <= wb_sel_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 (clk_sys_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';
nic_cr_rxthr_en_int <= '0';
nic_cr_sw_rst_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.maxrxbw_load_o <= '0';
eic_idr_write_int <= '0';
eic_ier_write_int <= '0';
eic_isr_write_int <= '0';
elsif rising_edge(clk_sys_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
nic_cr_sw_rst_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.maxrxbw_load_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.maxrxbw_load_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
nic_cr_rx_en_int <= wrdata_reg(0);
nic_cr_tx_en_int <= wrdata_reg(1);
nic_cr_rxthr_en_int <= wrdata_reg(2);
nic_cr_sw_rst_int <= wrdata_reg(31);
end if;
rddata_reg(0) <= nic_cr_rx_en_int;
rddata_reg(1) <= nic_cr_tx_en_int;
rddata_reg(2) <= nic_cr_rxthr_en_int;
rddata_reg(31) <= '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';
ack_sreg(2) <= '1';
ack_in_progress <= '1';
when "0001" =>
if (wb_we_i = '1') then
regs_o.sr_rec_load_o <= '1';
regs_o.sr_tx_done_load_o <= '1';
regs_o.sr_tx_error_load_o <= '1';
end if;
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';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "0010" =>
if (wb_we_i = '1') then
end if;
rddata_reg(31 downto 0) <= regs_i.rxbw_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "0011" =>
if (wb_we_i = '1') then
regs_o.maxrxbw_load_o <= '1';
end if;
rddata_reg(15 downto 0) <= regs_i.maxrxbw_i;
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';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "1000" =>
if (wb_we_i = '1') then
eic_idr_write_int <= '1';
end if;
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';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "1001" =>
if (wb_we_i = '1') then
eic_ier_write_int <= '1';
end if;
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';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "1010" =>
if (wb_we_i = '1') then
end if;
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';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "1011" =>
if (wb_we_i = '1') then
eic_isr_write_int <= '1';
end if;
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';
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_adr_i )
begin
case rwaddr_reg(6 downto 5) is
when "01" =>
wb_dat_o(31 downto 0) <= nic_dtx_rddata_int;
when "10" =>
wb_dat_o(31 downto 0) <= nic_drx_rddata_int;
when others =>
wb_dat_o <= rddata_reg;
end case;
end process;
-- Read & write lines decoder for RAMs
process (wb_adr_i, rd_int, wr_int )
begin
if (wb_adr_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_adr_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;
-- Rx bandwidth throttling enable
regs_o.cr_rxthr_en_o <= nic_cr_rxthr_en_int;
-- Software Reset
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
nic_cr_sw_rst_dly0 <= '0';
regs_o.cr_sw_rst_o <= '0';
elsif rising_edge(clk_sys_i) then
nic_cr_sw_rst_dly0 <= nic_cr_sw_rst_int;
regs_o.cr_sw_rst_o <= nic_cr_sw_rst_int and (not nic_cr_sw_rst_dly0);
end if;
end process;
-- 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
-- Bytes-per-second
-- KBytes-per-second
regs_o.maxrxbw_o <= wrdata_reg(15 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 => clk_sys_i,
clk_b_i => clk_sys_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 => clk_sys_i,
clk_b_i => clk_sys_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 => clk_sys_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_int_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_adr_i;
wb_stall_o <= (not ack_sreg(0)) and (wb_stb_i and wb_cyc_i);
-- ACK signal generation. Just pass the LSB of ACK counter.
wb_ack_o <= ack_sreg(0);
end syn;
-------------------------------------------------------------------------------
-- Title : Network Interface Controller
-- Project : White Rabbit Switch
-------------------------------------------------------------------------------
-- File : wr_nic.vhd
-- Author : Tomasz Wlostowski, Grzegorz Daniluk
-- Company : CERN BE-CO-HT
-- Created : 2012-01-19
-- Last update: 2014-02-14
-- Platform : FPGA-generic
-- Standard : VHDL
-------------------------------------------------------------------------------
-- Description:
-- std-logic-based wrapper for xwr_nic module
--
-------------------------------------------------------------------------------
--
-- Copyright (c) 2012 - 2014 CERN / BE-CO-HT
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
library work;
use work.wishbone_pkg.all;
use work.wr_fabric_pkg.all;
entity wr_nic is
generic
(
g_interface_mode : t_wishbone_interface_mode := CLASSIC;
g_address_granularity : t_wishbone_address_granularity := WORD;
g_src_cyc_on_stall : boolean := false;
g_port_mask_bits : integer := 32); --should be num_ports+1
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
pps_p_i : in std_logic;
pps_valid_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(g_port_mask_bits-1 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;
int_o : out std_logic
);
end wr_nic;
architecture rtl of wr_nic is
component xwr_nic
generic (
g_interface_mode : t_wishbone_interface_mode;
g_address_granularity : t_wishbone_address_granularity;
g_src_cyc_on_stall : boolean := false;
g_port_mask_bits : integer := 32);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
pps_p_i : in std_logic;
pps_valid_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(g_port_mask_bits-1 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;
int_o : out std_logic);
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 : xwr_nic
generic map (
g_interface_mode => g_interface_mode,
g_address_granularity => g_address_granularity,
g_src_cyc_on_stall => g_src_cyc_on_stall,
g_port_mask_bits => g_port_mask_bits)
port map (
clk_sys_i => clk_sys_i,
rst_n_i => rst_n_i,
pps_p_i => pps_p_i,
pps_valid_i => pps_valid_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,
int_o => int_o);
-- 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;
end rtl;
-- -*- 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 \
\
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;
};
field {
name = "Rx bandwidth throttling enable";
description = "Enables bandwidth throttling for received traffic. \
This is to prevent blocking ARM CPU with interrupts coming from NIC";
prefix = "rxthr_en";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Software Reset";
description = "write 1: reset the NIC, zero all registers and reset the state of the module \
write 0: no effect";
prefix = "sw_rst";
size = 1;
align = 31;
type = MONOSTABLE;
};
};
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 = "NIC Current Rx Bandwidth Register";
prefix = "RXBW";
field {
name = "Bytes-per-second";
type = SLV;
size = 32;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
load = LOAD_EXT;
};
};
reg {
name = "NIC Max Rx Bandwidth Register";
prefix = "MAXRXBW";
field {
name = "KBytes-per-second";
type = SLV;
size = 16;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
load = LOAD_EXT;
};
};
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 = 16;
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 = 16;
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;
};
field {
name = "RX Timestamp (possibly) incorrect";
prefix = "TS_INCORRECT";
align = 15;
description = "1 - there is a risk that the timestamp in RX_D2 is invalid, because it was taken during counter adjustment,\
0 - RX timestamp OK.";
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";
prefix = "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";
prefix = "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 = 16;
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 = 16;
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(1);
-------------------------------------------------------------------------------
-- Title : Network Interface Controller
-- Project : White Rabbit Switch
-------------------------------------------------------------------------------
-- File : xwr_nic.vhd
-- Author : Tomasz Wlostowski, Grzegorz Daniluk
-- Company : CERN BE-CO-HT
-- Created : 2012-01-19
-- Last update: 2014-02-14
-- Platform : FPGA-generic
-- Standard : VHDL
-------------------------------------------------------------------------------
-- Description:
-- Module responsible for passing Ethernet frames between the Linux running on
-- main ARM processor and 18 ports of the WR Switch. It contains a frame
-- buffer and two RAM blocks (TX descriptors memory, RX descriptors memory)
-- storing descriptors for frames received and frames to be sent. Frame buffer
-- stores all frames received from physical ports of the WR Switch (addressed to
-- the main processor) and frames that main processor wants to send to the ports
-- of WR Switch. Each frame has an associated descriptor which contains various
-- information about its structure.
--
-------------------------------------------------------------------------------
--
-- Copyright (c) 2012 - 2014 CERN / BE-CO-HT
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
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 xwr_nic is
generic
(
g_interface_mode : t_wishbone_interface_mode := CLASSIC;
g_address_granularity : t_wishbone_address_granularity := WORD;
g_src_cyc_on_stall : boolean := false;
g_port_mask_bits : integer := 32; --should be num_ports+1
g_rmon_events_pp : integer := 1);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
pps_p_i : in std_logic;
pps_valid_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(g_port_mask_bits-1 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;
int_o: out std_logic;
-------------------------------------------------------------------------------
-- RMON events
-------------------------------------------------------------------------------
rmon_events_o : out std_logic_vector(g_port_mask_bits*g_rmon_events_pp-1 downto 0)
);
end xwr_nic;
architecture rtl of xwr_nic is
component nic_descriptor_manager
generic (
g_desc_mode : string;
g_num_descriptors : integer;
g_num_descriptors_log2 : integer;
g_port_mask_bits : integer := 32);
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;
pps_p_i : in std_logic;
pps_valid_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;
bna_i : in std_logic;
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;
clk_sys_i : in std_logic;
wb_adr_i : in std_logic_vector(6 downto 0);
wb_dat_i : in std_logic_vector(31 downto 0);
wb_dat_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_stall_o : out std_logic;
wb_int_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
generic(
g_port_mask_bits : integer := 32;
g_cyc_on_stall : boolean := false;
g_rmon_events_pp : integer := 1);
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(g_port_mask_bits-1 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);
rmon_events_o : out std_logic_vector(g_port_mask_bits*g_rmon_events_pp-1 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);
wb_out.err <= '0';
wb_out.rty <= '0';
nic_reset_n <= rst_n_i and (not regs_fromwb.cr_sw_rst_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,
clk_sys_i => clk_sys_i,
wb_adr_i => wb_in.adr(6 downto 0),
wb_dat_i => wb_in.dat,
wb_dat_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_stall_o=> wb_out.stall,
wb_int_o => int_o,
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,
g_port_mask_bits => g_port_mask_bits)
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,
pps_p_i => pps_p_i,
pps_valid_i => pps_valid_i,
snk_i => snk_i,
snk_o => snk_o,
bna_i => regs_towb_main.sr_bna_i,
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,
g_port_mask_bits => g_port_mask_bits)
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
generic map(
g_cyc_on_stall => g_src_cyc_on_stall,
g_port_mask_bits => g_port_mask_bits,
g_rmon_events_pp => g_rmon_events_pp)
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,
rmon_events_o => rmon_events_o);
end rtl;
`define ADDR_NIC_CR 9'h0
`define NIC_CR_RX_EN_OFFSET 0
`define NIC_CR_RX_EN 32'h00000001
`define NIC_CR_TX_EN_OFFSET 1
`define NIC_CR_TX_EN 32'h00000002
`define NIC_CR_RXTHR_EN_OFFSET 2
`define NIC_CR_RXTHR_EN 32'h00000004
`define NIC_CR_SW_RST_OFFSET 31
`define NIC_CR_SW_RST 32'h80000000
`define ADDR_NIC_SR 9'h4
`define NIC_SR_BNA_OFFSET 0
`define NIC_SR_BNA 32'h00000001
`define NIC_SR_REC_OFFSET 1
`define NIC_SR_REC 32'h00000002
`define NIC_SR_TX_DONE_OFFSET 2
`define NIC_SR_TX_DONE 32'h00000004
`define NIC_SR_TX_ERROR_OFFSET 3
`define NIC_SR_TX_ERROR 32'h00000008
`define NIC_SR_CUR_TX_DESC_OFFSET 8
`define NIC_SR_CUR_TX_DESC 32'h00000700
`define NIC_SR_CUR_RX_DESC_OFFSET 16
`define NIC_SR_CUR_RX_DESC 32'h00070000
`define ADDR_NIC_RXBW 9'h8
`define ADDR_NIC_MAXRXBW 9'hc
`define ADDR_NIC_EIC_IDR 9'h20
`define NIC_EIC_IDR_RCOMP_OFFSET 0
`define NIC_EIC_IDR_RCOMP 32'h00000001
`define NIC_EIC_IDR_TCOMP_OFFSET 1
`define NIC_EIC_IDR_TCOMP 32'h00000002
`define NIC_EIC_IDR_TXERR_OFFSET 2
`define NIC_EIC_IDR_TXERR 32'h00000004
`define ADDR_NIC_EIC_IER 9'h24
`define NIC_EIC_IER_RCOMP_OFFSET 0
`define NIC_EIC_IER_RCOMP 32'h00000001
`define NIC_EIC_IER_TCOMP_OFFSET 1
`define NIC_EIC_IER_TCOMP 32'h00000002
`define NIC_EIC_IER_TXERR_OFFSET 2
`define NIC_EIC_IER_TXERR 32'h00000004
`define ADDR_NIC_EIC_IMR 9'h28
`define NIC_EIC_IMR_RCOMP_OFFSET 0
`define NIC_EIC_IMR_RCOMP 32'h00000001
`define NIC_EIC_IMR_TCOMP_OFFSET 1
`define NIC_EIC_IMR_TCOMP 32'h00000002
`define NIC_EIC_IMR_TXERR_OFFSET 2
`define NIC_EIC_IMR_TXERR 32'h00000004
`define ADDR_NIC_EIC_ISR 9'h2c
`define NIC_EIC_ISR_RCOMP_OFFSET 0
`define NIC_EIC_ISR_RCOMP 32'h00000001
`define NIC_EIC_ISR_TCOMP_OFFSET 1
`define NIC_EIC_ISR_TCOMP 32'h00000002
`define NIC_EIC_ISR_TXERR_OFFSET 2
`define NIC_EIC_ISR_TXERR 32'h00000004
`define BASE_NIC_DTX 9'h80
`define SIZE_NIC_DTX 32'h20
`define BASE_NIC_DRX 9'h100
`define SIZE_NIC_DRX 32'h20
`ifndef __SIMDRV_WR_NIC_SVH
`define __SIMDRV_WR_NIC_SVH 1
`timescale 1ns/1ps
`include "simdrv_defs.svh"
`include "eth_packet.svh"
`include "wb_packet_source.svh"
`include "wb_packet_sink.svh"
`include "regs/nic_regs.vh"
`define MAX_PACKET_SIZE 1536
// fake, simulated spinlock
typedef struct {
int locked;
} spinlock_t;
// RX and TX descriptor definitions
typedef struct {
bit empty;
bit error;
bit[5:0] port_id;
bit got_ts;
bit[27:0] ts_r;
bit[3:0] ts_f;
bit[15:0] length;
bit[15:0] offset;
} nic_rx_descriptor_t ;
typedef struct {
bit ready;
bit error;
bit pad_e;
bit ts_e;
bit[15:0] ts_id;
bit[31:0] dpm;
bit[15:0] length;
bit[15:0] offset;
} nic_tx_descriptor_t ;
`define NUM_RX_DESC 8
`define NUM_TX_DESC 8
`define PACKET_QUEUE_SIZE 64
`define BASE_NIC_MEM 'h8000
class CSimDrv_NIC;
bit little_endian;
int tx_oob_fid;
int rx_head_idx;
int tx_head_idx;
int tx_irq_enabled;
int tx_queue_active = 0;
protected uint16_t untag_tab[256];
spinlock_t tx_lock;
EthPacket rx_queue[$], tx_queue[$];
CBusAccessor acc_regs;
uint64_t base_addr;
function new(CBusAccessor regs_, uint64_t base_addr_, bit little_endian_=1);
base_addr = base_addr_;
acc_regs = regs_;
little_endian = little_endian_;
endfunction // new
function automatic logic[31:0] swap_endian(input [31:0] data);
if(little_endian)
return {data[7:0], data[15:8], data[23:16], data[31:24]};
else
return data;
endfunction // swap_endian
task writel(uint32_t addr, uint32_t val);
acc_regs.write(base_addr + addr, val, 4);
endtask // writel
task readl(uint32_t addr, output uint32_t val);
uint64_t tmp;
acc_regs.read(base_addr + addr, tmp, 4);
val = tmp;
endtask // readl
task automatic enable_rx();
bit[31:0] tmp;
readl(`ADDR_NIC_CR, tmp);
writel(`ADDR_NIC_CR, tmp | `NIC_CR_RX_EN);
writel(`ADDR_NIC_EIC_IER, `NIC_EIC_IER_RCOMP); // enable RX interrupt
endtask // automatic
task automatic enable_tx();
bit[31:0] tmp;
tx_irq_enabled = 1;
readl(`ADDR_NIC_CR, tmp);
writel(`ADDR_NIC_CR, tmp | `NIC_CR_TX_EN);
writel(`ADDR_NIC_EIC_IER, `NIC_EIC_IER_TCOMP | `NIC_EIC_IER_TXERR); // enable TXCOMP & TXERR interrupts
endtask // automatic
task automatic disable_tx();
bit[31:0] tmp;
readl(`ADDR_NIC_CR, tmp);
tmp = tmp & ~(`NIC_CR_TX_EN);
writel(`ADDR_NIC_CR, tmp);
writel(`ADDR_NIC_EIC_IDR, `NIC_EIC_IER_TCOMP | `NIC_EIC_IER_TXERR); // enable TXCOMP & TXERR interrupts
tx_irq_enabled = 0;
endtask // automatic
task automatic disable_rx();
bit[31:0] tmp;
readl(`ADDR_NIC_CR, tmp);
tmp = tmp & (~`NIC_CR_RX_EN);
writel(`ADDR_NIC_CR, tmp);
writel(`ADDR_NIC_EIC_IDR, `NIC_EIC_IER_RCOMP); // disable RX interrupt
endtask // automatic
task automatic write_rx_desc(int idx, nic_rx_descriptor_t desc);
// IF RX is enabled, make sure we're not chaging the address/length of an active (empty) descriptor.
writel(`BASE_NIC_DRX + (idx * 16 + 8), (desc.length << 16) | desc.offset);
writel(`BASE_NIC_DRX + (idx * 16), { 30'h0 , 1'b0, desc.empty} );
endtask // write_rx_desc
task automatic write_tx_desc(int idx, nic_tx_descriptor_t desc);
// IF RX is enabled, make sure we're not chaging the address/length of an active (empty) descriptor.
writel(`BASE_NIC_DTX + (idx * 16 + 8), (desc.dpm));
writel(`BASE_NIC_DTX + (idx * 16 + 4), (desc.length << 16) | desc.offset);
writel(`BASE_NIC_DTX + (idx * 16), { desc.ts_id, 12'h0, desc.pad_e, desc.ts_e , 1'b0, desc.ready} );
endtask // write_tx_desc
task automatic read_rx_desc(int idx, output nic_rx_descriptor_t desc);
bit [31:0] tmp;
// $display("IDx %d\n", idx);
readl(`BASE_NIC_DRX + (idx * 16 + 0), tmp);
// $display("r0 %x", tmp);
desc.port_id = tmp[13:8];
desc.got_ts = tmp[14];
desc.error = tmp[1];
desc.empty = tmp[0];
readl(`BASE_NIC_DRX + (idx * 16 + 4), tmp);
// $display("r1 %x", tmp);
desc.ts_f = tmp[31:28];
desc.ts_r = tmp[27:0];
readl(`BASE_NIC_DRX + (idx * 16 + 8), tmp);
// $display("r2 %x", tmp);
desc.length = tmp[31:16];
desc.offset = tmp[15:0];
endtask // write_rx_desc
task automatic read_tx_desc(int idx, output nic_tx_descriptor_t desc);
bit[31:0] tmp;
readl(`BASE_NIC_DTX + (idx * 16 + 0), tmp);
desc.ts_id = tmp[31:16];
desc.pad_e = tmp[3];
desc.ts_e = tmp[2];
desc.error = tmp[1];
desc.ready = tmp[0];
readl(`BASE_NIC_DTX + (idx * 16 + 4), tmp);
desc.length = tmp[31:16];
desc.offset = tmp[15:0];
readl(`BASE_NIC_DTX + (idx * 16 + 8), tmp);
desc.dpm = tmp;
endtask // read_tx_desc
task automatic create_rx_desc(int idx, int offset, int length);
nic_rx_descriptor_t desc;
desc.offset = offset;
desc.length = length;
desc.empty = 1;
desc.error = 0;
desc.got_ts = 0;
write_rx_desc(idx, desc);
endtask // automatic
task automatic create_tx_desc(int idx, int offset, int length, int ts_e);
nic_tx_descriptor_t desc;
desc.offset = offset;
desc.length = length;
desc.ready = 1;
desc.pad_e = (length < 59) ? 1: 0;
desc.ts_e = ts_e;
desc.ts_id = (ts_e ? tx_oob_fid ++ : 0);
desc.dpm = 32'hffffffff;
write_tx_desc(idx, desc);
endtask // automatic
int count;
task automatic nic_hw_rx(nic_rx_descriptor_t desc);
EthPacket pkt;
int i, n;
string s;
u64_array_t pbuff;
byte_array_t payload, p2;
pbuff = new[2048];
count++;
// $display("Cnt %d [dsize %d]", count, desc.length);
for(i=0; i<(desc.length+8)/4 ; i++)
begin
bit [31:0] tmp;
readl(`BASE_NIC_MEM + desc.offset + i * 4, tmp);
tmp = swap_endian(tmp);
pbuff[i] = tmp;
end
pkt = new;
payload = SimUtils.unpack(pbuff, 4, desc.length + 2);
p2 = new[desc.length];
for (i=0;i<desc.length;i++)
p2[i] = payload[i+2];
pkt.deserialize(p2);
pkt.error = desc.error;
rx_queue.push_back(pkt);
endtask // automatic
task spin_lock_init(inout spinlock_t lck);
lck.locked =0;
endtask // spinlock_init
task spin_lock(inout spinlock_t lck);
while(lck.locked) #1ns;
lck.locked =1;
endtask // spin_lock
task spin_unlock(inout spinlock_t lck);
lck.locked =0;
endtask // spin_unlock
task automatic nic_hw_tx(int idx, EthPacket pkt);
nic_tx_descriptor_t desc;
reg[31:0] tmp;
u64_array_t pbuf;
byte payload[];
int i;
pkt.serialize(payload);
desc.offset = 'h4000 + idx * 'h800;
desc.length = payload.size();
desc.pad_e = (desc.length < 60 ? 1 : 0);
desc.ts_e = (pkt.oob == TX_FID ? 1: 0);
desc.dpm = 32'hffffffff;
desc.ts_id = tx_oob_fid++;
desc.ready = 1;
desc.error = 0;
pbuf = SimUtils.pack({0,0,payload}, 4, 1);
for(i=0;i<pbuf.size(); i++)
writel(`BASE_NIC_MEM + desc.offset + i * 4, swap_endian(pbuf[i]));
write_tx_desc(idx, desc);
endtask // automatic
task automatic nic_start_xmit(EthPacket pkt, output ok);
//FIXME: check if there are any free descriptors
reg[31:0] rval;
nic_tx_descriptor_t desc;
spin_lock(tx_lock); // make sure the interrupt handler won't make a mess here
read_tx_desc(tx_head_idx, desc);
if(desc.ready) // the head descriptor still hasn't been transmitted? Perhaps the NIC is still transmitting it.
begin
$display("nic_start_xmit: no free tx descriptors");
spin_unlock(tx_lock);
ok = 0;
return;
end
nic_hw_tx(tx_head_idx, pkt);
tx_head_idx++;
if(tx_head_idx == `NUM_TX_DESC)
tx_head_idx = 0;
spin_unlock(tx_lock);
enable_tx();
ok =1;
endtask // nic_start_xmit
task automatic handle_rcomp_irq();
nic_rx_descriptor_t desc;
int n_read;
n_read = 0;
forever begin
read_rx_desc(rx_head_idx, desc);
if(desc.empty /* || n_read == `NUM_RX_DESC */)
break;
// $display("Offset: %x len: %d error: %d port_id %d ts_r %d ts_f %d got_ts %d",desc.offset, desc.length, desc.error, desc.port_id, desc.ts_r, desc.ts_f, desc.got_ts);
nic_hw_rx(desc);
create_rx_desc(rx_head_idx, 'h800*rx_head_idx, 1600);
rx_head_idx++;
if(rx_head_idx == `NUM_RX_DESC)
rx_head_idx = 0;
n_read++;
end
writel(`ADDR_NIC_EIC_ISR, `NIC_EIC_ISR_RCOMP);
endtask // automatic
task automatic handle_tcomp_irq();
nic_tx_descriptor_t desc;
EthPacket pkt;
spin_lock(tx_lock);
if(!tx_queue.size())
begin
disable_tx(); // disable TX irq
tx_head_idx = 0;
writel(`ADDR_NIC_EIC_ISR, `NIC_EIC_ISR_TCOMP);
spin_unlock(tx_lock);
return;
end
while(tx_queue.size() > 0)
begin
read_tx_desc(tx_head_idx, desc);
if(desc.ready || desc.error) // the head descriptor still hasn't been transmitted? Perhaps the NIC is still transmitting it.
begin
$display("handle_tcomp_irq: no free TX descriptors at the moment");
break;
end
pkt = tx_queue.pop_front();
nic_hw_tx(tx_head_idx, pkt);
tx_head_idx++;
if(tx_head_idx == `NUM_TX_DESC)
tx_head_idx = 0;
end // while (tx_queue.get_count())
writel(`ADDR_NIC_EIC_ISR, `NIC_EIC_ISR_TCOMP);
spin_unlock(tx_lock);
endtask // handle_tcomp_irq
task automatic handle_txerr_irq();
nic_tx_descriptor_t desc;
int cur_tx_desc;
reg[31:0] tmp;
readl(`ADDR_NIC_SR, tmp);
cur_tx_desc = (tmp & `NIC_SR_CUR_TX_DESC) >> `NIC_SR_CUR_TX_DESC_OFFSET;
read_tx_desc(cur_tx_desc, desc);
$display("TXerror: faulty descriptor %d error %b ready %b offset %x len %d", cur_tx_desc,desc.error, desc.ready, desc.offset, desc.length);
desc.error = 0;
desc.ready = 1; // just clear the error and try to retransmit
write_tx_desc(cur_tx_desc, desc);
writel(`ADDR_NIC_EIC_ISR, `NIC_EIC_ISR_TXERR);
// $stop;
endtask // automatic
task automatic nic_irq_handler();
reg[31:0] isr;
readl(`ADDR_NIC_EIC_ISR, isr);
// $display("irq_handler: isr %x", isr[2:0]);
if(isr & `NIC_EIC_ISR_RCOMP)
handle_rcomp_irq();
if(isr & `NIC_EIC_ISR_TXERR)
handle_txerr_irq();
if(isr & `NIC_EIC_ISR_TCOMP)
handle_tcomp_irq();
endtask // automatic
task automatic init();
int i;
disable_rx();
disable_tx();
spin_lock_init(tx_lock);
for(i=0; i<`NUM_RX_DESC * 4; i++)
begin
writel(`BASE_NIC_DRX + i *4, 0); // clear the descriptor tables
writel(`BASE_NIC_DTX + i *4, 0); // clear the descriptor tables
end
for(i=0; i<`NUM_RX_DESC; i++)
create_rx_desc(i, 'h800*i, 1600); // create NUM_RX_DESC empty RX descriptors
rx_head_idx = 0;
tx_head_idx = 0;
tx_oob_fid = 100;
tx_queue_active = 1;
enable_rx();
endtask
task update(bit nic_irq);
if(nic_irq) begin
nic_irq_handler();
#50ns;
end
if(tx_queue_active && tx_queue.size() > 0 && !tx_irq_enabled) begin
reg ok;
EthPacket pkt;
pkt = tx_queue.pop_front();
nic_start_xmit(pkt, ok);
end
endtask // update
endclass // CSimDrv_NIC
class NICPacketSource extends EthPacketSource;
CSimDrv_NIC nic;
function new (ref CSimDrv_NIC nic_);
nic = nic_;
endfunction // new
task send(ref EthPacket pkt, ref int result = _null);
nic.tx_queue.push_back(pkt);
endtask // send
endclass
class NICPacketSink extends EthPacketSink;
CSimDrv_NIC nic;
function new (ref CSimDrv_NIC nic_);
nic = nic_;
endfunction // new
function int poll();
return (nic.rx_queue.size() > 0) ? 1 :0;
endfunction // poll
//ML stuff
function int permanent_stall_enable();
//empty
return 0;
endfunction
//ML stuff
function int permanent_stall_disable();
// empty
return 0;
endfunction
task recv(ref EthPacket pkt, ref int result = _null);
while(!nic.rx_queue.size()) #1ns;
pkt = nic.rx_queue.pop_front();
endtask
endclass // NICPacketSink
`endif
This source diff could not be displayed because it is too large. You can view the blob instead.
target = "xilinx"
action = "simulation"
sim_tool = "modelsim"
top_module = "main"
syn_device = "XC6VLX130T"
fetchto = "../../ip_cores"
vlog_opt = "+incdir+../../sim +incdir+../../sim/wr-hdl"
files = [ "main.sv" ]
include_dirs = [ "../../sim" ]
modules = { "local" : ["../../top/bare_top",
"../../ip_cores/general-cores",
"../../ip_cores/wr-cores"] }
`include "if_wb_master.svh"
`include "if_wb_slave.svh"
`include "if_wb_link.svh"
`include "wb_packet_source.svh"
`include "wb_packet_sink.svh"
import wr_fabric_pkg::*;
`define WIRE_WB_SINK(iface, prefix) \
.prefix``_adr_i(iface.adr), \
.prefix``_dat_i(iface.dat_o), \
.prefix``_stb_i(iface.stb), \
.prefix``_sel_i(iface.sel), \
.prefix``_cyc_i(iface.cyc), \
.prefix``_ack_o(iface.ack), \
.prefix``_err_o(iface.err), \
.prefix``_stall_o(iface.stall)
`define WIRE_WB_SOURCE(iface, prefix) \
.prefix``_adr_o(iface.adr), \
.prefix``_dat_o(iface.dat_i), \
.prefix``_stb_o(iface.stb), \
.prefix``_sel_o(iface.sel), \
.prefix``_cyc_o(iface.cyc), \
.prefix``_ack_i(iface.ack), \
.prefix``_err_i(iface.err), \
.prefix``_stall_i(iface.stall)
`define WIRE_WRF_SRC(dst, src) \
assign dst``_o.cyc = src.cyc; \
assign dst``_o.stb = src.stb; \
assign dst``_o.adr = src.adr; \
assign dst``_o.dat = src.dat_o; \
assign dst``_o.sel = src.sel; \
assign src.ack = dst``_i.ack; \
assign src.err = dst``_i.err; \
assign src.stall = dst``_i.stall;
`define WIRE_WRF_SRC_I(dst, src, i) \
assign dst``_o[i].cyc = src.cyc; \
assign dst``_o[i].stb = src.stb; \
assign dst``_o[i].adr = src.adr; \
assign dst``_o[i].dat = src.dat_o; \
assign dst``_o[i].sel = src.sel; \
assign src.ack = dst``_i[i].ack; \
assign src.err = dst``_i[i].err; \
assign src.stall = dst``_i[i].stall;
`define WIRE_WRF_SNK(dst, src) \
assign dst.cyc = src``_i.cyc; \
assign dst.stb = src``_i.stb; \
assign dst.adr = src``_i.adr; \
assign dst.dat_i = src``_i.dat; \
assign dst.sel = src``_i.sel; \
assign src``_o.ack = dst.ack; \
assign src``_o.err = dst.err; \
assign src``_o.stall = dst.stall;
`define WIRE_WRF_SNK_I(dst, src, i) \
assign dst.cyc = src``_i[i].cyc; \
assign dst.stb = src``_i[i].stb; \
assign dst.adr = src``_i[i].adr; \
assign dst.dat_i = src``_i[i].dat; \
assign dst.sel = src``_i[i].sel; \
assign src``_o[i].ack = dst.ack; \
assign src``_o[i].err = dst.err; \
assign src``_o[i].stall = dst.stall;
module mux_svwrap (
input clk_sys_i,
input rst_n_i,
input pps_i,
input [15:0]maxbw,
input new_set
);
IWishboneMaster #(2,16) U_ep_src (clk_sys_i, rst_n_i);
IWishboneMaster #(2,16) U_minic_src (clk_sys_i, rst_n_i);
IWishboneMaster #(2,16) U_ext_src (clk_sys_i, rst_n_i);
IWishboneSlave #(2,16) U_ep_snk (clk_sys_i, rst_n_i);
IWishboneSlave #(2,16) U_minic_snk (clk_sys_i, rst_n_i);
IWishboneSlave #(2,16) U_ext_snk (clk_sys_i, rst_n_i);
IWishboneMaster #(2,16) U_mux_src (clk_sys_i, rst_n_i);
IWishboneSlave #(2,16) U_mux_snk (clk_sys_i, rst_n_i);
t_wrf_source_out ep_src_o;
t_wrf_source_in ep_src_i;
t_wrf_sink_out ep_snk_o;
t_wrf_sink_in ep_snk_i;
`WIRE_WRF_SRC(ep_src, U_ep_src);
`WIRE_WRF_SNK(U_ep_snk, ep_snk);
t_wrf_source_out mux_src_o[2:0];
t_wrf_source_in mux_src_i[2:0];
t_wrf_sink_out mux_snk_o[2:0];
t_wrf_sink_in mux_snk_i[2:0];
`WIRE_WRF_SRC_I(mux_src, U_minic_src, 0);
`WIRE_WRF_SNK_I(U_minic_snk, mux_snk, 0);
//assign U_minic_snk.cyc = 1'b1; //mux_snk_i[0].cyc;
//assign U_minic_snk.stb = mux_snk_i[0].stb;
//assign mux_snk_o[0].ack = U_minic_snk.ack;
//assign mux_snk_o[0].err= U_minic_snk.err;
//assign mux_snk_o[0].stall = U_minic_snk.stall;
`WIRE_WRF_SRC_I(mux_src, U_ext_src, 1);
`WIRE_WRF_SNK_I(U_ext_snk, mux_snk, 1);
`WIRE_WRF_SRC_I(mux_src, U_mux_src, 2);
`WIRE_WRF_SNK_I(U_mux_snk, mux_snk, 2);
reg [7:0]muxclass[2:0] = {8'h03, 8'h0c, 8'hf0};
nic_bw_throttling
U_DUT
(
.rst_n_i (rst_n_i),
.clk_sys_i (clk_sys_i),
.pps_valid_i(1'b1),
.pps_p_i(pps_i),
.new_limit_i(new_set),
.bwmax_kbps_i(maxbw), //(16'hE0),
.snk_i (mux_src_o[0]),
.snk_o (mux_src_i[0]),
.src_i (ep_snk_o),
.src_o (ep_snk_i),
.en_i(1'b1)
);
assign U_ep_snk.we = 1;
assign U_minic_snk.we = 1;
assign U_ext_snk.we = 1;
assign U_mux_snk.we = 1;
WBPacketSource ep_src, minic_src, ext_src, mux_src;
WBPacketSink ep_snk, minic_snk, ext_snk, mux_snk;
initial begin
@(posedge rst_n_i);
@(posedge clk_sys_i);
ep_src = new(U_ep_src.get_accessor());
minic_src = new(U_minic_src.get_accessor());
ext_src = new(U_ext_src.get_accessor());
mux_src = new(U_mux_src.get_accessor());
ep_snk = new(U_ep_snk.get_accessor());
minic_snk = new(U_minic_snk.get_accessor());
ext_snk = new(U_ext_snk.get_accessor());
mux_snk = new(U_mux_snk.get_accessor());
U_ep_src.settings.cyc_on_stall = 1;
U_minic_src.settings.cyc_on_stall = 1;
U_ext_src.settings.cyc_on_stall = 1;
U_mux_src.settings.cyc_on_stall = 1;
end
endmodule // mux_svwrap
module main;
reg clk_ref = 1'b0;
wire clk_sys ;
reg rst_n = 1'b0;
reg pps = 1'b0;
reg [15:0]maxbw;
reg new_set;
always #2ns clk_ref <= ~clk_ref;
assign clk_sys = clk_ref;
initial begin
repeat(3) @(posedge clk_sys);
rst_n <= 1'b1;
end
always #1196us begin
pps <= 1'b1;
#4ns
pps <= 1'b0;
end
initial begin
maxbw <= 16'h00;
new_set <= 1'b0;
#14ns;
maxbw <= 16'hE0;
new_set <= 1'b1;
#4ns;
new_set <= 1'b0;
#4015856ns;
maxbw <= 16'h70;
new_set <= 1'b1;
#4ns;
new_set <= 1'b0;
end
mux_svwrap DUT (clk_sys, rst_n, pps, maxbw, new_set);
task verify_rx_queue(WBPacketSink snk, EthPacket q[$], output int n_packets);
automatic int n;
n =0;
while(snk.poll())
begin
EthPacket from_q, pkt;
n++;
snk.recv(pkt);
from_q = q.pop_front();
if(!pkt.equal(from_q))
begin
pkt.dump();
from_q.dump(); $stop;
end
end
n_packets = n;
endtask // verify_rx_queue
task automatic send_random_packets(WBPacketSource src,ref EthPacket q[$], input int n_packets, input int pclass);
EthPacket pkt, tmpl;
EthPacketGenerator gen = new;
int i;
tmpl = new;
tmpl.src = '{1,2,3,4,5,6};
tmpl.dst = '{10,11,12,13,14,15};
tmpl.has_smac = 1;
tmpl.is_q = 0;
gen.set_randomization(EthPacketGenerator::SEQ_PAYLOAD | EthPacketGenerator::ETHERTYPE /*| EthPacketGenerator::RX_OOB*/) ;
gen.set_template(tmpl);
gen.set_size(46, 1000);
for(i=0;i<n_packets;i++)
begin
pkt = gen.gen();
pkt.pclass = pclass;
q.push_back(pkt);
src.send(pkt);
end
endtask // send_random_packets
task test_classifier(int n_packets);
int i, seed = 0,n1=0,n2=0;
EthPacket pkt, tmpl;
EthPacket to_ext[$], to_minic[$];
EthPacketGenerator gen = new;
tmpl = new;
tmpl.src = '{1,2,3,4,5,6};
tmpl.dst = '{10,11,12,13,14,15};
tmpl.has_smac = 1;
tmpl.is_q = 0;
gen.set_randomization(EthPacketGenerator::SEQ_PAYLOAD | EthPacketGenerator::ETHERTYPE /*| EthPacketGenerator::RX_OOB*/) ;
gen.set_template(tmpl);
gen.set_size(46, 1000);
for(i=0;i<n_packets;i++)
begin
pkt = gen.gen();
pkt.pclass = (1<<$dist_uniform(seed,0,7));
if(pkt.pclass & 'hf0)
to_minic.push_back(pkt);
else
to_ext.push_back(pkt);
DUT.ep_src.send(pkt);
end
verify_rx_queue(DUT.ext_snk, to_ext, n1);
verify_rx_queue(DUT.minic_snk, to_minic, n2);
if(n1+n2 != n_packets)
$error("FAILURE n1 %d n2 %d n_packets %d", n1, n2, n_packets);
else
$display("PASS");
endtask // test_classifier
task automatic test_arbiter(int n_packets);
int n, n1, n2;
EthPacket from_ext[$], from_minic[$], pkt;
n = 0;
n1 = 0;
n2 = 0;
fork
send_random_packets(DUT.ext_src, from_ext, n_packets, 1);
send_random_packets(DUT.minic_src, from_minic, n_packets, 2);
send_random_packets(DUT.mux_src, from_minic, n_packets, 3);
join
while(DUT.ep_snk.poll())
begin
EthPacket from_q;
DUT.ep_snk.recv(pkt);
if(pkt.pclass == 1)
begin
from_q = from_ext.pop_front();
n1++;
end
else
begin
from_q = from_minic.pop_front();
n2++;
end
if(!from_q.equal(pkt))
begin
from_q.dump();
pkt.dump();
$error("FAIL at %d (%d,%d)\n", n,n1,n2);
break;
end
n++;
end // while (DUT.ep_snk.poll())
$display("PASS");
endtask // test_arbiter
initial begin
int i;
EthPacket pkt, tmpl;
EthPacketGenerator gen = new;
@(posedge rst_n);
@(posedge clk_sys);
// test_classifier(100);
test_arbiter(100000);
end
//task gen_random_drops();
// static int drop_remaining = 0;
// static int seed = 0;
// static int t = 20;
// if (probability_hit(0.1) || drop_remaining > 0)
// begin
// if(drop_remaining == 0)
// drop_remaining = 100;
// if(drop_remaining)
// drop_remaining--;
// force DUT.U_DUT.drop_frame = 1;
// end else
// release DUT.U_DUT.drop_frame;
//endtask
//always @posedge clk_sys begin
// gen_random_drops();
//end
endmodule // main
#vlog -sv main.sv +incdir+"." +incdir+../../sim
#-- make -f Makefile
#vsim -L unisim -t 10fs work.main -voptargs="+acc"
make -f Makefile
vsim -L secureip -L unisim -L xilinxcorelib -t 10fs work.main -voptargs="+acc" +nowarn8684 +nowarn8683
set StdArithNoWarnings 1
set NumericStdNoWarnings 1
do wave.do
radix -hexadecimal
run 200ms
wave zoomfull
radix -hexadecimal
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate /main/clk_sys
add wave -noupdate /main/rst_n
add wave -noupdate -expand -group SNK -expand /main/DUT/U_DUT/snk_i
add wave -noupdate -expand -group SNK -expand /main/DUT/U_DUT/snk_o
add wave -noupdate -expand -group SRC -expand /main/DUT/U_DUT/src_o
add wave -noupdate -expand -group SRC -expand /main/DUT/U_DUT/src_i
add wave -noupdate /main/DUT/U_DUT/bw_bps_o
add wave -noupdate /main/DUT/U_DUT/bw_bps_cnt
add wave -noupdate /main/DUT/U_DUT/bwcur_kbps
add wave -noupdate /main/DUT/U_DUT/pps_p_i
add wave -noupdate /main/DUT/U_DUT/pps_valid_i
add wave -noupdate -height 16 /main/DUT/U_DUT/state_fwd
add wave -noupdate /main/DUT/U_DUT/wrf_reg
add wave -noupdate /main/DUT/U_DUT/drop_frame
add wave -noupdate /main/DUT/U_DUT/rnd_reg
add wave -noupdate /main/DUT/U_DUT/drop_thr
add wave -noupdate /main/DUT/U_DUT/bwmin_kbps
add wave -noupdate /main/DUT/U_DUT/new_limit_i
add wave -noupdate /main/DUT/U_DUT/bwmax_kbps_i
add wave -noupdate /main/DUT/U_DUT/thr_step_kbps
add wave -noupdate /main/DUT/U_DUT/last_thr_kbps
add wave -noupdate /main/DUT/U_DUT/dbg_frame_dropped
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {4015874000000 fs} 1}
configure wave -namecolwidth 150
configure wave -valuecolwidth 100
configure wave -justifyvalue left
configure wave -signalnamewidth 1
configure wave -snapdistance 10
configure wave -datasetprefix 0
configure wave -rowmargin 4
configure wave -childrowmargin 2
configure wave -gridoffset 0
configure wave -gridperiod 1
configure wave -griddelta 40
configure wave -timeline 0
configure wave -timelineunits us
update
WaveRestoreZoom {4015779439820 fs} {4016029859720 fs}
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