Commit 069fb021 authored by Javier Díaz's avatar Javier Díaz

fecthing sources from switch hdl project

parent a216d4a9
fetchto = "ip_cores"
modules = {"local" :
[ "modules/wrsw_nic",
"modules/wrsw_txtsu",
"modules/wrsw_dio"
],
"git" : "git://ohwr.org/hdl-core-lib/wr-cores.git::wishbonized",
"svn" : "http://svn.ohwr.org/gn4124-core/trunk/hdl/gn4124core/rtl"
}
modules = { "local" : ["modules/wrsw_dio"],
"git" : ["git://ohwr.org/white-rabbit/wr-switch-hdl.git",
"git://ohwr.org/hdl-core-lib/general-cores.git::no_coregen"],
"svn" : "http://svn.ohwr.org/gn4124-core/trunk/hdl/gn4124core/rtl"
}
......@@ -18,7 +18,7 @@ pandoc --toc -o wr-nic.pdf wr-nic.mkd
Additional info
=====================
Find peripherals register map from wbgen2 tool on NIC_peripheral_registers compressed file.
Find peripherals register map from wbgen2 tool on file NIC_peripheral_registers.tar.gz.
Problems?
------------
......
% White-Rabbit NIC Gateware
% Javier Díaz, UGR-7S
% 21 Jun. 2012
% 30 Jul. 2012
Introduction
=========================
......@@ -33,7 +33,7 @@ The `GN4124 core` is a bridge between the GN4124 PCIe interface chip and the int
* The `TxTSU module` collect timestamps with associated Ethernet frame identifiers and puts them in a shared FIFO (port identifier is also included although not required for the SPEC card because only one Ethernet port is available but it is include to provide a common descriptor with the switch data). A IRQ is triggered when FIFO is not empty so drivers could read TX timestamps and frame/port identifiers.
In the next sections we provide a little more information about `DIO core` and the `WRPC (White Rabbit PTP Core)` in order to understand better how the whole system works.
Finally, it is important to know that current HDL code contains commented code to activate on-chip logic analyzer circuitry for debugging based on Chipscope of Xilinx. Top file as well as different peripherals include the signals TRIG0 - TRIG3 to help on this purpose. Nevertheless, by default they are commented to avoid wasting unnecessary resources.
Finally, it is important to know that current HDL code contains commented code to activate on-chip logic analyzer circuitry for debugging based on Chipscope of Xilinx. Top file as well as different peripherals include the signals TRIG0 - TRIG3 to help on this purpose. Nevertheless, by default they are commented to avoid wasting unnecessary resources (in fact it could be required to reduce blockram utilization, for instance of NIC or wr_core module in order to use Chipscope on the project, otherwise design is overmapped).
WRPC (White Rabbit PTP Core)
----------------------------
......@@ -143,18 +143,18 @@ This project could be used as starting demo with White-Rabbit technology, illust
* Applications examples.
Both elements are described in the software manual of the WR-NIC project and it is out of the scope of current document to describe their functionalities. Please read that document in order to have a global understanding of the NIC project.
Both elements are described in the software manual of the WR-NIC project and it is out of the scope of current document to describe them with further details. Please read that document in order to have a complete understanding of the NIC project.
Finally, as working examples, current release already provide the following applications:
* Simple transmission of timing information from the master to the slave, with nothing hooked to the external inputs of the boards.
* The master host could be configured as grandmasters (if external PPS and 10 MHz signal is available from GPS or Cesium clock) or just work as simple master (free-running).
* Simple transmission of timing information from the master to the slave, with nothing necessarily hooked to the external inputs of the boards.
* The master host could be configured as grandmaster (if external PPS and 10 MHz signal is available from GPS or Cesium clock) or just work as simple master (free-running).
* The slave host schedule a pulse output each second. Looking at the outputs on a scope we should see them perfectly aligned.
* Network latency measurements. This is interesting if we connect a switch between the SPEC cards. By using the timestamps on Ethernet frames we could get the measurement of the network latency, verify it it is constant or how traffic affect this parameter.
Many other options are possible. For instance, we could transmit an external frequency and schedule a similar output with a fixed delay on both nodes. We should be able to see a constant time offset between the two pulses on the scope. New examples will be added on next releases.
Many other options are possible. For instance, we could transmit an external frequency and schedule a similar output with a fixed delay on other nodes. We should be able to see a constant time offset between the two pulses on the scope. Examples like this could be added on next releases.
Troubleshooting
......
......@@ -62,7 +62,7 @@ architecture rtl of immed_pulse_counter is
-- Signal for synchronization (in fact they are not so necessary for current system...)
signal pulse_start_d0, pulse_start_d1, pulse_start_d2, pulse_start_d3 : std_logic;
signal nozerolength : boolean;
signal nozerolength, nozerolength_aux : boolean;
-- Aux
constant zeros : std_logic_vector(pulse_length_width-1 downto 0) := (others=>'0');
......@@ -83,8 +83,9 @@ begin -- architecture rtl
pulse_start_d1<=pulse_start_d0;
pulse_start_d2<=pulse_start_d1;
pulse_start_d3<=pulse_start_d2;
nozerolength_aux<=pulse_length_i/=zeros;
if (pulse_start_d2='1' and pulse_start_d1='0') then
nozerolength<=pulse_length_i/=zeros;
nozerolength<=nozerolength_aux;
end if;
end if;
end process;
......
files = [ "nic_constants_pkg.vhd" ,
"nic_descriptors_pkg.vhd" ,
"nic_wishbone_slave.vhd" ,
"nic_descriptor_manager.vhd" ,
"nic_rx_fsm.vhd" ,
"nic_tx_fsm.vhd" ,
"nic_buffer.vhd" ,
"nic_elastic_buffer.vhd",
"nic_wbgen2_pkg.vhd",
"xwrsw_nic.vhd",
"wrsw_nic.vhd"];
#!/bin/bash
mkdir -p doc
wbgen2 -D ./doc/wrsw_nic.html -V nic_wishbone_slave.vhd --cstyle defines --lang vhdl -K ../../sim/regs/nic_regs.vh -p nic_wbgen2_pkg.vhd --hstyle record wr_nic.wb
-------------------------------------------------------------------------------
-- Title : Mini Embedded DMA Network Interface Controller
-- Project : WhiteRabbit Core
-------------------------------------------------------------------------------
-- File : nic_buffer.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-Co-HT
-- Created : 2010-07-26
-- Last update: 2011-03-15
-- Platform : FPGA-generic
-- Standard : VHDL
-------------------------------------------------------------------------------
-- Description: RAM-based packet buffer for the NIC
-------------------------------------------------------------------------------
-- Copyright (c) 2010 Tomasz Wlostowski
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-07-26 1.0 twlostow Created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use work.genram_pkg.all;
entity nic_buffer is
generic (
g_memsize_log2 : integer := 14);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
addr_i : in std_logic_vector(g_memsize_log2-1 downto 0);
data_i : in std_logic_vector(31 downto 0);
wr_i : in std_logic;
data_o : out std_logic_vector(31 downto 0);
wb_data_i : in std_logic_vector(31 downto 0);
wb_data_o : out std_logic_vector(31 downto 0);
wb_addr_i : in std_logic_vector(g_memsize_log2-1 downto 0);
wb_cyc_i : in std_logic;
wb_stb_i : in std_logic;
wb_we_i : in std_logic;
wb_ack_o : out std_logic
);
end nic_buffer;
architecture syn of nic_buffer is
signal host_we : std_logic;
signal host_ack : std_logic;
begin -- syn
ack_gen : process(clk_sys_i, rst_n_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
host_ack <= '0';
else
host_ack <= (wb_cyc_i and wb_stb_i) and (not host_ack);
end if;
end if;
end process;
wb_ack_o <= host_ack;
host_we <= wb_cyc_i and wb_stb_i and (wb_we_i and not host_ack);
RAM : generic_dpram
generic map (
g_data_width => 32,
g_size => 2**g_memsize_log2,
g_dual_clock => false)
port map (
-- host port
rst_n_i => rst_n_i,
clka_i => clk_sys_i,
clkb_i => clk_sys_i,
wea_i => host_we,
bwea_i => x"0",
aa_i => wb_addr_i,
da_i => wb_data_i,
qa_o => wb_data_o,
web_i => wr_i,
bweb_i => x"f",
ab_i => addr_i,
db_i => data_i,
qb_o => data_o);
end syn;
-------------------------------------------------------------------------------
-- Title : WR NIC - constants package
-- Project : WhiteRabbit Switch
-------------------------------------------------------------------------------
-- File : nic_constants_pkg.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-Co-HT
-- Created : 2010-11-24
-- Last update: 2010-11-27
-- Platform : FPGA-generic
-- Standard : VHDL
-------------------------------------------------------------------------------
-- Description: Package with global NIC constants
-------------------------------------------------------------------------------
-- Copyright (c) 2010 Tomasz Wlostowski
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-11-24 1.0 twlostow Created
-------------------------------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
package nic_constants_pkg is
-- number of TX descriptors. Must be a power of 2.
constant c_nic_num_tx_descriptors : integer := 8;
-- log2(c_nic_num_tx_descriptors)
constant c_nic_num_tx_descriptors_log2 : integer := 3;
-- number of RX descriptors. Must be a power of 2.
constant c_nic_num_rx_descriptors : integer := 8;
-- log2(c_nic_num_rx_descriptors)
constant c_nic_num_rx_descriptors_log2 : integer := 3;
-- endianess of the packet buffer
constant c_nic_buf_little_endian : boolean := true;
-- log2(size of the packet buffer)
constant c_nic_buf_size_log2 : integer := 15;
end package nic_constants_pkg;
-------------------------------------------------------------------------------
-- Title : WR NIC - RX descriptor management unit
-- Project : WhiteRabbit Switch
-------------------------------------------------------------------------------
-- File : nic_descriptor_manager.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-Co-HT
-- Created : 2010-11-24
-- Last update: 2012-01-13
-- Platform : FPGA-generic
-- Standard : VHDL
-------------------------------------------------------------------------------
-- Description:
-------------------------------------------------------------------------------
-- Copyright (c) 2010 Tomasz Wlostowski
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-11-24 1.0 twlostow Created
-- 2010-11-27 1.0 twlostow Unified RX and TX descriptor mgmt
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.NUMERIC_STD.all;
library work;
use work.nic_constants_pkg.all;
use work.nic_descriptors_pkg.all;
entity nic_descriptor_manager is
generic (
g_desc_mode : string := "tx";
g_num_descriptors : integer;
g_num_descriptors_log2 : integer);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
enable_i : in std_logic;
bna_o : out std_logic;
bna_clear_i : in std_logic;
cur_desc_idx_o : out std_logic_vector(g_num_descriptors_log2-1 downto 0);
-------------------------------------------------------------------------------
-- Descriptor RAM interface
-------------------------------------------------------------------------------
dtbl_addr_o : out std_logic_vector(g_num_descriptors_log2+1 downto 0);
dtbl_data_i : in std_logic_vector(31 downto 0);
dtbl_rd_o : out std_logic;
dtbl_data_o : out std_logic_vector(31 downto 0);
dtbl_wr_o : out std_logic;
-------------------------------------------------------------------------------
-- RX/TX FSM Interface
-------------------------------------------------------------------------------
desc_reload_current_i : in std_logic;
desc_request_next_i : in std_logic;
desc_grant_o : out std_logic;
rxdesc_current_o : out t_rx_descriptor;
rxdesc_new_i : in t_rx_descriptor;
txdesc_current_o : out t_tx_descriptor;
txdesc_new_i : in t_tx_descriptor;
desc_write_i : in std_logic;
desc_write_done_o : out std_logic
);
end nic_descriptor_manager;
architecture behavioral of nic_descriptor_manager is
type t_desc_arb_state is (ARB_DISABLED, ARB_START_SCAN, ARB_CHECK_EMPTY, ARB_FETCH, ARB_GRANT, ARB_UPDATE, ARB_WRITE_DESC);
signal state : t_desc_arb_state;
signal granted_desc_tx : t_tx_descriptor;
signal granted_desc_rx : t_rx_descriptor;
signal granted_desc_idx : unsigned(g_num_descriptors_log2-1 downto 0);
signal desc_idx_d0 : unsigned(g_num_descriptors_log2-1 downto 0);
signal desc_idx : unsigned(g_num_descriptors_log2-1 downto 0);
signal desc_subreg : unsigned(1 downto 0);
signal cntr : unsigned(1 downto 0);
signal check_count : unsigned(g_num_descriptors_log2 downto 0);
signal stupid_hack : std_logic;
impure function f_write_marshalling(index : integer)
return std_logic_vector is
begin
if(g_desc_mode = "rx") then
return f_marshall_rx_descriptor(granted_desc_rx, index);
elsif (g_desc_mode = "tx") then
return f_marshall_tx_descriptor(granted_desc_tx, index);
end if;
end function;
begin -- behavioral
dtbl_addr_o <= std_logic_vector(desc_idx & desc_subreg);
dtbl_rd_o <= '1';
cur_desc_idx_o <= std_logic_vector(desc_idx);
p_rxdesc_arbiter : process(clk_sys_i, rst_n_i)
variable tmp_desc_rx : t_rx_descriptor;
variable tmp_desc_tx : t_tx_descriptor;
-- variable l:line ;
begin
if rising_edge(clk_sys_i) then
if(rst_n_i = '0') then
desc_write_done_o <= '0';
desc_grant_o <= '0';
state <= ARB_DISABLED;
desc_idx <= (others => '0');
desc_subreg <= (others => '0');
dtbl_wr_o <= '0';
-- dtbl_rd_o <= '0';
dtbl_data_o <= (others => '0');
else
case state is
when ARB_DISABLED =>
desc_idx <= (others => '0');
desc_subreg <= (others => '0');
if(enable_i = '1') then
-- dtbl_rd_o <= '1';
state <= ARB_START_SCAN;
desc_idx <= (others => '0');
check_count <= (others => '0');
end if;
when ARB_START_SCAN =>
if(enable_i = '0') then
state <= ARB_DISABLED;
else
-- wait until the current descriptor is read from the memorry
state <= ARB_CHECK_EMPTY;
-- dtbl_rd_o <='1';
dtbl_wr_o <= '0';
end if;
when ARB_CHECK_EMPTY =>
p_unmarshall_rx_descriptor(dtbl_data_i, 1, tmp_desc_rx);
p_unmarshall_tx_descriptor(dtbl_data_i, 1, tmp_desc_tx);
if((tmp_desc_rx.empty = '1' and g_desc_mode = "rx") or (tmp_desc_tx.ready = '1' and g_desc_mode = "tx")) then
granted_desc_tx <= tmp_desc_tx;
granted_desc_rx <= tmp_desc_rx;
desc_subreg <= "01";
state <= ARB_FETCH;
bna_o <= '0';
else
bna_o <= '1';
end if;
when ARB_FETCH =>
case desc_subreg is
when "10" => -- ignore the timestamps for RX
-- descriptors (they're
-- write-only by the NIC)
p_unmarshall_tx_descriptor(dtbl_data_i, 2, tmp_desc_tx);
granted_desc_tx.len <= tmp_desc_tx.len;
granted_desc_tx.offset <= tmp_desc_tx.offset;
when "11" =>
p_unmarshall_tx_descriptor(dtbl_data_i, 3, tmp_desc_tx); -- TX
granted_desc_tx.dpm <= tmp_desc_tx.dpm;
p_unmarshall_rx_descriptor(dtbl_data_i, 3, tmp_desc_rx); -- RX
granted_desc_rx.len <= tmp_desc_rx.len;
granted_desc_rx.offset <= tmp_desc_rx.offset;
state <= ARB_GRANT;
when others => null;
end case;
desc_subreg <= desc_subreg + 1;
when ARB_GRANT =>
if(desc_request_next_i = '1') then
desc_grant_o <= '1';
if(g_desc_mode = "tx") then
txdesc_current_o <= granted_desc_tx;
elsif (g_desc_mode = "rx") then
rxdesc_current_o <= granted_desc_rx;
end if;
state <= ARB_UPDATE;
end if;
desc_write_done_o <= '0';
when ARB_UPDATE =>
desc_grant_o <= '0';
if(desc_write_i = '1') then
if(g_desc_mode = "rx") then
granted_desc_rx <= rxdesc_new_i;
elsif(g_desc_mode = "tx") then
granted_desc_tx <= txdesc_new_i;
end if;
desc_subreg <= (others => '0');
-- dtbl_rd_o <= '0';
state <= ARB_WRITE_DESC;
cntr <= "00";
end if;
when ARB_WRITE_DESC =>
cntr <= cntr + 1;
-- fprint(output,l, "WriteDesc %b %b\n",fo(cntr),fo(f_write_marshalling(1)));
case cntr is
when "00" =>
desc_subreg <= "00";
dtbl_data_o <= f_write_marshalling(1);
dtbl_wr_o <= '1';
when "01" =>
desc_subreg <= "01";
dtbl_data_o <= f_write_marshalling(2);
dtbl_wr_o <= '1';
when "10" =>
desc_subreg <= "10";
dtbl_data_o <= f_write_marshalling(3);
dtbl_wr_o <= '1';
when "11" =>
dtbl_wr_o <= '0';
desc_subreg <= (others => '0');
state <= ARB_START_SCAN;
if(desc_reload_current_i = '0') then
desc_idx <= desc_idx + 1;
end if;
desc_write_done_o <= '1';
when others => null;
end case;
when others => null;
end case;
end if;
end if;
end process;
end behavioral;
-------------------------------------------------------------------------------
-- Title : WR NIC - descriptors package
-- Project : WhiteRabbit Switch
-------------------------------------------------------------------------------
-- File : nic_descriptors_pkg.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-Co-HT
-- Created : 2010-11-24
-- Last update: 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 Tomasz Wlostowski
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-11-24 1.0 twlostow Created
-------------------------------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
library work;
use work.nic_constants_pkg.all;
package nic_descriptors_pkg is
type t_tx_descriptor is record
ts_id : std_logic_vector(15 downto 0); -- OOB frame id (for TX timestamping)
pad_e : std_logic; -- padding enable
ts_e : std_logic; -- timestamp enable
error : std_logic; -- TX error indication
ready : std_logic; -- Descriptor ready for transmission flag
len : std_logic_vector(c_nic_buf_size_log2-1 downto 0); -- Length of the packet
offset : std_logic_vector(c_nic_buf_size_log2-1 downto 0); -- Offset of the packet in the buffer
dpm : std_logic_vector(31 downto 0); -- Destination port mask
end record;
type t_rx_descriptor is record
empty : std_logic; -- Descriptor empty (ready for
-- reception) flag
error : std_logic; -- RX error indication
port_id : std_logic_vector(5 downto 0); -- Packet source port ID
got_ts : std_logic; -- Got a timestamp?
ts_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;
procedure p_unmarshall_tx_descriptor(mem_input : in std_logic_vector(31 downto 0);
regnum : in integer;
desc : inout t_tx_descriptor);
procedure p_unmarshall_rx_descriptor(mem_input : in std_logic_vector(31 downto 0);
regnum : in integer;
desc : inout t_rx_descriptor);
function f_resize_slv(x : std_logic_vector;
newsize : integer) return std_logic_vector;
end NIC_descriptors_pkg;
package body NIC_descriptors_pkg is
function f_resize_slv(x : std_logic_vector; newsize : integer) return std_logic_vector is
variable tmp:std_logic_vector(newsize-1 downto 0);
begin
tmp(x'length-1 downto 0) := x;
tmp(newsize-1 downto x'length) := (others => '0');
return tmp;
end f_resize_slv;
function f_marshall_tx_descriptor(desc : t_tx_descriptor; regnum : integer) return std_logic_vector is
variable tmp : std_logic_vector(31 downto 0);
begin
case regnum is
when 1 => tmp := desc.ts_id & x"000" & desc.pad_e & desc.ts_e & desc.error & desc.ready;
when 2 => tmp := f_resize_slv(desc.len, 16) & f_resize_slv(desc.offset, 16);
when 3 => tmp := desc.dpm;
when others => null;
end case;
return tmp;
end f_marshall_tx_descriptor;
function f_marshall_rx_descriptor(desc : t_rx_descriptor; regnum : integer) return std_logic_vector is
variable tmp : std_logic_vector(31 downto 0);
begin
case regnum is
when 1 => tmp := "0000000000000000" & desc.ts_incorrect & desc.got_ts & desc.port_id & "000000" & desc.error & desc.empty;
when 2 => tmp := desc.ts_f & desc.ts_r;
when 3 => tmp := f_resize_slv(desc.len, 16) & f_resize_slv(desc.offset, 16);
when others => null;
end case;
return tmp;
end f_marshall_rx_descriptor;
procedure p_unmarshall_tx_descriptor(mem_input : in std_logic_vector(31 downto 0);
regnum : in integer;
desc : inout t_tx_descriptor) is
begin
case regnum is
when 1 =>
desc.ts_id := mem_input(31 downto 16);
desc.pad_e := mem_input(3);
desc.ts_e := mem_input(2);
desc.error := mem_input(1);
desc.ready := mem_input(0);
when 2 =>
desc.len := mem_input(16+c_nic_buf_size_log2-1 downto 16);
desc.offset := mem_input(c_nic_buf_size_log2-1 downto 0);
when 3 =>
desc.dpm := mem_input;
when others => null;
end case;
end p_unmarshall_tx_descriptor;
procedure p_unmarshall_rx_descriptor(mem_input : in std_logic_vector(31 downto 0);
regnum : in integer;
desc : inout t_rx_descriptor) is
begin
case regnum is
when 1 =>
desc.empty := mem_input(0);
desc.error := mem_input(1);
desc.port_id := mem_input(13 downto 8);
desc.got_ts := mem_input(14);
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;
end p_unmarshall_rx_descriptor;
end package body;
library ieee;
use ieee.std_logic_1164.all;
use ieee.NUMERIC_STD.all;
library work;
use work.endpoint_private_pkg.all; -- dirty hack, again
use work.genram_pkg.all;
use work.wr_fabric_pkg.all;
entity nic_elastic_buffer is
generic (
g_depth : integer := 64);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
snk_i : in t_wrf_sink_in;
snk_o : out t_wrf_sink_out;
fab_o : out t_ep_internal_fabric;
dreq_i : in std_logic
);
end nic_elastic_buffer;
architecture rtl of nic_elastic_buffer is
function log2 (A : natural) return natural is
begin
for I in 1 to 64 loop -- Works for up to 32 bits
if (2**I > A) then
return(I-1);
end if;
end loop;
return(63);
end function log2;
constant c_fifo_width : integer := 16 + 2 + 5;
signal fifo_write : std_logic;
signal fifo_read : std_logic;
signal fifo_in_ser : std_logic_vector(c_fifo_width-1 downto 0);
signal fifo_out_ser : std_logic_vector(c_fifo_width-1 downto 0);
signal fifo_full : std_logic;
signal fifo_empty : std_logic;
signal fifo_usedw : std_logic_vector(log2(g_depth)-1 downto 0);
signal output_valid : std_logic;
signal got_empty : std_logic;
signal cyc_d0 : std_logic;
signal fifo_in : t_ep_internal_fabric;
signal fifo_out : t_ep_internal_fabric;
signal snk_out : t_wrf_sink_out;
signal stall_int : std_logic;
begin -- rtl
p_delay_cyc : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
cyc_d0 <= '0';
else
cyc_d0 <= snk_i.cyc;
end if;
end if;
end process;
snk_o <= snk_out;
snk_out.err <= fifo_full and snk_i.cyc and snk_i.stb;
snk_out.rty <= '0';
p_gen_ack : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
snk_out.ack <= '0';
else
snk_out.ack <= snk_i.cyc and snk_i.stb and not snk_out.stall;
end if;
end if;
end process;
fifo_in.sof <= not cyc_d0 and snk_i.cyc;
fifo_in.eof <= cyc_d0 and not snk_i.cyc;
fifo_in.data <= snk_i.dat;
fifo_in.dvalid <= snk_i.stb and snk_i.cyc and not snk_out.stall;
fifo_in.addr <= snk_i.adr;
fifo_in.error <= '1' when (fifo_in.dvalid = '1') and
snk_i.adr = c_WRF_STATUS and
(f_unmarshall_wrf_status(snk_i.dat).error = '1') else '0';
fifo_in.bytesel <= not snk_i.sel(0);
fifo_write <= fifo_in.sof or fifo_in.eof or fifo_in.dvalid or fifo_in.error;
fifo_in_ser <= fifo_in.bytesel & fifo_in.sof & fifo_in.eof & fifo_in.dvalid & fifo_in.error & fifo_in.addr & fifo_in.data;
p_gen_stall : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
stall_int <= '0';
else
if (unsigned(fifo_usedw) < g_depth/2) then
stall_int <= '0';
elsif (unsigned(fifo_usedw) > g_depth-5) then
stall_int <= '1';
end if;
end if;
end if;
end process;
snk_out.stall <= fifo_in.sof or stall_int;
fifo_read <= not fifo_empty and dreq_i;
p_gen_valid_flag : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
output_valid <= '0';
else
output_valid <= fifo_read;
end if;
end if;
end process;
U_fifo : generic_sync_fifo
generic map (
g_data_width => c_fifo_width,
g_size => g_depth,
g_with_count => true)
port map (
rst_n_i => rst_n_i,
clk_i => clk_sys_i,
we_i => fifo_write,
d_i => fifo_in_ser,
rd_i => fifo_read,
q_o => fifo_out_ser,
empty_o => fifo_empty,
full_o => fifo_full,
count_o => fifo_usedw
);
fab_o.data <= fifo_out_ser(15 downto 0);
fab_o.addr <= fifo_out_ser(17 downto 16);
fab_o.error <= fifo_out_ser(18) and output_valid;
fab_o.dvalid <= fifo_out_ser(19) and output_valid;
fab_o.eof <= fifo_out_ser(20) and output_valid;
fab_o.sof <= fifo_out_ser(21) and output_valid;
fab_o.bytesel <= fifo_out_ser(22);
end rtl;
This diff is collapsed.
This diff is collapsed.
---------------------------------------------------------------------------------------
-- 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 : Fri Jul 27 17:22:06 2012
-- Standard : VHDL'87
---------------------------------------------------------------------------------------
-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE wr_nic.wb
-- DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
---------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.wbgen2_pkg.all;
package nic_wbgen2_pkg is
-- Input registers (user design -> WB slave)
type t_nic_in_registers is record
sr_bna_i : std_logic;
sr_rec_i : std_logic;
sr_tx_done_i : std_logic;
sr_tx_error_i : std_logic;
sr_cur_tx_desc_i : std_logic_vector(2 downto 0);
sr_cur_rx_desc_i : std_logic_vector(2 downto 0);
end record;
constant c_nic_in_registers_init_value: t_nic_in_registers := (
sr_bna_i => '0',
sr_rec_i => '0',
sr_tx_done_i => '0',
sr_tx_error_i => '0',
sr_cur_tx_desc_i => (others => '0'),
sr_cur_rx_desc_i => (others => '0')
);
-- Output registers (WB slave -> user design)
type t_nic_out_registers is record
cr_rx_en_o : std_logic;
cr_tx_en_o : std_logic;
sr_rec_o : std_logic;
sr_rec_load_o : std_logic;
sr_tx_done_o : std_logic;
sr_tx_done_load_o : std_logic;
sr_tx_error_o : std_logic;
sr_tx_error_load_o : std_logic;
reset_o : std_logic_vector(31 downto 0);
reset_wr_o : std_logic;
end record;
constant c_nic_out_registers_init_value: t_nic_out_registers := (
cr_rx_en_o => '0',
cr_tx_en_o => '0',
sr_rec_o => '0',
sr_rec_load_o => '0',
sr_tx_done_o => '0',
sr_tx_done_load_o => '0',
sr_tx_error_o => '0',
sr_tx_error_load_o => '0',
reset_o => (others => '0'),
reset_wr_o => '0'
);
function "or" (left, right: t_nic_in_registers) return t_nic_in_registers;
function f_x_to_zero (x:std_logic) return std_logic;
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 = 'X' or x = 'U') then
return '0';
else
return x;
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) = 'X' or x(i) = 'U') then
tmp(i):= '0';
else
tmp(i):=x(i);
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);
return tmp;
end function;
end package body;
This diff is collapsed.
This diff is collapsed.
library ieee;
use ieee.std_logic_1164.all;
library work;
use work.wishbone_pkg.all;
use work.wr_fabric_pkg.all;
entity wrsw_nic is
generic
(
g_interface_mode : t_wishbone_interface_mode := CLASSIC;
g_address_granularity : t_wishbone_address_granularity := WORD
);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
-------------------------------------------------------------------------------
-- Pipelined Wishbone interface
-------------------------------------------------------------------------------
-- WBP Master (TX)
src_dat_o : out std_logic_vector(15 downto 0);
src_adr_o : out std_logic_vector(1 downto 0);
src_sel_o : out std_logic_vector(1 downto 0);
src_cyc_o : out std_logic;
src_stb_o : out std_logic;
src_we_o : out std_logic;
src_stall_i : in std_logic;
src_err_i : in std_logic;
src_ack_i : in std_logic;
-- WBP Slave (RX)
snk_dat_i : in std_logic_vector(15 downto 0);
snk_adr_i : in std_logic_vector(1 downto 0);
snk_sel_i : in std_logic_vector(1 downto 0);
snk_cyc_i : in std_logic;
snk_stb_i : in std_logic;
snk_we_i : in std_logic;
snk_stall_o : out std_logic;
snk_err_o : out std_logic;
snk_ack_o : out std_logic;
-------------------------------------------------------------------------------
-- "Fake" RTU interface
-------------------------------------------------------------------------------
rtu_dst_port_mask_o : out std_logic_vector(31 downto 0);
rtu_prio_o : out std_logic_vector(2 downto 0);
rtu_drop_o : out std_logic;
rtu_rsp_valid_o : out std_logic;
rtu_rsp_ack_i : in std_logic;
-------------------------------------------------------------------------------
-- Wishbone bus
-------------------------------------------------------------------------------
wb_cyc_i : in std_logic;
wb_stb_i : in std_logic;
wb_we_i : in std_logic;
wb_sel_i : in std_logic_vector(c_wishbone_data_width/8-1 downto 0);
wb_adr_i : in std_logic_vector(c_wishbone_address_width-1 downto 0);
wb_dat_i : in std_logic_vector(c_wishbone_data_width-1 downto 0);
wb_dat_o : out std_logic_vector(c_wishbone_data_width-1 downto 0);
wb_ack_o : out std_logic;
wb_stall_o : out std_logic;
wb_irq_o : out std_logic
);
end wrsw_nic;
architecture rtl of wrsw_nic is
component xwrsw_nic
generic (
g_interface_mode : t_wishbone_interface_mode;
g_address_granularity : t_wishbone_address_granularity);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
snk_i : in t_wrf_sink_in;
snk_o : out t_wrf_sink_out;
src_i : in t_wrf_source_in;
src_o : out t_wrf_source_out;
rtu_dst_port_mask_o : out std_logic_vector(31 downto 0);
rtu_prio_o : out std_logic_vector(2 downto 0);
rtu_drop_o : out std_logic;
rtu_rsp_valid_o : out std_logic;
rtu_rsp_ack_i : in std_logic;
wb_i : in t_wishbone_slave_in;
wb_o : out t_wishbone_slave_out);
end component;
signal snk_out : t_wrf_sink_out;
signal snk_in : t_wrf_sink_in;
signal src_out : t_wrf_source_out;
signal src_in : t_wrf_source_in;
signal wb_out : t_wishbone_slave_out;
signal wb_in : t_wishbone_slave_in;
begin
U_Wrapped_NIC : xwrsw_nic
generic map (
g_interface_mode => g_interface_mode,
g_address_granularity => g_address_granularity)
port map (
clk_sys_i => clk_sys_i,
rst_n_i => rst_n_i,
snk_i => snk_in,
snk_o => snk_out,
src_i => src_in,
src_o => src_out,
rtu_dst_port_mask_o => rtu_dst_port_mask_o,
rtu_prio_o => rtu_prio_o,
rtu_drop_o => rtu_drop_o,
rtu_rsp_valid_o => rtu_rsp_valid_o,
rtu_rsp_ack_i => rtu_rsp_ack_i,
wb_i => wb_in,
wb_o => wb_out);
-- WBP Master (TX)
src_dat_o <= src_out.dat;
src_adr_o <= src_out.adr;
src_sel_o <= src_out.sel;
src_cyc_o <= src_out.cyc;
src_stb_o <= src_out.stb;
src_we_o <= src_out.we;
src_in.stall <= src_stall_i;
src_in.err <= src_err_i;
src_in.ack <= src_ack_i;
-- WBP Slave (RX)
snk_in.dat <= snk_dat_i;
snk_in.adr <= snk_adr_i;
snk_in.sel <= snk_sel_i;
snk_in.cyc <= snk_cyc_i;
snk_in.stb <= snk_stb_i;
snk_in.we <= snk_we_i;
snk_stall_o <= snk_out.stall;
snk_err_o <= snk_out.err;
snk_ack_o <= snk_out.ack;
wb_in.cyc <= wb_cyc_i;
wb_in.stb <= wb_stb_i;
wb_in.we <= wb_we_i;
wb_in.sel <= wb_sel_i;
wb_in.adr <= wb_adr_i;
wb_in.dat <= wb_dat_i;
wb_dat_o <= wb_out.dat;
wb_ack_o <= wb_out.ack;
wb_stall_o <= wb_out.stall;
wb_irq_o <= wb_out.int;
end rtl;
This diff is collapsed.
files = ["xwrsw_txtsu.vhd",
"wrsw_txtsu_wb.vhd",
"wrsw_txtsu_pkg.vhd"]
#!/bin/bash
mkdir -p doc
wbgen2 -D ./doc/txtsu.htm -V wrsw_txtsu_wb.vhd --cstyle defines --lang vhdl -K ../../sim/tx_tstsu_regs.vh wrsw_txtsu.wb
-- -*- Mode: LUA; tab-width: 2 -*-
peripheral {
name = "Shared TX Timestamping Unit (TXTSU)";
prefix="txtsu";
hdl_entity="wrsw_txtsu_wb";
-- TXTSU shared FIFO
fifo_reg {
size = 256; -- or more. We'll see :)
direction = CORE_TO_BUS;
prefix = "tsf";
name = "Timestamp FIFO";
description = "This FIFO holds the TX packet timestamps gathered from all switch endpoints. Each entry contains a single timestamp value consisting of 2 numbers:\
- VAL_R - the timestamp taken at rising clock edge. This is the main timestamp value\
- VAL_F - few LSBs of timestamp taken at falling clock edge. It's used in conjunction with VAL_R to determine if the timestamp has been taken\
properly (there was no metastability/setup/hold violation)\
Entries also contain information required to identify the endpoint and frame for which the timestamp was taken:\
- FID - Frame identifier assigned by the NIC\
- PID - TXTSU port ID to which came the timestamp. Used to distinguish the timestamps for broadcast/multicast frames;\
- INCORRECT - timestamp may be incorrect, it has been generated during timebase adjustment";
flags_bus = {FIFO_FULL, FIFO_EMPTY, FIFO_COUNT};
flags_dev = {FIFO_FULL, FIFO_EMPTY};
field {
name = "Rising edge timestamp";
descritpion = "Timestamp value taken on rising clock edge (full word)";
prefix = "val_r";
type = SLV;
size = 28;
};
field {
name = "Falling edge timestamp";
description = "Timestamp value taken on falling clock edge (few LSBs)";
prefix = "val_f";
type = SLV;
size = 4;
};
field {
name ="Physical port ID";
description = "Identifier of the TXTSU port to which came the timestamp. There may be multiple timestamps sharing the same FID value for broadcast/multicast packets.";
prefix = "pid";
type = SLV;
size = 5;
align= 16;
};
field {
name = "Frame ID";
description = "OOB Frame Identifier. Used to associate the timestamp value with transmitted packet.";
prefix = "fid";
type = SLV;
size = 16;
align = 16;
};
field {
name = "Timestamp (possibly) incorrect";
description = "1: This timestamp may be incorrect (generated during PPS adjustment)\
0: Timestamp is correct.";
prefix = "incorrect";
type = BIT;
};
};
-- TXTSU interrupts
irq {
name = "TXTSU fifo not-empty";
description = "Interrupt active when TXTSU shared FIFO contains any timestamps.";
prefix = "nempty";
trigger = LEVEL_1;
};
};
\ No newline at end of file
library ieee;
use ieee.std_logic_1164.all;
package wrsw_txtsu_pkg is
type t_txtsu_timestamp is record
stb : std_logic;
tsval : std_logic_vector(31 downto 0);
port_id : std_logic_vector(5 downto 0);
frame_id : std_logic_vector(15 downto 0);
incorrect : std_logic;
end record;
type t_txtsu_timestamp_array is array(integer range <>) of t_txtsu_timestamp;
end wrsw_txtsu_pkg;
This diff is collapsed.
-------------------------------------------------------------------------------
-- Title : TX Timestamping Unit
-- Project : White Rabbit Switch
-------------------------------------------------------------------------------
-- File : xwrsw_txtsu.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-Co-HT
-- Created : 2010-04-26
-- Last update: 2012-03-16
-- Platform : FPGA-generic
-- Standard : VHDL
-------------------------------------------------------------------------------
-- Description: Shared timestamping unit for all switch endpoints. It collects
-- TX timestamps with associated frame identifiers and puts them (along
-- with the identifier of requesting port) in a shared FIFO. Each FIFO entry
-- contains:
-- - Frame ID value (from OOB field of transmitted frame)
-- - Timestamp value (from the endpoint)
-- - Port ID value (ID of the TXTSU port to which the timstamp+frame id came).
-- FIFO is accessible from the Wishbone bus. An IRQ (level-active) is triggered
-- when the FIFO is not empty. The driver reads TX timestamps (with associated
-- port and frame identifiers) and passes them to PTP daemon.
-------------------------------------------------------------------------------
-- Copyright (c) 2010 Tomasz Wlostowski
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-04-26 1.0 twlostow Created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.wishbone_pkg.all;
use work.wrsw_txtsu_pkg.all;
entity xwrsw_tx_tsu is
generic (
g_num_ports : integer := 10;
g_interface_mode : t_wishbone_interface_mode := CLASSIC;
g_address_granularity : t_wishbone_address_granularity := WORD);
port (
-- reference clock / 2 (62.5 MHz). All signals below are synchronous to this clock
clk_sys_i : in std_logic;
-- sync reset, active LO
rst_n_i : in std_logic;
-------------------------------------------------------------------------------
-- TX timestamp interface (from endpoints)
-------------------------------------------------------------------------------
-- frame identifier inputs (separate for each port)
timestamps_i : in t_txtsu_timestamp_array(g_num_ports-1 downto 0);
timestamps_ack_o : out std_logic_vector(g_num_ports -1 downto 0);
-------------------------------------------------------------------------------
-- Wishbone bus
-------------------------------------------------------------------------------
wb_i : in t_wishbone_slave_in;
wb_o : out t_wishbone_slave_out
);
end xwrsw_tx_tsu;
architecture syn of xwrsw_tx_tsu is
component wrsw_txtsu_wb
port (
rst_n_i : in std_logic;
clk_sys_i : in std_logic;
wb_adr_i : in std_logic_vector(2 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;
txtsu_tsf_wr_req_i : in std_logic;
txtsu_tsf_wr_full_o : out std_logic;
txtsu_tsf_wr_empty_o : out std_logic;
txtsu_tsf_val_r_i : in std_logic_vector(27 downto 0);
txtsu_tsf_val_f_i : in std_logic_vector(3 downto 0);
txtsu_tsf_pid_i : in std_logic_vector(4 downto 0);
txtsu_tsf_fid_i : in std_logic_vector(15 downto 0);
txtsu_tsf_incorrect_i : in std_logic;
irq_nempty_i : in std_logic);
end component;
signal txtsu_tsf_wr_req : std_logic;
signal txtsu_tsf_wr_full : std_logic;
signal txtsu_tsf_wr_empty : std_logic;
signal txtsu_tsf_val_r : std_logic_vector(27 downto 0);
signal txtsu_tsf_val_f : std_logic_vector(3 downto 0);
signal txtsu_tsf_pid : std_logic_vector(4 downto 0);
signal txtsu_tsf_fid : std_logic_vector(15 downto 0);
signal txtsu_tsf_incorrect : std_logic;
signal irq_nempty : std_logic;
signal scan_cntr : unsigned(4 downto 0);
type t_txtsu_state is (TSU_SCAN, TSU_ACK);
signal state : t_txtsu_state;
signal cur_ep : integer;
signal wb_out : t_wishbone_slave_out;
signal wb_in : t_wishbone_slave_in;
begin -- syn
U_Adapter : wb_slave_adapter
generic map (
g_master_use_struct => true,
g_master_mode => PIPELINED,
g_master_granularity => WORD,
g_slave_use_struct => true,
g_slave_mode => g_interface_mode,
g_slave_granularity => g_address_granularity)
port map (
clk_sys_i => clk_sys_i,
rst_n_i => rst_n_i,
master_i => wb_out,
master_o => wb_in,
slave_i => wb_i,
slave_o => wb_o);
cur_ep <= to_integer(scan_cntr);
process(clk_sys_i, rst_n_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
state <= TSU_SCAN;
scan_cntr <= (others => '0');
txtsu_tsf_wr_req <= '0';
timestamps_ack_o <= (others => '0');
else
case state is
when TSU_SCAN =>
if(timestamps_i(cur_ep).stb = '1') then
timestamps_ack_o(cur_ep) <= '1';
state <= TSU_ACK;
if(txtsu_tsf_wr_full = '0') then
txtsu_tsf_pid <= timestamps_i(cur_ep).port_id(4 downto 0);
txtsu_tsf_fid <= timestamps_i(cur_ep).frame_id;
txtsu_tsf_val_f <= timestamps_i(cur_ep).tsval(31 downto 28);
txtsu_tsf_val_r <= timestamps_i(cur_ep).tsval(27 downto 0);
txtsu_tsf_incorrect <= timestamps_i(cur_ep).incorrect;
txtsu_tsf_wr_req <= '1';
end if;
else
if(scan_cntr = g_num_ports-1)then
scan_cntr <= (others => '0');
else
scan_cntr <= scan_cntr + 1;
end if;
end if;
when TSU_ACK =>
timestamps_ack_o(cur_ep) <= '0';
txtsu_tsf_wr_req <= '0';
state <= TSU_SCAN;
if(scan_cntr = g_num_ports-1)then
scan_cntr <= (others => '0');
else
scan_cntr <= scan_cntr + 1;
end if;
when others => null;
end case;
end if;
end if;
end process;
U_WB_SLAVE : wrsw_txtsu_wb
port map (
rst_n_i => rst_n_i,
clk_sys_i => clk_sys_i,
wb_adr_i => wb_in.adr(2 downto 0),
wb_dat_i => wb_in.dat,
wb_dat_o => wb_out.dat,
wb_cyc_i => wb_in.cyc,
wb_sel_i => wb_in.sel,
wb_stb_i => wb_in.stb,
wb_we_i => wb_in.we,
wb_ack_o => wb_out.ack,
wb_stall_o => wb_out.stall,
wb_int_o => wb_out.int,
txtsu_tsf_wr_req_i => txtsu_tsf_wr_req,
txtsu_tsf_wr_full_o => txtsu_tsf_wr_full,
txtsu_tsf_wr_empty_o => txtsu_tsf_wr_empty,
txtsu_tsf_val_r_i => txtsu_tsf_val_r,
txtsu_tsf_val_f_i => txtsu_tsf_val_f,
txtsu_tsf_pid_i => txtsu_tsf_pid,
txtsu_tsf_fid_i => txtsu_tsf_fid,
txtsu_tsf_incorrect_i => txtsu_tsf_incorrect,
irq_nempty_i => irq_nempty);
irq_nempty <= not txtsu_tsf_wr_empty;
end syn;
files = [ "wr_xilinx_pkg.vhd" ]
modules = {"local" : ["wr_gtp_phy", "chipscope"]}
files = [ "gtp_bitslide.vhd",
"gtp_phase_align.vhd",
"gtp_phase_align_virtex6.vhd",
"gtx_reset.vhd",
"whiterabbitgtx_wrapper_gtx.vhd",
# "whiterabbitgtp_wrapper.vhd",
"whiterabbitgtp_wrapper_tile.vhd",
"wr_gtp_phy_spartan6.vhd",
"wr_gtx_phy_virtex6.vhd"];
-------------------------------------------------------------------------------
-- Title : Deterministic Xilinx GTP wrapper - bitslide state machine
-- Project : White Rabbit Switch
-------------------------------------------------------------------------------
-- File : gtp_bitslide.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-CO-HT
-- Created : 2010-11-18
-- Last update: 2011-09-12
-- Platform : FPGA-generic
-- Standard : VHDL'93
-------------------------------------------------------------------------------
-- Description: Module implements a manual bitslide alignment state machine and
-- provides the obtained bitslide value to the MAC.
-------------------------------------------------------------------------------
--
-- Original EASE design (c) 2010 NIKHEF / Peter Jansweijer and Henk Peek
-- VHDL port (c) 2010 CERN / Tomasz Wlostowski
--
-- <license>
--
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-11-18 0.4 twlostow Ported EASE design to VHDL
-- 2011-02-07 0.5 twlostow Verified on Spartan6 GTP
-- 2011-09-12 0.6 twlostow Virtex6 port
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity gtp_bitslide is
generic (
-- set to non-zero value to enable some simulation speedups (reduce delays)
g_simulation : integer;
g_target : string := "spartan6");
port (
gtp_rst_i : in std_logic;
-- GTP
gtp_rx_clk_i : in std_logic;
-- '1' indicates that the GTP has detected a comma in the incoming serial stream
gtp_rx_comma_det_i : in std_logic;
gtp_rx_byte_is_aligned_i : in std_logic;
-- GTP ready flag (PLL locked and RX signal present)
serdes_ready_i : in std_logic;
-- GTP manual bitslip control line
gtp_rx_slide_o : out std_logic;
-- GTP CDR reset, asserted when the link is lost to set the bitslide to a known
-- value
gtp_rx_cdr_rst_o : out std_logic;
-- Current bitslide, in UIs
bitslide_o : out std_logic_vector(4 downto 0);
-- '1' when the bitsliding has been completed and the link is up
synced_o : out std_logic
);
end gtp_bitslide;
architecture behavioral of gtp_bitslide is
function f_eval_sync_detect_threshold
return integer is
begin
if(g_simulation /= 0) then
return 256;
elsif(g_target = "spartan6") then
return 8192;
else
return 16384;
end if;
end f_eval_sync_detect_threshold;
function f_eval_pause_tics return integer is
begin
if(g_target = "spartan6") then
return 31;
else
return 63;
end if;
end f_eval_pause_tics;
constant c_pause_tics : integer := f_eval_pause_tics;
constant c_sync_detect_threshold : integer := f_eval_sync_detect_threshold;
type t_bitslide_fsm_state is (S_SYNC_LOST, S_STABILIZE, S_SLIDE, S_PAUSE, S_GOT_SYNC, S_RESET_CDR);
signal cur_slide : unsigned(4 downto 0);
signal state : t_bitslide_fsm_state;
signal counter : unsigned(15 downto 0);
signal commas_missed : unsigned(1 downto 0);
begin -- behavioral
p_do_slide : process(gtp_rx_clk_i, gtp_rst_i)
begin
if gtp_rst_i = '1' then
state <= S_SYNC_LOST;
gtp_rx_slide_o <= '0';
counter <= (others => '0');
synced_o <= '0';
gtp_rx_cdr_rst_o <= '0';
elsif rising_edge(gtp_rx_clk_i) then
if(serdes_ready_i = '0') then
state <= S_SYNC_LOST;
end if;
case state is
-- State: synchronization lost. Waits until a comma pattern is detected
when S_SYNC_LOST =>
cur_slide <= (others => '0');
counter <= (others => '0');
gtp_rx_slide_o <= '0';
synced_o <= '0';
gtp_rx_cdr_rst_o <= '0';
commas_missed <= (others => '0');
if(gtp_rx_comma_det_i = '1') then
state <= S_STABILIZE;
end if;
-- State: stabilize:
when S_STABILIZE =>
if(gtp_rx_comma_det_i = '1') then
counter <= counter + 1;
commas_missed <= (others => '0');
else
commas_missed <= commas_missed + 1;
if(commas_missed(1) = '1') then
state <= S_SYNC_LOST;
end if;
end if;
if(counter = to_unsigned(c_sync_detect_threshold, counter'length)) then
counter <= (others => '0');
state <= S_PAUSE;
end if;
if(serdes_ready_i = '0') then
state <= S_SYNC_LOST;
end if;
when S_SLIDE =>
cur_slide <= cur_slide + 1;
gtp_rx_slide_o <= '1';
counter <= (others => '0');
state <= S_PAUSE;
if(serdes_ready_i = '0') then
state <= S_SYNC_LOST;
end if;
when S_PAUSE =>
counter <= counter + 1;
gtp_rx_slide_o <= '0';
if(counter = to_unsigned(c_pause_tics, counter'length)) then
if(gtp_rx_byte_is_aligned_i = '0') then
state <= S_SLIDE;
else
state <= S_GOT_SYNC;
end if;
end if;
when S_GOT_SYNC =>
gtp_rx_slide_o <= '0';
bitslide_o <= std_logic_vector(cur_slide);
synced_o <= '1';
if(gtp_rx_byte_is_aligned_i = '0' or serdes_ready_i = '0') then
gtp_rx_cdr_rst_o <= '1';
state <= S_SYNC_LOST;
end if;
when others => null;
end case;
end if;
end process;
end behavioral;
------------------------------------------------------------------------------
-- Title : Deterministic Xilinx GTP wrapper - TX phase alignment
-- Project : White Rabbit Switch
-------------------------------------------------------------------------------
-- File : gtp_phase_align.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-CO-HT
-- Created : 2010-11-18
-- Last update: 2011-09-12
-- Platform : FPGA-generic
-- Standard : VHDL'93
-------------------------------------------------------------------------------
-- Description: TX phase alignment state machine, as recommended by Xilinx.
-------------------------------------------------------------------------------
--
-- Original EASE design (c) 2010 NIKHEF / Peter Jansweijer and Henk Peek
-- VHDL port (c) 2010 CERN / Tomasz Wlostowski
--
-- <license>
--
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2010-11-18 0.4 twlostow Ported EASE design to VHDL
-- 2011-02-07 0.5 twlostow Verified on Spartan6 GTP
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity gtp_phase_align is
generic
(g_simulation : integer);
port (
gtp_rst_i : in std_logic;
gtp_tx_clk_i : in std_logic;
gtp_tx_en_pma_phase_align_o : out std_logic;
gtp_tx_pma_set_phase_o : out std_logic;
align_en_i : in std_logic;
align_done_o : out std_logic
);
end gtp_phase_align;
architecture behavioral of gtp_phase_align is
constant c_wait_en_phase_align : integer := 32;
constant c_wait_set_phase_align : integer := 512;
constant c_phase_align_duration : integer := 8192;
type t_align_state is (S_ALIGN_IDLE, S_ALIGN_PAUSE, S_ALIGN_WAIT, S_ALIGN_SET_PHASE, S_ALIGN_DONE);
signal counter : unsigned(13 downto 0);
signal state : t_align_state;
begin -- behavioral
p_align : process(gtp_tx_clk_i, gtp_rst_i)
begin
if rising_edge(gtp_tx_clk_i) then
if gtp_rst_i = '1' then
gtp_tx_en_pma_phase_align_o <= '0';
gtp_tx_pma_set_phase_o <= '0';
counter <= (others => '0');
align_done_o <= '0';
state <= S_ALIGN_IDLE;
else
if(align_en_i = '0') then
state <= S_ALIGN_IDLE;
else
case (state) is
when S_ALIGN_IDLE =>
gtp_tx_en_pma_phase_align_o <= '0';
gtp_tx_pma_set_phase_o <= '0';
counter <= (others => '0');
align_done_o <= '0';
if(align_en_i = '1') then
state <= S_ALIGN_PAUSE;
end if;
when S_ALIGN_PAUSE =>
counter <= counter + 1;
if(counter = to_unsigned(c_wait_en_phase_align, counter'length)) then
state <= S_ALIGN_WAIT;
end if;
when S_ALIGN_WAIT =>
gtp_tx_en_pma_phase_align_o <= '1';
counter <= counter + 1;
if(counter = to_unsigned(c_wait_en_phase_align + c_wait_set_phase_align, counter'length)) then
state <= S_ALIGN_SET_PHASE;
end if;
when S_ALIGN_SET_PHASE =>
counter <= counter +1;
gtp_tx_pma_set_phase_o <= '1';
if(counter = to_unsigned(c_wait_en_phase_align + c_wait_set_phase_align + c_phase_align_duration, counter'length)) then
state <= S_ALIGN_DONE;
end if;
when S_ALIGN_DONE =>
gtp_tx_pma_set_phase_o <= '0';
counter <= (others => '0');
align_done_o <= '1';
when others => null;
end case;
end if;
end if;
end if;
end process;
end behavioral;
This diff is collapsed.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity gtx_reset is
port (
clk_tx_i : in std_logic;
rst_i : in std_logic;
txpll_lockdet_i : in std_logic;
gtx_test_o : out std_logic_vector(12 downto 0)
);
end gtx_reset;
architecture behavioral of gtx_reset is
type t_state is (IDLE, PAUSE, FIRST_RST, PAUSE2, SECOND_RST, DONE);
signal state : t_state;
signal counter : unsigned(15 downto 0);
begin -- behavioral
process(clk_tx_i)
begin
if rising_edge(clk_tx_i) then
if rst_i = '1' then
state <= IDLE;
counter <= (others => '0');
else
if(txpll_lockdet_i = '0') then
state <= IDLE;
else
case state is
when IDLE =>
counter <= (others => '0');
gtx_test_o <= "1000000000000";
if(txpll_lockdet_i = '1') then
state <= PAUSE;
end if;
when PAUSE =>
counter <= counter + 1;
gtx_test_o <= "1000000000000";
if(counter = 1024) then
state <= FIRST_RST;
end if;
when FIRST_RST =>
counter <= counter + 1;
gtx_test_o <= "1000000000010";
if(counter = 1024 + 256) then
state <= PAUSE2;
end if;
when PAUSE2=>
counter <= counter + 1;
gtx_test_o <= "1000000000000";
if(counter = 1024 + 2*256) then
state <= SECOND_RST;
end if;
when SECOND_RST =>
counter <= counter + 1;
gtx_test_o <= "1000000000010";
if(counter = 1024 + 3*256) then
state <= DONE;
end if;
when DONE =>
gtx_test_o <= "1000000000000";
end case;
end if;
end if;
end if;
end process;
end behavioral;
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -9,7 +9,8 @@ syn_package = "fgg484"
syn_top = "wr_nic_sdb_top"
syn_project = "wr_nic.xise"
modules = { "local" :
modules = {"local" :
[ "../../top/spec",
"../../platform/xilinx/chipscope" ]
}
"../../platform/xilinx"
]
}
This diff is collapsed.
action = "simulation"
target = "xilinx"
fetchto = "../../ip_cores"
vlog_opt="+incdir+../../sim"
files = [ "main.sv" ]
modules = { "local" : "../.." }
This diff is collapsed.
vlog -sv main.sv +incdir+"." +incdir+../../sim
make -f Makefile
vsim -L unisim -t 10fs work.main -voptargs="+acc"
set StdArithNoWarnings 1
set NumericStdNoWarnings 1
do wave.do
radix -hexadecimal
run 25us
wave zoomfull
radix -hexadecimal
This diff is collapsed.
This diff is collapsed.
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