Commit e69cf523 authored by Evangelia Gousiou's avatar Evangelia Gousiou

Merge branch 'tom-may08' into feature/convention

# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
parents 182ada36 1bd089d1
Subproject commit 1a1293900e6334bc41251ee84d0ae7d19980e584
Subproject commit 3879a6d33227704f8925e76eb68064da155de2b0
Subproject commit b3d2bfc24e01b95acef5d4240cb476c3f2f42566
Subproject commit cbe5c7ee4c1adcff1f4c987772066af26908062c
......@@ -448,7 +448,8 @@ begin
gen_with_dma_readout : if g_USE_DMA_READOUT generate
U_DMA_Engine : entity work.tdc_dma_engine
generic map (
g_CLOCK_FREQ => 62500000)
g_CLOCK_FREQ => 62500000,
g_SIMULATION => g_SIMULATION)
port map (
clk_i => clk_sys_i,
rst_n_i => rst_sys_n_i,
......@@ -656,7 +657,8 @@ begin
end loop;
end process;
timestamp_ready <= (others => '1');
sim_timestamp_ready_o <= '1'; -- fixme: do we care about flow control in simulations?
end generate gen_use_fake_timestamps;
......
......@@ -159,7 +159,7 @@ package tdc_core_pkg is
wbd_width => x"4", -- 32-bit port granularity
sdb_component =>
(addr_first => x"0000000000000000",
addr_last => x"000000000000000F",
addr_last => x"000000000000003F",
product =>
(vendor_id => x"000000000000CE42", -- CERN
device_id => x"00000605", -- "WB-FMC-ADC.EIC " | md5sum | cut -c1-8
......@@ -192,7 +192,7 @@ package tdc_core_pkg is
wbd_width => x"4", -- 32-bit port granularity
sdb_component => (
addr_first => x"0000000000000000",
addr_last => x"000000000000000F",
addr_last => x"000000000000003F",
product => (
vendor_id => x"000000000000CE42", -- CERN
device_id => x"26ec6086", -- "WB-FMC-TDC.EIC " | md5sum | cut -c1-8
......@@ -814,6 +814,7 @@ package body tdc_core_pkg is
function f_pack_raw_acam_timestamp ( ts : t_raw_acam_timestamp ) return std_logic_vector is
variable rv : std_logic_vector(127 downto 0);
begin
rv:= (others => '0');
rv(31 downto 0) := ts.seconds;
rv(48 downto 32) := ts.acam_bins(16 downto 0);
rv(56 downto 49) := ts.acam_start_nb;
......
......@@ -10,7 +10,8 @@ use work.gencores_pkg.all;
entity tdc_dma_engine is
generic (
g_CLOCK_FREQ : integer := 62500000
g_CLOCK_FREQ : integer := 62500000;
g_SIMULATION : boolean := false
);
port (
clk_i : in std_logic;
......@@ -55,9 +56,19 @@ architecture rtl of tdc_dma_engine is
3 => x"000001c0",
4 => x"000001c0");
constant c_TIMER_PERIOD_MS : integer := 1;
constant c_TIMER_DIVIDER_VALUE : integer := g_CLOCK_FREQ * c_TIMER_PERIOD_MS / 1000 - 1;
impure function f_pick_timer_divider return integer is
begin
if g_SIMULATION then
return 1000;
else
return g_CLOCK_FREQ * c_TIMER_PERIOD_MS / 1000 - 1;
end if;
end f_pick_timer_divider;
constant c_TIMER_DIVIDER_VALUE : integer := f_pick_timer_divider;
signal irq_tick_div : unsigned(15 downto 0);
signal irq_tick : std_logic;
......
`define SPEC_BASE_REGS_SIZE 8192
`define ADDR_SPEC_BASE_REGS_METADATA 'h0
`define SPEC_BASE_REGS_METADATA_SIZE 64
`define ADDR_SPEC_BASE_REGS_CSR 'h40
`define SPEC_BASE_REGS_CSR_SIZE 32
`define ADDR_SPEC_BASE_REGS_CSR_APP_OFFSET 'h40
`define ADDR_SPEC_BASE_REGS_CSR_RESETS 'h44
`define SPEC_BASE_REGS_CSR_RESETS_GLOBAL_OFFSET 0
`define SPEC_BASE_REGS_CSR_RESETS_GLOBAL 'h1
`define SPEC_BASE_REGS_CSR_RESETS_APPL_OFFSET 1
`define SPEC_BASE_REGS_CSR_RESETS_APPL 'h2
`define ADDR_SPEC_BASE_REGS_CSR_FMC_PRESENCE 'h48
`define ADDR_SPEC_BASE_REGS_CSR_GN4124_STATUS 'h4c
`define ADDR_SPEC_BASE_REGS_CSR_DDR_STATUS 'h50
`define SPEC_BASE_REGS_CSR_DDR_STATUS_CALIB_DONE_OFFSET 0
`define SPEC_BASE_REGS_CSR_DDR_STATUS_CALIB_DONE 'h1
`define ADDR_SPEC_BASE_REGS_CSR_PCB_REV 'h54
`define SPEC_BASE_REGS_CSR_PCB_REV_REV_OFFSET 0
`define SPEC_BASE_REGS_CSR_PCB_REV_REV 'hf
`define ADDR_SPEC_BASE_REGS_THERM_ID 'h70
`define SPEC_BASE_REGS_THERM_ID_SIZE 16
`define ADDR_SPEC_BASE_REGS_FMC_I2C 'h80
`define SPEC_BASE_REGS_FMC_I2C_SIZE 32
`define ADDR_SPEC_BASE_REGS_FLASH_SPI 'ha0
`define SPEC_BASE_REGS_FLASH_SPI_SIZE 32
`define ADDR_SPEC_BASE_REGS_DMA 'hc0
`define SPEC_BASE_REGS_DMA_SIZE 64
`define ADDR_SPEC_BASE_REGS_VIC 'h100
`define SPEC_BASE_REGS_VIC_SIZE 256
`define ADDR_SPEC_BASE_REGS_BUILDINFO 'h200
`define SPEC_BASE_REGS_BUILDINFO_SIZE 256
`define ADDR_SPEC_BASE_REGS_WRC_REGS 'h1000
`define SPEC_BASE_REGS_WRC_REGS_SIZE 4096
`define ADDR_TDC_BUF_CSR 5'h0
`define TDC_BUF_CSR_ENABLE_OFFSET 0
`define TDC_BUF_CSR_ENABLE 32'h00000001
`define TDC_BUF_CSR_IRQ_TIMEOUT_OFFSET 1
`define TDC_BUF_CSR_IRQ_TIMEOUT 32'h000007fe
`define TDC_BUF_CSR_BURST_SIZE_OFFSET 11
`define TDC_BUF_CSR_BURST_SIZE 32'h001ff800
`define TDC_BUF_CSR_SWITCH_BUFFERS_OFFSET 21
`define TDC_BUF_CSR_SWITCH_BUFFERS 32'h00200000
`define TDC_BUF_CSR_DONE_OFFSET 22
`define TDC_BUF_CSR_DONE 32'h00400000
`define TDC_BUF_CSR_OVERFLOW_OFFSET 23
`define TDC_BUF_CSR_OVERFLOW 32'h00800000
`define ADDR_TDC_BUF_CUR_BASE 5'h4
`define ADDR_TDC_BUF_CUR_COUNT 5'h8
`define ADDR_TDC_BUF_CUR_SIZE 5'hc
`define TDC_BUF_CUR_SIZE_SIZE_OFFSET 0
`define TDC_BUF_CUR_SIZE_SIZE 32'h3fffffff
`define TDC_BUF_CUR_SIZE_VALID_OFFSET 30
`define TDC_BUF_CUR_SIZE_VALID 32'h40000000
`define ADDR_TDC_BUF_NEXT_BASE 5'h10
`define ADDR_TDC_BUF_NEXT_SIZE 5'h14
`define TDC_BUF_NEXT_SIZE_SIZE_OFFSET 0
`define TDC_BUF_NEXT_SIZE_SIZE 32'h3fffffff
`define TDC_BUF_NEXT_SIZE_VALID_OFFSET 30
`define TDC_BUF_NEXT_SIZE_VALID 32'h40000000
`define ADDR_TDC_EIC_EIC_IDR 6'h20
`define ADDR_TDC_EIC_EIC_IDR 6'h00
`define TDC_EIC_EIC_IDR_TDC_FIFO1_OFFSET 0
`define TDC_EIC_EIC_IDR_TDC_FIFO1 32'h00000001
`define TDC_EIC_EIC_IDR_TDC_FIFO2_OFFSET 1
......@@ -19,7 +19,7 @@
`define TDC_EIC_EIC_IDR_TDC_DMA4 32'h00000100
`define TDC_EIC_EIC_IDR_TDC_DMA5_OFFSET 9
`define TDC_EIC_EIC_IDR_TDC_DMA5 32'h00000200
`define ADDR_TDC_EIC_EIC_IER 6'h24
`define ADDR_TDC_EIC_EIC_IER 6'h04
`define TDC_EIC_EIC_IER_TDC_FIFO1_OFFSET 0
`define TDC_EIC_EIC_IER_TDC_FIFO1 32'h00000001
`define TDC_EIC_EIC_IER_TDC_FIFO2_OFFSET 1
......@@ -40,7 +40,7 @@
`define TDC_EIC_EIC_IER_TDC_DMA4 32'h00000100
`define TDC_EIC_EIC_IER_TDC_DMA5_OFFSET 9
`define TDC_EIC_EIC_IER_TDC_DMA5 32'h00000200
`define ADDR_TDC_EIC_EIC_IMR 6'h28
`define ADDR_TDC_EIC_EIC_IMR 6'h08
`define TDC_EIC_EIC_IMR_TDC_FIFO1_OFFSET 0
`define TDC_EIC_EIC_IMR_TDC_FIFO1 32'h00000001
`define TDC_EIC_EIC_IMR_TDC_FIFO2_OFFSET 1
......@@ -61,7 +61,7 @@
`define TDC_EIC_EIC_IMR_TDC_DMA4 32'h00000100
`define TDC_EIC_EIC_IMR_TDC_DMA5_OFFSET 9
`define TDC_EIC_EIC_IMR_TDC_DMA5 32'h00000200
`define ADDR_TDC_EIC_EIC_ISR 6'h2c
`define ADDR_TDC_EIC_EIC_ISR 6'h0c
`define TDC_EIC_EIC_ISR_TDC_FIFO1_OFFSET 0
`define TDC_EIC_EIC_ISR_TDC_FIFO1 32'h00000001
`define TDC_EIC_EIC_ISR_TDC_FIFO2_OFFSET 1
......
......@@ -6,8 +6,8 @@ package buildinfo_pkg is
constant buildinfo : string :=
"buildinfo:1" & LF
& "module:main" & LF
& "commit:29c1fdd2e474c7bdb52e11db26e94b502814290e" & LF
& "commit:745e912cee76d4ee9e8c3fded1c9ee9b5e694cdd" & LF
& "syntool:modelsim" & LF
& "syndate:2020-04-24, 17:39 CEST" & LF
& "synauth:Evangelia Gousiou" & LF;
& "syndate:2020-04-24, 22:37 CEST" & LF
& "synauth:Tomasz Wlostowski" & LF;
end buildinfo_pkg;
......@@ -6,19 +6,40 @@
`include "vic_wb.vh"
`include "dma_controller_wb.vh"
`include "regs/tdc_buffer_control_regs.vh"
`include "regs/spec_base_regs.vh"
`include "gn4124_bfm.svh"
`include "acam_model.svh"
`define DMA_BASE 'h00c0
`define VIC_BASE 'h0100
// don't use the ACAM model, we're testing the readout here
`undef USE_ACAM_MODEL
`define TDC_CORE_BASE 'h20000
`define TDC_CORE_CFG_BASE 'h2000
`define FIFO1_BASE 'h5000
`define TDC_EIC_BASE 'h3000
`define TDC_DMA_BASE 'h6000
import tdc_core_pkg::*;
// Base addresses of the cores (relative to the beginning of gn4124 BAR0)
`define BASE_SPEC_CSR 'h0000
`define BASE_GENNUM_DMA 'h00c0
`define BASE_VIC 'h0100
`define BASE_TDC_CORE 'h20000
// Offsets of TDC core subcomponents
`define OFFSET_TDC_CORE_CFG 'h2000
`define OFFSET_TDC_FIFO1 'h5000
`define OFFSET_TDC_EIC 'h3000
`define OFFSET_TDC_BUFFER_CONTROLLER 'h6000
// VIC IRQ line assignemnts
`define VIC_IRQ_GENNUM_DMA 2
`define VIC_IRQ_TDC_CORE 6
// base address of the Gennum BAR with system RAM
`define BASE_HOST_MEM 'h20000000
`define TDC_EIC_BUFFER0 (5)
// internal TDC timestamp structure
typedef struct {
uint32_t tai;
uint32_t coarse;
......@@ -30,39 +51,427 @@ typedef struct {
typedef fmc_tdc_timestamp_t fmc_tdc_timestamp_queue_t[$];
class FmcTdcDriver;
CBusAccessor m_acc;
uint64_t m_base;
// generates a stream of fake (random) timestamps. They are stored in an internal
// queue so that later they can be compared against the values read out over DMA.
class FakeTimestampGenerator;
protected fmc_tdc_timestamp_queue_t m_queue;
protected int m_seq, m_channel;
protected int m_enabled;
protected int m_count;
function new(int channel);
m_channel = channel;
m_seq = 0;
m_enabled = 0;
m_count = 0;
endfunction // new
function int is_enabled();
return m_enabled;
endfunction // is_enabled
fmc_tdc_timestamp_queue_t m_queues[5];
task automatic enable(int e);
m_enabled = e;
endtask // enable
// new
function new(CBusAccessor acc, uint64_t base, bit use_dma);
m_acc = acc;
function automatic fmc_tdc_timestamp_queue_t get_queue();
return m_queue;
endfunction // get_queue
// produces a signle fake timestamp. Returns it and also stores in the local queue for further
// verification
function automatic t_tdc_timestamp generate_hw_timestamp( int slope = 0);
fmc_tdc_timestamp_t ts;
t_tdc_timestamp ts_hw;
ts.tai = m_count | ( 1<<11 );
ts.coarse = m_count | ( 2 << 11 );
ts.frac = m_count;
ts.seq = m_seq | (3<<11);
ts.slope = slope;
ts.channel = m_channel;
m_count++;
ts_hw.tai = ts.tai;
ts_hw.coarse = ts.coarse;
ts_hw.frac = ts.frac;
ts_hw.channel = ts.channel;
ts_hw.slope = ts.slope;
ts_hw.seq = ts.seq;
ts_hw.meta = 'hdeadbeef;
m_seq++;
return ts_hw;
endfunction // generate_hw_timestamp
endclass // FakeTimestampGenerator
// Base interface class for a Device (with an assigned base address) connected to a particular bus.
class IBusDevice;
CBusAccessor m_acc;
uint64_t m_base;
function new ( CBusAccessor acc, uint64_t base );
m_acc =acc;
m_base = base;
endfunction
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);
endtask // write
virtual task read32( uint32_t addr, output uint32_t val );
automatic uint64_t val64;
m_acc.read(m_base + addr, val64);
val = val64;
endtask // write
endclass // BusDevice
// Driver for the VIC.
class VICDriver extends IBusDevice;
function new(CBusAccessor bus, uint64_t base);
super.new(bus, base);
endfunction // new
task automatic init();
int i;
for(i=0;i<32;i++)
write32(`BASE_VIC_IVT_RAM + i * 4, i);
write32(`ADDR_VIC_CTL, `VIC_CTL_ENABLE);
endtask // init
task automatic enable_irqs(uint32_t mask);
write32(`ADDR_VIC_IER, mask);
endtask // enable_irqs
task automatic disable_irqs(uint32_t mask);
write32(`ADDR_VIC_IDR, mask);
endtask // enable_irqs
task automatic get_pending_irq(output uint32_t id);
read32(`ADDR_VIC_VAR, id);
endtask // get_pending_irqs
task automatic clear_pending_irq(uint32_t mask);
write32(`ADDR_VIC_EOIR, mask);
endtask // get_pending_irqs
endclass // VICDriver
// abstract interface implementing an interrupt handler. Used by IrqLine module
// to redirect IRQ events to an appropriate handler function/class.
virtual class IrqHandler;
pure virtual task irq(int id);
endclass // IrqHandler
// Trivial driver for the Gennum DMA
class GennumDMA extends IBusDevice;
protected bit m_dma_pending;
protected time m_t_start, m_t_end;
protected uint32_t m_last_size;
function new(CBusAccessor bus, uint64_t base);
super.new(bus, base);
m_dma_pending = 0;
endfunction // new
// executes a Local-to-Host DMA transfer.
task automatic dma_to_host( uint32_t addr_card, uint32_t addr_host, uint32_t size);
// DMA transfer
$display("[Info] Start GN4124 DMA: card=0x%x host=0x%x size=%d", addr_card,addr_host,size);
write32(`ADDR_DMA_CSTART, addr_card); // dma start addr (card address space)
write32(`ADDR_DMA_HSTARTL, addr_host); // host addr
write32(`ADDR_DMA_HSTARTH, 'h00000000);
write32(`ADDR_DMA_LEN, size); // length
write32(`ADDR_DMA_NEXTL, 'h00000000); // next (we don't use chained transfers for the moment)
write32(`ADDR_DMA_NEXTH, 'h00000000);
write32(`ADDR_DMA_ATTRIB, 'h00000000); // attrib: pcie -> host
write32(`ADDR_DMA_CTRL, 'h00000001); // xfer start
m_t_start = $time;
m_last_size = size;
m_dma_pending = 1;
endtask // dma_to_host
// IRQ handler for the DMA complete interrupt
task automatic irq_dma_complete();
// strange, we got an IRQ without a pending DMA xfer?
if ( !m_dma_pending )
$display("[Error] GN4124 DMA irq without a pending transfer");
write32(`ADDR_DMA_STAT, (1<<2) ); // clear pending IRQ
m_t_end = $time;
$display("[Info] GN4124 DMA transfer complete, %d bytes took %.0f us",
m_last_size, real'(m_t_end - m_t_start) / real'(1us) );
m_dma_pending = 0;
endtask // on_dma_complete
function bit is_dma_pending();
return m_dma_pending;
endfunction // is_dma_pending
endclass // GennumDMA
// Main SPEC TDC driver. Mostly a copy-paste (+ systemverilog translation) of the
// relevant fmc-tdc driver code.
class FmcTdcSPECDriver extends IBusDevice;
protected GennumDMA m_gennum_dma;
protected VICDriver m_vic;
protected int m_using_dma;
// size of the DDR channel buffer
protected const uint32_t TDC_CHANNEL_BUFFER_SIZE_BYTES = 'h100000;
protected const int dma_buf_ddr_burst_size_default = 16;
fmc_tdc_timestamp_queue_t m_queues[5];
// buffer descriptor, as in the driver
typedef struct
{
uint32_t addr[2];
uint32_t active_buffer;
uint32_t size;
uint32_t host_mem_addr;
int total_timestamps;
} tdc_dma_buffer_t;
protected tdc_dma_buffer_t m_buffers[5];
// Gennum DMA IRQ handler - just forward to the Gennum driver
task automatic irq_gennum_dma();
$display("[Info] Handling GN4124 DMA IRQ");
m_gennum_dma.irq_dma_complete();
endtask // irq_gennum_dma
// TDC Core IRQ handler
task automatic irq_tdc_core();
uint32_t isr;
int i;
$display("[Info] Handling TDC Buffer IRQ");
read32(`OFFSET_TDC_EIC + `ADDR_TDC_EIC_EIC_ISR, isr);
// check DMA interrupts, call handler for the buffer(s) for which IRQ(s)
// is/are pending
for(int i = 0; i < 5; i++)
if( isr & ( 1<< (`TDC_EIC_EIC_ISR_TDC_DMA1_OFFSET + i) ) )
irq_dma_buffer(i);
endtask // irq_tdc_core
// IRQ handler for a single DMA buffer
task automatic irq_dma_buffer(int channel);
uint32_t count;
int transfer_buffer;
// tell the TDC to start putting samples in the other buffer so that
// continuous acquisition can be possible
buffer_switch(channel, transfer_buffer);
// Once the buffer is switched, read how many samples we ahve in the previous
// buffer
buffer_get_count(channel , count );
$display("DMA Buffer IRQ: %d, count %d", channel, count);
if( m_gennum_dma.is_dma_pending() )
begin
$error("[Error] Trying to trigger DMA transfer while previous transfer is still pending");
return;
end
// each timestamp is 16 bytes, trigger the gennum DMA xfer
m_gennum_dma.dma_to_host( m_buffers[channel].addr[transfer_buffer],
m_buffers[channel].host_mem_addr, count * 16 );
m_buffers[channel].host_mem_addr += count * 16;
m_buffers[channel].total_timestamps += count;
endtask // irq_dma_buffer
function int get_ts_count(int channel);
return m_buffers[channel].total_timestamps;
endfunction // get_ts_count
function VICDriver get_vic();
return m_vic;
endfunction // get_vic
function new(CBusAccessor bus);
super.new(bus, `BASE_TDC_CORE );
// create the necessary sub-peripherals (VIC and GN4124)
m_vic = new (bus, `BASE_VIC );
m_gennum_dma = new (bus, `BASE_GENNUM_DMA);
m_using_dma = 0;
endfunction // new
task automatic buffer_get_count(int channel, output uint32_t count);
uint32_t base = `OFFSET_TDC_BUFFER_CONTROLLER + ('h40 * channel);
read32( base + `ADDR_TDC_BUF_CUR_COUNT, count );
endtask // buffer_get_count
task automatic buffer_burst_disable(int channel);
uint32_t tmp;
uint32_t base = `OFFSET_TDC_BUFFER_CONTROLLER + ('h40 * channel);
read32( base + `ADDR_TDC_BUF_CSR, tmp );
tmp &= ~`TDC_BUF_CSR_ENABLE;
write32(base + `ADDR_TDC_BUF_CSR, tmp );
endtask // buffer_burst_disable
task automatic buffer_burst_enable(int channel);
uint32_t tmp;
uint32_t base = `OFFSET_TDC_BUFFER_CONTROLLER + ('h40 * channel);
read32( base + `ADDR_TDC_BUF_CSR, tmp );
tmp |= `TDC_BUF_CSR_ENABLE;
write32( base + `ADDR_TDC_BUF_CSR, tmp );
endtask // buffer_burst_disable
task automatic buffer_burst_size_set(int channel, int size);
uint32_t tmp;
uint32_t base = `OFFSET_TDC_BUFFER_CONTROLLER + ('h40 * channel);
read32( base + `ADDR_TDC_BUF_CSR, tmp );
tmp &= ~`TDC_BUF_CSR_BURST_SIZE;
tmp |= size << `TDC_BUF_CSR_BURST_SIZE_OFFSET;
write32( base + `ADDR_TDC_BUF_CSR, tmp );
endtask // buffer_burst_size_set
task automatic buffer_irq_timeout_set(int channel, int tmo);
uint32_t tmp;
uint32_t base = `OFFSET_TDC_BUFFER_CONTROLLER + ('h40 * channel);
read32( base + `ADDR_TDC_BUF_CSR, tmp );
tmp &= ~`TDC_BUF_CSR_IRQ_TIMEOUT;
tmp |= tmo << `TDC_BUF_CSR_IRQ_TIMEOUT_OFFSET;
write32( base + `ADDR_TDC_BUF_CSR, tmp );
endtask // buffer_burst_size_set
task automatic buffer_switch(int channel, output int transfer_buffer);
uint32_t csr;
uint32_t base = `OFFSET_TDC_BUFFER_CONTROLLER + ('h40 * channel);
uint32_t base_cur;
read32( base + `ADDR_TDC_BUF_CSR, csr );
csr |= `TDC_BUF_CSR_SWITCH_BUFFERS;
write32( base + `ADDR_TDC_BUF_CSR, csr );
/*
* It waits until all pending DDR memory transactions from the active
* buffer are committed to the memory.
* This is almost instant (e.g. < 1us), but we never know with
* the PCs going ever faster
*/
forever begin
read32( base + `ADDR_TDC_BUF_CSR, csr );
if( csr & `TDC_BUF_CSR_DONE )
break;
end
/* clear CSR.DONE flag (write 1) */
read32( base + `ADDR_TDC_BUF_CSR, csr );
csr |= `TDC_BUF_CSR_DONE;
write32( base + `ADDR_TDC_BUF_CSR, csr );
/*
* we have two buffers in the hardware: the current one and the 'next'
* one. From the point of view of this interrupt handler, the current
* one is to be read out and switched to the 'next' buffer.,
*/
transfer_buffer = m_buffers[channel].active_buffer;
base_cur = m_buffers[channel].addr [ m_buffers[channel].active_buffer ];
m_buffers[channel].active_buffer = 1 - m_buffers[channel].active_buffer;
/* update the pointer to the next buffer */
write32( base + `ADDR_TDC_BUF_NEXT_BASE, base_cur);
write32( base + `ADDR_TDC_BUF_NEXT_SIZE, m_buffers[channel].size | `TDC_BUF_NEXT_SIZE_VALID );
endtask // buffer_switch
task automatic configure_buffers();
int channel;
uint32_t rv, val;
for(channel=0;channel<5;channel++)
begin
uint32_t base = `OFFSET_TDC_BUFFER_CONTROLLER + ('h40 * channel);
m_buffers[channel].active_buffer = 0;
m_buffers[channel].host_mem_addr = `BASE_HOST_MEM + channel * 'h1000000; // reserve a lot of host memory for each channel
m_buffers[channel].total_timestamps = 0;
m_buffers[channel].size = TDC_CHANNEL_BUFFER_SIZE_BYTES;
buffer_burst_disable(channel);
/* Buffer 1 */
m_buffers[channel].addr[0] = TDC_CHANNEL_BUFFER_SIZE_BYTES * (2 * channel);
write32 ( base + `ADDR_TDC_BUF_CUR_BASE, m_buffers[channel].addr[0] );
val = (m_buffers[channel].size << `TDC_BUF_CUR_SIZE_SIZE_OFFSET);
val |= `TDC_BUF_CUR_SIZE_VALID;
write32( base + `ADDR_TDC_BUF_CUR_SIZE, val );
// writel
task automatic writel(uint32_t addr, uint32_t value);
m_acc.write(addr + m_base ,value);
//$display("[Info] writel %x: %x", addr+m_base, value);
endtask
/* Buffer 2 */
m_buffers[channel].addr[1] = TDC_CHANNEL_BUFFER_SIZE_BYTES * (2 * channel + 1);
write32 ( base + `ADDR_TDC_BUF_NEXT_BASE, m_buffers[channel].addr[1] );
// readl
task automatic readl( uint32_t addr, ref uint32_t value );
automatic uint64_t rv;
m_acc.read(addr + m_base , rv);
//$display("[Info] readl %x: %x", addr+m_base, rv);
value = rv;
endtask
val = (m_buffers[channel].size << `TDC_BUF_NEXT_SIZE_SIZE_OFFSET);
val |= `TDC_BUF_NEXT_SIZE_VALID;
write32 ( base + `ADDR_TDC_BUF_NEXT_SIZE, val );
buffer_burst_size_set(channel, dma_buf_ddr_burst_size_default);
buffer_irq_timeout_set(channel, 3);
buffer_burst_enable(channel);
$display("[Info] Config channel %d: base = %x buf[0] = 0x%08x, buf[1] = 0x%08x, %d timestamps per buffer",
channel, base, m_buffers[channel].addr[0],
m_buffers[channel].addr[1],
m_buffers[channel].size );
read32( base + `ADDR_TDC_BUF_CSR, val);
end // for (channel=0;channel<5;channel++)
endtask // configure_buffers
// init
task automatic init();
uint32_t d;
// we need at least these 2 IRQs to test DMA transfers:
$display("[Info] Init VIC");
m_vic.init();
m_vic.enable_irqs( (1<<`VIC_IRQ_GENNUM_DMA) | (1<<`VIC_IRQ_TDC_CORE ) );
$display("[Info] TDC core base addr: %x", m_base);
readl('h0, d);
read32('h0, d);
if( d != 'h5344422d )
begin
$error("[Error!] Can't read the SDB signature, reading: %x.", d);
......@@ -74,60 +483,75 @@ class FmcTdcDriver;
$display("[Info] Found the SDB signature: %x", d);
end
// Configure the EIC for an interrupt on FIFO
writel(`TDC_EIC_BASE + `ADDR_TDC_EIC_EIC_IER, 'h1F);
// Configure the VIC
writel(`VIC_BASE + `ADDR_VIC_IER, 'h7f);
writel(`VIC_BASE + `ADDR_VIC_CTL, 'h1);
// Configure the TDC
$display("[Info] Setting up TDC core..");
writel(`ADDR_TDC_CORE_CSR_UTC+`TDC_CORE_CFG_BASE, 1234); // set UTC
writel(`ADDR_TDC_CORE_CSR_CTRL+`TDC_CORE_CFG_BASE, 1<<9); // load UTC
writel(`ADDR_TDC_CORE_CSR_ENABLE+`TDC_CORE_CFG_BASE, 'h1f0000); // enable all ACAM inputs
writel(`ADDR_TDC_CORE_CSR_IRQ_TSTAMP_THRESH+`TDC_CORE_CFG_BASE, 2); // FIFO threshold = 2 ts
writel(`ADDR_TDC_CORE_CSR_IRQ_TIME_THRESH+`TDC_CORE_CFG_BASE, 2); // FIFO threshold = 2 ms
writel(`ADDR_TDC_CORE_CSR_CTRL+`TDC_CORE_CFG_BASE, (1<<0)); // start acquisition
writel('h20bc, ((-1)<<1)); // test?
write32(`ADDR_TDC_CORE_CSR_UTC+`OFFSET_TDC_CORE_CFG, 1234); // set UTC
write32(`ADDR_TDC_CORE_CSR_CTRL+`OFFSET_TDC_CORE_CFG, 1<<9); // load UTC
write32(`ADDR_TDC_CORE_CSR_IRQ_TSTAMP_THRESH+`OFFSET_TDC_CORE_CFG, 2); // FIFO threshold = 2 ts
write32(`ADDR_TDC_CORE_CSR_IRQ_TIME_THRESH+`OFFSET_TDC_CORE_CFG, 2); // FIFO threshold = 2 ms
write32('h20bc, ((-1)<<1)); // test?
$display("[Info] TDC acquisition started");
endtask // init
task automatic start_acquisition( int use_dma );
m_using_dma = use_dma;
if( use_dma )
begin
// allocate memory ranges for DDR acquisition buffers for each channel
configure_buffers();
// Configure the EIC for an interrupt on DMA buffer
write32(`OFFSET_TDC_EIC + `ADDR_TDC_EIC_EIC_IER, 'h1F << 5);
$display("[Info] Starting acquisition in DMA mode");
end else begin
write32(`OFFSET_TDC_EIC + `ADDR_TDC_EIC_EIC_IER, 'h1F); // enable FIFO irq
// fixme: FIFO mode not supported
end
endtask
write32(`ADDR_TDC_CORE_CSR_ENABLE+`OFFSET_TDC_CORE_CFG, 'h1f0000); // enable all ACAM inputs
write32(`ADDR_TDC_CORE_CSR_CTRL+`OFFSET_TDC_CORE_CFG, (1<<0)); // start acquisition
endtask // start_acquisition
// update
task automatic update();
// fixme: likely doesn't work
task automatic readout_fifo();
automatic uint32_t csr, t[4];
for(int i = 0; i < 1; i++) //(int i = 0; i < 5; i++)
begin
automatic uint32_t FIFObase = `FIFO1_BASE + i * 'h100;
automatic fmc_tdc_timestamp_t ts, ts1, ts2;
for(int i = 0; i < 1; i++) //(int i = 0; i < 5; i++)
begin
automatic uint32_t FIFObase = `OFFSET_TDC_FIFO1 + i * 'h100;
automatic fmc_tdc_timestamp_t ts, ts1, ts2;
readl(FIFObase + `ADDR_TSF_FIFO_CSR, csr);
//$display("!!!csr %x: %x", FIFObase + `ADDR_TSF_FIFO_CSR, csr);
read32(FIFObase + `ADDR_TSF_FIFO_CSR, csr);
//$display("!!!csr %x: %x", FIFObase + `ADDR_TSF_FIFO_CSR, csr);
if( ! (csr & `TSF_FIFO_CSR_EMPTY ) ) begin
//$display("!!!FIFO not empty!!! csr %x; empty: %x", csr, `TSF_FIFO_CSR_EMPTY);
readl(FIFObase + `ADDR_TSF_FIFO_R0, t[0]);
readl(FIFObase + `ADDR_TSF_FIFO_R1, t[1]);
readl(FIFObase + `ADDR_TSF_FIFO_R2, t[2]);
readl(FIFObase + `ADDR_TSF_FIFO_R3, t[3]);
ts.tai = t[0];
ts.coarse = t[1];
ts.frac = t[2] & 'hfff;
ts.slope = t[3] & 'h8 ? 1: 0;
ts.seq = t[3] >> 4;
ts.channel = i;
m_queues[i].push_back(ts);
//$display("!!!Pushed in FIFO!!!");
end
end // for (int i = 0; i < 5; i++)
endtask // update
if( ! (csr & `TSF_FIFO_CSR_EMPTY ) ) begin
//$display("!!!FIFO not empty!!! csr %x; empty: %x", csr, `TSF_FIFO_CSR_EMPTY);
read32(FIFObase + `ADDR_TSF_FIFO_R0, t[0]);
read32(FIFObase + `ADDR_TSF_FIFO_R1, t[1]);
read32(FIFObase + `ADDR_TSF_FIFO_R2, t[2]);
read32(FIFObase + `ADDR_TSF_FIFO_R3, t[3]);
ts.tai = t[0];
ts.coarse = t[1];
ts.frac = t[2] & 'hfff;
ts.slope = t[3] & 'h8 ? 1: 0;
ts.seq = t[3] >> 4;
ts.channel = i;
m_queues[i].push_back(ts);
//$display("!!!Pushed in FIFO!!!");
end
end // for (int i = 0; i < 5; i++)
endtask // update
task automatic readout_dma();
endtask // readout_dma
function int poll();
//$display("[Info] m_queues[0].size: %d", m_queues[0].size());
return (m_queues[0].size() > 2);
......@@ -137,42 +561,187 @@ class FmcTdcDriver;
return m_queues[0].pop_front();
endfunction // get
// update DMA i/f
task automatic update_dma();
automatic uint32_t DMA_CH_base = `TDC_DMA_BASE + 'h100;
automatic uint32_t dma_pos, dma_len;
// read position?
//readl(`DMA_CH_base + `POS, dma_pos); position in DDR /////
$display("<%t> Start DMA, position in DDR: %.8x", $realtime, dma_pos);
// read length?
//readl(`DMA_CH_base + `POS, dma_len); position in DDR /////
$display("<%t> Start DMA, position in DDR: %.8x", $realtime, dma_len);
endclass // FmcTdcDriver
// DMA transfer
writel(`DMA_BASE + `ADDR_DMA_CSTART, dma_pos); // dma start addr
// Master IRQ dispatcher for the SPEC - TDC
class FmcTdcSPECIrqHandler extends IrqHandler;
FmcTdcSPECDriver m_driver;
function new ( FmcTdcSPECDriver drv );
m_driver = drv;
endfunction
writel(`DMA_BASE + `ADDR_DMA_HSTARTL, 'h00001000); // host addr
writel(`DMA_BASE + `ADDR_DMA_HSTARTH, 'h00000000);
// this gets called by IrqLine when the gn_gpio(0) is asserted.
task irq(int id);
uint32_t irq_id;
VICDriver vic = m_driver.get_vic();
// read the pending IRQ ID from the VIC
vic.get_pending_irq(irq_id);
$display("[Info] VIC got irq %d", irq_id);
// dispatch it to the right handler
case(irq_id)
`VIC_IRQ_GENNUM_DMA:
m_driver.irq_gennum_dma();
`VIC_IRQ_TDC_CORE:
m_driver.irq_tdc_core();
default:
$error("[Error] spurious VIC irq %d", irq_id);
endcase // case (irq_id)
// clear IRQ
vic.clear_pending_irq(irq_id);
endtask // irq
endclass // IrqHandler
// module that observes an interrupt line and if it's asserted
// calls a handler (IrqHandler object) set through set_handler() method.
module IRQLine (
input irq_i
);
// length =
writel(`DMA_BASE + `ADDR_DMA_LEN, dma_len); // length
IrqHandler m_handler;
task set_handler(IrqHandler h);
m_handler = h;
endtask // set_handler
writel(`DMA_BASE + `ADDR_DMA_NEXTL, 'h00000000); // next
writel(`DMA_BASE + `ADDR_DMA_NEXTH, 'h00000000);
initial forever
begin
if(!irq_i)
@(posedge irq_i);
writel(`DMA_BASE + `ADDR_DMA_ATTRIB, 'h00000000); // attrib: pcie -> host
if(irq_i)
begin
while(irq_i && m_handler)
begin
m_handler.irq(0);
#5us; // give some grace...
end
end else
#100ns;
end
endmodule // IRQLine
module WBBusMonitor
#(
parameter g_data_width = 32,
parameter g_addr_width = 32,
parameter string g_name = "")
(
input clk_i,
input rst_n_i,
input [g_addr_width-1:0] wb_adr_i,
input [g_data_width-1:0] wb_dat_i_i,
input [g_data_width-1:0] wb_dat_o_i,
input wb_stall_i,
input wb_ack_i,
input wb_cyc_i,
input wb_stb_i,
input wb_we_i
);
writel(`DMA_BASE + `ADDR_DMA_ATTRIB, 'h00000001); // xfer start
reg inside_cycle = 0;
//wait (DUT.inst_spec_base.irqs[2]);
$display("<%t> END DMA", $realtime);
writel(`DMA_BASE + `ADDR_DMA_STAT, 'h04); // clear DMA IRQ
writel(`VIC_BASE + `ADDR_DMA_NEXTH, 'h0);
endtask // update_dma
typedef struct
{
bit [g_addr_width-1:0] addr;
bit [g_addr_width-1:0] data;
int is_write;
} request_t;
request_t reqs[$];
endclass // FmcTdcDriver
always@(posedge clk_i)
if(!rst_n_i)
begin
inside_cycle <= 0;
reqs= '{};
end else begin
if(wb_cyc_i)
begin
if(!inside_cycle)
begin
$display("[wbmon-%s] Start cycle", g_name);
inside_cycle <= 1;
reqs = '{};
end
if(wb_stb_i && !wb_stall_i)
begin
if(wb_we_i)
begin
automatic request_t req;
req.addr = wb_adr_i;
req.data = wb_dat_i_i;
req.is_write = 1;
reqs.push_back(req);
end
else
begin
automatic request_t req;
req.addr = wb_adr_i;
req.is_write = 0;
reqs.push_back(req);
end
end
if(wb_ack_i)
begin
automatic request_t req = reqs[0];
reqs.pop_front();
if(req.is_write)
$display("[wbmon-%s] Write %08x = %08x", g_name, req.addr, req.data);
else
$display("[wbmon-%s] Read %08x = %08x", g_name, req.addr, wb_dat_o_i);
end
end else begin
if(inside_cycle)
begin
$display("[wbmon-%s] End cycle", g_name);
inside_cycle <= 0;
reqs= '{};
end
end // else: !if(wb_cyc_i)
end
endmodule // WBBusMonitor
//////////////// main ////////////////
......@@ -217,6 +786,13 @@ module main;
wire [2:0] ddr_ba;
wire ddr_rzq;
reg sim_ts_valid = 0;
wire sim_ts_ready;
t_tdc_timestamp sim_ts;
`ifdef USE_ACAM_MODEL
// ACAM model instantiation
tdc_gpx_model
......@@ -252,85 +828,98 @@ module main;
.D(tdc_data)
);
`endif // !`ifdef USE_ACAM_MODEL
// GN4124 model instantiation
IGN4124PCIMaster Host ();
wire [1:0] gn_gpio;
// TDC core instantiation
wr_spec_tdc
#(
.g_simulation(1)
.g_simulation(1),
.g_use_fake_timestamps_for_sim(1)
) DUT (
.clk_125m_pllref_p_i(clk_125m),
.clk_125m_pllref_n_i(~clk_125m),
.clk_125m_gtp_p_i(clk_125m),
.clk_125m_gtp_n_i(~clk_125m),
.fmc0_tdc_clk_125m_p_i(clk_125m),
.fmc0_tdc_clk_125m_n_i(~clk_125m),
.fmc0_tdc_acam_refclk_p_i(clk_acam),
.fmc0_tdc_acam_refclk_n_i(~clk_acam),
.clk_20m_vcxo_i(clk_20m),
.fmc0_tdc_pll_status_i(1'b1),
.fmc0_tdc_ef1_i(tdc_ef1),
.fmc0_tdc_ef2_i(tdc_ef2),
.fmc0_tdc_err_flag_i(tdc_err_flag),
.fmc0_tdc_int_flag_i(tdc_int_flag),
.fmc0_tdc_rd_n_o(tdc_rd_n),
.fmc0_tdc_wr_n_o(tdc_wr_n),
.fmc0_tdc_oe_n_o(tdc_oe_n),
.fmc0_tdc_cs_n_o(tdc_cs_n),
.fmc0_tdc_data_bus_io(tdc_data),
.fmc0_tdc_address_o(tdc_addr),
.fmc0_tdc_start_from_fpga_o(tdc_start),
.fmc0_tdc_start_dis_o(tdc_start_dis),
.fmc0_tdc_stop_dis_o(tdc_stop_dis[1]),
//`GENNUM_WIRE_SPEC_BTRAIN_REF(Host)
.gn_rst_n_i (Host.rst_n),
.gn_p2l_clk_n_i (Host.p2l_clk_n),
.gn_p2l_clk_p_i (Host.p2l_clk_p),
.gn_p2l_rdy_o (Host.p2l_rdy),
.gn_p2l_dframe_i (Host.p2l_dframe),
.gn_p2l_valid_i (Host.p2l_valid),
.gn_p2l_data_i (Host.p2l_data),
.gn_p_wr_req_i (Host.p_wr_req),
.gn_p_wr_rdy_o (Host.p_wr_rdy),
.gn_rx_error_o (Host.rx_error),
.gn_l2p_clk_n_o (Host.l2p_clk_n),
.gn_l2p_clk_p_o (Host.l2p_clk_p),
.gn_l2p_dframe_o (Host.l2p_dframe),
.gn_l2p_valid_o (Host.l2p_valid),
.gn_l2p_edb_o (Host.l2p_edb),
.gn_l2p_data_o (Host.l2p_data),
.gn_l2p_rdy_i (Host.l2p_rdy),
.gn_l_wr_rdy_i (Host.l_wr_rdy),
.gn_p_rd_d_rdy_i (Host.p_rd_d_rdy),
.gn_tx_error_i (Host.tx_error),
.gn_vc_rdy_i (Host.vc_rdy),
.gn_gpio_b (),
.ddr_a_o (ddr_a),
.ddr_ba_o (ddr_ba),
.ddr_cas_n_o (ddr_cas_n),
.ddr_ck_n_o (ddr_ck_n),
.ddr_ck_p_o (ddr_ck_p),
.ddr_cke_o (ddr_cke),
.ddr_dq_b (ddr_dq),
.ddr_ldm_o (ddr_dm[0]),
.ddr_ldqs_n_b (ddr_dqs_n[0]),
.ddr_ldqs_p_b (ddr_dqs_p[0]),
.ddr_odt_o (ddr_odt),
.ddr_ras_n_o (ddr_ras_n),
.ddr_reset_n_o (ddr_reset_n),
.ddr_rzq_b (ddr_rzq),
.ddr_udm_o (ddr_dm[1]),
.ddr_udqs_n_b (ddr_dqs_n[1]),
.ddr_udqs_p_b (ddr_dqs_p[1]),
.ddr_we_n_o (ddr_we_n)
);
.clk_125m_pllref_p_i(clk_125m),
.clk_125m_pllref_n_i(~clk_125m),
.clk_125m_gtp_p_i(clk_125m),
.clk_125m_gtp_n_i(~clk_125m),
.fmc0_tdc_clk_125m_p_i(clk_125m),
.fmc0_tdc_clk_125m_n_i(~clk_125m),
.fmc0_tdc_acam_refclk_p_i(clk_acam),
.fmc0_tdc_acam_refclk_n_i(~clk_acam),
.clk_20m_vcxo_i(clk_20m),
.fmc0_tdc_pll_status_i(1'b1),
.fmc0_tdc_ef1_i(tdc_ef1),
.fmc0_tdc_ef2_i(tdc_ef2),
.fmc0_tdc_err_flag_i(tdc_err_flag),
.fmc0_tdc_int_flag_i(tdc_int_flag),
.fmc0_tdc_rd_n_o(tdc_rd_n),
.fmc0_tdc_wr_n_o(tdc_wr_n),
.fmc0_tdc_oe_n_o(tdc_oe_n),
.fmc0_tdc_cs_n_o(tdc_cs_n),
.fmc0_tdc_data_bus_io(tdc_data),
.fmc0_tdc_address_o(tdc_addr),
.fmc0_tdc_start_from_fpga_o(tdc_start),
.fmc0_tdc_start_dis_o(tdc_start_dis),
.fmc0_tdc_stop_dis_o(tdc_stop_dis[1] ),
//`GENNUM_WIRE_SPEC_BTRAIN_REF(Host)
.gn_rst_n_i (Host.rst_n),
.gn_p2l_clk_n_i (Host.p2l_clk_n),
.gn_p2l_clk_p_i (Host.p2l_clk_p),
.gn_p2l_rdy_o (Host.p2l_rdy),
.gn_p2l_dframe_i (Host.p2l_dframe),
.gn_p2l_valid_i (Host.p2l_valid),
.gn_p2l_data_i (Host.p2l_data),
.gn_p_wr_req_i (Host.p_wr_req),
.gn_p_wr_rdy_o (Host.p_wr_rdy),
.gn_rx_error_o (Host.rx_error),
.gn_l2p_clk_n_o (Host.l2p_clk_n),
.gn_l2p_clk_p_o (Host.l2p_clk_p),
.gn_l2p_dframe_o (Host.l2p_dframe),
.gn_l2p_valid_o (Host.l2p_valid),
.gn_l2p_edb_o (Host.l2p_edb),
.gn_l2p_data_o (Host.l2p_data),
.gn_l2p_rdy_i (Host.l2p_rdy),
.gn_l_wr_rdy_i (Host.l_wr_rdy),
.gn_p_rd_d_rdy_i (Host.p_rd_d_rdy),
.gn_tx_error_i (Host.tx_error),
.gn_vc_rdy_i (Host.vc_rdy),
.gn_gpio_b (gn_gpio),
.ddr_a_o (ddr_a),
.ddr_ba_o (ddr_ba),
.ddr_cas_n_o (ddr_cas_n),
.ddr_ck_n_o (ddr_ck_n),
.ddr_ck_p_o (ddr_ck_p),
.ddr_cke_o (ddr_cke),
.ddr_dq_b (ddr_dq),
.ddr_ldm_o (ddr_dm[0]),
.ddr_ldqs_n_b (ddr_dqs_n[0]),
.ddr_ldqs_p_b (ddr_dqs_p[0]),
.ddr_odt_o (ddr_odt),
.ddr_ras_n_o (ddr_ras_n),
.ddr_reset_n_o (ddr_reset_n),
.ddr_rzq_b (ddr_rzq),
.ddr_udm_o (ddr_dm[1]),
.ddr_udqs_n_b (ddr_dqs_n[1]),
.ddr_udqs_p_b (ddr_dqs_p[1]),
.ddr_we_n_o (ddr_we_n),
.sim_timestamp_valid_i(sim_ts_valid),
.sim_timestamp_ready_o(sim_ts_ready),
.sim_timestamp_i(sim_ts)
);
// DDR3 model instantiation
ddr3 #
......@@ -359,7 +948,88 @@ module main;
.odt (ddr_odt)
);
`ifndef USE_ACAM_MODEL
// loop that produces fake timestamps. We're not using ACAM here, instead
// the sim_ts inputs (simulation only) of the SPEC top level are routed directly
// to the acquisition core. This speeds up the simulation and also allows to check
// the data integrity of acquisition alone without bothering with all the math associated
// with conversion of the data coming from the ACAM chip.
FakeTimestampGenerator fakeTsGen;
initial
begin
fakeTsGen = new( 0 );
forever begin
while(!fakeTsGen.is_enabled())
repeat(100) @(posedge DUT.clk_sys_62m5);
sim_ts <= fakeTsGen.generate_hw_timestamp(0);
sim_ts_valid <= 1;
@(posedge DUT.clk_sys_62m5);
while(!sim_ts_ready)
@(posedge DUT.clk_sys_62m5);
sim_ts_valid <= 0;
@(posedge DUT.clk_sys_62m5);
// wait for some idle time, don't bomb the design with too many timestamps ;-)
repeat(100) @(posedge DUT.clk_sys_62m5);
end
end // initial begin
`endif
IRQLine
irq_line_gennum_master
(
.irq_i(gn_gpio[0])
);
WBBusMonitor
#(
.g_name("dma-ch0")
)
U_Mon_CH0
(
.clk_i(DUT.clk_sys_62m5),
.rst_n_i(DUT.rst_sys_62m5_n),
.wb_cyc_i(DUT.inst_spec_base.ddr_dma_wb_cyc_i),
.wb_adr_i(DUT.inst_spec_base.ddr_dma_wb_adr_i),
.wb_stb_i(DUT.inst_spec_base.ddr_dma_wb_stb_i),
.wb_we_i(DUT.inst_spec_base.ddr_dma_wb_we_i),
.wb_dat_i_i(DUT.inst_spec_base.ddr_dma_wb_dat_i),
.wb_ack_i(DUT.inst_spec_base.ddr_dma_wb_ack_o),
.wb_stall_i(DUT.inst_spec_base.ddr_dma_wb_stall_o)
);
WBBusMonitor
#(
.g_name("gennum-ddr")
)
U_Mon_DDR2Gennum
(
.clk_i(DUT.clk_sys_62m5),
.rst_n_i(DUT.rst_sys_62m5_n),
.wb_cyc_i(DUT.inst_spec_base.gen_with_ddr.cmp_ddr_ctrl_bank3.wb1_cyc_i),
.wb_adr_i(DUT.inst_spec_base.gen_with_ddr.cmp_ddr_ctrl_bank3.wb1_addr_i),
.wb_stb_i(DUT.inst_spec_base.gen_with_ddr.cmp_ddr_ctrl_bank3.wb1_stb_i),
.wb_we_i(DUT.inst_spec_base.gen_with_ddr.cmp_ddr_ctrl_bank3.wb1_we_i),
.wb_dat_o_i(DUT.inst_spec_base.gen_with_ddr.cmp_ddr_ctrl_bank3.wb1_data_o),
.wb_ack_i(DUT.inst_spec_base.gen_with_ddr.cmp_ddr_ctrl_bank3.wb1_ack_o),
.wb_stall_i(DUT.inst_spec_base.gen_with_ddr.cmp_ddr_ctrl_bank3.wb1_stall_o)
);
assign tdc_stop_dis[4] = tdc_stop_dis[1];
assign tdc_stop_dis[3] = tdc_stop_dis[1];
......@@ -368,52 +1038,96 @@ module main;
// initial
initial begin
CBusAccessor acc;
FmcTdcDriver drv;
uint64_t d;
acc = Host.get_accessor();
#5us;
// test read
acc.read('h2208c, d);
CBusAccessor acc;
FmcTdcSPECDriver drv;
FmcTdcSPECIrqHandler irq_handler;
int i;
uint64_t d;
acc = Host.get_accessor();
drv = new (acc);
irq_handler = new(drv);
$display("Waiting for the DDR3 controller to bootstrap...");
#4us;
// fixme: poll SPEC reigsters...
$display("DDR3 calibration complete");
// connect the Gennum IRQ line to FMC TDC Driver interrupt routing
irq_line_gennum_master.set_handler( irq_handler );
// init the board
drv.init();
// start acquisition
drv.start_acquisition( 1 );
`ifndef USE_ACAM_MODEL
fakeTsGen.enable(1); // generate a bunch of fake timestamps
`endif
// let it run for a while
#200us;
`ifndef USE_ACAM_MODEL
fakeTsGen.enable(0);
`endif
#50us; // fixme: check if all dma xfers are done instead of dumb wait
// device instantiation
drv = new (acc, `TDC_CORE_BASE, 0 );
drv.init();
// Read back. The verification of DDR timestamps against the ones in the queue of FakeTimestampGenerator is left to the reader ;-)
$display("[Info] Channel 0 got %d timestamps", drv.get_ts_count(0) );
$display("HOST MEM DUMP: ");
for(i=0;i<drv.get_ts_count(0) * 4; i++)
begin
uint64_t rv;
Host.host_mem_read(i*8, rv);
$display("hostMem[0x%08x]=0x%016x", i*8, rv);
end
/*
$display("[Info] Start operation");
fork
forever begin
drv.update();
if(drv.poll()) begin
fmc_tdc_timestamp_t ts1, ts2;
uint64_t timestmp1, timestmp2, diff;
ts1 = drv.get();
timestmp1 = ts1.tai*1e12 + ts1.coarse*8e3 + ts1.frac*81.03;
$display("[Info] ts%d [%d:%d:%d src %d, slp: %d]: %d ps", ts1.seq, ts1.tai, ts1.coarse, ts1.frac, ts1.channel, ts1.slope, timestmp1);
ts2 = drv.get();
timestmp2 = ts2.tai*1e12 + ts2.coarse*8e3 + ts2.frac*81.03;
$display("[Info] ts%d [%d:%d:%d src %d, slp: %d]: %d ps", ts2.seq, ts2.tai, ts2.coarse, ts2.frac, ts2.channel, ts2.slope, timestmp2);
if (timestmp1 > timestmp2) begin
diff = timestmp1 - timestmp2;
$display("[Info] Period: ts%d - ts%d: %d", ts1.seq, ts2.seq, diff);
end else begin
diff = timestmp2 - timestmp1;
$display("[Info] Period: ts%d - ts%d: %d", ts2.seq, ts1.seq, diff);
end
end
end
forever begin
// generate pulses to TDC channel 1
fork
forever begin
drv.readout_fifo();
if(drv.poll()) begin
fmc_tdc_timestamp_t ts1, ts2;
uint64_t timestmp1, timestmp2, diff;
ts1 = drv.get();
timestmp1 = ts1.tai*1e12 + ts1.coarse*8e3 + ts1.frac*81.03;
$display("[Info] ts%d [%d:%d:%d src %d, slp: %d]: %d ps", ts1.seq, ts1.tai, ts1.coarse, ts1.frac, ts1.channel, ts1.slope, timestmp1);
ts2 = drv.get();
timestmp2 = ts2.tai*1e12 + ts2.coarse*8e3 + ts2.frac*81.03;
$display("[Info] ts%d [%d:%d:%d src %d, slp: %d]: %d ps", ts2.seq, ts2.tai, ts2.coarse, ts2.frac, ts2.channel, ts2.slope, timestmp2);
if (timestmp1 > timestmp2) begin
diff = timestmp1 - timestmp2;
$display("[Info] Period: ts%d - ts%d: %d", ts1.seq, ts2.seq, diff);
end else begin
diff = timestmp2 - timestmp1;
$display("[Info] Period: ts%d - ts%d: %d", ts2.seq, ts1.seq, diff);
end
end
end
forever begin
// generate pulses to TDC channel 1
#700ns;
tdc_stop[1] <= 1;
#300ns;
tdc_stop[1] <= 0;
end
join
end
join
*/
end
endmodule // main
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -400,7 +400,7 @@ architecture rtl of wr_spec_tdc is
end if;
end f_to_string;
signal dma_reg_adr : std_logic_vector(31 downto 0);
signal dma_wb_adr : std_logic_vector(31 downto 0);
......@@ -409,6 +409,8 @@ architecture rtl of wr_spec_tdc is
--=================================================================================================
begin
dma_wb_adr <= "00" & fmc0_wb_ddr_out.adr(31 downto 2);
-- synthesis translate_off
sim_ts <= sim_timestamp_i;
sim_ts_valid <= sim_timestamp_valid_i;
......@@ -556,11 +558,11 @@ begin
ddr_udqs_p_b => ddr_udqs_p_b,
ddr_we_n_o => ddr_we_n_o,
----------------------------------
ddr_dma_clk_i => clk_ref_125m,
ddr_dma_rst_n_i => rst_ref_125m_n,
ddr_dma_clk_i => clk_sys_62m5,
ddr_dma_rst_n_i => rst_sys_62m5_n,
ddr_dma_wb_cyc_i => fmc0_wb_ddr_out.cyc,
ddr_dma_wb_stb_i => fmc0_wb_ddr_out.stb,
ddr_dma_wb_adr_i => fmc0_wb_ddr_out.adr,
ddr_dma_wb_adr_i => dma_wb_adr,
ddr_dma_wb_sel_i => fmc0_wb_ddr_out.sel,
ddr_dma_wb_we_i => fmc0_wb_ddr_out.we,
ddr_dma_wb_dat_i => fmc0_wb_ddr_out.dat,
......@@ -705,7 +707,13 @@ begin
dma_wb_o => fmc0_wb_ddr_out,
irq_o => irq_vector(0),
clk_125m_tdc_o => tdc0_clk_125m);
clk_125m_tdc_o => tdc0_clk_125m,
sim_timestamp_i => sim_ts,
sim_timestamp_valid_i => sim_ts_valid,
sim_timestamp_ready_o => sim_ts_ready
);
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
fmc0_wb_ddr_in.err <= '0';
......
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