Commit ecccdb6d authored by Maciej Lipinski's avatar Maciej Lipinski Committed by Tomasz Wlostowski

Added WR Streamers developed by Tomasz Wlostowski (VHDL, testbenches, spec_top, sythesis) .

The added code is based on the one provided for White Rabbit Core Hands-on
Training (http://www.ohwr.org/projects/wr-cores/wiki/Handson_training). The
code has been only adapted to
- fit the structure of wr-cores repository
- work with the newest wrpc-v3.0
parent 1d048108
......@@ -13,5 +13,6 @@ modules = {"local" :
"modules/wr_eca",
"modules/wr_tlu",
"modules/wrc_core",
"modules/wr_streamers",
"platform"]
}
files = ["streamers_pkg.vhd", "xtx_streamer.vhd", "tx_streamer.vhd", "xrx_streamer.vhd", "rx_streamer.vhd", "gc_escape_inserter.vhd", "gc_escape_detector.vhd", "dropping_buffer.vhd"]
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.genram_pkg.all;
entity dropping_buffer is
generic (
g_size : integer;
g_data_width : integer);
port
(
clk_i : in std_logic;
rst_n_i : in std_logic;
d_i : in std_logic_vector(g_data_width-1 downto 0);
d_req_o : out std_logic;
d_drop_i : in std_logic;
d_accept_i : in std_logic;
d_valid_i : in std_logic;
d_o : out std_logic_vector(g_data_width-1 downto 0);
d_valid_o : out std_logic;
d_req_i : in std_logic);
end dropping_buffer;
architecture behavioral of dropping_buffer is
type t_mem_array is array(0 to g_size-1) of std_logic_vector(g_data_width-1 downto 0);
subtype t_counter is unsigned(f_log2_size(g_size)-1 downto 0);
signal wr_ptr, rd_ptr, boundary : t_counter := (others => '0');
signal full, empty_comb : std_logic;
signal empty_reg : std_logic := '0';
signal mem : t_mem_array;
begin -- behavioral
p_counters : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
wr_ptr <= (others => '0');
rd_ptr <= (others => '0');
boundary <= (others => '0');
else
if(d_accept_i = '1') then
boundary <= wr_ptr;
end if;
if(d_drop_i = '1') then
wr_ptr <= boundary;
elsif(d_valid_i = '1' and full = '0') then
wr_ptr <= wr_ptr + 1;
end if;
if (d_req_i = '1' and empty_reg = '0' and empty_comb = '0') then
rd_ptr <= rd_ptr + 1;
end if;
end if;
end if;
end process;
empty_comb <= '1' when (boundary = rd_ptr) else '0';
full <= '1' when (wr_ptr + 1 = rd_ptr) else '0';
d_req_o <= not full;
p_empty_reg : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
empty_reg <= '1';
else
empty_reg <= empty_comb;
end if;
end if;
end process;
p_mem_read : process(clk_i)
begin
if rising_edge(clk_i) then
if(d_req_i = '1' and empty_reg = '0' and empty_comb = '0') then
d_o <= mem(to_integer(rd_ptr));
d_valid_o <= '1';
else
d_valid_o <= '0';
end if;
end if;
end process;
p_mem_write : process(clk_i)
begin
if rising_edge(clk_i) then
if(d_valid_i = '1') then
mem(to_integer(wr_ptr)) <= d_i;
end if;
end if;
end process;
end behavioral;
library ieee;
use ieee.std_logic_1164.all;
entity escape_detector is
generic(
g_data_width : integer;
g_escape_code : std_logic_vector
);
port(
clk_i : in std_logic;
rst_n_i : in std_logic;
d_i : in std_logic_vector(g_data_width-1 downto 0);
d_detect_enable_i : in std_logic;
d_valid_i : in std_logic;
d_req_o : out std_logic;
d_o : out std_logic_vector(g_data_width-1 downto 0);
d_escape_o : out std_logic;
d_valid_o : out std_logic;
d_req_i : in std_logic
);
end escape_detector;
architecture behavioral of escape_detector is
type t_state is (IDLE, CHECK_ESCAPE);
signal state : t_state;
signal is_escape_code : std_logic;
begin -- behavioral
d_req_o <= d_req_i;
is_escape_code <= '1' when (d_detect_enable_i = '1' and state = IDLE and d_valid_i = '1' and d_i = g_escape_code) else '0';
d_o <= g_escape_code when (state = CHECK_ESCAPE and d_i = x"0000") else d_i;
d_valid_o <= d_valid_i and not is_escape_code;
d_escape_o <= '1' when (state = CHECK_ESCAPE and d_i /= x"0000") else '0';
p_fsm : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' or d_detect_enable_i = '0' then
state <= IDLE;
else
case state is
when IDLE =>
if(d_i = g_escape_code and d_valid_i = '1') then
state <= CHECK_ESCAPE;
end if;
when CHECK_ESCAPE =>
if(d_valid_i = '1') then
state <= IDLE;
end if;
end case;
end if;
end if;
end process;
end behavioral;
-------------------------------------------------------------------------------
-- Title : Escape insertion unit
-- Project : General cores library
-------------------------------------------------------------------------------
-- File : gc_escape_inserter.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN BE-CO-HT
-- Created : 2012-10-01
-- Last update: 2012-10-10
-- Platform : FPGA-generic
-- Standard : VHDL '93
------------------------------------------------------------------------------
-- Description: Unit for inserting escaped codes in a continuous data stream.
-- Allows for insertion of easily distinguishable control codes, such as start-
-- or end-of-frame markers. Given an input tuple (E[d_escape_i], D[d_i]), the
-- output (d_o) is:
-- - D when E == 0 and D != g_escape_code
-- - g_escape_code followed by 0 when E == 0 and D == g_escape_code
-- - g_escape_code followed by D when E == 1.
-- Note: When E == 1, D must not be 0.
------------------------------------------------------------------------------
--
-- Copyright (c) 2012 CERN
--
-- 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;
entity gc_escape_inserter is
generic(
-- data path width
g_data_width : integer;
-- unique escape character (of g_data_width bits), must not be 0.
g_escape_code : std_logic_vector
);
port(
clk_i : in std_logic;
rst_n_i : in std_logic;
-- data input (unescaped)
d_i : in std_logic_vector(g_data_width-1 downto 0);
-- when 1, escape insertion logic is enabled (i.e. if d_i == g_escape_code,
-- it's translated to g_escape_code followed by 0 instead of just being passed
-- through
d_insert_enable_i : in std_logic;
-- when 1, d_i is treated as a escaped character
d_escape_i : in std_logic;
-- when 1, d_i and d_escape_i contain valid character
d_valid_i : in std_logic;
-- when 1, module can accept data in the following clock cycle.
d_req_o : out std_logic;
-- data output
d_o : out std_logic_vector (g_data_width-1 downto 0);
-- when 1, d_o contains a valid character
d_valid_o : out std_logic;
-- when 1, d_o/d_valid_o may output a character in the next clock cycle.
d_req_i : in std_logic
);
end gc_escape_inserter;
architecture behavioral of gc_escape_inserter is
type t_state is (IDLE, INSERT_ESCAPE);
signal d_prev : std_logic_vector(g_data_width-1 downto 0);
signal d_req_prev : std_logic;
signal state : t_state;
signal match_esc_code : std_logic;
begin -- behavioral
match_esc_code <= '1' when d_i = g_escape_code else '0';
-- stop the traffic if we need to insert an escaped sequence. This
-- can happen when
-- - the input character is an escape code (d_escape_i = '1')
-- - the input character is not to be escaped, but it's equal to g_escape_code
d_req_o <= d_req_i and not (d_valid_i and (d_escape_i or match_esc_code));
d_o <= d_prev when (state = INSERT_ESCAPE) else
d_i when d_escape_i = '0' else
g_escape_code;
d_valid_o <= d_valid_i when (state = IDLE) else
d_req_prev;
p_fsm : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' or d_insert_enable_i = '0' then
state <= IDLE;
d_req_prev <= '0';
else
d_req_prev <= d_req_i;
case state is
when IDLE =>
-- case 1: escape the escape character sent as normal character
if(d_i = g_escape_code and d_valid_i = '1' and d_escape_i = '0') then
state <= INSERT_ESCAPE;
d_prev <= x"0000";
-- case 2: send an escaped character
elsif(d_escape_i = '1' and d_valid_i = '1') then
state <= INSERT_ESCAPE;
d_prev <= d_i;
end if;
when INSERT_ESCAPE =>
if(d_req_prev = '1') then
state <= IDLE;
end if;
end case;
end if;
end if;
end process;
end behavioral;
-- see xrx_streamer.vhd for port documentation
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.wishbone_pkg.all;
use work.wr_fabric_pkg.all;
entity rx_streamer is
generic (
g_data_width : integer := 32;
g_buffer_size : integer := 128;
g_filter_remote_mac : boolean := false
);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
-- Endpoint/WRC interface
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_ack_o : out std_logic;
snk_err_o : out std_logic;
snk_rty_o : out std_logic;
clk_ref_i : in std_logic := '0';
tm_time_valid_i : in std_logic := '0';
tm_tai_i : in std_logic_vector(39 downto 0) := x"0000000000";
tm_cycles_i : in std_logic_vector(27 downto 0) := x"0000000";
rx_first_o : out std_logic;
rx_last_o : out std_logic;
rx_data_o : out std_logic_vector(g_data_width-1 downto 0);
rx_valid_o : out std_logic;
rx_dreq_i : in std_logic;
rx_lost_o : out std_logic := '0';
rx_latency_o : out std_logic_vector(27 downto 0);
rx_latency_valid_o : out std_logic;
cfg_mac_local_i : in std_logic_vector(47 downto 0);
cfg_mac_remote_i : in std_logic_vector(47 downto 0);
cfg_ethertype_i : in std_logic_vector(15 downto 0) := x"dbff";
cfg_accept_broadcasts_i : in std_logic := '1'
);
end rx_streamer;
architecture wrapper of rx_streamer is
component xrx_streamer
generic (
g_data_width : integer;
g_buffer_size : integer;
g_filter_remote_mac : boolean);
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;
clk_ref_i : in std_logic := '0';
tm_time_valid_i : in std_logic := '0';
tm_tai_i : in std_logic_vector(39 downto 0) := x"0000000000";
tm_cycles_i : in std_logic_vector(27 downto 0) := x"0000000";
rx_first_o : out std_logic;
rx_last_o : out std_logic;
rx_data_o : out std_logic_vector(g_data_width-1 downto 0);
rx_valid_o : out std_logic;
rx_dreq_i : in std_logic;
rx_lost_o : out std_logic := '0';
rx_latency_o : out std_logic_vector(27 downto 0);
rx_latency_valid_o : out std_logic;
cfg_mac_local_i : in std_logic_vector(47 downto 0);
cfg_mac_remote_i : in std_logic_vector(47 downto 0);
cfg_ethertype_i : in std_logic_vector(15 downto 0) := x"dbff";
cfg_accept_broadcasts_i : in std_logic := '1');
end component;
signal snk_in : t_wrf_sink_in;
signal snk_out : t_wrf_sink_out;
begin -- rtl
U_Wrapped_Streamer : xrx_streamer
generic map (
g_data_width => g_data_width,
g_filter_remote_mac => g_filter_remote_mac,
g_buffer_size => g_buffer_size)
port map (
clk_sys_i => clk_sys_i,
clk_ref_i => clk_ref_i,
tm_tai_i => tm_tai_i,
tm_time_valid_i => tm_time_valid_i,
tm_cycles_i => tm_cycles_i,
rst_n_i => rst_n_i,
snk_i => snk_in,
snk_o => snk_out,
rx_data_o => rx_data_o,
rx_valid_o => rx_valid_o,
rx_dreq_i => rx_dreq_i,
rx_lost_o => rx_lost_o,
rx_first_o => rx_first_o,
rx_last_o => rx_last_o,
rx_latency_valid_o => rx_latency_valid_o,
rx_latency_o => rx_latency_o,
cfg_mac_local_i => cfg_mac_local_i,
cfg_mac_remote_i => cfg_mac_remote_i,
cfg_ethertype_i => cfg_ethertype_i,
cfg_accept_broadcasts_i => cfg_accept_broadcasts_i);
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_ack_o <= snk_out.ack;
snk_err_o <= snk_out.err;
snk_rty_o <= snk_out.rty;
end wrapper;
library ieee;
use ieee.std_logic_1164.all;
use work.wr_fabric_pkg.all;
package streamers_pkg is
component xtx_streamer
generic (
g_data_width : integer := 32;
g_tx_threshold : integer := 16;
g_tx_max_words_per_frame : integer := 128;
g_tx_timeout : integer := 128);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
src_i : in t_wrf_source_in;
src_o : out t_wrf_source_out;
clk_ref_i : in std_logic := '0';
tm_time_valid_i : in std_logic := '0';
tm_tai_i : in std_logic_vector(39 downto 0) := x"0000000000";
tm_cycles_i : in std_logic_vector(27 downto 0) := x"0000000";
tx_data_i : in std_logic_vector(g_data_width-1 downto 0);
tx_valid_i : in std_logic;
tx_dreq_o : out std_logic;
tx_last_i : in std_logic := '1';
tx_flush_i : in std_logic := '0';
tx_reset_seq_i : in std_logic := '0';
cfg_mac_local_i : in std_logic_vector(47 downto 0) := x"000000000000";
cfg_mac_target_i : in std_logic_vector(47 downto 0);
cfg_ethertype_i : in std_logic_vector(15 downto 0) := x"dbff");
end component;
component xrx_streamer
generic (
g_data_width : integer := 32;
g_buffer_size : integer := 16;
g_filter_remote_mac : boolean := false);
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;
clk_ref_i : in std_logic := '0';
tm_time_valid_i : in std_logic := '0';
tm_tai_i : in std_logic_vector(39 downto 0) := x"0000000000";
tm_cycles_i : in std_logic_vector(27 downto 0) := x"0000000";
rx_first_o : out std_logic;
rx_last_o : out std_logic;
rx_data_o : out std_logic_vector(g_data_width-1 downto 0);
rx_valid_o : out std_logic;
rx_dreq_i : in std_logic;
rx_lost_o : out std_logic := '0';
rx_latency_o : out std_logic_vector(27 downto 0);
rx_latency_valid_o : out std_logic;
cfg_mac_local_i : in std_logic_vector(47 downto 0) := x"000000000000";
cfg_mac_remote_i : in std_logic_vector(47 downto 0) := x"000000000000";
cfg_ethertype_i : in std_logic_vector(15 downto 0) := x"dbff";
cfg_accept_broadcasts_i : in std_logic := '1');
end component;
end streamers_pkg;
-- see xtx_streamer.vhd for comments
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.wishbone_pkg.all;
use work.wr_fabric_pkg.all;
use work.streamers_pkg.all;
entity tx_streamer is
generic (
g_data_width : integer := 32;
g_tx_threshold : integer := 16;
g_tx_max_words_per_frame : integer := 128;
g_tx_timeout : integer := 1024
);
port (
clk_sys_i : in std_logic;
rst_n_i : in std_logic;
-- Endpoint/WRC interface
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_ack_i : in std_logic;
src_err_i : in std_logic;
clk_ref_i : in std_logic := '0';
tm_time_valid_i : in std_logic := '0';
tm_tai_i : in std_logic_vector(39 downto 0) := x"0000000000";
tm_cycles_i : in std_logic_vector(27 downto 0) := x"0000000";
tx_flush_i : in std_logic := '0';
tx_last_i : in std_logic := '1';
tx_data_i : in std_logic_vector(g_data_width-1 downto 0);
tx_reset_seq_i : in std_logic := '0';
tx_valid_i : in std_logic;
tx_dreq_o : out std_logic;
-- MAC address
cfg_mac_local_i : in std_logic_vector(47 downto 0) := x"000000000000";
cfg_mac_target_i : in std_logic_vector(47 downto 0) := x"ffffffffffff";
cfg_ethertype_i : in std_logic_vector(15 downto 0) := x"dbff"
);
end tx_streamer;
architecture rtl of tx_streamer is
signal src_in : t_wrf_source_in;
signal src_out : t_wrf_source_out;
begin -- rtl
U_Wrapped_Streamer : xtx_streamer
generic map (
g_data_width => g_data_width,
g_tx_threshold => g_tx_threshold,
g_tx_max_words_per_frame => g_tx_max_words_per_frame,
g_tx_timeout => g_tx_timeout)
port map (
clk_sys_i => clk_sys_i,
rst_n_i => rst_n_i,
src_i => src_in,
src_o => src_out,
tx_last_i => tx_last_i,
tx_data_i => tx_data_i,
tx_reset_seq_i => tx_reset_seq_i,
tx_valid_i => tx_valid_i,
tx_dreq_o => tx_dreq_o,
tx_flush_i => tx_flush_i,
clk_ref_i => clk_ref_i,
tm_time_valid_i => tm_time_valid_i,
tm_tai_i => tm_tai_i,
tm_cycles_i => tm_cycles_i,
cfg_mac_local_i => cfg_mac_local_i,
cfg_mac_target_i => cfg_mac_target_i,
cfg_ethertype_i => cfg_ethertype_i);
src_adr_o <= src_out.adr;
src_dat_o <= src_out.dat;
src_sel_o <= src_out.sel;
src_stb_o <= src_out.stb;
src_we_o <= src_out.we;
src_cyc_o <= src_out.cyc;
src_in.ack <= src_ack_i;
src_in.stall <= src_stall_i;
src_in.err <= src_err_i;
end rtl;
This diff is collapsed.
This diff is collapsed.
action= "simulation"
target= "xilinx"
syn_device="xc6slx45t"
sim_tool="modelsim"
top_module="main"
fetchto="../../ip_cores"
vlog_opt="+incdir+../../../sim +incdir"
modules = { "local" : ["../../..",
"../../../modules/wr_streamers",
"../../../top/spec_1_1/wr_streamers_demo",
"../../../ip_cores/general-cores"]}
files = ["main.sv"]
//
// White Rabbit Core Hands-On Course
//
// Lesson 04a: Trivial streamer demo
//
// Objectives:
// - Demonstrate pulse distribution example on a simulation
//
// Brief description:
// Testbench instantiates two SPEC cards connected to each other via a Gigabit
// Ethernet link. SPEC A sends input trigger pulses to SPEC B, which reproduces them with
// fixed, 20us delay.
`timescale 10fs/10fs // need very fine timestep to correctly simulate the GTP.
module main;
// Parameters
// Reference clock period.
parameter g_ref_clock_period = 8ns;
reg clk_20m = 0, clk_ref = 0;
wire uart_txd;
wire [7:0] uart_data;
wire uart_data_valid;
// Generate the reference clock
always #(g_ref_clock_period / 2) clk_ref <= ~clk_ref;
// Generate the 20 MHz VCXO clock
always #(50ns / 2) clk_20m <= ~clk_20m;
reg pulse_in = 0;
wire pulse_out;
wire [4:0] dio_out_b;
// This time we have two SPECs talking to each other in the same testbench
spec_top
#(
.g_simulation (1)
) SPEC_A (
.clk_125m_pllref_p_i (clk_ref),
.clk_125m_pllref_n_i (~clk_ref),
.fpga_pll_ref_clk_101_p_i (clk_ref),
.fpga_pll_ref_clk_101_n_i (~clk_ref),
.clk_20m_vcxo_i(clk_20m),
// Connect the gigabit output of one SPEC with the RX input of the other,
// and vice-versa.
.sfp_txp_o(a_to_b_p),
.sfp_txn_o(a_to_b_n),
.sfp_rxp_i(b_to_a_p),
.sfp_rxn_i(b_to_a_n),
.dio_p_i( {3'b0, pulse_in, 1'b0} ),
.dio_n_i( {3'b1, ~pulse_in, 1'b1} )
);
spec_top
#(
.g_simulation (1)
) SPEC_B (
.clk_125m_pllref_p_i (clk_ref),
.clk_125m_pllref_n_i (~clk_ref),
.fpga_pll_ref_clk_101_p_i (clk_ref),
.fpga_pll_ref_clk_101_n_i (~clk_ref),
.clk_20m_vcxo_i(clk_20m),
// Connect the gigabit output of one SPEC with the RX input of the other,
// and vice-versa.
.sfp_txp_o(b_to_a_p),
.sfp_txn_o(b_to_a_n),
.sfp_rxp_i(a_to_b_p),
.sfp_rxn_i(a_to_b_n),
.dio_p_o ( dio_out_b )
);
assign pulse_out = dio_out_b[2];
// observe the link LEDs on both sides, and tell us when the link is ready.
wire link_up_a = SPEC_A.U_The_WR_Core.led_link_o;
wire link_up_b = SPEC_B.U_The_WR_Core.led_link_o;
initial begin
// wait until both SPECs see the Ethernet link. Otherwise the packet we're going
// to send might end up in void...
wait(link_up_a == 1'b1 && link_up_b == 1'b1);
forever begin // send a pulse every 30 us;
pulse_in = 1;
#1us;
pulse_in = 0;
#30us;
end
end
endmodule // main
make -f Makefile > /dev/null 2>&1
vsim -L unisim -L secureip work.main -voptargs="+acc" -suppress 8684,8683
set NumericStdNoWarnings 1
set StdArithNoWarnings 1
do wave.do
run 400us
wave zoomfull
radix -hex
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate -divider {SPEC A-common}
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_Pulse_Stamper/clk_ref_i
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_Pulse_Stamper/clk_sys_i
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_Pulse_Stamper/rst_n_i
add wave -noupdate -divider {SPEC A - WR timing}
add wave -noupdate /main/SPEC_A/dio_p_i(1)
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_Pulse_Stamper/tm_time_valid_i
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_Pulse_Stamper/tm_tai_i
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_Pulse_Stamper/tm_cycles_i
add wave -noupdate -divider {SPEC A - pulse stamper}
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_Pulse_Stamper/tag_tai_o
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_Pulse_Stamper/tag_cycles_o
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_Pulse_Stamper/tag_valid_o
add wave -noupdate -divider {SPEC A - TX Streamer}
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_TX_Streamer/tx_data_i
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_TX_Streamer/tx_valid_i
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_TX_Streamer/tx_dreq_o
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_TX_Streamer/src_i
add wave -noupdate -radix hexadecimal /main/SPEC_A/U_TX_Streamer/src_o
add wave -noupdate -divider {SPEC A - PHY}
add wave -noupdate -radix hexadecimal /main/SPEC_A/phy_tx_data
add wave -noupdate -radix hexadecimal /main/SPEC_A/phy_tx_k
add wave -noupdate -radix hexadecimal /main/SPEC_A/phy_tx_disparity
add wave -noupdate -radix hexadecimal /main/SPEC_A/phy_tx_enc_err
add wave -noupdate -divider {SPEC B - PHY}
add wave -noupdate -radix hexadecimal /main/SPEC_B/phy_rx_data
add wave -noupdate -radix hexadecimal /main/SPEC_B/phy_rx_rbclk
add wave -noupdate -radix hexadecimal /main/SPEC_B/phy_rx_k
add wave -noupdate -radix hexadecimal /main/SPEC_B/phy_rx_enc_err
add wave -noupdate -divider {SPEC B - WR timing}
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Pulse_Stamper/tm_time_valid_i
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Pulse_Stamper/tm_tai_i
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Pulse_Stamper/tm_cycles_i
add wave -noupdate -divider {SPEC B - RX streamer}
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_RX_Streamer/snk_i
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_RX_Streamer/snk_o
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_RX_Streamer/rx_data_o
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_RX_Streamer/rx_valid_o
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_RX_Streamer/rx_dreq_i
add wave -noupdate -divider {SPEC B - Timestamp adder}
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Add_Delay1/valid_i
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Add_Delay1/a_tai_i
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Add_Delay1/a_cycles_i
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Add_Delay1/b_tai_i
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Add_Delay1/b_cycles_i
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Add_Delay1/q_tai_o
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Add_Delay1/q_cycles_o
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Add_Delay1/valid_o
add wave -noupdate -divider {SPEC B - pulse generator}
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Pulse_Generator/trig_tai_i
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Pulse_Generator/trig_cycles_i
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Pulse_Generator/trig_valid_i
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Pulse_Generator/trig_ready_o
add wave -noupdate -radix hexadecimal /main/SPEC_B/U_Pulse_Generator/pulse_o
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {98492029160 fs} 0}
configure wave -namecolwidth 150
configure wave -valuecolwidth 152
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 ns
update
WaveRestoreZoom {0 fs} {210 us}
action= "simulation"
target= "xilinx"
syn_device="xc6slx45t"
sim_tool="modelsim"
top_module="main"
fetchto="../../../ip_cores"
vlog_opt="+incdir+../../../sim"
modules = { "local" : ["../../..",
"../../../modules/wr_streamers",
"../../../ip_cores/general-cores"]}
files = ["main.sv"]
//
// White Rabbit Core Hands-On Course
//
// Lesson 04: Simulating the streamers
//
// Objectives:
// - demonstrate packet transfers in WR Core MAC interface
// - demonstrate the user interface of tx_streamer/rx_streamer modules.
// - demonstrate latency measurement feature of the streamers
//
// Brief description:
// A continuous sequence of 64-bit numbers (counting up from 0) is streamed
// via the TX streamer, sent as Ethernet packets over WR MAC interface and decoded
// in the RX streamer module.
//
`include "../../../sim/if_wb_link.svh"
`timescale 1ns/1ns
module main;
// Parameters
// Size of data record to be used by the streamers - in our case, a 64-bit
// word.
parameter g_record_size = 64;
// MAC address of the TX side
parameter bit [47:0] g_mac_tx = 48'h112233445566;
// MAC address of the RX side
parameter bit [47:0] g_mac_rx = 48'hcafebabedead;
// Ethertype for distinguishing our streamer frames
parameter bit [15:0] g_ethertype = 16'hdbff;
// 16-bit data, 2-bit address Wishbone bus that connects the WR MAC interfaces
// of both streamers
IWishboneLink #(16, 2) mac();
// Clock & reset
reg clk = 0;
reg rst = 0;
// TX Streamer signals
reg tx_streamer_dvalid = 0;
reg [g_record_size-1:0] tx_streamer_data = 0;
wire tx_streamer_dreq;
// RX Streamer signals
reg rx_streamer_dreq = 0;
wire [g_record_size-1:0] rx_streamer_data;
wire rx_streamer_dvalid;
wire rx_streamer_lost;
wire [27:0] rx_latency;
wire rx_latency_valid;
// Fake White Rabbit reference clock (125 MHz) and cycle counte (we don't use
// TAI counter as the latency never exceeds 1 second...)
reg clk_ref = 0;
reg [27:0] tm_cycle_counter = 0;
// Currently transmitted counter value
integer tx_counter = 0;
initial #100 rst = 1;
always #10 clk <= ~clk;
// transfer queue. Used to pass sent data to the verification process.
logic [g_record_size-1:0] queue[$];
always #4ns clk_ref <= ~clk_ref; //generate 125 MHz WR Clock
always@(posedge clk_ref)
tm_cycle_counter <= tm_cycle_counter + 1;
// TX data stream generation.
always@(posedge clk)
if(!rst)
begin
tx_streamer_dvalid <= 0;
tx_counter <= 0;
end else begin
// TX streamer is fed with a subsequent data word at random intervals (you can
// change the probability in the contition below). New value is sent only when
// the streamer can accept it (i.e. its tx_dreq_o output is active)
if({$random} % 100 < 50 && tx_streamer_dreq) begin
queue.push_back(tx_counter);
tx_streamer_data <= tx_counter;
tx_streamer_dvalid <= 1;
tx_counter++;
end else
tx_streamer_dvalid <= 0;
end // if (rst)
// Instantiation of the streamers. The TX streamer will assemble packets
// containing max. 8 records, or flush the buffer after 512 clk cycles if
// it contains less than 8 records to prevent latency buildup.
tx_streamer
#(
.g_data_width (g_record_size),
.g_tx_threshold (8),
.g_tx_timeout (512)
)
U_TX_Streamer
(
.clk_sys_i(clk),
.rst_n_i (rst),
.src_dat_o (mac.dat_i),
.src_adr_o (mac.adr),
.src_sel_o (mac.sel),
.src_cyc_o (mac.cyc),
.src_stb_o (mac.stb),
.src_we_o (mac.we),
.src_stall_i(mac.stall),
.src_err_i (mac.err),
.src_ack_i (mac.ack),
.clk_ref_i(clk_ref), // fake WR time
.tm_time_valid_i(1'b1),
.tm_cycles_i(tm_cycle_counter),
.tx_data_i (tx_streamer_data),
.tx_valid_i (tx_streamer_dvalid),
.tx_dreq_o (tx_streamer_dreq),
.cfg_mac_local_i (g_mac_tx),
.cfg_mac_target_i (g_mac_rx),
.cfg_ethertype_i (g_ethertype)
);
rx_streamer
#(
.g_data_width (g_record_size)
)
U_RX_Streamer
(
.clk_sys_i (clk),
.rst_n_i (rst),
.snk_dat_i (mac.dat_i),
.snk_adr_i (mac.adr),
.snk_sel_i (mac.sel),
.snk_cyc_i (mac.cyc),
.snk_stb_i (mac.stb),
.snk_we_i (mac.we),
.snk_stall_o (mac.stall),
.snk_ack_o (mac.ack),
.snk_err_o (mac.err),
.snk_rty_o (mac.rty),
.clk_ref_i(clk_ref), // fake WR time
.tm_time_valid_i(1'b1),
.tm_cycles_i(tm_cycle_counter),
.rx_data_o (rx_streamer_data),
.rx_valid_o (rx_streamer_dvalid),
.rx_dreq_i (rx_streamer_dreq),
.rx_latency_o (rx_latency),
.rx_latency_valid_o(rx_latency_valid),
.cfg_mac_local_i (g_mac_rx),
.cfg_mac_remote_i (g_mac_tx),
.cfg_ethertype_i (g_ethertype)
);
// Client-side reception logic. Compares the received records with their copies
// stored in the queue.
always@(posedge clk)
if(!rst)
begin
rx_streamer_dreq <= 0;
end else begin
// throttle the RX path a little bit
rx_streamer_dreq <= {$random}%100 < 80;
if(rx_streamer_dvalid)
begin
// Got a record? Compare it against the copy stored in queue.
automatic logic [g_record_size-1:0] d = queue.pop_front();
$display("Received value: %d", rx_streamer_data);
if(rx_streamer_data != d)
begin
$display("Failure: Got %d, should be: %d\n", rx_streamer_data, d);
$stop;
end
end // if (rx_streamer_dvalid)
end // else: !if(!rst)
// Show the latency value when a new frame arrives
always@(posedge clk)
if(rst && rx_latency_valid)
$display("This frame's latency: %.3f microseconds\n", real'(rx_latency) * 0.008);
endmodule // main
make -f Makefile > /dev/null 2>&1
vsim -L unisim work.main -voptargs="+acc" -suppress 8684,8683
set NumericStdNoWarnings 1
set StdArithNoWarnings 1
do wave.do
run 10us
wave zoomfull
radix -hex
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate /main/U_TX_Streamer/clk_sys_i
add wave -noupdate /main/U_TX_Streamer/rst_n_i
add wave -noupdate -divider {TX streamer - User side}
add wave -noupdate /main/U_TX_Streamer/tx_flush_i
add wave -noupdate /main/U_TX_Streamer/tx_last_i
add wave -noupdate /main/U_TX_Streamer/tx_data_i
add wave -noupdate /main/U_TX_Streamer/tx_reset_seq_i
add wave -noupdate /main/U_TX_Streamer/tx_valid_i
add wave -noupdate /main/U_TX_Streamer/tx_dreq_o
add wave -noupdate -divider Wishbone
add wave -noupdate /main/mac/g_data_width
add wave -noupdate /main/mac/g_addr_width
add wave -noupdate /main/mac/adr
add wave -noupdate /main/mac/dat_o
add wave -noupdate /main/mac/dat_i
add wave -noupdate /main/mac/sel
add wave -noupdate /main/mac/ack
add wave -noupdate /main/mac/stall
add wave -noupdate /main/mac/err
add wave -noupdate /main/mac/rty
add wave -noupdate /main/mac/cyc
add wave -noupdate /main/mac/stb
add wave -noupdate /main/mac/we
add wave -noupdate -divider {RX streamer - user side}
add wave -noupdate /main/U_RX_Streamer/rx_first_o
add wave -noupdate /main/U_RX_Streamer/rx_last_o
add wave -noupdate /main/U_RX_Streamer/rx_data_o
add wave -noupdate /main/U_RX_Streamer/rx_valid_o
add wave -noupdate /main/U_RX_Streamer/rx_dreq_i
add wave -noupdate /main/U_RX_Streamer/rx_lost_o
add wave -noupdate /main/U_RX_Streamer/rx_latency_o
add wave -noupdate /main/U_RX_Streamer/rx_latency_valid_o
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {1370 ns} 0}
configure wave -namecolwidth 150
configure wave -valuecolwidth 152
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 ns
update
WaveRestoreZoom {0 ns} {10500 ns}
action= "simulation"
target= "xilinx"
syn_device="xc6slx45t"
sim_tool="modelsim"
top_module="main"
fetchto="../../ip_cores"
vlog_opt="+incdir+../../../sim +incdir"
modules = { "local" : ["../../..",
"../../../modules/wr_streamers",
"../../../top/spec_1_1/wr_streamers_demo",
"../../../ip_cores/general-cores"]}
files = ["main.sv"]
//
// White Rabbit Core Hands-On Course
//
// Lesson 04b: Multiword transfers
//
// Objectives:
// - demonstrate multiword transfers using tx_last, rx_first and rx_last lines.
//
//
`include "../../../sim/if_wb_link.svh"
`timescale 1ns/1ns
module main;
// Parameters
// Size of data record to be used by the streamers - in our case, a 64-bit
// word.
parameter g_word_width = 64;
parameter g_block_size_min = 1;
parameter g_block_size_max = 3;
// MAC address of the TX side
parameter bit [47:0] g_mac_tx = 48'h112233445566;
// MAC address of the RX side
parameter bit [47:0] g_mac_rx = 48'hcafebabedead;
// Ethertype for distinguishing our streamer frames
parameter bit [15:0] g_ethertype = 16'hdbff;
// 16-bit data, 2-bit address Wishbone bus that connects the WR MAC interfaces
// of both streamers
IWishboneLink #(16, 2) mac();
// Clock & reset
reg clk = 0;
reg rst_n = 0;
// TX Streamer signals
reg tx_streamer_dvalid = 0;
reg [g_word_width-1:0] tx_streamer_data = 0;
reg tx_streamer_last = 0;
wire tx_streamer_dreq;
// RX Streamer signals
reg rx_streamer_dreq = 0;
wire [g_word_width-1:0] rx_streamer_data;
wire rx_streamer_dvalid;
wire rx_streamer_lost;
wire rx_streamer_first;
wire rx_streamer_last;
wire [27:0] rx_latency;
wire rx_latency_valid;
// Fake White Rabbit reference clock (125 MHz) and cycle counter (we don't use
// TAI counter as the latency never exceeds 1 second...)
reg clk_ref = 0;
reg [27:0] tm_cycle_counter = 0;
// Currently transmitted counter value
integer tx_counter = 0;
initial #100 rst_n = 1;
always #10 clk <= ~clk;
typedef struct
{
bit[g_word_width-1:0] data[$];
} block_t;
// transfer queue. Used to pass sent data to the verification process.
block_t queue[$];
always #4ns clk_ref <= ~clk_ref; //generate 125 MHz WR Clock
always@(posedge clk_ref)
tm_cycle_counter <= tm_cycle_counter + 1;
int count = 0;
int seed = 0;
// generate a block of data words of random size, containing subsequent numbers
task automatic generate_block(ref block_t blk);
int size = $dist_uniform(seed, g_block_size_min, g_block_size_max);
int i;
for(i = 0; i<size; i++)
blk.data.push_back(count++);
endtask // generate_block
// sends out a data block (blk) by driving TX_(DVALID, DATA, LAST) lines of the TX streamer
task automatic send_block(ref block_t blk);
int i = 0;
$display("Sending block of %d words...", blk.data.size());
while(i < blk.data.size())
begin
if(tx_streamer_dreq) begin
// assert the TX_LAST line on the last word in the current block
tx_streamer_last <= (i == (blk.data.size() - 1)) ? 1 : 0;
tx_streamer_data <= blk.data[i];
tx_streamer_dvalid <= 1;
i++;
end else
tx_streamer_dvalid <= 0;
@(posedge clk);
end // while (i < blk.data.size())
tx_streamer_dvalid <= 0;
tx_streamer_last <= 0;
@(posedge clk);
endtask // send_block
// receives a data block from the RX streamer and puts it in (blk). Returns non-zero done value when
// blk contains a complete block
task automatic receive_block(ref block_t blk, ref int done);
// drive dreq line permanently to 1 to make the testbench a bit clearer
rx_streamer_dreq <= 1;
if(rx_streamer_dvalid)
begin
if(rx_streamer_first)
blk.data = {};
blk.data.push_back(rx_streamer_data);
if(rx_streamer_last)
begin
done = 1;
end
else
done = 0;
end
endtask // receive_block
// TX block stream generation
initial forever begin
block_t blk;
blk.data={};
generate_block(blk);
queue.push_back(blk);
send_block(blk);
end
// Instantiation of the streamers. The TX streamer will assemble packets
// containing max. 8 records, or flush the buffer after 512 clk cycles if
// it contains less than 8 records to prevent latency buildup.
tx_streamer
#(
.g_data_width (g_word_width),
.g_tx_threshold (8),
.g_tx_timeout (128)
)
U_TX_Streamer
(
.clk_sys_i(clk),
.rst_n_i (rst_n),
.src_dat_o (mac.dat_i),
.src_adr_o (mac.adr),
.src_sel_o (mac.sel),
.src_cyc_o (mac.cyc),
.src_stb_o (mac.stb),
.src_we_o (mac.we),
.src_stall_i(mac.stall),
.src_err_i (mac.err),
.src_ack_i (mac.ack),
.clk_ref_i(clk_ref), // fake WR time
.tm_time_valid_i(1'b1),
.tm_cycles_i(tm_cycle_counter),
.tx_data_i (tx_streamer_data),
.tx_valid_i (tx_streamer_dvalid),
.tx_dreq_o (tx_streamer_dreq),
.tx_last_i (tx_streamer_last),
.cfg_mac_local_i (g_mac_tx),
.cfg_mac_target_i (g_mac_rx),
.cfg_ethertype_i (g_ethertype)
);
rx_streamer
#(
.g_data_width (g_word_width)
)
U_RX_Streamer
(
.clk_sys_i (clk),
.rst_n_i (rst_n),
.snk_dat_i (mac.dat_i),
.snk_adr_i (mac.adr),
.snk_sel_i (mac.sel),
.snk_cyc_i (mac.cyc),
.snk_stb_i (mac.stb),
.snk_we_i (mac.we),
.snk_stall_o (mac.stall),
.snk_ack_o (mac.ack),
.snk_err_o (mac.err),
.snk_rty_o (mac.rty),
.clk_ref_i(clk_ref), // fake WR time
.tm_time_valid_i(1'b1),
.tm_cycles_i(tm_cycle_counter),
.rx_data_o (rx_streamer_data),
.rx_valid_o (rx_streamer_dvalid),
.rx_dreq_i (rx_streamer_dreq),
.rx_first_o (rx_streamer_first),
.rx_last_o (rx_streamer_last),
.rx_latency_o (rx_latency),
.rx_latency_valid_o(rx_latency_valid),
.cfg_mac_local_i (g_mac_rx),
.cfg_mac_remote_i (g_mac_tx),
.cfg_ethertype_i (g_ethertype)
);
// Client-side reception logic. Compares the received records with their copies
// stored in the queue.
always@(posedge clk)
if(rst_n)
begin
block_t rblk;
automatic int done = 0;
receive_block(rblk, done);
if(done)
begin
automatic block_t tblk = queue.pop_front();
$display("Received block of %d words.\n", rblk.data.size());
if(tblk.data != rblk.data)
begin
$error("Sent block does not match received block\n");
$stop;
end
end
end // else: !if(!rst_n)
// always@(posedge clk)
// if(rst && rx_latency_valid)
// $display("This frame's latency: %.3f microseconds\n", real'(rx_latency) * 0.008);
endmodule // main
make -f Makefile
vsim -L unisim work.main -voptargs="+acc" -suppress 8684,8683
set NumericStdNoWarnings 1
set StdArithNoWarnings 1
do wave.do
run 10us
wave zoomfull
radix -hex
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate /main/U_TX_Streamer/tx_flush_i
add wave -noupdate /main/U_TX_Streamer/tx_last_i
add wave -noupdate /main/U_TX_Streamer/tx_data_i
add wave -noupdate /main/U_TX_Streamer/tx_reset_seq_i
add wave -noupdate /main/U_TX_Streamer/tx_valid_i
add wave -noupdate /main/U_TX_Streamer/tx_dreq_o
add wave -noupdate /main/mac/adr
add wave -noupdate /main/mac/dat_o
add wave -noupdate /main/mac/dat_i
add wave -noupdate /main/mac/sel
add wave -noupdate /main/mac/ack
add wave -noupdate /main/mac/stall
add wave -noupdate /main/mac/err
add wave -noupdate /main/mac/rty
add wave -noupdate /main/mac/cyc
add wave -noupdate /main/mac/stb
add wave -noupdate /main/mac/we
add wave -noupdate /main/U_RX_Streamer/rx_first_o
add wave -noupdate /main/U_RX_Streamer/rx_last_o
add wave -noupdate /main/U_RX_Streamer/rx_data_o
add wave -noupdate /main/U_RX_Streamer/rx_valid_o
add wave -noupdate /main/U_RX_Streamer/rx_dreq_i
add wave -noupdate /main/U_RX_Streamer/rx_lost_o
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {867 ns} 0}
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 ns
update
WaveRestoreZoom {0 ns} {915 ns}
files = ["spec_top.vhd", "spec_top.ucf", "spec_reset_gen.vhd","timestamp_adder.vhd" ]
modules = { "local" : ["../../../", "../../../platform/xilinx/chipscope"] }
\ No newline at end of file
library ieee;
use ieee.STD_LOGIC_1164.all;
use ieee.NUMERIC_STD.all;
use work.gencores_pkg.all;
entity spec_reset_gen is
port (
clk_sys_i : in std_logic;
rst_pcie_n_a_i : in std_logic;
rst_button_n_a_i : in std_logic;
rst_n_o : out std_logic
);
end spec_reset_gen;
architecture behavioral of spec_reset_gen is
signal powerup_cnt : unsigned(7 downto 0) := x"00";
signal button_synced_n : std_logic;
signal pcie_synced_n : std_logic;
signal powerup_n : std_logic := '0';
begin -- behavioral
U_EdgeDet_PCIe : gc_sync_ffs port map (
clk_i => clk_sys_i,
rst_n_i => '1',
data_i => rst_pcie_n_a_i,
ppulse_o => pcie_synced_n);
U_Sync_Button : gc_sync_ffs port map (
clk_i => clk_sys_i,
rst_n_i => '1',
data_i => rst_button_n_a_i,
synced_o => button_synced_n);
p_powerup_reset : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if(powerup_cnt /= x"ff") then
powerup_cnt <= powerup_cnt + 1;
powerup_n <= '0';
else
powerup_n <= '1';
end if;
end if;
end process;
rst_n_o <= powerup_n and button_synced_n and (not pcie_synced_n);
end behavioral;
#####################
# Clocks, buttons, reset
#####################
NET "clk_125m_pllref_n_i" LOC = F10;
NET "clk_125m_pllref_n_i" IOSTANDARD = "LVDS_25";
NET "clk_125m_pllref_p_i" LOC = G9;
NET "clk_125m_pllref_p_i" IOSTANDARD = "LVDS_25";
NET "fpga_pll_ref_clk_101_n_i" LOC = D11;
NET "fpga_pll_ref_clk_101_n_i" IOSTANDARD = "LVDS_25";
NET "fpga_pll_ref_clk_101_p_i" LOC = C11;
NET "fpga_pll_ref_clk_101_p_i" IOSTANDARD = "LVDS_25";
NET "clk_20m_vcxo_i" LOC = H12;
NET "clk_20m_vcxo_i" IOSTANDARD = "LVCMOS25";
NET "l_rst_n" LOC = N20;
NET "l_rst_n" IOSTANDARD = "LVCMOS18";
NET "button1_n_i" LOC = C22;
NET "button1_n_i" IOSTANDARD = "LVCMOS18";
######################
# SFP Pins
######################
NET "sfp_txp_o" LOC= B16;
NET "sfp_txn_o" LOC= A16;
NET "sfp_rxp_i" LOC= D15;
NET "sfp_rxn_i" LOC= C15;
NET "sfp_det_i" LOC = G15;
NET "sfp_det_i" IOSTANDARD = "LVCMOS25";
NET "sfp_scl_b" LOC = C17;
NET "sfp_scl_b" IOSTANDARD = "LVCMOS25";
NET "sfp_sda_b" LOC = G16;
NET "sfp_sda_b" IOSTANDARD = "LVCMOS25";
NET "sfp_rate_select_b" LOC = H14;
NET "sfp_rate_select_b" IOSTANDARD = "LVCMOS25";
NET "sfp_tx_fault_i" LOC = A17;
NET "sfp_tx_fault_i" IOSTANDARD = "LVCMOS25";
NET "sfp_tx_disable_o" LOC = F17;
NET "sfp_tx_disable_o" IOSTANDARD = "LVCMOS25";
NET "sfp_los_i" LOC = D18;
NET "sfp_los_i" IOSTANDARD = "LVCMOS25";
NET "sfp_led_green_o" LOC = E5;
NET "sfp_led_green_o" IOSTANDARD = "LVCMOS25";
NET "sfp_led_red_o" LOC = D5;
NET "sfp_led_red_o" IOSTANDARD = "LVCMOS25";
#################
# Oscillator control
#################
NET "dac_sclk_o" LOC = A4;
NET "dac_sclk_o" IOSTANDARD = "LVCMOS25";
NET "dac_din_o" LOC = C4;
NET "dac_din_o" IOSTANDARD = "LVCMOS25";
NET "dac_cs1_n_o" LOC = A3;
NET "dac_cs1_n_o" IOSTANDARD = "LVCMOS25";
NET "dac_cs2_n_o" LOC = B3;
NET "dac_cs2_n_o" IOSTANDARD = "LVCMOS25";
#################
# Misc pins
#################
NET "fmc_scl_b" LOC = F7;
NET "fmc_scl_b" IOSTANDARD = "LVCMOS25";
NET "fmc_sda_b" LOC = F8;
NET "fmc_sda_b" IOSTANDARD = "LVCMOS25";
NET "thermo_id_b" LOC = D4;
NET "thermo_id_b" IOSTANDARD = "LVCMOS25";
NET "uart_txd_o" LOC= B2;
NET "uart_txd_o" IOSTANDARD=LVCMOS25;
NET "uart_rxd_i" LOC= A2;
NET "uart_rxd_i" IOSTANDARD=LVCMOS25;
########################################################
## Pin definitions for FmcDio5chttl + SPEC v1.1/2.0 ##
########################################################
# DIO outputs
NET "dio_p_o[4]" LOC= T8;
NET "dio_n_o[4]" LOC= U8;
NET "dio_p_o[4]" IOSTANDARD=LVDS_25;
NET "dio_n_o[4]" IOSTANDARD=LVDS_25;
NET "dio_p_o[3]" LOC= U9;
NET "dio_n_o[3]" LOC= V9;
NET "dio_p_o[3]" IOSTANDARD=LVDS_25;
NET "dio_n_o[3]" IOSTANDARD=LVDS_25;
NET "dio_p_o[2]" LOC= R9;
NET "dio_n_o[2]" LOC= R8;
NET "dio_p_o[2]" IOSTANDARD=LVDS_25;
NET "dio_n_o[2]" IOSTANDARD=LVDS_25;
NET "dio_p_o[1]" LOC= Y16;
NET "dio_n_o[1]" LOC= W15;
NET "dio_p_o[1]" IOSTANDARD=LVDS_25;
NET "dio_n_o[1]" IOSTANDARD=LVDS_25;
NET "dio_p_o[0]" LOC= W17;
NET "dio_n_o[0]" LOC= Y18;
NET "dio_p_o[0]" IOSTANDARD=LVDS_25;
NET "dio_n_o[0]" IOSTANDARD=LVDS_25;
# DIO output enable/termination enable
NET "dio_oe_n_o[4]" LOC= AA6;
NET "dio_oe_n_o[3]" LOC= W10;
NET "dio_oe_n_o[2]" LOC= W11;
NET "dio_oe_n_o[1]" LOC= Y14;
NET "dio_oe_n_o[0]" LOC= V17;
NET "dio_oe_n_o[4]" IOSTANDARD=LVCMOS25;
NET "dio_oe_n_o[3]" IOSTANDARD=LVCMOS25;
NET "dio_oe_n_o[2]" IOSTANDARD=LVCMOS25;
NET "dio_oe_n_o[1]" IOSTANDARD=LVCMOS25;
NET "dio_oe_n_o[0]" IOSTANDARD=LVCMOS25;
NET "dio_term_en_o[4]" LOC=AB7;
NET "dio_term_en_o[3]" LOC=Y7;
NET "dio_term_en_o[2]" LOC=AB6;
NET "dio_term_en_o[1]" LOC=AB5;
NET "dio_term_en_o[0]" LOC=W18;
NET "dio_term_en_o[4]" IOSTANDARD=LVCMOS25;
NET "dio_term_en_o[3]" IOSTANDARD=LVCMOS25;
NET "dio_term_en_o[2]" IOSTANDARD=LVCMOS25;
NET "dio_term_en_o[1]" IOSTANDARD=LVCMOS25;
NET "dio_term_en_o[0]" IOSTANDARD=LVCMOS25;
# DIO inputs
NET "dio_p_i[4]" LOC =Y11;
NET "dio_p_i[4]" IOSTANDARD=LVDS_25;
NET "dio_n_i[4]" LOC =AB11;
NET "dio_n_i[4]" IOSTANDARD=LVDS_25;
NET "dio_p_i[3]" LOC =V7;
NET "dio_p_i[3]" IOSTANDARD=LVDS_25;
NET "dio_n_i[3]" LOC =W8;
NET "dio_n_i[3]" IOSTANDARD=LVDS_25;
NET "dio_p_i[2]" LOC =W12;
NET "dio_p_i[2]" IOSTANDARD=LVDS_25;
NET "dio_n_i[2]" LOC =Y12;
NET "dio_n_i[2]" IOSTANDARD=LVDS_25;
NET "dio_p_i[1]" LOC =R11;
NET "dio_p_i[1]" IOSTANDARD=LVDS_25;
NET "dio_n_i[1]" LOC =T11;
NET "dio_n_i[1]" IOSTANDARD=LVDS_25;
NET "dio_p_i[0]" LOC =C19;
NET "dio_p_i[0]" IOSTANDARD=LVDS_25;
NET "dio_n_i[0]" LOC =A19;
NET "dio_n_i[0]" IOSTANDARD=LVDS_25;
NET "dio_led_top_o" LOC= AA12;
NET "dio_led_top_o" IOSTANDARD=LVCMOS25;
NET "dio_led_bot_o" LOC= AB12;
NET "dio_led_bot_o" IOSTANDARD=LVCMOS25;
##Created by Constraints Editor (xc6slx45t-fgg484-3) - 2012/08/07
#ML: INST "U_The_WR_Core/WRPC/U_SOFTPLL/U_Wrapped_Softpll/gen_feedback_dmtds[0].DMTD_FB/clk_in" TNM = skew_limit;
#ML: INST "U_The_WR_Core/WRPC/U_SOFTPLL/U_Wrapped_Softpll/gen_feedback_dmtds[1].DMTD_FB/clk_in" TNM = skew_limit;
#ML: INST "U_The_WR_Core/WRPC/U_SOFTPLL/U_Wrapped_Softpll/gen_ref_dmtds[0].DMTD_REF/clk_in" TNM = skew_limit;
INST "*/U_SOFTPLL/U_Wrapped_Softpll/gen_feedback_dmtds*/clk_in" TNM = skew_limit;
INST "*/U_SOFTPLL/U_Wrapped_Softpll/gen_ref_dmtds*/clk_in" TNM = skew_limit;
TIMESPEC TS_ = FROM "skew_limit" TO "FFS" 1 ns DATAPATHONLY;
#Created by Constraints Editor (xc6slx45t-fgg484-3) - 2012/08/08
INST "U_The_WR_Core/WRPC/U_Endpoint/U_Wrapped_Endpoint/U_PCS_1000BASEX/gen_8bit.U_RX_PCS/timestamp_trigger_p_a_o" TNM = rx_ts_trig;
TIMESPEC TS_RXTS = FROM "rx_ts_trig" TO "FFS" 1 ns DATAPATHONLY;
#Created by Constraints Editor (xc6slx45t-fgg484-3) - 2013/03/14
NET "clk_20m_vcxo_i" TNM_NET = clk_20m_vcxo_i;
TIMESPEC TS_clk_20m_vcxo_i = PERIOD "clk_20m_vcxo_i" 50 ns HIGH 50%;
NET "clk_125m_pllref_p_i" TNM_NET = clk_125m_pllref_p_i;
TIMESPEC TS_clk_125m_pllref_p_i = PERIOD "clk_125m_pllref_p_i" 8 ns HIGH 50%;
NET "fpga_pll_ref_clk_101_n_i" TNM_NET = fpga_pll_ref_clk_101_n_i;
TIMESPEC TS_fpga_pll_ref_clk_101_n_i = PERIOD "fpga_pll_ref_clk_101_n_i" 8 ns HIGH 50%;
NET "clk_125m_pllref_n_i" TNM_NET = clk_125m_pllref_n_i;
TIMESPEC TS_clk_125m_pllref_n_i = PERIOD "clk_125m_pllref_n_i" 8 ns HIGH 50%;
NET "fpga_pll_ref_clk_101_p_i" TNM_NET = fpga_pll_ref_clk_101_p_i;
TIMESPEC TS_fpga_pll_ref_clk_101_p_i = PERIOD "fpga_pll_ref_clk_101_p_i" 8 ns HIGH 50%;
NET "U_GTP/ch1_gtp_clkout_int<1>" TNM_NET = U_GTP/ch1_gtp_clkout_int<1>;
TIMESPEC TS_U_GTP_ch1_gtp_clkout_int_1_ = PERIOD "U_GTP/ch1_gtp_clkout_int<1>" 8 ns HIGH 50%;
This diff is collapsed.
-------------------------------------------------------------------------------
-- Title : Pipelined timestamp adder with normalization
-- Project : Fine Delay Core (FmcDelay1ns4cha)
-------------------------------------------------------------------------------
-- File : fd_ts_adder.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN
-- Created : 2011-08-29
-- Last update: 2013-03-13
-- Platform : FPGA-generic
-- Standard : VHDL'93
-------------------------------------------------------------------------------
-- Description: Pipelined timestamp adder with re-normalization of the result.
-- Adds a to b, producing normalized timestamp q. A timestmap is normalized when
-- the 0 <= frac < 2**g_frac_bits, 0 <= coarse <= g_coarse_range-1 and utc >= 0.
-- For correct operation of renormalizer, input timestamps must meet the
-- following constraints:
-- 1. 0 <= (a/b)_frac_i <= 2**g_frac_bits-1
-- 2. -g_coarse_range+1 <= (a_coarse_i + b_coarse_i) <= 3*g_coarse_range-1
-------------------------------------------------------------------------------
--
-- Copyright (c) 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
-- 2011-08-29 1.0 twlostow Created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity timestamp_adder is
generic
(
-- sizes of the respective bitfields of the input/output timestamps
g_frac_bits : integer := 12;
g_cycles_bits : integer := 28;
g_tai_bits : integer := 40;
-- upper bound of the coarse part
g_ref_clk_rate: integer := 125000000
);
port(
clk_i : in std_logic;
rst_n_i : in std_logic;
valid_i : in std_logic; -- when HI, a_* and b_* contain valid timestamps
enable_i : in std_logic := '1'; -- pipeline enable
-- Input timestamps
a_tai_i : in std_logic_vector(g_tai_bits-1 downto 0);
a_cycles_i : in std_logic_vector(g_cycles_bits-1 downto 0);
a_frac_i : in std_logic_vector(g_frac_bits-1 downto 0) := (others => '0');
b_tai_i : in std_logic_vector(g_tai_bits-1 downto 0);
b_cycles_i : in std_logic_vector(g_cycles_bits-1 downto 0);
b_frac_i : in std_logic_vector(g_frac_bits-1 downto 0) := (others => '0');
-- Normalized sum output (valid when valid_o == 1)
valid_o : out std_logic;
q_tai_o : out std_logic_vector(g_tai_bits-1 downto 0);
q_cycles_o : out std_logic_vector(g_cycles_bits-1 downto 0);
q_frac_o : out std_logic_vector(g_frac_bits-1 downto 0)
);
end timestamp_adder;
architecture rtl of timestamp_adder is
constant c_NUM_PIPELINE_STAGES : integer := 4;
type t_internal_sum is record
utc : signed(g_tai_bits-1 downto 0);
coarse : signed(g_cycles_bits+1 downto 0);
frac : signed(g_frac_bits+1 downto 0);
end record;
type t_internal_sum_array is array (integer range <>) of t_internal_sum;
signal pipe : std_logic_vector(c_NUM_PIPELINE_STAGES-1 downto 0);
signal sums : t_internal_sum_array(0 to c_NUM_PIPELINE_STAGES-1);
signal ovf_frac : std_logic;
signal ovf_coarse : std_logic_vector(1 downto 0);
signal unf_coarse : std_logic;
begin -- rtl
-- Pipeline stage 0: just add the two timestamps field by field
p_stage0 : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
pipe(0) <= '0';
elsif(enable_i = '1') then
pipe(0) <= valid_i;
sums(0).frac <= signed("00" & a_frac_i) + signed("00" & b_frac_i);
sums(0).coarse <= resize(signed(a_cycles_i), sums(0).coarse'length) +
resize(signed(b_cycles_i), sums(0).coarse'length);
sums(0).utc <= signed(a_tai_i) + signed(b_tai_i);
else
pipe(0) <= '0';
end if;
end if;
end process;
ovf_frac <= std_logic(sums(0).frac(g_frac_bits));
-- Pipeline stage 1: check the fractional sum for overflow and eventually adjust
-- the coarse sum
p_stage1 : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
pipe(1) <= '0';
else
pipe(1) <= pipe(0);
if(ovf_frac = '1') then
sums(1).frac <= sums(0).frac - 2**g_frac_bits;
sums(1).coarse <= sums(0).coarse + 1;
else
sums(1).frac <= sums(0).frac;
sums(1).coarse <= sums(0).coarse;
end if;
sums(1).utc <= sums(0).utc;
end if;
end if;
end process;
-- Pipeline stage 2: check the coarse sum for under/overflows
p_stage2 : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
pipe(2) <= '0';
else
sums(2) <= sums(1);
pipe(2) <= pipe(1);
if(sums(1).coarse < 0) then
unf_coarse <= '1';
ovf_coarse <= "00";
elsif(sums(1).coarse >= 2 * g_ref_clk_rate) then
ovf_coarse <= "10";
unf_coarse <= '0';
elsif(sums(1).coarse >= g_ref_clk_rate) then
ovf_coarse <= "01";
unf_coarse <= '0';
else
ovf_coarse <= "00";
unf_coarse <= '0';
end if;
end if;
end if;
end process;
-- Pipeline stage 3: adjust the coarse & UTC sums according to normalize the
-- previously detected under/overflows
p_stage3 : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
pipe(3) <= '0';
else
pipe(3) <= pipe(2);
if(unf_coarse = '1') then
sums(3).coarse <= sums(2).coarse + g_ref_clk_rate;
sums(3).utc <= sums(2).utc - 1;
elsif(ovf_coarse = "10") then
sums(3).coarse <= sums(2).coarse - (2*g_ref_clk_rate);
sums(3).utc <= sums(2).utc + 2;
elsif(ovf_coarse = "01") then
sums(3).coarse <= sums(2).coarse - g_ref_clk_rate;
sums(3).utc <= sums(2).utc + 1;
else
sums(3).coarse <= sums(2).coarse;
sums(3).utc <= sums(2).utc;
end if;
sums(3).frac <= sums(2).frac;
end if;
end if;
end process;
-- clip the extra bits and output the result
valid_o <= pipe(c_NUM_PIPELINE_STAGES-1);
q_tai_o <= std_logic_vector(sums(c_NUM_PIPELINE_STAGES-1).utc(g_tai_bits-1 downto 0));
q_cycles_o <= std_logic_vector(sums(c_NUM_PIPELINE_STAGES-1).coarse(g_cycles_bits-1 downto 0));
q_frac_o <= std_logic_vector(sums(c_NUM_PIPELINE_STAGES-1).frac(g_frac_bits-1 downto 0));
end rtl;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment