Commit 484a0bc3 authored by Dimitris Lampridis's avatar Dimitris Lampridis

sim: first working version of SPEC FMC-ADC testbench.

TODO:

1. Remove hard-coded FMC-ADC values from WRTD testbench classes
2. Make it work for more than one rules
3. Finalise support for alarms
4. Add support for accessing the logs
parent 0ad009fa
......@@ -4,7 +4,7 @@
// https://ohwr.org/projects/wrtd
//------------------------------------------------------------------------------
//
// unit name: WrtdAlarm, WrtdAlarmCollection
// unit name: WrtdAlarm
//
// description: A SystemVerilog Class for a WRTD "alarm" repeated capability
//
......@@ -29,30 +29,54 @@
class WrtdAlarm extends WrtdRepCap;
protected WrtdTstamp setup_time;
protected wrtd_event ev;
protected int repeat_count;
protected uint32_t period_ns;
function new ( int core, int index, string name = "" );
super.new ( core, index, name );
this.setup_time = new();
this.ev.ts = new();
this.ev.id = new();
clear();
endfunction // new
function void clear ( );
super.clear();
this.setup_time.zero();
this.ev.ts.zero();
this.ev.id.clear();
this.ev.seq = 0;
this.ev.flags = 0;
this.repeat_count = 0;
this.period_ns = 0;
endfunction // clear
function repcap_data data_pack ( );
function wrtd_data data_pack ( );
wrtd_data ret = new[`WRTD_ALRM_WORD_SIZE];
ret[0:2] = this.setup_time.data_pack();
ret[3:5] = this.ev.ts.data_pack();
ret[6:9] = this.ev.id.data_pack();
ret[10] = this.ev.seq;
ret[11] = this.ev.flags;
ret[12] = this.enabled;
ret[13] = this.repeat_count;
ret[14] = this.period_ns;
return ret;
endfunction // data_pack
function void data_unpack ( repcap_data data );
function void data_unpack ( wrtd_data data );
this.setup_time.data_unpack ( data[0:2] );
this.ev.ts.data_unpack ( data[3:5] );
this.ev.id.data_unpack ( data[6:9] );
this.ev.seq = data[10];
this.ev.flags = data[11];
this.enabled = data[12];
this.repeat_count = data[13];
this.period_ns = data[14];
endfunction // data_unpack
endclass //WrtdAlarm
class WrtdAlarmCollection extends WrtdRepCapCollection;
protected WrtdAlarm collection[];
function new ( int size, string name );
super.new ( size, name );
endfunction // new
endclass // WrtdAlarmCollection
`endif // `ifndef __WRTD_ALARM_INCLUDED
......@@ -32,12 +32,15 @@
`define WRTD_ID_LEN 16
`define WRTD_IO_MSG_WORD_SIZE 3
`define WRTD_IO_MSG_WORD_SIZE 2
`define WRTD_CFG_MSG_WORD_SIZE 5
`define WRTD_ROOT_WORD_SIZE 13
`define WRTD_RULE_WORD_SIZE 40
`define WRTD_ALRM_WORD_SIZE 15
`define WRTD_DEST_CPU_LOCAL 'hfe
`define WRTD_DEST_CH_NET 'hff
enum {
WRTD_ACTION_GET_CONFIG,
WRTD_ACTION_READW,
......@@ -49,6 +52,12 @@ enum {
WRTD_DIR_OUTPUT
} wrtd_dir;
typedef uint32_t wrtd_data[];
function int wrtd_gen_hash ( string s );
return ( s[0] ^ s[3] ^ s[4] ^ s[7] );
endfunction // wrtd_gen_hash
class WrtdTstamp;
protected string name;
protected uint32_t seconds;
......@@ -78,12 +87,95 @@ class WrtdTstamp;
this.frac = frac;
endfunction // set
function uint32_t get_sec ( );
return this.seconds;
endfunction // get_sec
function uint32_t get_ns ( );
return this.ns;
endfunction // get_ns
function uint32_t get_frac ( );
return this.frac;
endfunction // get_frac
function wrtd_data data_pack ( );
wrtd_data ret=new[3];
ret[0] = this.seconds;
ret[1] = this.ns;
ret[2] = this.frac;
return ret;
endfunction // data_pack
function void data_unpack ( wrtd_data data);
this.seconds = data[0];
this.ns = data[1];
this.frac = data[2];
endfunction // data_unpack
function void zero ( );
set ( 0, 0, 0);
set ( 0, 0, 0 );
endfunction // zero
endclass // WrtdTstamp
class WrtdId;
protected string id;
function new ();
clear();
endfunction // new
function void clear ();
id = "";
endfunction // clear
function void set ( string id );
if ( id.len() > `WRTD_ID_LEN )
$error ( "length of string longer than the available storage" );
else
begin
this.clear();
this.id = id;
end
endfunction // set
function string get ( );
return this.id;
endfunction // get
function wrtd_data data_pack ( );
int i;
wrtd_data d;
d = new[`WRTD_ID_LEN / 4];
for ( i = 0; i < `WRTD_ID_LEN / 4; i ++ )
d[i] = 0;
for ( i = 0; i < this.id.len(); i ++ )
d[i/4] |= this.id[i] << ( 8 * ( i % 4 ) );
return d;
endfunction // data_pack
function void data_unpack ( wrtd_data data );
if ( data.size() > `WRTD_ID_LEN / 4 )
$error ( "length of data longer than the available storage" );
else
this.id = { <<32 { { <<8 { data } } } };
endfunction // data_unpack
function int is_empty ( );
return ( this.id.len() == 0 );
endfunction // is_empty
endclass // WrtdId
typedef struct {
WrtdTstamp ts;
WrtdId id;
uint32_t seq;
byte unsigned flags;
} wrtd_event;
typedef struct {
uint32_t addr;
uint32_t nbr_alarms;
......@@ -94,6 +186,36 @@ typedef struct {
uint32_t devs_addr[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
......@@ -27,11 +27,9 @@
`include "wrtd_definitions.svh"
typedef uint32_t repcap_data[];
virtual class WrtdRepCap;
protected string name;
protected string rep_cap_id;
protected WrtdId rep_cap_id;
protected int core;
protected int index;
protected int enabled;
......@@ -40,11 +38,12 @@ virtual class WrtdRepCap;
this.core = core;
this.index = index;
this.name = name;
this.rep_cap_id = new();
clear();
endfunction // new
function void clear ( );
this.rep_cap_id = "";
this.rep_cap_id.clear();
this.enabled = 0;
endfunction // clear
......@@ -66,19 +65,19 @@ virtual class WrtdRepCap;
endfunction // get_index
function string get_rep_cap_id ( );
return this.rep_cap_id;
return this.rep_cap_id.get();
endfunction // get_rep_cap_id
function void set_rep_cap_id ( string id );
this.rep_cap_id = id;
this.rep_cap_id.set( id );
endfunction // set_rep_cap_id
function int match ( string id );
return ( this.rep_cap_id.compare ( id ) == 0 );
return ( get_rep_cap_id().compare ( id ) == 0 );
endfunction // is_equal
function int is_free ( );
return ( this.rep_cap_id.len == 0 );
return this.rep_cap_id.is_empty();
endfunction // is_free
function int is_enabled ( );
......@@ -93,19 +92,19 @@ virtual class WrtdRepCap;
this.enabled = 0;
endfunction // set_disable
pure virtual function repcap_data data_pack ( );
pure virtual function wrtd_data data_pack ( );
pure virtual function void data_unpack ( repcap_data data );
pure virtual function void data_unpack ( wrtd_data data );
endclass //WrtdRepCap
virtual class WrtdRepCapCollection;
class WrtdRepCapCollection;
protected string name;
protected WrtdRepCap collection[];
WrtdRepCap collection[$];
function new ( int size, string name );
this.name = name;
this.collection = new[size];
function new ( string name );
this.name = name;
this.collection.delete();
endfunction // new
task mdisplay ( string str );
......@@ -118,49 +117,12 @@ virtual class WrtdRepCapCollection;
endtask // mdisplay
function void validate_id ( string rep_cap_id );
if ( rep_cap_id.len > `WRTD_ID_LEN )
if ( rep_cap_id.len() > `WRTD_ID_LEN )
$error ( "repeated capability name '%s' is too long", rep_cap_id );
if ( rep_cap_id.len == 0 )
if ( rep_cap_id.len() == 0 )
$error ( "repeated capability name is null" );
endfunction // validate_id
function void init_element ( int idx, int core, int rule );
this.collection[idx] = new ( core, rule, this.name );
endfunction // init_element
function int collection_size( );
return this.collection.size();
endfunction // collection_size
function int is_free ( int idx );
return ( this.collection[idx].is_free() );
endfunction // is_free
function int get_core ( int idx );
return this.collection[idx].get_core();
endfunction // get_core
function int get_index ( int idx );
return this.collection[idx].get_index();
endfunction // get_index
function void set_enable ( int idx );
this.collection[idx].set_enable();
endfunction // set_enable
function void set_disable (int idx );
this.collection[idx].set_disable();
endfunction // set_disable
function repcap_data data_pack ( int idx );
return this.collection[idx].data_pack();
endfunction // data_pack
function void data_unpack ( int idx, repcap_data data );
this.collection[idx].data_unpack ( data );
endfunction // data_unpack
function int add ( string rep_cap_id );
int i, idx;
......@@ -168,19 +130,22 @@ virtual class WrtdRepCapCollection;
idx = -1;
for ( i = 0; i < collection_size(); i++ )
for ( i = 0; i < this.collection.size(); i++ )
begin
if ( this.collection[i].match ( rep_cap_id ) )
$error ( "%s repeated capability ID already exists", rep_cap_id );
begin
$error ( "'%s' repeated capability ID already exists", rep_cap_id );
return -1;
end
if ( idx == -1 && this.collection[i].is_free() )
idx = i;
end
if ( idx == -1 )
$error ( "cannot add %s repeated capability, no space available", rep_cap_id );
this.collection[idx].set_rep_cap_id ( rep_cap_id );
$error ( "cannot add '%s' repeated capability, no space available", rep_cap_id );
else
this.collection[idx].set_rep_cap_id ( rep_cap_id );
return idx;
endfunction // add
......@@ -190,7 +155,7 @@ virtual class WrtdRepCapCollection;
validate_id ( rep_cap_id );
for ( i = 0; i < collection_size(); i++ )
for ( i = 0; i < this.collection.size(); i++ )
if ( this.collection[i].match ( rep_cap_id ) )
return i;
......@@ -203,17 +168,19 @@ virtual class WrtdRepCapCollection;
idx = find ( rep_cap_id );
if ( idx == -1 )
$error ( "%s repeated capability ID cannot be removed because it does not exist", rep_cap_id );
begin
$error ( "%s repeated capability ID cannot be removed because it does not exist", rep_cap_id );
return idx;
end
if ( this.collection[idx].is_enabled() )
if ( this.collection[idx].is_enabled ( ) )
$error ( "%s repeated capability ID cannot be removed because it is enabled", rep_cap_id );
this.collection[idx].clear();
else
this.collection[idx].clear();
return idx;
endfunction // remove
endclass // WrtdRepCapCollection
`endif // `ifndef __WRTD_REPCAP_INCLUDED
......@@ -4,7 +4,7 @@
// https://ohwr.org/projects/wrtd
//------------------------------------------------------------------------------
//
// unit name: WrtdRule, WrtdRuleCollection
// unit name: WrtdRule
//
// description: A SystemVerilog Class for a WRTD "rule" repeated capability
//
......@@ -28,74 +28,149 @@
`include "wrtd_rep_cap.svh"
class WrtdRule extends WrtdRepCap;
protected string src;
protected string dst;
protected WrtdTstamp delay;
protected int send_late;
protected WrtdId src;
protected WrtdId dst;
protected byte unsigned dest_cpu;
protected byte unsigned dest_ch;
protected byte unsigned send_late;
protected uint32_t repeat_count;
protected uint32_t delay_ns;
protected uint32_t hold_off_ns;
protected uint32_t resync_period_ns;
protected uint32_t resync_delay_ns;
int hash_chain;
protected uint32_t rx_events;
protected WrtdTstamp rx_last;
protected uint32_t tx_events;
protected WrtdTstamp tx_last;
protected uint32_t lat_max_ns;
protected uint32_t lat_lo_ns;
protected uint32_t lat_hi_ns;
protected uint32_t lat_nbr;
protected uint32_t miss_holdoff;
protected uint32_t miss_late;
protected WrtdTstamp miss_last;
protected WrtdTstamp hold_off;
protected uint32_t seq;
function new ( int core, int index, string name = "" );
super.new ( core, index, name );
this.delay = new ();
this.src = new();
this.dst = new();
this.rx_last = new();
this.tx_last = new();
this.miss_last = new();
this.hold_off = new();
clear();
endfunction // new
function void clear ( );
super.clear();
this.delay.zero();
this.src = "";
this.dst = "";
this.send_late = 1;
this.src.clear();
this.dst.clear();
this.rx_last.zero();
this.tx_last.zero();
this.miss_last.zero();
this.hold_off.zero();
this.dest_cpu = 0;
this.dest_ch = 0;
this.send_late = 1;
this.repeat_count = 0;
this.delay_ns = 0;
this.hold_off_ns = 0;
this.resync_period_ns = 0;
this.resync_delay_ns = 0;
this.hash_chain = -1;
endfunction // clear
function repcap_data data_pack ( );
function wrtd_data data_pack ( );
wrtd_data ret = new[`WRTD_RULE_WORD_SIZE];
ret[0:3] = this.rep_cap_id.data_pack();
ret[4:7] = this.src.data_pack();
ret[8:11] = this.dst.data_pack();
ret[12] = this.dest_cpu << 0;
ret[12] |= this.dest_ch << 8;
ret[12] |= this.enabled << 16;
ret[12] |= this.send_late << 24;
ret[13] = this.repeat_count;
ret[14] = this.delay_ns;
ret[15] = this.hold_off_ns;
ret[16] = this.resync_period_ns;
ret[17] = this.resync_delay_ns;
ret[18] = this.hash_chain;
ret[19] = this.rx_events;
ret[20:22] = this.rx_last.data_pack();
ret[23] = this.tx_events;
ret[24:26] = this.tx_last.data_pack();
ret[27] = this.lat_max_ns;
ret[28] = this.lat_lo_ns;
ret[29] = this.lat_hi_ns;
ret[30] = this.lat_nbr;
ret[31] = this.miss_holdoff;
ret[32] = this.miss_late;
ret[33:35] = this.miss_last.data_pack();
ret[36:38] = this.hold_off.data_pack();
ret[39] = this.seq;
return ret;
endfunction // data_pack
function void data_unpack ( repcap_data data );
function void data_unpack ( wrtd_data data );
this.rep_cap_id.data_unpack ( data[0:3] );
this.src.data_unpack (data[4:7] );
this.dst.data_unpack( data[8:11] );
this.dest_cpu = ( data[12] & 'h000000ff ) >> 0;
this.dest_ch = ( data[12] & 'h0000ff00 ) >> 8;
this.enabled = ( data[12] & 'h00ff0000 ) >> 16;
this.send_late = ( data[12] & 'hff000000 ) >> 24;
this.repeat_count = data[13];
this.delay_ns = data[14];
this.hold_off_ns = data[15];
this.resync_period_ns = data[16];
this.resync_delay_ns = data[17];
this.hash_chain = data[18];
this.rx_events = data[19];
this.rx_last.data_unpack ( data[20:22] );
this.tx_events = data[23];
this.tx_last.data_unpack ( data[24:26] );
this.lat_max_ns = data[27];
this.lat_lo_ns = data[28];
this.lat_hi_ns = data[29];
this.lat_nbr = data[30];
this.miss_holdoff = data[31];
this.miss_late = data[32];
this.miss_last.data_unpack ( data[33:35] );
this.hold_off.data_unpack ( data[36:38] );
this.seq = data[39];
endfunction // data_unpack
function string get_src ( );
return this.src;
return this.src.get();
endfunction // get_src
function void set ( WrtdTstamp delay, string src, string dst );
if ( delay != null )
this.delay = delay;
else
this.delay.zero();
this.src = src;
this.dst = dst;
endfunction // set
function string get_dst ( );
return this.dst.get();
endfunction // get_dst
endclass //WrtdRule
class WrtdRuleCollection extends WrtdRepCapCollection;
protected WrtdRule collection[];
function new ( int size, string name );
super.new ( size, name );
endfunction // new
function int set ( string rep_cap_id, WrtdTstamp delay,
string src, string dst );
int idx;
function void set_src ( string src );
this.src.set ( src );
endfunction // set_src
idx = find ( rep_cap_id );
function void set_dst ( string dst );
this.dst.set ( dst );
endfunction // set_src
if ( idx == -1 )
$error ( "%s repeated capability ID cannot be set because it does not exist", rep_cap_id );
function void set_dest_cpu ( uint32_t dest_cpu );
this.dest_cpu = dest_cpu;
endfunction // set_dest_cpu
if ( this.collection[idx].is_enabled() )
$error ( "%s repeated capability ID cannot be set because it is enabled", rep_cap_id );
function void set_dest_ch ( uint32_t dest_ch );
this.dest_ch = dest_ch;
endfunction // set_dest_ch
this.collection[idx].set ( delay, src, dst );
function void set_delay_ns ( uint32_t delay_ns );
this.delay_ns = delay_ns;
endfunction // set_delay_ns
return idx;
endfunction // set
function string get_src ( int idx );
return this.collection[idx].get_src();
endfunction // get_src
endclass // WrtdRuleCollection
endclass //WrtdRule
`endif // `ifndef __WRTD_RULE_INCLUDED
......@@ -76,7 +76,8 @@ module dut_env
wrtd_ref_spec150t_adc #
(
.g_SIMULATION (1)
.g_SIMULATION (1),
.g_WRPC_INITF ("../../../dependencies/wr-cores/bin/wrpc/wrc_phy8_sim.bram")
)
DUT
(
......
......@@ -25,29 +25,30 @@
`timescale 1ns/1ps
`include "gn4124_bfm.svh"
`include "wrtd_dev.svh"
`include "wrtd_driver.svh"
`include "fmc_adc_100Ms_csr.v"
`include "fmc_adc_alt_trigout.v"
`define ADC_CSR_BASE 'h5000
module main;
IGN4124PCIMaster hostA ();
//IGN4124PCIMaster hostB ();
IGN4124PCIMaster hostB ();
reg duta_ext_trig, dutb_ext_trig;
wire[2:0] duta_acq_state, dutb_acq_state;
dut_env DUTA (hostA, duta_acq_state, a2b_txp, a2b_txn, a2b_rxp, a2b_rxn, duta_ext_trig);
//dut_env DUTB (hostB, dutb_acq_state, a2b_rxp, a2b_rxn, a2b_txp, a2b_txn, dutb_ext_trig);
dut_env DUTB (hostB, dutb_acq_state, a2b_rxp, a2b_rxn, a2b_txp, a2b_txn, dutb_ext_trig);
IMockTurtleIRQ MtIrqMonitorA (`MT_ATTACH_IRQ(DUTA.DUT.cmp_mock_turtle));
//IMockTurtleIRQ MtIrqMonitorB (`MT_ATTACH_IRQ(DUTB.DUT.cmp_mock_turtle));
IMockTurtleIRQ MtIrqMonitorB (`MT_ATTACH_IRQ(DUTB.DUT.cmp_mock_turtle));
CBusAccessor accA, accB;
WrtdDev devA, devB;
WrtdDrv devA, devB;
const uint64_t MT_BASE = 'h0002_0000;
......@@ -59,86 +60,156 @@ module main;
duta_ext_trig <= 1'b0;
wait (hostA.ready == 1'b1);// && (hostB.ready == 1'b1));
wait ((hostA.ready == 1'b1) && (hostB.ready == 1'b1));
accA = hostA.get_accessor();
//accB = hostB.get_accessor();
fork
begin
accA = hostA.get_accessor();
accA.set_default_xfer_size(4);
devA = new (accA, MT_BASE, MtIrqMonitorA, "DUT:A");
devA.init();
devA.add_rule ( "rule0" );
devA.set_rule ( "rule0", "ADCI5", "NET0", 0 );
devA.enable_rule ( "rule0" );
// Config DUTA to trigger on external trigger and get 64 samples
accA.write(`ADC_CSR_BASE + `ADDR_FMC_ADC_100MS_CSR_PRE_SAMPLES, 'h00);
accA.write(`ADC_CSR_BASE + `ADDR_FMC_ADC_100MS_CSR_POST_SAMPLES, 'h40);
accA.write(`ADC_CSR_BASE + `ADDR_FMC_ADC_100MS_CSR_SHOTS, 'h01);
accA.write(`ADC_CSR_BASE + `ADDR_FMC_ADC_100MS_CSR_CH1_GAIN, 'h8000);
accA.write(`ADC_CSR_BASE + `ADDR_FMC_ADC_100MS_CSR_CH2_GAIN, 'h8000);