Commit c0571874 authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

hdl: trivial top-level testbench for SPEC

parent 7d858b70
ctrls = ["bank3_32b_32b"]
action = "simulation"
target = "xilinx"
vcom_opt="-mixedsvvh l"
fetchto = "../../ip_cores"
include_dirs = ["gn4124_bfm",
"../../include",
"../../ip_cores/general-cores/modules/wishbone/wb_spi/",
"../../ip_cores/general-cores/sim/",
"../../ip_cores/general-cores/modules/wishbone/wb_lm32/src/"]
syn_device = "xc6slx45t"
sim_tool = "modelsim"
sim_top = "main"
top_module = "main"
files = ["main.sv","buildinfo_pkg.vhd"]
modules = {"local": ["../../top/spec", "gn4124_bfm"]}
#try:
exec(open(fetchto + "/general-cores/tools/gen_buildinfo.py").read())
#except:
# pass
`timescale 1ns/1ps
`include "simdrv_defs.svh"
`include "regs/fd_main_regs.vh"
`include "regs/simple_debug_recorder_regs.vh"
`include "vhd_wishbone_master.svh"
const uint64_t BASE_WRPC = 'h00c0000;
const uint64_t BASE_FINEDELAY = 'h0010000;
class IBusDevice;
CBusAccessor m_acc;
uint64_t m_base;
function new ( CBusAccessor acc, uint64_t base );
m_acc =acc;
m_base = base;
endfunction // new
virtual task write32( uint32_t addr, uint32_t val );
// $display("write32 addr %x val %x", m_base + addr, val);
m_acc.write(m_base +addr, val);
// #100ns;
endtask // write
virtual task read32( uint32_t addr, output uint32_t val );
automatic uint64_t val64;
m_acc.read(m_base + addr, val64);
// $display("read32 addr %x val %x", m_base + addr, val64);
val = val64;
// #100ns;
endtask // write
endclass // BusDevice
class FineDelayDev extends IBusDevice;
function new(CBusAccessor bus, uint64_t base);
super.new(bus, base);
endfunction // new
/* -----\/----- EXCLUDED -----\/-----
`define FD_SCR_DATA_OFFSET 0
`define FD_SCR_DATA 32'h00ffffff
`define FD_SCR_SEL_DAC_OFFSET 24
`define FD_SCR_SEL_DAC 32'h01000000
`define FD_SCR_SEL_PLL_OFFSET 25
`define FD_SCR_SEL_PLL 32'h02000000
`define FD_SCR_SEL_GPIO_OFFSET 26
`define FD_SCR_SEL_GPIO 32'h04000000
`define FD_SCR_READY_OFFSET 27
`define FD_SCR_READY 32'h08000000
`define FD_SCR_CPOL_OFFSET 28
`define FD_SCR_CPOL 32'h10000000
`define FD_SCR_START_OFFSET 29
`define FD_SCR_START 32'h20000000
-----/\----- EXCLUDED -----/\----- */
const int FD_CS_PLL = 0;
const int FD_CS_GPIO = 1;
task set_idelay_taps( int taps );
uint64_t tdcsr;
$display("Set Idelay taps : %d\n", taps);
write32(`ADDR_FD_IODELAY_ADJ, taps);
endtask // set_idelay_taps
task automatic fd_spi_xfer ( input int ss, int num_bits,
uint32_t in, output uint32_t out);
uint32_t scr = 0, r;
int i;
$display("SPI Xfer ss %d in %x (SCR @ %x)", ss, in, `ADDR_FD_SCR );
scr = (in << `FD_SCR_DATA_OFFSET) | `FD_SCR_CPOL;
if(ss == FD_CS_PLL)
scr |= `FD_SCR_SEL_PLL;
else if(ss == FD_CS_GPIO)
scr |= `FD_SCR_SEL_GPIO;
write32(`ADDR_FD_SCR, scr);
write32(`ADDR_FD_SCR, scr | `FD_SCR_START);
forever begin
read32( `ADDR_FD_SCR, scr );
// $display("SCR %x", scr);
if( scr & `FD_SCR_READY )
begin
$display("READY");
break;
end
end
read32( `ADDR_FD_SCR, scr );
out = r & `FD_SCR_DATA;
endtask // r
task automatic pll_writel( int val, int r );
uint32_t dummy;
fd_spi_xfer( FD_CS_PLL, 24, (r << 8) | val, dummy );
endtask // pll_writel
task automatic pll_readl( int val, output int r );
uint32_t rv;
fd_spi_xfer( FD_CS_PLL, 24, (r << 8) | val | (1<<23), rv );
r = rv;
endtask // pll_writel
task automatic unreset();
uint32_t rval;
write32(`ADDR_FD_RSTR, 'hdeadffff); /* Un-reset the card */
read32('h4, rval);
$display("FD.IDR = %x", rval);
endtask // configure
task automatic setup_irqs();
write32(`ADDR_FD_EIC_IER, 'hffffffff);
endtask // setup_irqs
endclass // FineDelayDev
/* -----\/----- EXCLUDED -----\/-----
`define ADDR_SDER_CSR 4'h0
`define SDER_CSR_START_OFFSET 0
`define SDER_CSR_START 32'h00000001
`define SDER_CSR_STOP_OFFSET 1
`define SDER_CSR_STOP 32'h00000002
`define SDER_CSR_FORCE_OFFSET 2
`define SDER_CSR_FORCE 32'h00000004
`define SDER_CSR_TRIG_SEL_OFFSET 3
`define SDER_CSR_TRIG_SEL 32'h000000f8
`define SDER_CSR_TRIG_EDGE_OFFSET 8
`define SDER_CSR_TRIG_EDGE 32'h00000100
`define SDER_CSR_TRIGGERED_OFFSET 9
`define SDER_CSR_TRIGGERED 32'h00000200
`define SDER_CSR_TRIG_PRE_SAMPLES_OFFSET 10
`define SDER_CSR_TRIG_PRE_SAMPLES 32'h03fffc00
`define ADDR_SDER_MEM_ADDR 4'h4
`define SDER_MEM_ADDR_ADDR_OFFSET 0
`define SDER_MEM_ADDR_ADDR 32'h0000ffff
`define ADDR_SDER_TRIG_POS 4'h8
`define SDER_TRIG_POS_POS_OFFSET 0
`define SDER_TRIG_POS_POS 32'h0000ffff
`define ADDR_SDER_MEM_DATA 4'hc
`define SDER_MEM_DATA_DATA_OFFSET 0
`define SDER_MEM_DATA_DATA 32'hffffffff
-----/\----- EXCLUDED -----/\----- */
class DebugRecorderDev extends IBusDevice;
function new(CBusAccessor bus, uint64_t base);
super.new(bus, base);
endfunction // new
task automatic configure(int trig_in, int trig_edge, int pre_samples);
uint32_t csr;
csr = (trig_in << `SDER_CSR_TRIG_SEL_OFFSET);
if(trig_edge)
csr|=`SDER_CSR_TRIG_EDGE;
csr |= (pre_samples << `SDER_CSR_TRIG_PRE_SAMPLES_OFFSET);
write32(`ADDR_SDER_CSR, csr);
endtask // configure
task automatic run();
uint32_t csr;
read32(`ADDR_SDER_CSR, csr);
csr |= `SDER_CSR_START;
write32(`ADDR_SDER_CSR, csr);
endtask // run
task automatic readout();
uint32_t csr, pos, mdata, mtag;
int i;
$error("RDS");
forever begin
read32(`ADDR_SDER_CSR, csr);
$display("trig CSR %x", csr);
if( csr & `SDER_CSR_TRIGGERED)
break;
#5us;
end
csr |= `SDER_CSR_STOP;
write32(`ADDR_SDER_CSR, csr);
$display("Readout!");
read32(`ADDR_SDER_TRIG_POS, pos);
$display("Trig pos: %x", pos);
for(i=0;i<10;i++)
begin
write32(`ADDR_SDER_MEM_ADDR, 2*i);
read32(`ADDR_SDER_MEM_DATA, mdata);
write32(`ADDR_SDER_MEM_ADDR, 2*i+1);
read32(`ADDR_SDER_MEM_DATA, mtag);
$display("pos %d %x %x", i, mdata, mtag);
end
endtask // readout
endclass // FineDelayDev
module main;
reg clk_125m_pllref = 0;
reg clk_20m_vcxo = 0;
reg clk_fd_ref = 0;
reg tdc_start = 0;
always #4ns clk_125m_pllref <= ~clk_125m_pllref;
always #4ns clk_fd_ref <= ~clk_fd_ref;
always #100ns tdc_start <= ~tdc_start;
always #20ns clk_20m_vcxo <= ~clk_20m_vcxo;
wire clk_sys;
wire rst_sys_n;
wire t_wishbone_master_out sim_wb_in;
wire t_wishbone_master_in sim_wb_out;
spec_fine_delay_top
#(.g_simulation(1)
)
DUT (
.clk_125m_pllref_p_i(clk_125m_pllref),
.clk_125m_pllref_n_i(~clk_125m_pllref),
.clk_125m_gtp_p_i(clk_125m_pllref),
.clk_125m_gtp_n_i(~clk_125m_pllref),
.clk_20m_vcxo_i(clk_20m_vcxo),
.button1_n_i(1'b1),
.fmc0_fd_clk_ref_p_i(clk_fd_ref),
.fmc0_fd_clk_ref_n_i(~clk_fd_ref),
.fmc0_fd_tdc_start_p_i(tdc_start),
.fmc0_fd_tdc_start_n_i(~tdc_start),
.fmc0_fd_pll_status_i(1'b1),
.sim_wb_i(sim_wb_in),
.sim_wb_o(sim_wb_out)
// `GENNUM_WIRE_SPEC_PINS_V2(I_Gennum)
);
IVHDWishboneMaster Host
(
.clk_i (DUT.clk_sys_62m5),
.rst_n_i (DUT.rst_sys_62m5_n));
assign sim_wb_in = Host.out;
assign Host.in = sim_wb_out;
assign clk_sys = DUT.clk_sys_62m5;
assign rst_sys_n = DUT.rst_sys_62m5_n;
initial begin
uint64_t rval;
int tmp;
CBusAccessor acc ;
FineDelayDev fd;
DebugRecorderDev rec;
acc = Host.get_accessor();
fd = new(acc, BASE_FINEDELAY);
rec = new(acc, BASE_FINEDELAY + 'h180 * 4);
while (!rst_sys_n)
@(posedge clk_sys);
repeat(100)
@(posedge clk_sys);
// $error("START");
$display("Startup");
fd.unreset();
fd.setup_irqs();
fd.set_idelay_taps(10);
#10us;
fd.set_idelay_taps(20);
#10us;
$stop;
// rec.configure(4, 0, 100);
// rec.run();
// fd.pll_readl('h1f, tmp);
// $error("done");
// rec.readout();
end
endmodule // main
#vlog -sv main.sv +incdir+"." +incdir+gn4124_bfm +incdir+../../include/wb +incdir+../../include
#make -f Makefile
vsim -L unisim -L secureip work.main -voptargs="+acc" -t 10fs -novopt
set StdArithNoWarnings 1
set NumericStdNoWarnings 1
do wave.do
radix -hexadecimal
run 200us
wave zoomfull
radix -hexadecimal
`include "regs/fd_main_regs.vh"
`include "regs/fd_channel_regs.vh"
`include "wb/simdrv_defs.svh"
const int SPI_PLL = 0;
const int SPI_GPIO = 1;
const int SPI_DAC = 2;
int dly_seed= 10;
class CSimDrv_FineDelay;
protected CBusAccessor m_acc;
protected Timestamp ts_queue[$];
const real c_acam_bin = 27.012; // [ps]
const real c_ref_period = 8000; // [ps]
const int c_frac_bits = 12;
const int c_scaler_shift = 12;
const int c_acam_start_offset = 10000;
const int c_acam_merge_c_threshold = 1;
const int c_acam_merge_f_threshold = 2000;
task set_idelay_taps( int taps );
uint64_t tdcsr;
$display("Set Idelay taps : %d\n", taps);
writel(`ADDR_FD_IODELAY_ADJ, taps);
endtask // set_idelay_taps
/* fixme - maybe use real mcp23s17 model instead of this stub? */
task sgpio_write(int value);
uint64_t scr;
scr = `FD_SCR_SEL_GPIO | `FD_SCR_CPOL | (value << `FD_SCR_DATA_OFFSET);
m_acc.write(`ADD_FD_SCR, scr);
m_acc.write(`ADD_FD_SCR, scr | `FD_SCR_START);
while(1)
begin
m_acc.read(`ADDR_FD_SCR, scr);
if(scr & `FD_SCR_READY)
break;
end
endtask // sgpio_write
function new(CBusAccessor acc);
m_acc = acc;
endfunction // new
task acam_write(int addr, int value);
sgpio_write(addr);
#10ns;
m_acc.write(`ADDR_FD_TDR, value);
m_acc.write(`ADDR_FD_TDCSR, `FD_TDCSR_WRITE);
endtask // acam_write
task acam_read(int addr, output int value);
uint64_t rval;
m_acam.addr = addr;
#10ns;
m_acc.write(`ADDR_FD_TDR, (addr<<28));
m_acc.write(`ADDR_FD_TDCSR, `FD_TDCSR_READ);
#(500ns);
m_acc.read(`ADDR_FD_TDR, rval);
value = rval;
endtask // acam_read
task get_time(ref Timestamp t);
uint64_t tcr, secl, sech, cycles;
m_acc.read(`ADDR_FD_TCR, tcr);
m_acc.write(`ADDR_FD_TCR, tcr | `FD_TCR_CAP_TIME);
m_acc.read(`ADDR_FD_TM_SECL, secl);
m_acc.read(`ADDR_FD_TM_SECH, sech);
m_acc.read(`ADDR_FD_TM_CYCLES, cycles);
t.utc = (sech << 32) | secl;
t.coarse = cycles;
t.frac = 0;
endtask // get_time
task set_time(Timestamp t);
uint64_t tcr;
m_acc.read(`ADDR_FD_TCR, tcr);
m_acc.write(`ADDR_FD_TM_SECL, t.utc & 32'hffffffff);
m_acc.write(`ADDR_FD_TM_SECH, t.utc >> 32);
m_acc.write(`ADDR_FD_TM_CYCLES, t.coarse);
m_acc.write(`ADDR_FD_TCR, tcr | `FD_TCR_SET_TIME);
endtask // set_time
task set_reference(int wr);
if(wr)
begin
uint64_t rval;
$display("Enabling White Rabbit time reference...");
m_acc.write(`ADDR_FD_TCR, `FD_TCR_WR_ENABLE);
forever begin
m_acc.read(`ADDR_FD_TCR, rval);
if(rval & `FD_TCR_WR_LOCKED) break;
end
$display("WR Locked");
end
else begin
Timestamp t = new(0,0,0);
set_time(t);
end
endtask // set_reference
task rbuf_update();
Timestamp ts;
uint64_t utc, coarse, seq_frac, stat, sech, secl;
m_acc.read(`ADDR_FD_TSBCR, stat);
if((stat & `FD_TSBCR_EMPTY) == 0) begin
m_acc.write(`ADDR_FD_TSBR_ADVANCE, 1);
m_acc.read(`ADDR_FD_TSBR_SECH, sech);
m_acc.read(`ADDR_FD_TSBR_SECL, secl);
m_acc.read(`ADDR_FD_TSBR_CYCLES, coarse);
m_acc.read(`ADDR_FD_TSBR_FID, seq_frac);
ts = new (0,0,0);
ts.source = seq_frac & 'h7;
ts.utc = (sech << 32) | secl;
ts.coarse = coarse & 'hfffffff;
ts.seq_id = (seq_frac >> 16) & 'hffff;
ts.frac = (seq_frac>>4) & 'hfff;
ts_queue.push_back(ts);
end
endtask // rbuf_read
function int poll();
return (ts_queue.size() > 0);
endfunction // poll
function Timestamp get();
return ts_queue.pop_front();
endfunction // get
typedef enum
{
DELAY = 0,
PULSE_GEN = 1
} channel_mode_t;
task config_output( int channel,channel_mode_t mode, int enable, Timestamp start_delay, uint64_t width_ps, uint64_t delta_ps=0, int rep_count=1);
uint64_t dcr, base, rep;
Timestamp t_start, t_end, t_delta, t_width;
t_width = new;
t_width.unflatten(int'(real'(width_ps) * 4096.0 / 8000.0));
t_start = start_delay;
t_end = start_delay.add(t_width);
t_delta = new;
t_delta.unflatten(int'(real'(delta_ps) * 4096.0 / 8000.0));
base = 'h100 + 'h100 * channel;
m_acc.write(base + `ADDR_FD_FRR, 800);
m_acc.write(base + `ADDR_FD_U_STARTH, t_start.utc >> 32);
m_acc.write(base + `ADDR_FD_U_STARTL, t_start.utc & 'hffffffff);
m_acc.write(base + `ADDR_FD_C_START, t_start.coarse);
m_acc.write(base + `ADDR_FD_F_START, t_start.frac);
m_acc.write(base + `ADDR_FD_U_ENDH, t_end.utc >> 32);
m_acc.write(base + `ADDR_FD_U_ENDL, t_end.utc & 'hffffffff);
m_acc.write(base + `ADDR_FD_C_END, t_end.coarse);
m_acc.write(base + `ADDR_FD_F_END, t_end.frac);
m_acc.write(base + `ADDR_FD_U_DELTA, t_delta.utc & 'hf);
m_acc.write(base + `ADDR_FD_C_DELTA, t_delta.coarse);
m_acc.write(base + `ADDR_FD_F_DELTA, t_delta.frac);
if(rep_count < 0)
rep = `FD_RCR_CONT;
else
rep = (rep_count-1) << `FD_RCR_REP_CNT_OFFSET;
m_acc.write(base + `ADDR_FD_RCR, rep);
dcr = (enable? `FD_DCR_ENABLE : 0) | `FD_DCR_UPDATE ;
if(mode == PULSE_GEN)
dcr |= `FD_DCR_MODE;
if((width_ps < 200000) || (((delta_ps-width_ps) < 150000) && (rep_count > 1)))
dcr |= `FD_DCR_NO_FINE;
m_acc.write('h100 + 'h100 * channel + `ADDR_FD_DCR, dcr);
if(mode == PULSE_GEN)
m_acc.write('h100 + 'h100 * channel + `ADDR_FD_DCR, dcr | `FD_DCR_PG_ARM);
endtask // config_output
task init();
int rval;
Timestamp t = new;
m_acc.write(`ADDR_FD_RSTR, 'hdeadffff); /* Un-reset the card */
m_acc.write(`ADDR_FD_TDCSR, `FD_TDCSR_START_DIS | `FD_TDCSR_STOP_DIS);
m_acc.write(`ADDR_FD_GCR, `FD_GCR_BYPASS);
acam_write(5, c_acam_start_offset); // set StartOffset
acam_read(5, rval);
m_acam.addr= 8; /* permanently select FIFO1 */
// Clear the ring buffer
m_acc.write(`ADDR_FD_TSBCR, `FD_TSBCR_ENABLE | `FD_TSBCR_PURGE | `FD_TSBCR_RST_SEQ | (3 << `FD_TSBCR_CHAN_MASK_OFFSET));
m_acc.write(`ADDR_FD_ADSFR, int' (real'(1<< (c_frac_bits + c_scaler_shift)) * c_acam_bin / c_ref_period));
m_acc.write(`ADDR_FD_ASOR, c_acam_start_offset * 3);
m_acc.write(`ADDR_FD_ATMCR, c_acam_merge_c_threshold | (c_acam_merge_f_threshold << 4));
// Enable trigger input
m_acc.write(`ADDR_FD_GCR, 0);
t.utc = 0;
t.coarse = 0;
set_time(t);
// Enable trigger input
m_acc.write(`ADDR_FD_GCR, `FD_GCR_INPUT_EN);
endtask // init
task force_cal_pulse(int channel, int delay_setpoint);
m_acc.write(`ADDR_FD_FRR + (channel * 'h20), delay_setpoint);
m_acc.write(`ADDR_FD_DCR + (channel * 'h20), `FD_DCR_FORCE_DLY);
m_acc.write(`ADDR_FD_CALR, `FD_CALR_CAL_PULSE | ((1<<channel) << `FD_CALR_PSEL_OFFSET));
endtask // force_cal_pulse
endclass // CSimDrv_FineDelay
`ifndef __VHD_WISHBONE_MASTER_INCLUDED
`define __VHD_WISHBONE_MASTER_INCLUDED
`include "simdrv_defs.svh"
`include "if_wb_master.svh"
import wishbone_pkg::*;
interface IVHDWishboneMaster
(
input clk_i,
input rst_n_i
);
parameter g_addr_width = 32;
parameter g_data_width = 32;
typedef virtual IWishboneMaster VIWishboneMaster;
IWishboneMaster #(g_addr_width, g_data_width) TheMaster (clk_i, rst_n_i);
t_wishbone_master_in in;
t_wishbone_master_out out;
modport master
(
input in,
output out
);
assign out.cyc = TheMaster.cyc;
assign out.stb = TheMaster.stb;
assign out.we = TheMaster.we;
assign out.sel = TheMaster.sel;
assign out.adr = TheMaster.adr;
assign out.dat = TheMaster.dat_o;
assign TheMaster.ack = in.ack;
assign TheMaster.stall = in.stall;
assign TheMaster.rty = in.rty;
assign TheMaster.err = in.err;
assign TheMaster.dat_i = in.dat;
function automatic CWishboneAccessor get_accessor();
automatic CWishboneAccessor acc = TheMaster.get_accessor();
return acc;
endfunction // get_accessor
initial begin
automatic CWishboneAccessor acc;
@(posedge rst_n_i);
@(posedge clk_i);
acc = TheMaster.get_accessor();
acc.set_mode(PIPELINED);
$display("BFM Initialized");
TheMaster.settings.addr_gran = BYTE;
TheMaster.settings.cyc_on_stall = 1;
end
endinterface // IVHDWishboneMaster
`endif // `ifndef __VHD_WISHBONE_MASTER_INCLUDED
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment