Commit 563d4184 authored by Dimitris Lampridis's avatar Dimitris Lampridis

hdl: align testbench with updated wrtd library

parent 7d0c067c
......@@ -34,8 +34,8 @@ class WrtdAlarm extends WrtdRepCap;
protected int repeat_count;
protected uint32_t period_ns;
function new ( int core, int index, string name = "" );
super.new ( core, index, name );
function new ( string name = "" );
super.new ( name );
this.setup_time = new();
this.ev.ts = new();
this.ev.id = new();
......
......@@ -36,13 +36,18 @@
`define WRTD_IO_MSG_WORD_SIZE 2
`define WRTD_CFG_MSG_WORD_SIZE 5
`define WRTD_ROOT_WORD_SIZE 13
`define WRTD_ROOT_WORD_SIZE 12
`define WRTD_RULE_WORD_SIZE 40
`define WRTD_ALRM_WORD_SIZE 15
`define WRTD_DEST_CPU_LOCAL 'hfe
`define WRTD_DEST_CH_NET 'hff
`define WRTD_CAP_NET_RX 1
`define WRTD_CAP_NET_TX 2
`define WRTD_CAP_LOCAL_RX 4
`define WRTD_CAP_LOCAL_TX 8
enum {
WRTD_ACTION_GET_CONFIG,
WRTD_ACTION_READW,
......@@ -211,44 +216,15 @@ typedef struct {
typedef struct {
uint32_t addr;
uint32_t fw_id;
uint32_t nbr_alarms;
uint32_t alarms_addr;
uint32_t nbr_rules;
uint32_t capabilities;
uint32_t rules_addr;
uint32_t nbr_devs;
uint32_t devs_addr[4];
uint32_t nbr_channels[4];
uint32_t channel_dir[4];
} wrtd_root;
typedef struct {
int core;
int index;
int ch_en;
} wrtd_dev;
typedef struct {
string name;
uint32_t dir;
uint32_t nbr_chs;
string channels[];
/* -----\/----- EXCLUDED -----\/-----
enum wrtd_status (*configure)(struct wrtd_dev *wrtd,
unsigned cpu, unsigned dev,
unsigned int mask);
-----/\----- EXCLUDED -----/\----- */
} wrtd_mt_device;
typedef struct {
uint32_t fw_id;
uint32_t nbr_devices;
wrtd_mt_device devices[`WRTD_MAX_DEVS];
} wrtd_mt_cpu_config;
typedef struct {
uint32_t mt_app_id;
uint32_t nbr_cpus;
uint32_t tx_cpu;
uint32_t rx_cpu;
wrtd_mt_cpu_config cpus[`WRTD_MAX_CPUS];
} wrtd_mt_config;
`endif // `ifndef __WRTD_DEFINE_INCLUDED
......@@ -39,9 +39,7 @@ class WrtdDrv;
protected uint32_t nbr_cpus;
protected uint32_t free_rule_slots[];
protected uint32_t hmq_words[];
protected wrtd_mt_config cfg;
protected wrtd_root roots[];
protected wrtd_dev devices[$];
protected WrtdRepCapCollection rules;
protected WrtdRepCapCollection alarms;
......@@ -75,39 +73,12 @@ class WrtdDrv;
WrtdAlarm new_alarm;
wrtd_dev new_dev;
uint32_t data[];
this.ready = 0;
mt.init ( );
// TODO: replace with non-hardcoded values
this.cfg.mt_app_id = 'h115790d1;
this.cfg.nbr_cpus = 1;
this.cfg.tx_cpu = 0;
this.cfg.rx_cpu = 0;
this.cfg.cpus[0].fw_id = 'h35b0;
this.cfg.cpus[0].nbr_devices = 2;
this.cfg.cpus[0].devices[0].name = "FMC ADCin 5CH";
this.cfg.cpus[0].devices[0].dir = WRTD_DIR_INPUT;
this.cfg.cpus[0].devices[0].nbr_chs = 5;
this.cfg.cpus[0].devices[0].channels = new[5];
this.cfg.cpus[0].devices[0].channels[0] = "ADCI1";
this.cfg.cpus[0].devices[0].channels[1] = "ADCI2";
this.cfg.cpus[0].devices[0].channels[2] = "ADCI3";
this.cfg.cpus[0].devices[0].channels[3] = "ADCI4";
this.cfg.cpus[0].devices[0].channels[4] = "ADCI5";
this.cfg.cpus[0].devices[1].name = "FMC ADCout";
this.cfg.cpus[0].devices[1].dir = WRTD_DIR_OUTPUT;
this.cfg.cpus[0].devices[1].nbr_chs = 1;
this.cfg.cpus[0].devices[1].channels = new[1];
this.cfg.cpus[0].devices[1].channels[0] = "ADCO1";
this.nbr_cpus = mt.rom.getCoreCount ( );
this.free_rule_slots = new[this.nbr_cpus];
......@@ -135,9 +106,12 @@ class WrtdDrv;
while ( cpu_ready == 0 )
begin
val = 0;
mt.get_single_cpu_notification ( 0, val );
if ( val == TRTL_CPU_NOTIFY_MAIN )
cpu_ready = 1;
if ( mt.pending_cpu_notifications ( i ) != 0 )
begin
mt.get_single_cpu_notification ( i, val );
if ( val == TRTL_CPU_NOTIFY_MAIN )
cpu_ready = 1;
end
# 1us;
end
// retrieve address of root
......@@ -145,17 +119,23 @@ class WrtdDrv;
this.roots[i].addr = data[0];
// retrieve root
msg_readw ( i, this.roots[i].addr, `WRTD_ROOT_WORD_SIZE, data );
this.roots[i].nbr_rules = ( data[1] & 'h00ff0000 ) >> 16;
this.roots[i].nbr_alarms = ( data[1] & 'h0000ff00 ) >> 8;
this.roots[i].nbr_devs = ( data[1] & 'h000000ff ) >> 0;
this.roots[i].devs_addr[0:3] = data[4:7];
this.roots[i].rules_addr = data[8];
this.roots[i].alarms_addr = data[9];
this.roots[i].fw_id = data[1];
this.roots[i].capabilities = ( data[2] & 'hff000000 ) >> 24;
this.roots[i].nbr_rules = ( data[2] & 'h00ff0000 ) >> 16;
this.roots[i].nbr_alarms = ( data[2] & 'h0000ff00 ) >> 8;
this.roots[i].nbr_devs = ( data[2] & 'h000000ff ) >> 0;
for ( j = 0; j < 4; j++)
begin
this.roots[i].nbr_channels[j] = ( data[5] >> j*8 ) & 'hff;
this.roots[i].channel_dir[j] = ( data[6] >> j*8 ) & 'hff;
end
this.roots[i].rules_addr = data[7];
this.roots[i].alarms_addr = data[8];
// init free rule slots
this.free_rule_slots[i] = this.roots[i].nbr_rules;
// turn on all logging if enabled
if ( this.enable_logging )
msg_writew ( i, this.roots[i].addr + 12, 1, { data[3] | 32'hff } );
msg_writew ( i, this.roots[i].addr + 16, 1, { data[4] | 32'hff } );
end
// initialise rules
......@@ -163,7 +143,7 @@ class WrtdDrv;
for ( i = 0; i < this.nbr_cpus; i++ )
for ( j = 0; j < this.roots[i].nbr_rules; j++ )
begin
new_rule = new ( i, j, this.name );
new_rule = new ( this.name );
this.rules.collection.push_back ( new_rule );
end
......@@ -172,29 +152,14 @@ class WrtdDrv;
for ( i = 0; i < this.nbr_cpus; i++ )
for ( j = 0; j < this.roots[i].nbr_alarms; j++ )
begin
new_alarm = new ( i, j, this.name );
new_alarm = new ( this.name );
this.alarms.collection.push_back ( new_alarm );
end
// initialise devices
this.devices.delete();
for ( i = 0; i < this.nbr_cpus; i++ )
for ( j = 0; j < this.roots[i].nbr_devs; j++ )
begin
new_dev.core = i;
new_dev.index = j;
new_dev.ch_en = 0;
this.devices.push_back ( new_dev );
end
// TODO remove hard-coded ADC init
adc_init ();
this.ready = 1;
end
begin
while ( this.ready == 0 )
while ( i != this.nbr_cpus )
begin
mt.update ( );
# 1us;
......@@ -202,6 +167,8 @@ class WrtdDrv;
end
join
this.ready = 1;
endtask // init
task msg_get_config ( int core, ref uint32_t data[] );
......@@ -293,16 +260,6 @@ class WrtdDrv;
endtask // msg_writew
task adc_init ( );
uint32_t addr;
uint32_t data[1];
addr = this.roots[0].devs_addr[0] + 'h4;
data[0] = 'h10f;
msg_writew ( 0, addr, 1, data );
endtask // adc_init
task add_rule ( string rep_cap_id );
int idx;
idx = this.rules.add ( rep_cap_id );
......@@ -352,18 +309,50 @@ class WrtdDrv;
$cast ( rule, this.rules.collection[idx] );
hash = wrtd_gen_hash ( rule.get_src() ) % this.rules.collection.size();
hash = wrtd_gen_hash ( rule.get_src() ) % this.roots[core].nbr_rules;
core = rule.get_core ( );
addr = this.roots[core].rules_addr + hash * `WRTD_RULE_WORD_SIZE * 4;
data = rule.data_pack ( );
msg_writew ( core, addr, `WRTD_RULE_WORD_SIZE, data );
endtask // write_rule
function void map_local_channel_to_cpu ( string ch_id, int ch_dir,
ref int core, ref int ch_idx );
int i, j, k, idx_in, idx_out, dev_dir;
string dev_id;
idx_in = 1;
idx_out = 1;
core = -1;
ch_idx = -1;
for ( i = 0; i < this.nbr_cpus; i++ )
for ( j = 0; j < this.roots[i].nbr_devs; j++ )
begin
dev_dir = this.roots[i].channel_dir[j];
for ( k = 0; k < this.roots[i].nbr_channels[j]; k++ )
begin
if ( dev_dir == WRTD_DIR_INPUT )
dev_id = $sformatf ( "LC-I%0d", idx_in++ );
else
dev_id = $sformatf ( "LC-O%0d", idx_out++ );
if ( ( dev_dir == ch_dir ) && ( dev_id == ch_id ) )
begin
core = i;
ch_idx = k;
return;
end
end
end
endfunction // map_local_channel_to_cpu
task enable_rule ( string rep_cap_id );
int idx;
int idx, src_cpu, dst_cpu, src_ch, dst_ch;
string id;
uint32_t src_cpu;
WrtdRule rule;
......@@ -374,22 +363,65 @@ class WrtdDrv;
$cast ( rule, this.rules.collection[idx] );
rule.set_enable ( );
// TODO, replace hard-coding
src_cpu = 0;
if ( this.free_rule_slots[src_cpu] == 0 )
$error ( "no more available free rule slots on CPU %d", src_cpu );
this.free_rule_slots[src_cpu] -= 1;
rule.set_dest_cpu ( `WRTD_DEST_CPU_LOCAL );
id = rule.get_dst ( );
if ( id == "ADCO1" )
rule.set_dest_ch ( 0 );
else
rule.set_dest_ch ( `WRTD_DEST_CH_NET );
/* Place the rule on the same CPU as the input source.
If source is network, src_cpu = -1 for now */
map_local_channel_to_cpu ( rule.get_src(), WRTD_DIR_INPUT, src_cpu, src_ch );
// TODO: check if rule source is alarm
/* Set destination cpu and channel */
map_local_channel_to_cpu ( rule.get_dst(), WRTD_DIR_OUTPUT, dst_cpu, dst_ch );
if ( dst_cpu >= 0 ) // local output device
begin
/* If source is network message and this cpu can receive from
network, set cpu affinity to this cpu */
if ( ( src_cpu == -1 ) && ( this.roots[dst_cpu].capabilities & `WRTD_CAP_NET_RX ) )
src_cpu = dst_cpu;
/* Otherwise find the first cpu that is capable of net RX */
else
for ( src_cpu = 0; src_cpu < this.nbr_cpus; src_cpu++ )
if ( this.roots[src_cpu].capabilities & `WRTD_CAP_NET_RX )
break;
end
else // network destination
begin
dst_ch = `WRTD_DEST_CH_NET;
/* If source cpu can also send to
network, set dest cpu affinity to that cpu */
if ( ( src_cpu >= 0 ) && ( this.roots[src_cpu].capabilities & `WRTD_CAP_NET_TX ) )
dst_cpu = src_cpu;
/* Otherwise find the first cpu that is capable of net TX */
else
for ( dst_cpu = 0; dst_cpu < this.nbr_cpus; dst_cpu++ )
if ( this.roots[dst_cpu].capabilities & `WRTD_CAP_NET_TX )
break;
end
// TODO: handle network to network events
if ( ( src_cpu < 0 ) || ( dst_cpu < 0 ) ||
( src_cpu >= this.nbr_cpus ) || ( dst_cpu >= this.nbr_cpus ) )
$error ( "cannot determine source and/or destination cpu for rule" );
/* If the same CPU can handle both input and output, use special value so that
the firmware will know not to forward this event to another CPU (it does not
know its own index) */
if ( src_cpu == dst_cpu )
dst_cpu = `WRTD_DEST_CPU_LOCAL;
// TODO: handle free_rule_slots per cpu
rule.set_core ( src_cpu );
rule.set_dest_cpu ( dst_cpu );
rule.set_dest_ch ( dst_ch );
rule.set_enable ( 1 );
// TODO: properly recalculate and rewrite rules
write_rule ( idx );
endtask // enable_rule
// TODO: properly support alarms
task add_alarm ( string rep_cap_id );
int idx;
idx = this.alarms.add ( rep_cap_id );
......@@ -415,7 +447,7 @@ class WrtdDrv;
$error ( "cannot write alarm with negative index" );
core = this.alarms.collection[idx].get_core ( );
index = this.alarms.collection[idx].get_index ();
//index = this.alarms.collection[idx].get_index ();
addr = this.roots[core].alarms_addr + index * `WRTD_ALRM_WORD_SIZE * 4;
data = this.alarms.collection[idx].data_pack( );
......
......@@ -31,12 +31,9 @@ virtual class WrtdRepCap;
protected string name;
protected WrtdId rep_cap_id;
protected int core;
protected int index;
protected int enabled;
function new ( int core, int index, string name = "" );
this.core = core;
this.index = index;
function new ( string name = "" );
this.name = name;
this.rep_cap_id = new();
clear();
......@@ -44,7 +41,7 @@ virtual class WrtdRepCap;
function void clear ( );
this.rep_cap_id.clear();
this.enabled = 0;
this.enabled = 0;
endfunction // clear
task mdisplay ( string str );
......@@ -60,9 +57,9 @@ virtual class WrtdRepCap;
return this.core;
endfunction // get_core
function int get_index ( );
return this.index;
endfunction // get_index
function void set_core ( int core );
this.core = core;
endfunction // set_core
function string get_rep_cap_id ( );
return this.rep_cap_id.get();
......@@ -84,8 +81,11 @@ virtual class WrtdRepCap;
return ( this.enabled > 0 );
endfunction // is_enabled
function void set_enable ( );
this.enabled = 1;
function void set_enable ( int enable );
if ( enable > 0)
this.enabled = 1;
else
this.enabled = 0;
endfunction // set_enable
function void set_disable ( );
......
......@@ -53,8 +53,8 @@ class WrtdRule extends WrtdRepCap;
protected WrtdTstamp hold_off;
protected uint32_t seq;
function new ( int core, int index, string name = "" );
super.new ( core, index, name );
function new ( string name = "" );
super.new ( name );
this.src = new();
this.dst = new();
this.rx_last = new();
......
......@@ -69,7 +69,7 @@ module main;
devA = new (accA, MT_BASE, MtIrqMonitorA, "DUT:A");
devA.init();
devA.add_rule ( "rule0" );
devA.set_rule ( "rule0", "ADCI5", "NET0", 0 );
devA.set_rule ( "rule0", "LC-I5", "NET0", 0 );
devA.enable_rule ( "rule0" );
// Config DUTA to trigger on external trigger and get 64 samples
......@@ -85,7 +85,8 @@ module main;
accA.write(`ADC_CSR_BASE + `ADDR_FMC_ADC_100MS_CSR_CH3_SAT, 'h7fff);
accA.write(`ADC_CSR_BASE + `ADDR_FMC_ADC_100MS_CSR_CH4_SAT, 'h7fff);
val = (1'b1 << `FMC_ADC_100MS_CSR_TRIG_EN_EXT_OFFSET);
val = (1'b1 << `FMC_ADC_100MS_CSR_TRIG_EN_EXT_OFFSET);
val |= (1'b1 << `FMC_ADC_100MS_CSR_TRIG_EN_FWD_EXT_OFFSET);
accA.write(`ADC_CSR_BASE + `ADDR_FMC_ADC_100MS_CSR_TRIG_EN, val);
expected = 'h39;
......@@ -103,7 +104,7 @@ module main;
devB = new (accB, MT_BASE, MtIrqMonitorB, "DUT:B");
devB.init();
devB.add_rule ( "rule0" );
devB.set_rule ( "rule0", "NET0", "ADCO1", 50000 );
devB.set_rule ( "rule0", "NET0", "LC-O1", 50000 );
devB.enable_rule ( "rule0" );
// Config DUTB to trigger on WRTD and get 64 samples
......
......@@ -26,7 +26,6 @@
`timescale 1ns/1ps
`include "vhd_wishbone_master.svh"
`include "simdrv_defs.svh"
module simple_tdc_driver
(
......@@ -78,7 +77,7 @@ module simple_tdc_driver
now = $time;
if (t.ts <= now)
$display("TDC: pulse in the past (%t now=%t)!", t.ts, now);
$display("[DUT] <%t> TDC: pulse in the past (%t now=%t)!", $realtime, t.ts, now);
else
begin
const int fifo_n = t.channel / 4;
......@@ -91,8 +90,8 @@ module simple_tdc_driver
val[17] = 1'b1;
val[16:0] = (t.ts - start_time) / 81ps;
$display("TDC: pulse at %t for channel %0d (start #0x%x, time_data 0x%x, start_time %t)",
t.ts, t.channel, start, val[16:0], start_time);
$display("[DUT] <%t> TDC: pulse at %t for channel %0d (start #0x%x, time_data 0x%x, start_time %t)",
$realtime, t.ts, t.channel, start, val[16:0], start_time);
fifos[t.channel / 4].push_back(val);
end
......@@ -137,7 +136,7 @@ module simple_tdc_driver
rdata <= start01;
end
else begin
$display("invalid ACAM read 0x%x", addr);
$display("[DUT] <%t> invalid ACAM read 0x%x", $realtime, addr);
end
end
end
......@@ -146,8 +145,9 @@ module simple_tdc_driver
assign ef2 = fifos[1].size() == 0;
always@(negedge wr) begin
// Unused in simulation mode.
$display("invalid ACAM write 0x%x <- 0x%08x", addr, data);
/* Not supposed to have writes to the ACAM if
firmware is compiled with -DSIMULATION */
$display("[DUT] <%t> invalid ACAM write 0x%x <- 0x%08x", $realtime, addr, data);
end
endmodule // simple_tdc_driver
......@@ -212,11 +212,11 @@ endmodule // simple_fdelay_mon
module dut_env
(
IVHDWishboneMaster host,
output sfp_txp_o, sfp_txn_o,
output clk_sys, rst_sys_n,
sfp_txp_o, sfp_txn_o,
input sfp_rxp_i, sfp_rxn_i
);
reg clk_125m_pll = 0;
reg clk_125m_gtp = 0;
reg clk_20m_vcxo = 0;
......@@ -240,6 +240,9 @@ module dut_env
wire sfp_scl, sfp_sda, sfp_sda_en;
assign clk_sys = DUT.clk_sys_62m5;
assign rst_sys_n = DUT.rst_sys_62m5_n;
//---------------------------------------------------------------------------
// The DUT
//---------------------------------------------------------------------------
......@@ -248,13 +251,12 @@ module dut_env
(
.g_SIMULATION (1),
.g_SIM_BYPASS_VME (1),
.g_WRPC_INITF ("../../../dependencies/wr-cores/bin/wrpc/wrc_phy8_sim.bram"),
.g_MT_CPU0_INITF ("../../../software/firmware/tdc/wrtd-rt-tdc.bram"),
.g_MT_CPU1_INITF ("../../../software/firmware/fd/wrtd-rt-fd.bram")
.g_WRPC_INITF ("../../../dependencies/wr-cores/bin/wrpc/wrc_phy8_sim.bram")
)
DUT
(
.rst_n_i (1'b1),
.vme_sysreset_n_i (1'b1),
.clk_125m_pllref_p_i (clk_125m_pll),
.clk_125m_pllref_n_i (~clk_125m_pll),
.clk_125m_gtp_p_i (clk_125m_gtp),
......@@ -367,10 +369,9 @@ module dut_env
push_pulse(1, start + 30us);
push_pulse(2, start + 50us);
#(start + 200us) ;
#(start + 1000us) ;
// Should have been finished by the FD monitor.
$fatal(1, "FAILED");
end
initial begin
......
//
// unit name: ListDriver
//
// description: A SystemVerilog Class to provide an abstraction of a complete
// LIST system.
//
//------------------------------------------------------------------------------
// Copyright CERN 2018
//------------------------------------------------------------------------------
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 2.0 (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-2.0.
// Unless required by applicable law or agreed to in writing, software,
// hardware and materials distributed under this License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
// or implied. See the License for the specific language governing permissions
// and limitations under the License.
//------------------------------------------------------------------------------
`ifndef __LIST_DRIVER_INCLUDED
`define __LIST_DRIVER_INCLUDED
`include "mock_turtle_driver.svh"
`define LIST_HMQ_LOG_SLOT 0
typedef struct {
uint32_t system;
uint32_t source_port;
uint32_t trigger;
} list_trig_id;
typedef struct {
uint64_t seconds;
uint32_t ticks;
uint32_t frac;
} wr_timestamp;
typedef enum {
NOT_MISSED = -1,
DEAD_TIME = 0,
OVERFLOW = 1,
NO_WR = 2,
TIMEOUT = 3
} list_log_miss_reason;
typedef enum {
RAW = (1 << 0),
SENT = (1 << 1),
PROMISC = (1 << 2),
FILTERED = (1 << 3),
EXECUTED = (1 << 4),
MISSED = (1 << 5)
} list_log_type;
typedef enum {
LIST_IN = 2,
LIST_OUT = 6
} list_log_origin;
class ListLogMsg;
list_log_origin origin;
list_log_type ltype;
uint32_t seq;
int channel;
list_trig_id id;
wr_timestamp ts;
list_log_miss_reason miss_reason;
function new ( MQueueMsg msg );
this.origin = list_log_origin'(msg.header.msg_id);
this.ltype = list_log_type'(msg.data[0]);
this.seq = msg.data[1];
this.channel = msg.data[2];
this.id.system = msg.data[3];
this.id.source_port = msg.data[4];
this.id.trigger = msg.data[5];
this.ts.seconds = (msg.data[7] << 32) | msg.data[6];
this.ts.ticks = msg.data[8];
this.ts.frac = msg.data[9];
if ( this.ltype == MISSED )
this.miss_reason = list_log_miss_reason'(msg.data[10]);
else
this.miss_reason = NOT_MISSED;
endfunction // new
function string tostring ();
string str;
str = $sformatf ( {"[%8s] TYPE: %8s, SEQ: %3d, CHANNEL: %2d, ",
"TRIG_SYS: %0d, TRIG_PORT: %0d, TRIG_ID: %0d, ",
"TS_SEC: %2d, TS_TICKS: %10dns" },
origin.name(), ltype.name(), seq, channel,
id.system, id.source_port, id.trigger,
ts.seconds, ts.ticks * 8);
if ( ts.frac > 0 )
str = { str, $sformatf ( ", TS_FRAC: %0d", ts.frac ) };
if ( miss_reason != NOT_MISSED )
str = { str, $sformatf ( ", MISS_REASON: %s", miss_reason ) };
return str;
endfunction // tostring
endclass // ListLogMsg
class ListDriver;
protected string name;
protected int hmq_log_slot;
protected MockTurtleDriver mt;
function new ( CBusAccessor acc, uint64_t base,
vIMockTurtleIRQ irq, string name = "" );
this.name = name;
this.mt = new (acc, base, irq, name);
endfunction // new
task mdisplay ( string str );
string tmp;
if (this.name == "")
tmp = $sformatf("<%t> %s", $realtime, str);
else
tmp = $sformatf("[%s] <%t> %s", this.name, $realtime, str);
$display (tmp);
endtask // mdisplay