Commit 8657ed23 authored by kblantos's avatar kblantos

Merge remote-tracking branch 'origin/alen-test-branch' into kostas_dev

parents 74930ea5 c9a9d911
......@@ -9,6 +9,6 @@ files = [
"masterfip_wbgen2_pkg.vhd",
"wf_package.vhd",
"spi_slave.vhd",
"mt_profip_translator.vhd",
"mt_profip_translator.vhd"
]
--============================================================================--
--! @file rmq_stream_fifo.vhd
--! @author Alen Arias Vazquez <alen.arias.vazquez@cern.ch>
--! @company CERN
--! @date 2023-03-01
--! @brief Fifo encapsulation of RMQ frames
--============================================================================--
--============================================================================--
-- Libraries & Packages --
--============================================================================--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.mt_mqueue_pkg.all;
use work.gencores_pkg.all;
--============================================================================--
-- Entity declaration for rmq_stream_fifo --
--============================================================================--
entity rmq_stream_fifo is
generic (
g_DATA_WIDTH : natural;
g_CDC_ENABLE : natural range 0 to 1;
g_FIFO_DEPTH : natural := 128;
g_show_ahead : boolean := true
);
port (
rst_n_i : in std_logic; --! FPGA reset
--! RX
rmq_src_clk_i : in std_logic;
rmq_src_i : in t_mt_stream_source_in; --! (ready, pkt_ready)
rmq_src_o : out t_mt_stream_source_out; --! (data, hdr, valid, last, error)
rmq_src_config_i : in t_mt_stream_config_out; --! (adr, dat, we)
rmq_src_config_o : out t_mt_stream_config_in; --! (dat)
--! TX
rmq_snk_clk_i : in std_logic;
rmq_snk_i : in t_mt_stream_sink_in; --! (data, hdr, valid, last, error)
rmq_snk_o : out t_mt_stream_sink_out; --! (ready, pkt_ready)
rmq_snk_config_i : in t_mt_stream_config_out; --! (adr, dat, we)
rmq_snk_config_o : out t_mt_stream_config_in --! (dat)
);
end entity rmq_stream_fifo;
--============================================================================--
-- Architecture declaration --
--============================================================================--
architecture struct of rmq_stream_fifo is
--! Data encapsulation
signal s_fifo_input : std_logic_vector(g_DATA_WIDTH+2 downto 0);
signal s_fifo_output : std_logic_vector(g_DATA_WIDTH+2 downto 0);
--! Write enable
signal s_input_full : std_logic;
signal s_write_enable : std_logic;
--! Read enable
signal s_output_empty : std_logic;
signal s_read_enable : std_logic;
--------------------------------------------------------------------------------
-- Architecture Begin
--------------------------------------------------------------------------------
begin
----------------------------------------------------------------------------
--! Unused
rmq_src_config_o.dat <= (others => '0');
rmq_snk_config_o.dat <= (others => '0');
----------------------------------------------------------------------------
CDC_check: assert g_CDC_ENABLE = 0
report "The port rmq_snk_clk_i is ignored" severity note;
s_fifo_input <= rmq_snk_i.hdr & rmq_snk_i.last & rmq_snk_i.error & rmq_snk_i.data;
s_write_enable <= not(s_input_full) and rmq_snk_i.valid;
rmq_snk_o.ready <= not (s_input_full);
rmq_snk_o.pkt_ready <= not (s_input_full);
gen_CDC_false: if g_CDC_ENABLE = 0 generate
cmp_fifo: entity work.inferred_sync_fifo
generic map (
g_data_width => g_DATA_WIDTH+3,
g_size => g_FIFO_DEPTH,
g_show_ahead => g_show_ahead,
g_show_ahead_legacy_mode => true,
g_with_empty => true,
g_with_full => true,
g_with_almost_empty => false,
g_with_almost_full => false,
g_with_count => false,
g_register_flag_outputs => false,
g_almost_empty_threshold => 0,
g_almost_full_threshold => 0
)
port map(
rst_n_i => rst_n_i,
clk_i => rmq_src_clk_i,
d_i => s_fifo_input,
we_i => s_write_enable,
full_o => s_input_full,
q_o => s_fifo_output,
empty_o => s_output_empty,
rd_i => s_read_enable,
almost_empty_o => open,
almost_full_o => open,
count_o => open
);
end generate gen_CDC_false;
gen_CDC_true: if g_CDC_ENABLE = 1 generate
cmp_fifo: entity work.inferred_async_fifo
generic map (
g_data_width => g_DATA_WIDTH+3,
g_size => g_FIFO_DEPTH,
g_show_ahead => true,
g_with_rd_empty => true,
g_with_rd_full => false,
g_with_rd_almost_empty => false,
g_with_rd_almost_full => false,
g_with_rd_count => false,
g_with_wr_full => true,
g_with_wr_empty => false,
g_with_wr_almost_empty => false,
g_with_wr_almost_full => false,
g_with_wr_count => false,
g_almost_empty_threshold => 0,
g_almost_full_threshold => 0
)
port map (
rst_n_i => rst_n_i,
-- write port
clk_wr_i => rmq_snk_clk_i,
d_i => s_fifo_input,
we_i => s_write_enable,
wr_full_o => s_input_full,
wr_empty_o => open,
wr_almost_empty_o => open,
wr_almost_full_o => open,
wr_count_o => open,
-- read port
clk_rd_i => rmq_src_clk_i,
q_o => s_fifo_output,
rd_empty_o => s_output_empty,
rd_i => s_read_enable,
rd_full_o => open,
rd_almost_empty_o => open,
rd_almost_full_o => open,
rd_count_o => open
);
end generate gen_CDC_true;
rmq_src_o.data <= s_fifo_output(g_DATA_WIDTH-1 downto 0);
rmq_src_o.hdr <= s_fifo_output(g_DATA_WIDTH+2);
rmq_src_o.last <= s_fifo_output(g_DATA_WIDTH+1);
rmq_src_o.error <= s_fifo_output(g_DATA_WIDTH);
rmq_src_o.valid <= not (s_output_empty);
s_read_enable <= rmq_src_i.ready and not(s_output_empty);
end architecture struct;
--============================================================================--
-- End Architecture --
--============================================================================--
This diff is collapsed.
......@@ -15,12 +15,12 @@ sudo apt install -y make
yum install -y make
```
## Build Container
- [How to build docker container](docker/README.md)
## Requirements Windows
Unfortunately Windows is not supported yet
## Build Container
- [How to build docker container](docker/README.md)
## Developers
- [Konstantinos Blantos](mailto:konstantinos.blantos@cern.ch)
- [Alén Arias Vázquez](mailto:alen.arias.vazquez@cern.ch)
......@@ -7,6 +7,9 @@ ifeq (${SIM}, ghdl)
else ifeq (${SIM}, icarus)
TOPLEVEL_LANG:=verilog
COMPILE_ARGS+=-D$(WAVEFORM_NAME) -pfileline=1
else ifeq (${SIM}, questa)
TOPLEVEL_LANG?=vhdl
WAVES=1
endif
COCOTB_REDUCED_LOG_FMT?=1
......@@ -22,4 +25,5 @@ endif
clean::
rm -rf __pycache__
rm -fr *.xml *.pyc
rm -rf *.xml *.pyc
rm -rf vsim.wlf transcript modelsim.ini
"""
RMQ Class
"""
import cocotb
import random
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge, FallingEdge, Timer
from cocotb.result import *
from cocotb.queue import Queue, QueueFull
# RMQ Common
class RMQ:
def __init__(self, dut, clk, if_name):
self.dut = dut
self.clk = clk
self.rmq_i = getattr(dut, 'rmq_'+if_name+'_i')
self.rmq_o = getattr(dut, 'rmq_'+if_name+'_o')
self.fifo = Queue()
def get_fifo_size(self):
return self.fifo.qsize()
def check_fifo_empty(self):
return self.fifo.empty()
def push_fifo(self, data):
self.fifo.put_nowait(data)
def pop_fifo(self):
return self.fifo.get_nowait()
def get_data(self):
data = []
for i in range(self.get_fifo_size()):
data.append(self.pop_fifo())
return data
"""
RMQ Master
"""
class RMQMaster(RMQ):
def __init__(self, dut, clk, if_name, header_size=1):
RMQ.__init__(self, dut=dut, clk=clk, if_name=if_name)
self.dut._log.info("Init RMQ Master")
self.rmq_i.data.setimmediatevalue(0)
self.rmq_i.hdr.setimmediatevalue(0)
self.rmq_i.last.setimmediatevalue(0)
self.rmq_i.error.setimmediatevalue(0)
self.rmq_i.valid.setimmediatevalue(0)
self.hdr_size = header_size-1
def send_data(self, data):
data_len = len(data)
self.dut._log.info("Sending Data with length: {}".format(data_len))
for x in range(data_len):
if x <= self.hdr_size:
self.push_fifo('HDR')
if x == (data_len-1):
self.push_fifo('LAST')
self.push_fifo(data[x])
self.dut._log.info("Data sent")
@cocotb.coroutine
def input_data_rmq(self):
self.dut._log.info('Starting coroutine to write data')
self.rmq_i.valid.value = 0
fifo_data = 0
while(True):
yield RisingEdge(self.clk)
while( (self.rmq_i.valid.value == 1) and (self.rmq_o.ready.value == 0)):
yield RisingEdge(self.clk)
self.rmq_i.hdr.value = 0
self.rmq_i.last.value = 0
self.rmq_i.error.value = 0
while(self.check_fifo_empty()):
self.rmq_i.valid.value = 0
yield RisingEdge(self.clk)
fifo_data = self.pop_fifo()
if type(fifo_data) == str:
if fifo_data == 'HDR':
self.rmq_i.hdr.value = 1
fifo_data = self.pop_fifo()
if fifo_data == 'LAST':
self.rmq_i.last.value = 1
fifo_data = self.pop_fifo()
self.rmq_i.data.value = fifo_data
self.rmq_i.valid.value = 1
"""
RMQ Slave
"""
class RMQSlave(RMQ):
def __init__(self, dut, clk, if_name, header_size=2):
RMQ.__init__(self, dut=dut, clk=clk, if_name=if_name)
self.dut._log.info("Init RMQ Slave")
self.rmq_i.ready.setimmediatevalue(0)
self.rmq_i.pkt_ready.setimmediatevalue(0)
self.rmq_request_c = 0
self.rmq_word_c = 0
self.hdr_size = header_size -1
@cocotb.coroutine
def output_data_rmq(self):
self.dut._log.info('Starting coroutine to receive data')
yield RisingEdge(self.clk)
while(True):
if ((self.rmq_o.valid.value == 1) and (self.rmq_i.ready.value == 1)):
if (self.rmq_word_c <= self.hdr_size) and self.rmq_o.hdr.value == 0:
self.dut._log.error("Missing HEADER in reception")
raise SimFailure()
self.push_fifo(self.rmq_o.data.value.integer)
if self.rmq_o.last.value == 1:
self.rmq_word_c += 1
self.rmq_request_c = self.rmq_request_c + 1
self.dut._log.info("Received frame {} with length {}".format(self.rmq_request_c, self.rmq_word_c))
self.rmq_word_c = 0
else:
self.rmq_word_c += 1
yield RisingEdge(self.clk)
@cocotb.coroutine
def tready_behaviour(self, max_cycles_off=5, randomize=False):
self.rmq_i.pkt_ready.value = 1
if max_cycles_off == 0:
while(True):
self.rmq_i.ready.value = 1
yield RisingEdge(self.clk)
else:
self.dut._log.info('Starting coroutine to control RMQ Ready')
if randomize:
max_cycles = random.randint(1, max_cycles_off)
else:
max_cycles = max_cycles_off
self.rmq_i.ready.value = 0
for x in range(max_cycles_off):
yield RisingEdge(self.clk)
aux_rmq_valid = 1
while(True):
for x in range(max_cycles_off):
self.rmq_i.ready.value = aux_rmq_valid
yield RisingEdge(self.clk)
if aux_rmq_valid == 0:
aux_rmq_valid = 1
else:
aux_rmq_valid = 0
if randomize:
max_cycles = random.randint(1, max_cycles_off)
else:
max_cycles = max_cycles_off
\ No newline at end of file
......@@ -180,6 +180,7 @@ class SpiMaster(SpiDevice):
TX_STARTED = False
while self.check_tx_fifo_empty():
self.SCLK.value = int(self.CPOL)
self.CS.value = 1
self._idle.set()
self.sync.clear()
await self.sync.wait()
......
# List of vhdl srcs
SRC_VHDL=rmq_stream_fifo.vhd
VHDL_SOURCES:=$(addprefix $(PWD)/../../../../rtl/,$(SRC_VHDL))
VHDL_SOURCES+=../../../../ip_cores/general-cores/modules/common/gc_sync.vhd
VHDL_SOURCES+=../../../../ip_cores/general-cores/modules/common/gc_sync_ffs.vhd
VHDL_SOURCES+=../../../../ip_cores/general-cores/modules/common/gc_edge_detect.vhd
VHDL_SOURCES+=../../../../ip_cores/general-cores/modules/common/gc_sync_register.vhd
VHDL_SOURCES+=../../../../ip_cores/general-cores/modules/genrams/common/inferred_sync_fifo.vhd
VHDL_SOURCES+=../../../../ip_cores/general-cores/modules/genrams/common/inferred_async_fifo.vhd
VHDL_SOURCES+=../../../../ip_cores/general-cores/modules/genrams/xilinx/generic_dpram.vhd
VHDL_SOURCES+=../../../../ip_cores/general-cores/modules/genrams/xilinx/generic_dpram_sameclock.vhd
VHDL_SOURCES+=../../../../ip_cores/general-cores/modules/genrams/xilinx/generic_dpram_dualclock.vhd
VHDL_SOURCES+=../../../../ip_cores/general-cores/modules/genrams/memory_loader_pkg.vhd
VHDL_SOURCES+=../../../../ip_cores/general-cores/modules/wishbone/wishbone_pkg.vhd
VHDL_SOURCES+=../../../../ip_cores/general-cores/modules/common/gencores_pkg.vhd
VHDL_SOURCES+=../../../../ip_cores/general-cores/modules/genrams/genram_pkg.vhd
VHDL_SOURCES+=../../../../ip_cores/mockturtle/hdl/rtl/mqueue/mt_mqueue_pkg.vhd
# TOPLEVEL is the top level design and module is the python test
TOPLEVEL:=rmq_stream_fifo
MODULE:=tb_rmq_stream_fifo
RTL_LIBRARY?=work
# Define value variable for CI
CDC_ENABLE=$(shell expr $(shell date +'%M') % 2)
# Define variables, possible to modify using make g_CDC_ENABLE=0
g_DATA_WIDTH?=32
g_CDC_ENABLE?=$(CDC_ENABLE)
g_FIFO_DEPTH?=64
g_show_ahead?=true
SIM_ARGS=-voptargs=+acc=rn
SIM_ARGS+="-t ps"
# Generics for GHDL
SIM_ARGS+=-gg_DATA_WIDTH=${g_DATA_WIDTH}
SIM_ARGS+=-gg_CDC_ENABLE=${g_CDC_ENABLE}
SIM_ARGS+=-gg_FIFO_DEPTH=${g_FIFO_DEPTH}
SIM_ARGS+=-gg_show_ahead=${g_show_ahead}
VCOM_ARGS +=-autoorder -2008
SCRIPT_FILE=wave.do
# Target Simulator
SIM=questa
# PYHTON PATH to get python models
export PYTHONPATH:=$(PWD)/../models/:$(PYTHONPATH)
# Include common rules
include ../Makefile.config
"""
Test RMQ STREAM FIFO
"""
import cocotb
import numpy as np
import time
import random
import math
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge, FallingEdge, Timer
from cocotb.regression import TestFactory
from cocotb.result import *
from rmq import RMQMaster, RMQSlave
# ------------------------------------------------------------------------------
# fill data
def GetRMQFrame(header, data_len, data_width, randomize):
data = []
mask = 2**data_width - 1
data.append(header & mask)
data.append(~(header) & mask)
for i in range(data_len):
if randomize:
data.append(random.randint(0, (2**data_width)-1) & mask)
else:
if i % 8 == 0:
data.append(0xDEADC0DE & mask)
elif i % 8 == 1:
data.append(0xCAFED00D & mask)
elif i % 8 == 2:
data.append(0xDEADCAFE & mask)
elif i % 8 == 3:
data.append(0xBADC0FFE & mask)
elif i % 8 == 4:
data.append(0xBAADF00D & mask)
elif i % 8 == 5:
data.append(0xDEFEC8ED & mask)
elif i % 8 == 6:
data.append(0xDEADBEEF & mask)
elif i % 8 == 7:
data.append(0xFEEDBABE & mask)
return data
# ------------------------------------------------------------------------------
# Setup clock signal
def setup_clock(signal_name, period, units="ns"):
cocotb.start_soon(Clock(signal_name, period, units=units).start())
# ------------------------------------------------------------------------------
# Main Test
@cocotb.coroutine
async def test(dut, n_rst_cycles, data_len, randomize, ready_clk_off):
g_CDC = dut.g_CDC_ENABLE.value
data_width = dut.g_data_width.value
rmq_snk_msg = GetRMQFrame(header=0xFACEB00C, data_len=data_len, data_width=data_width, randomize=randomize)
m_rmq = RMQMaster(dut=dut, clk=dut.rmq_snk_clk_i, if_name='snk', header_size = 1)
s_rmq = RMQSlave(dut=dut, clk=dut.rmq_src_clk_i, if_name='src', header_size = 1)
if g_CDC == 1:
dut._log.warning("Clock domain crossing enable")
setup_clock(signal_name=dut.rmq_snk_clk_i, period=10)
setup_clock(signal_name=dut.rmq_src_clk_i, period=3*10)
else:
dut._log.warning("Clock domain crossing disable")
setup_clock(signal_name=dut.rmq_snk_clk_i, period=10)
setup_clock(signal_name=dut.rmq_src_clk_i, period=10)
cocotb.start_soon(reset(dut, n_rst_cycles))
await delay(dut.rmq_snk_clk_i, 1)
while dut.rst_n_i.value != 1:
await RisingEdge(dut.rmq_snk_clk_i)
cocotb.start_soon(m_rmq.input_data_rmq())
cocotb.start_soon(s_rmq.output_data_rmq())
cocotb.start_soon(s_rmq.tready_behaviour(max_cycles_off=ready_clk_off, randomize=randomize))
await delay(dut.rmq_snk_clk_i, 20)
m_rmq.send_data(rmq_snk_msg)
while not (s_rmq.rmq_request_c == 1):
await RisingEdge(dut.rmq_snk_clk_i)
rmq_src_msg = s_rmq.get_data()
if len(rmq_src_msg) != len(rmq_snk_msg):
dut._log.error("Expected length {} --- Read length {}".format(len(rmq_snk_msg),len(rmq_src_msg)))
dut._log.error("Length is not coherent")
raise SimFailure()
else:
dut._log.info("RMQ message length is coherent")
if (np.array_equal(rmq_src_msg, rmq_snk_msg)):
dut._log.info("RMQ message integrity is correct")
else:
for i in range(len(rmq_snk_msg)):
dut._log.warning("Data tx: {} ----- Data rx: {}".format(hex(rmq_snk_msg[i]),hex(rmq_src_msg[i])))
dut._log.error("Incossitence between tx and rx")
raise SimFailure()
await delay(dut.rmq_snk_clk_i, 10)
dut._log.info("Testbench finished successfully")
# ------------------------------------------------------------------------------
# Factory
factory = TestFactory(test)
factory.add_option("n_rst_cycles", [11])
factory.add_option("data_len", [4, 11, 17, 32, 71])
factory.add_option("randomize", [False, True])
factory.add_option("ready_clk_off", [1, 3, 7])
factory.generate_tests()
# ------------------------------------------------------------------------------
# Reset
@cocotb.coroutine
def reset(dut, n_rst_cycles):
dut._log.info("Asserting Sytem Reset")
dut.rst_n_i.setimmediatevalue(0)
dut.rmq_src_config_i.adr.setimmediatevalue(0)
dut.rmq_src_config_i.dat.setimmediatevalue(0)
dut.rmq_src_config_i.we.setimmediatevalue(0)
dut.rmq_snk_config_i.adr.setimmediatevalue(0)
dut.rmq_snk_config_i.dat.setimmediatevalue(0)
dut.rmq_snk_config_i.we.setimmediatevalue(0)
for i in range(n_rst_cycles):
yield RisingEdge(dut.rmq_snk_clk_i)
dut.rst_n_i.value = 1
yield RisingEdge(dut.rmq_snk_clk_i)
dut._log.info("Deasserting Sytem Reset")
# ------------------------------------------------------------------------------
# delay
@cocotb.coroutine
def delay(signal_name, n_cycles):
for i in range(n_cycles):
yield RisingEdge(signal_name)
# ##############################################################################
#
#
#
# ##############################################################################
onerror {resume}
quietly WaveActivateNextPane {} 0
#SNK
add wave -noupdate -expand -group SNK -color Orange /rmq_stream_fifo/rst_n_i
add wave -noupdate -expand -group SNK -color Orange /rmq_stream_fifo/rmq_src_clk_i
add wave -noupdate -expand -group SNK -color Orange /rmq_stream_fifo/rmq_snk_i.data
add wave -noupdate -expand -group SNK -color Orange /rmq_stream_fifo/rmq_snk_i.hdr
add wave -noupdate -expand -group SNK -color Orange /rmq_stream_fifo/rmq_snk_i.valid
add wave -noupdate -expand -group SNK -color Orange /rmq_stream_fifo/rmq_snk_i.last
add wave -noupdate -expand -group SNK -color Orange /rmq_stream_fifo/rmq_snk_i.error
add wave -noupdate -expand -group SNK -color Orange /rmq_stream_fifo/rmq_snk_o.ready
add wave -noupdate -expand -group SNK -color Orange /rmq_stream_fifo/rmq_snk_o.pkt_ready
# FIFO
add wave -noupdate -expand -group FIFO -color White /rmq_stream_fifo/gen_CDC_false/cmp_fifo/rst_n_i
add wave -noupdate -expand -group FIFO -color White /rmq_stream_fifo/gen_CDC_false/cmp_fifo/clk_i
add wave -noupdate -expand -group FIFO -color White /rmq_stream_fifo/gen_CDC_false/cmp_fifo/d_i
add wave -noupdate -expand -group FIFO -color White /rmq_stream_fifo/gen_CDC_false/cmp_fifo/we_i
add wave -noupdate -expand -group FIFO -color White /rmq_stream_fifo/gen_CDC_false/cmp_fifo/full_o
add wave -noupdate -expand -group FIFO -color White /rmq_stream_fifo/gen_CDC_false/cmp_fifo/q_o
add wave -noupdate -expand -group FIFO -color White /rmq_stream_fifo/gen_CDC_false/cmp_fifo/empty_o
add wave -noupdate -expand -group FIFO -color White /rmq_stream_fifo/gen_CDC_false/cmp_fifo/rd_i
add wave -noupdate -expand -group FIFO -color White /rmq_stream_fifo/gen_CDC_false/cmp_fifo/almost_empty_o
add wave -noupdate -expand -group FIFO -color White /rmq_stream_fifo/gen_CDC_false/cmp_fifo/almost_full_o
add wave -noupdate -expand -group FIFO -color White /rmq_stream_fifo/gen_CDC_false/cmp_fifo/count_o
add wave -noupdate -expand -group FIFO -color White /rmq_stream_fifo/gen_CDC_true/cmp_fifo/rst_n_i
add wave -noupdate -expand -group FIFO -color White /rmq_stream_fifo/gen_CDC_true/cmp_fifo/clk_wr_i
add wave -noupdate -expand -group FIFO -color White /rmq_stream_fifo/gen_CDC_true/cmp_fifo/d_i
add wave -noupdate -expand -group FIFO -color White /rmq_stream_fifo/gen_CDC_true/cmp_fifo/we_i
add wave -noupdate -expand -group FIFO -color White /rmq_stream_fifo/gen_CDC_true/cmp_fifo/wr_full_o
add wave -noupdate -expand -group FIFO -color White /rmq_stream_fifo/gen_CDC_true/cmp_fifo/clk_rd_i
add wave -noupdate -expand -group FIFO -color White /rmq_stream_fifo/gen_CDC_true/cmp_fifo/q_o
add wave -noupdate -expand -group FIFO -color White /rmq_stream_fifo/gen_CDC_true/cmp_fifo/rd_empty_o
add wave -noupdate -expand -group FIFO -color White /rmq_stream_fifo/gen_CDC_true/cmp_fifo/rd_i
#SRC
add wave -noupdate -expand -group SRC -color GReen /rmq_stream_fifo/rst_n_i
add wave -noupdate -expand -group SRC -color GReen /rmq_stream_fifo/rmq_src_clk_i
add wave -noupdate -expand -group SRC -color GReen /rmq_stream_fifo/rmq_src_o.data
add wave -noupdate -expand -group SRC -color GReen /rmq_stream_fifo/rmq_src_o.hdr
add wave -noupdate -expand -group SRC -color GReen /rmq_stream_fifo/rmq_src_o.valid
add wave -noupdate -expand -group SRC -color GReen /rmq_stream_fifo/rmq_src_o.last
add wave -noupdate -expand -group SRC -color GReen /rmq_stream_fifo/rmq_src_o.error
add wave -noupdate -expand -group SRC -color GReen /rmq_stream_fifo/rmq_src_i.ready
add wave -noupdate -expand -group SRC -color GReen /rmq_stream_fifo/rmq_src_i.pkt_ready
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {5542152000 ps} 0}
quietly wave cursor active 1
configure wave -namecolwidth 568
configure wave -valuecolwidth 100
configure wave -justifyvalue left
configure wave -signalnamewidth 0
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 ps
update
WaveRestoreZoom {5541518608 ps} {5575594505 ps}
# List of vhdl srcs
SRC_VHDL=spi_rmq_bridge.vhd
VHDL_SOURCES:=$(addprefix $(PWD)/../../../../rtl/,$(SRC_VHDL))
VHDL_SOURCES+=../../../../ip_cores/general-cores/modules/common/gc_sync.vhd
VHDL_SOURCES+=../../../../ip_cores/general-cores/modules/common/gc_sync_ffs.vhd
VHDL_SOURCES+=../../../../ip_cores/general-cores/modules/common/gc_edge_detect.vhd
VHDL_SOURCES+=../../../../ip_cores/general-cores/modules/common/gc_sync_register.vhd
VHDL_SOURCES+=../../../../ip_cores/general-cores/modules/genrams/common/inferred_sync_fifo.vhd
VHDL_SOURCES+=../../../../ip_cores/general-cores/modules/genrams/common/inferred_async_fifo.vhd
VHDL_SOURCES+=../../../../ip_cores/general-cores/modules/genrams/xilinx/generic_dpram.vhd
VHDL_SOURCES+=../../../../ip_cores/general-cores/modules/genrams/xilinx/generic_dpram_sameclock.vhd
VHDL_SOURCES+=../../../../ip_cores/general-cores/modules/genrams/xilinx/generic_dpram_dualclock.vhd
VHDL_SOURCES+=../../../../ip_cores/general-cores/modules/genrams/memory_loader_pkg.vhd
VHDL_SOURCES+=../../../../ip_cores/general-cores/modules/wishbone/wishbone_pkg.vhd
VHDL_SOURCES+=../../../../ip_cores/general-cores/modules/common/gencores_pkg.vhd
VHDL_SOURCES+=../../../../ip_cores/general-cores/modules/genrams/genram_pkg.vhd
VHDL_SOURCES+=../../../../ip_cores/mockturtle/hdl/rtl/mock_turtle_pkg.vhd
VHDL_SOURCES+=../../../../ip_cores/mockturtle/hdl/rtl/mqueue/mt_mqueue_pkg.vhd
# TOPLEVEL is the top level design and module is the python test
TOPLEVEL:=spi_rmq_bridge
MODULE:=tb_spi_rmq_bridge
RTL_LIBRARY?=work
# Define variables
g_DATA_WIDTH?=32
g_CPOL?=0
g_CPHA?=1
g_CDC_ENABLE?=1
SIM_ARGS=-voptargs=+acc=rn
SIM_ARGS+="-t ps"
# Generics for GHDL
SIM_ARGS+=-gg_DATA_WIDTH=${g_DATA_WIDTH}
SIM_ARGS+=-gg_CPOL=${g_CPOL}
SIM_ARGS+=-gg_CPHA=${g_CPHA}
SIM_ARGS+=-gg_CDC_ENABLE=${g_CDC_ENABLE}
VCOM_ARGS +=-autoorder -2008
SCRIPT_FILE=wave.do
# Target Simulator
SIM=questa
# PYHTON PATH to get python models
export PYTHONPATH:=$(PWD)/../models/:$(PYTHONPATH)
# Include common rules
include ../Makefile.config
# Simulation QuestaSim + Cocotb
## How to run
- Compile and simulate
```console
make
```
- View waveform:
```console
vsim -view vsim.wlf -do wave.do &
```
## Maintainers
- [Alén Arias Vázquez](mailto:alen.arias.vazquez@cern.ch)
"""
Test SPI RMQ BRIDGE
"""
import cocotb
import numpy as np
import time
import random
import math
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge, FallingEdge, Timer
from cocotb.regression import TestFactory
from cocotb.result import *
from spi import SpiClock, SpiMaster
from rmq import RMQMaster, RMQSlave
# ------------------------------------------------------------------------------
# Some functions to support the test
# Define SPI mode
def define_spi_mode(dut, g_CPOL=0, g_CPHA=0):
CPOL = False
CPHA = False
if g_CPOL == 1:
CPOL = True
if g_CPHA == 1:
CPHA = True
dut._log.info(" +-------------+")
dut._log.info(" | CPOL | CPHA |")
dut._log.info(" +-------------+")
dut._log.info("MODE | {} | {} |".format(g_CPOL,g_CPHA))
dut._log.info(" +-------------+")
return CPOL, CPHA
# ------------------------------------------------------------------------------
# fill data
def GetSpiFrame(ctrl, rmq_id, data_len, data_width, randomize):
spi_header = (ctrl << 24) | (rmq_id << 16) | (data_len << 8) | 0xFF
data = []
mask = 2**data_width - 1
data.append(spi_header & mask)
for i in range(data_len):
if randomize:
data.append(random.randint(0, (2**data_width)-1) & mask)
else:
if i % 8 == 0:
data.append(0xDEADC0DE & mask)
elif i % 8 == 1:
data.append(0xCAFED00D & mask)
elif i % 8 == 2:
data.append(0xDEADCAFE & mask)
elif i % 8 == 3:
data.append(0xBADC0FFE & mask)
elif i % 8 == 4:
data.append(0xBAADF00D & mask)
elif i % 8 == 5:
data.append(0xDEFEC8ED & mask)
elif i % 8 == 6:
data.append(0xDEADBEEF & mask)
elif i % 8 == 7:
data.append(0xFEEDBABE & mask)
return data
def GetSpiDummyFrame(ctrl, rmq_id, data_len, data_width):
data = []
spi_header = (ctrl << 24) | (rmq_id << 16) | (data_len << 8) | 0xFF
mask = 2**data_width - 1
data.append(spi_header & mask)
for i in range(data_len):
data.append(0)
return data
# ------------------------------------------------------------------------------
# Check if data written in RMQ is ok
def check_data_written(dut, rmq_src_msg, spi_frame):
rmq_encapsulated_msg = spi_frame[1:]
rmq_src_msg_sized = []
if len(rmq_encapsulated_msg) != len(rmq_src_msg)/2:
dut._log.error("Expected length {} --- Read length {}".format(len(data_written),len(rmq_src_msg)))
dut._log.error("Write data failed, length is wrong")
raise SimFailure()
else:
dut._log.info("RMQ Data length is consistent")
for i in range(len(rmq_encapsulated_msg)):
rmq_src_msg_sized.append((rmq_src_msg[2*i] << 16) + rmq_src_msg[(2*i)+1])
if (np.array_equal(rmq_src_msg_sized, rmq_encapsulated_msg)):
dut._log.info("RMQ Data integrity is correct")
else:
dut._log.warning("Data RD : {}".format(rmq_src_msg_sized))
dut._log.warning("Data Written: {}".format(rmq_encapsulated_msg))
dut._log.error("Write data failed, data is not the same in the SLAVE")
raise SimFailure()
# ------------------------------------------------------------------------------
# Generate Dummy Reply
def GetRMQDummyReply(rmq_src_msg):
rmq_snk_msg = []
rmq_snk_msg.append((rmq_src_msg[0] << 16) + rmq_src_msg[1])
for i in range(len(rmq_src_msg)-2):
rmq_snk_msg.append(rmq_src_msg[i+2])
return rmq_snk_msg
# ------------------------------------------------------------------------------
# Setup clock signal
def setup_clock(signal_name, period, units="ns"):
cocotb.start_soon(Clock(signal_name, period, units=units).start())
# ------------------------------------------------------------------------------
# Main Test
@cocotb.coroutine
async def test(dut, n_rst_cycles, data_len, sys_freq, spi_sample_freq, spi_freq, randomize):
# Get data to send
data_width = dut.g_data_width.value
g_cpol = dut.g_cpol.value
g_cpha = dut.g_cpha.value
g_CDC = dut.g_cdc_enable.value
CPOL, CPHA = define_spi_mode(dut=dut, g_CPOL=g_cpol, g_CPHA=g_cpha)
spi_frame = GetSpiFrame(ctrl=0x0, rmq_id=0x0, data_len=data_len, data_width=data_width, randomize=randomize)
spi_master = SpiMaster(
dut=dut,
sclk=dut.spi_clk_i,
mosi=dut.spi_mosi_i,
miso=dut.spi_miso_o,
cs=dut.spi_cs_n_i,
SpiFreqz = spi_freq,
CPOL = CPOL,
CPHA = CPHA,
word_width=data_width
)
m_rmq = RMQMaster(dut=dut, clk=dut.clk_i, if_name='snk')
s_rmq = RMQSlave(dut=dut, clk=dut.clk_i, if_name='src')
if g_CDC == 1:
dut._log.warning("CDC between SPI and System")
setup_clock(signal_name=dut.clk_i, period=(1e9/sys_freq))
setup_clock(signal_name=dut.spi_sample_clk_i, period=(1e9/spi_sample_freq))
else:
dut._log.warning("NO CDC between SPI and System")
setup_clock(signal_name=dut.clk_i, period=(1e9/sys_freq))
setup_clock(signal_name=dut.spi_sample_clk_i, period=(1e9/sys_freq))
cocotb.start_soon(reset(dut, n_rst_cycles))
await delay(dut.clk_i, 1)
while dut.rst_n_i.value != 1:
await RisingEdge(dut.clk_i)
cocotb.start_soon(m_rmq.input_data_rmq())
cocotb.start_soon(s_rmq.output_data_rmq())
cocotb.start_soon(s_rmq.tready_behaviour(max_cycles_off=0))
await spi_master.write(spi_frame)
await spi_master.read() #Empty fifo, don't care about data
while not (s_rmq.rmq_frame_c == 1):
await RisingEdge(dut.clk_i)
rmq_src_msg = s_rmq.get_data()
check_data_written(dut=dut, rmq_src_msg=rmq_src_msg, spi_frame=spi_frame)
rmq_snk_msg = GetRMQDummyReply(rmq_src_msg=rmq_src_msg)
m_rmq.send_data(rmq_snk_msg)
spi_dummy = GetSpiDummyFrame(ctrl=0x1, rmq_id=0x0, data_len=data_len, data_width=data_width)
await spi_master.write(spi_dummy)
data_read = await spi_master.read()
if len(data_read[1:]) != len(spi_frame[1:]):
dut._log.error("Expected length {} --- Read length {}".format(len(data_read[1:]),len(spi_frame[1:])))
dut._log.error("Read RMQ message failed")
raise SimFailure()
else:
dut._log.info("RMQ message length is consistent")
if (np.array_equal(data_read[1:], spi_frame[1:])):
dut._log.info("RMQ message integrity is correct")
else:
for i in range(len(data_read)-1):
dut._log.warning("Data TX SPI: {} ----- Data RX SPI: {}".format(hex(spi_frame[i+1]),hex(data_read[i+1])))
dut._log.error("Incossitence between transmition and reception")
raise SimFailure()
await delay(dut.clk_i, 100)
dut._log.info("Testbench finished successfully")
# ------------------------------------------------------------------------------
# Factory
factory = TestFactory(test)
factory.add_option("n_rst_cycles", [11])
factory.add_option("data_len", [4,16,32,255])
factory.add_option("sys_freq", [62.5e6])
factory.add_option("spi_sample_freq", [200e6])
factory.add_option("spi_freq", [20e6])
factory.add_option("randomize", [False, True])
factory.generate_tests()
# ------------------------------------------------------------------------------
# Reset
@cocotb.coroutine
def reset(dut, n_rst_cycles):
dut._log.info("Asserting Sytem Reset")
dut.rst_n_i.setimmediatevalue(0)
dut.rmq_src_config_i.adr.setimmediatevalue(0)
dut.rmq_src_config_i.dat.setimmediatevalue(0)
dut.rmq_src_config_i.we.setimmediatevalue(0)
dut.rmq_snk_config_i.adr.setimmediatevalue(0)
dut.rmq_snk_config_i.dat.setimmediatevalue(0)
dut.rmq_snk_config_i.we.setimmediatevalue(0)
for i in range(n_rst_cycles):
yield RisingEdge(dut.clk_i)
dut.rst_n_i.value = 1
yield RisingEdge(dut.clk_i)
dut._log.info("Deasserting Sytem Reset")
# ------------------------------------------------------------------------------
# delay
@cocotb.coroutine
def delay(signal_name, n_cycles):
for i in range(n_cycles):
yield RisingEdge(signal_name)
This diff is collapsed.
This diff is collapsed.
# ##############################################################################
#
#
#
# ##############################################################################
onerror {resume}
quietly WaveActivateNextPane {} 0
......
......@@ -7,7 +7,7 @@
#----------------------------------------
NET "uart_txd_o" LOC = U27;
NET "uart_rxd_i" LOC = U25;
NET "uart_txd_o" IOSTANDARD = "LVCMOS33";
NET "uart_rxd_i" IOSTANDARD = "LVCMOS33";
......@@ -16,7 +16,7 @@ NET "uart_rxd_i" IOSTANDARD = "LVCMOS33";
#----------------------------------------
NET "ertec_spi_clk_i" LOC = "AC15";
NET "ertec_spi_clk_i" TIG;
NET "ertec_spi_clk_i" CLOCK_DEDICATED_ROUTE = FALSE;
#NET "ertec_spi_clk_i" CLOCK_DEDICATED_ROUTE = FALSE;
NET "ertec_spi_clk_i" IOSTANDARD = "LVCMOS25";
NET "ertec_spi_cs_n_i" LOC = "AB19";
......@@ -62,10 +62,10 @@ NET "ertec_rmq_status_o[0]" IOSTANDARD = "LVCMOS25";
# BANK 4 P2V5: SPEC LEDs
#----------------------------------------
NET "LED_RED_O" LOC = "D5";
NET "LED_RED_O" LOC = "D5";
NET "LED_RED_O" IOSTANDARD = "LVCMOS25";
NET "LED_GREEN_O" LOC = "E5";
NET "LED_GREEN_O" LOC = "E5";
NET "LED_GREEN_O" IOSTANDARD = "LVCMOS25";
......@@ -93,13 +93,13 @@ NET "ertec_gpio_18_i" IOSTANDARD = "LVCMOS25";
#----------------------------------------
# BANK 0
NET "fmc_onewire_b" LOC = "K11";
NET "fmc_onewire_b" LOC = "K11";
NET "fmc_onewire_b" IOSTANDARD = "LVCMOS25";
NET "led_tx_err_n_o" LOC = "J12";
NET "led_tx_err_n_o" LOC = "J12";
NET "led_tx_err_n_o" IOSTANDARD = "LVCMOS25";
NET "led_tx_act_n_o" LOC = "H12";
NET "led_tx_act_n_o" LOC = "H12";
NET "led_tx_act_n_o" IOSTANDARD = "LVCMOS25";
NET "led_rx_err_n_o" LOC = "H11";
......@@ -174,3 +174,6 @@ NET "ertec_uart_rx_o" LOC = "AF23";
NET "ertec_uart_rx_o" IOSTANDARD = "LVCMOS25";
#PIN "cmp_mt_profip_translator/cmp_mosi_async_fifo/empty_int_BUFG.O" CLOCK_DEDICATED_ROUTE = FALSE;
TIMESPEC "TS_exception_cdc"= FROM "cmp_spi_rmq_bridge/clk_i" TO "cmp_spi_rmq_bridge/spi_sample_clk_i" TIG;
TIMESPEC "TS_exception_cdc_2"= FROM "cmp_spi_rmq_bridge/spi_sample_clk_i" TO "cmp_spi_rmq_bridge/clk_i" TIG;
#TIMESPEC "TS_exception666_3"= FROM "cmp_spi_rmq_bridge/spi_sample_clk_i/s_tx_reg_31" TO "cmp_spi_rmq_bridge/spi_miso_o" 15 ns DATAPATHONLY;
......@@ -272,8 +272,8 @@ entity svec_masterfip_mt_urv is
fp_gpio2_a2b_o : out std_logic;
fp_gpio34_a2b_o : out std_logic;
-- Signals added to remove synthesis errors due to
-- the usage of SVEC convention. They are not used
-- Signals added to remove synthesis errors due to
-- the usage of SVEC convention. They are not used
-- in this design
button1_n_i : in std_logic;
pcbrev_i : in std_logic_vector(4 downto 0);
......@@ -291,7 +291,7 @@ entity svec_masterfip_mt_urv is
carrier_scl_b : inout std_logic;
carrier_sda_b : inout std_logic
-- synthesis translate_off
-- synthesis translate_off
;
sim_wb_i : in t_wishbone_slave_in := cc_dummy_slave_in;
sim_wb_o : out t_wishbone_slave_out
......@@ -370,7 +370,7 @@ architecture rtl of svec_masterfip_mt_urv is
addr_last => x"000000000003ffff",
product => (
vendor_id => x"000000000000CE42", -- CERN
device_id => c_MSTRFIP_APP_ID,
device_id => c_MSTRFIP_APP_ID,
version => x"00000001",
date => x"20220916",
name => "xWB_METADATA_SDB_01")));
......@@ -918,8 +918,9 @@ begin
-- fp_gpio1_a2b_o <= '1'; -- 1 is for out, 0 is for in
-- fp_gpio2_a2b_o <= '1';
-- fp_gpio34_a2b_o <= '1';
end rtl;
--=================================================================================================
-- architecture end
--=================================================================================================
---------------------------------------------------------------------------------------------------
\ No newline at end of file
---------------------------------------------------------------------------------------------------
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