Commit 8b800231 authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

first version with per-channel FIFOs instead of a shared circular buffer

parent 4e08d33b
......@@ -3,7 +3,6 @@ files = [
"acam_databus_interface.vhd",
"acam_timecontrol_interface.vhd",
"carrier_info.vhd",
"circular_buffer.vhd",
"clks_rsts_manager.vhd",
"data_engine.vhd",
"data_formatting.vhd",
......@@ -12,7 +11,6 @@ files = [
"fmc_tdc_mezzanine.vhd",
"free_counter.vhd",
"incr_counter.vhd",
"irq_generator.vhd",
"leds_manager.vhd",
"local_pps_gen.vhd",
"reg_ctrl.vhd",
......@@ -23,5 +21,8 @@ files = [
"fmc_tdc_direct_readout_slave.vhd",
"fmc_tdc_direct_readout_slave_pkg.vhd",
"fmc_tdc_wrapper.vhd",
"timestamp_fifo.vhd",
"timestamp_fifo_wb.vhd",
"timestamp_fifo_wbgen2_pkg.vhd"
];
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -84,9 +84,8 @@ entity reg_ctrl is
(g_span : integer := 32;
g_width : integer := 32);
port
-- INPUTS
-- Signals from the clks_rsts_manager unit
(clk_sys_i : in std_logic;
(
clk_sys_i : in std_logic;
rst_n_sys_i : in std_logic; -- global reset, synched to clk_sys
clk_tdc_i : in std_logic;
......@@ -101,9 +100,6 @@ entity reg_ctrl is
acam_ififo2_i : in std_logic_vector(g_width-1 downto 0); -- keeps value read back from ACAM reg 9; for debug reasons only
acam_start01_i : in std_logic_vector(g_width-1 downto 0); -- keeps value read back from ACAM reg 10; for debug reasons only
-- Signals from the data_formatting unit
wr_index_i : in std_logic_vector(g_width-1 downto 0); -- index of the last circular_buffer adr written
-- Signals from the one_hz_gen unit
local_utc_i : in std_logic_vector(g_width-1 downto 0); -- local utc time
......@@ -130,10 +126,6 @@ entity reg_ctrl is
acam_rdbk_ififo2_p_o : out std_logic; -- enables reading of ACAM reg 9
acam_rdbk_start01_p_o : out std_logic; -- enables reading of ACAM reg 10
-- Signal to the data_formatting unit
dacapo_c_rst_p_o : out std_logic; -- clears the dacapo counter
deactivate_chan_o : out std_logic_vector(4 downto 0); -- stops registering timestamps from a specific channel
-- Signals to the clks_resets_manager unit
send_dac_word_p_o : out std_logic; -- initiates the reconfiguration of the DAC
dac_word_o : out std_logic_vector(23 downto 0);
......@@ -171,7 +163,7 @@ architecture rtl of reg_ctrl is
signal dac_word : std_logic_vector(23 downto 0);
signal pulse_extender_en : std_logic;
signal pulse_extender_c : std_logic_vector(2 downto 0);
signal dat_out, wrabbit_ctrl_reg, deactivate_chan : std_logic_vector(g_span-1 downto 0);
signal dat_out, wrabbit_ctrl_reg : std_logic_vector(g_span-1 downto 0);
signal ack_out_pipe0, ack_out_pipe1 : std_logic;
......@@ -356,7 +348,6 @@ begin
start_phase <= (others =>'0');
one_hz_phase <= (others =>'0');
wrabbit_ctrl_reg <= (others =>'0');
deactivate_chan <= (others =>'0');
irq_tstamp_threshold <= x"00000001"; -- default 256 timestamps: full memory
irq_time_threshold <= x"00000001"; -- default 200 ms
dac_word <= c_DEFAULT_DAC_WORD; -- default DAC Vout = 1.65
......@@ -395,9 +386,6 @@ begin
wrabbit_ctrl_reg <= wb_in.dat;
end if;
if reg_adr = c_DEACT_CHAN_ADR then
deactivate_chan <= wb_in.dat;
end if;
end if;
end if;
......@@ -411,7 +399,6 @@ begin
irq_time_threshold_o <= irq_time_threshold;
dac_word_o <= dac_word;
wrabbit_ctrl_reg_o <= wrabbit_ctrl_reg;
deactivate_chan_o <= deactivate_chan(4 downto 0);
---------------------------------------------------------------------------------------------------
-- Reception of TDC core Control Register --
......@@ -453,7 +440,6 @@ begin
acam_rdbk_start01_p_o <= ctrl_reg(7);
acam_rst_p_o <= ctrl_reg(8);
load_utc_p_o <= ctrl_reg(9);
dacapo_c_rst_p_o <= ctrl_reg(10) or ctrl_reg(1); -- dacapo register reset when the acquisition is deactivated
send_dac_word_p <= ctrl_reg(11);
-- ctrl_reg bits 12 to 31 not used for the moment!
......@@ -545,12 +531,12 @@ begin
-- regs written locally by the TDC core units
local_utc_i when c_LOCAL_UTC_ADR,
irq_code_i when c_IRQ_CODE_ADR,
wr_index_i when c_WR_INDEX_ADR,
x"00000000" when c_WR_INDEX_ADR,
core_status_i when c_CORE_STATUS_ADR,
-- White Rabbit regs
wrabbit_status_reg_i when c_WRABBIT_STATUS_ADR,
wrabbit_ctrl_reg when c_WRABBIT_CTRL_ADR,
deactivate_chan when c_DEACT_CHAN_ADR,
x"00000000" when c_DEACT_CHAN_ADR,
-- others
x"00000000" when others;
......
This diff is collapsed.
--_________________________________________________________________________________________________
-- |
-- |TDC core| |
-- |
-- CERN,BE/CO-HT |
--________________________________________________________________________________________________|
---------------------------------------------------------------------------------------------------
-- GNU LESSER GENERAL PUBLIC LICENSE |
-- ------------------------------------ |
-- This source file is free software; you can redistribute it and/or modify it under the terms of |
-- the GNU Lesser General Public License as published by the Free Software Foundation; either |
-- version 2.1 of the License, or (at your option) any later version. |
-- This source is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; |
-- without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
-- See the GNU Lesser General Public License for more details. |
-- You should have received a copy of the GNU Lesser General Public License along with this |
-- source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html |
---------------------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.NUMERIC_STD.all;
use work.tsf_wbgen2_pkg.all;
use work.wishbone_pkg.all;
use work.gencores_pkg.all;
entity timestamp_fifo is
generic (
g_channel : integer
);
port (
clk_sys_i : in std_logic;
clk_tdc_i : in std_logic;
rst_n_sys_i : in std_logic;
rst_tdc_i : in std_logic;
-- WB slave, system clock
slave_i : in t_wishbone_slave_in;
slave_o : out t_wishbone_slave_out;
irq_o : out std_logic; -- IRQ line, level high, system clock
enable_i : in std_logic; -- channel enable, TDC clock
tick_i : in std_logic; -- 1ms tick, TDC clock
irq_threshold_i : in std_logic_vector(9 downto 0);
irq_timeout_i : in std_logic_vector(9 downto 0);
timestamp_i : in std_logic_vector(127 downto 0);
timestamp_valid_i : in std_logic
);
end entity;
architecture rtl of timestamp_fifo is
component timestamp_fifo_wb is
port (
rst_n_i : in std_logic;
clk_sys_i : in std_logic;
wb_adr_i : in std_logic_vector(3 downto 0);
wb_dat_i : in std_logic_vector(31 downto 0);
wb_dat_o : out std_logic_vector(31 downto 0);
wb_cyc_i : in std_logic;
wb_sel_i : in std_logic_vector(3 downto 0);
wb_stb_i : in std_logic;
wb_we_i : in std_logic;
wb_ack_o : out std_logic;
wb_stall_o : out std_logic;
clk_tdc_i : in std_logic;
regs_i : in t_tsf_in_registers;
regs_o : out t_tsf_out_registers);
end component timestamp_fifo_wb;
signal tmr_timeout : unsigned(9 downto 0);
signal buf_irq_int : std_logic;
signal buf_count : unsigned(9 downto 0);
signal last_ts : std_logic_vector(127 downto 0);
signal regs_in : t_tsf_in_registers;
signal regs_out : t_tsf_out_registers;
signal channel_id : std_logic_vector(2 downto 0);
signal ts_match : std_logic;
begin
U_WB_Slave : timestamp_fifo_wb
port map (
rst_n_i => rst_n_sys_i,
clk_sys_i => clk_sys_i,
wb_adr_i => slave_i.adr(5 downto 2),
wb_dat_i => slave_i.dat,
wb_dat_o => slave_o.dat,
wb_cyc_i => slave_i.cyc,
wb_sel_i => slave_i.sel,
wb_stb_i => slave_i.stb,
wb_we_i => slave_i.we,
wb_ack_o => slave_o.ack,
wb_stall_o => slave_o.stall,
clk_tdc_i => clk_tdc_i,
regs_i => regs_in,
regs_o => regs_out);
buf_count <= unsigned(regs_out.fifo_wr_usedw_o);
ts_match <= '1' when timestamp_valid_i = '1' and unsigned(timestamp_i(98 downto 96)) = g_channel else '0';
p_fifo_write : process(clk_tdc_i)
begin
if rising_edge(clk_tdc_i) then
if rst_tdc_i = '1' then
regs_in.fifo_wr_req_i <= '0';
else
if(enable_i = '1' and regs_out.fifo_wr_full_o = '0' and ts_match = '1') then
regs_in.fifo_wr_req_i <= '1';
else
regs_in.fifo_wr_req_i <= '0';
end if;
end if;
end if;
end process;
p_latch_last_timestamp : process(clk_tdc_i)
begin
if rising_edge(clk_tdc_i) then
if rst_tdc_i = '1' then
regs_in.ltsctl_valid_i <= '0';
else
if (enable_i = '1' and ts_match = '1') then
regs_in.ltsctl_valid_i <= '1';
last_ts <= timestamp_i;
elsif (regs_out.ltsctl_valid_o = '0' and regs_out.ltsctl_valid_load_o = '1') then
regs_in.ltsctl_valid_i <= '0';
end if;
if (regs_out.ltsctl_valid_o = '0' and regs_out.ltsctl_valid_load_o = '1') then
regs_in.lts0_i <= last_ts(127 downto 96);
regs_in.lts1_i <= last_ts(95 downto 64);
regs_in.lts2_i <= last_ts(63 downto 32);
regs_in.lts3_i <= last_ts(31 downto 0);
end if;
end if;
end if;
end process;
p_coalesce_irq : process(clk_tdc_i)
begin
if rising_edge(clk_tdc_i) then
if rst_tdc_i = '1' or enable_i = '0' then
buf_irq_int <= '0';
else
if(buf_count = 0) then
buf_irq_int <= '0';
tmr_timeout <= (others => '0');
else
-- Simple interrupt coalescing :
-- Case 1: There is some data in the buffer
-- (but not exceeding the threshold) - assert the IRQ line after a
-- certain timeout.
if(buf_irq_int = '0') then
if(tmr_timeout = unsigned(irq_timeout_i(9 downto 0))) then
buf_irq_int <= '1';
tmr_timeout <= (others => '0');
elsif(tick_i = '1') then
tmr_timeout <= tmr_timeout + 1;
end if;
end if;
-- Case 2: amount of data exceeded the threshold - assert the IRQ
-- line immediately.
if(buf_count > unsigned(irq_threshold_i(9 downto 0))) then
buf_irq_int <= '1';
end if;
end if;
end if;
end if;
end process;
U_Sync_IRQ : gc_sync_ffs
port map (
clk_i => clk_sys_i,
rst_n_i => rst_n_sys_i,
data_i => buf_irq_int,
synced_o => irq_o);
end rtl;
This diff is collapsed.
-- -*- Mode: LUA; tab-width: 2 -*-
peripheral {
name = "Timestamp FIFO";
prefix="tsf";
hdl_entity="timestamp_fifo_wb";
-- TXTSU shared FIFO
fifo_reg {
size = 1024; -- or more. We'll see :)
direction = CORE_TO_BUS;
prefix = "fifo";
name = "Timestamp FIFO";
clock = "clk_tdc_i";
flags_bus = {FIFO_FULL, FIFO_EMPTY, FIFO_COUNT};
flags_dev = {FIFO_FULL, FIFO_EMPTY, FIFO_COUNT};
field {
name = "The timestamp";
prefix = "value";
type = SLV;
size = 128;
};
};
reg {
name = "Last Timestamp Word 0";
prefix = "LTS0";
field {
name = "Last Timestamp Word 0";
clock = "clk_tdc_i";
type = SLV;
size = 32;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
};
reg {
name = "Last Timestamp Word 1";
prefix = "LTS1";
field {
name = "Last Timestamp Word 1";
clock = "clk_tdc_i";
type = SLV;
size = 32;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
};
reg {
name = "Last Timestamp Word 2";
prefix = "LTS2";
field {
name = "Last Timestamp Word 2";
clock = "clk_tdc_i";
type = SLV;
size = 32;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
};
reg {
name = "Last Timestamp Word 3";
prefix = "LTS3";
field {
name = "Last Timestamp Word 3";
clock = "clk_tdc_i";
type = SLV;
size = 32;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
};
reg {
name = "Last Timestamp Control/Status";
prefix = "LTSCTL";
field {
name = "Last Timestamp Valid";
clock = "clk_tdc_i";
prefix = "VALID";
type = BIT;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
load = LOAD_EXT;
};
};
};
---------------------------------------------------------------------------------------
-- Title : Wishbone slave core for Timestamp FIFO
---------------------------------------------------------------------------------------
-- File : timestamp_fifo_wbgen2_pkg.vhd
-- Author : auto-generated by wbgen2 from timestamp_fifo_wb.wb
-- Created : Tue Apr 14 16:47:08 2015
-- Standard : VHDL'87
---------------------------------------------------------------------------------------
-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE timestamp_fifo_wb.wb
-- DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
---------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.wbgen2_pkg.all;
package tsf_wbgen2_pkg is
-- Input registers (user design -> WB slave)
type t_tsf_in_registers is record
fifo_wr_req_i : std_logic;
fifo_value_i : std_logic_vector(127 downto 0);
lts0_i : std_logic_vector(31 downto 0);
lts1_i : std_logic_vector(31 downto 0);
lts2_i : std_logic_vector(31 downto 0);
lts3_i : std_logic_vector(31 downto 0);
ltsctl_valid_i : std_logic;
end record;
constant c_tsf_in_registers_init_value: t_tsf_in_registers := (
fifo_wr_req_i => '0',
fifo_value_i => (others => '0'),
lts0_i => (others => '0'),
lts1_i => (others => '0'),
lts2_i => (others => '0'),
lts3_i => (others => '0'),
ltsctl_valid_i => '0'
);
-- Output registers (WB slave -> user design)
type t_tsf_out_registers is record
fifo_wr_full_o : std_logic;
fifo_wr_empty_o : std_logic;
fifo_wr_usedw_o : std_logic_vector(9 downto 0);
ltsctl_valid_o : std_logic;
ltsctl_valid_load_o : std_logic;
end record;
constant c_tsf_out_registers_init_value: t_tsf_out_registers := (
fifo_wr_full_o => '0',
fifo_wr_empty_o => '0',
fifo_wr_usedw_o => (others => '0'),
ltsctl_valid_o => '0',
ltsctl_valid_load_o => '0'
);
function "or" (left, right: t_tsf_in_registers) return t_tsf_in_registers;
function f_x_to_zero (x:std_logic) return std_logic;
function f_x_to_zero (x:std_logic_vector) return std_logic_vector;
end package;
package body tsf_wbgen2_pkg is
function f_x_to_zero (x:std_logic) return std_logic is
begin
if x = '1' then
return '1';
else
return '0';
end if;
end function;
function f_x_to_zero (x:std_logic_vector) return std_logic_vector is
variable tmp: std_logic_vector(x'length-1 downto 0);
begin
for i in 0 to x'length-1 loop
if(x(i) = 'X' or x(i) = 'U') then
tmp(i):= '0';
else
tmp(i):=x(i);
end if;
end loop;
return tmp;
end function;
function "or" (left, right: t_tsf_in_registers) return t_tsf_in_registers is
variable tmp: t_tsf_in_registers;
begin
tmp.fifo_wr_req_i := f_x_to_zero(left.fifo_wr_req_i) or f_x_to_zero(right.fifo_wr_req_i);
tmp.fifo_value_i := f_x_to_zero(left.fifo_value_i) or f_x_to_zero(right.fifo_value_i);
tmp.lts0_i := f_x_to_zero(left.lts0_i) or f_x_to_zero(right.lts0_i);
tmp.lts1_i := f_x_to_zero(left.lts1_i) or f_x_to_zero(right.lts1_i);
tmp.lts2_i := f_x_to_zero(left.lts2_i) or f_x_to_zero(right.lts2_i);
tmp.lts3_i := f_x_to_zero(left.lts3_i) or f_x_to_zero(right.lts3_i);
tmp.ltsctl_valid_i := f_x_to_zero(left.ltsctl_valid_i) or f_x_to_zero(right.ltsctl_valid_i);
return tmp;
end function;
end package body;
This diff is collapsed.
`include "simdrv_defs.svh"
`include "vme64x_bfm.svh"
`include "svec_vme_buffers.svh"
`include "../../rtl/timestamp_fifo_regs.vh"
module fake_acam(
input [3:0] addr,
output reg [27:0] data,
input wr,
input rd,
output reg ef1,
output reg ef2
);
typedef struct {
int channel;
time ts;
} acam_fifo_entry;
acam_fifo_entry fifo1[$], fifo2[$];
task pulse(int channel, time ts);
acam_fifo_entry ent;
ent.channel = channel % 4;
ent.ts = ts;
if (channel >= 0 && channel <= 3)
fifo1.push_back(ent);
else
fifo2.push_back(ent);
#100ns;
if(fifo1.size())
ef1 = 0;
if(fifo2.size())
ef2 = 0;
endtask // pulse
initial begin
ef1 = 1;
ef2 = 1;
data = 28'bz;
end
always@(negedge rd) begin
if (addr == 8) begin
acam_fifo_entry ent;
ent=fifo1.pop_front();
data <= ent.ts | (ent.channel << 26);
end else if (addr == 9) begin
acam_fifo_entry ent;
ent=fifo2.pop_front();
data <= ent.ts | (ent.channel << 26);
end else
data <= 28'bz;
#10ns;
ef1 <= (fifo1.size() ? 0 : 1);
ef2 <= (fifo2.size() ? 0 : 1);
end
endmodule
module main;
......@@ -19,20 +91,6 @@ module main;
`DECLARE_VME_BUFFERS(VME.slave);
reg tdc_ef1 = 1;
reg tdc_pulse = 0;
wire tdc_rd_n;
always@(posedge tdc_pulse) begin
#100ns;
tdc_ef1 <= 0;
while(tdc_rd_n != 0)
#1ns;
#10ns;
tdc_ef1 <= 1;
end
reg clk_acam = 0;
reg clk_62m5 = 0;
......@@ -43,6 +101,10 @@ module main;
always@(posedge clk_62m5)
clk_acam <= ~clk_acam;
wire [3:0] tdc_addr;
wire [27:0] tdc_data;
wr_svec_tdc #(
.g_with_wr_phy(0),
......@@ -65,20 +127,24 @@ module main;
.por_n_i(rst_n),
.tdc1_ef1_i(tdc_ef1),
.tdc1_ef2_i(1'b1),
.tdc1_ef2_i(tdc_ef2),
.tdc1_err_flag_i(1'b0),
.tdc1_int_flag_i(1'b0),
.tdc1_rd_n_o(tdc_rd_n),
.tdc1_in_fpga_1_i(tdc_pulse),
.tdc1_in_fpga_2_i(1'b0),
.tdc1_in_fpga_3_i(1'b0),
.tdc1_in_fpga_4_i(1'b0),
.tdc1_in_fpga_5_i(1'b0),
.tdc1_data_bus_io(28'hcafebab),
.tdc1_data_bus_io(tdc_data),
.tdc1_address_o(tdc_addr),
`WIRE_VME_PINS(8)
);
fake_acam ACAM(
.addr(tdc_addr),
.data(tdc_data),
.wr(1'b0),
.rd(tdc_rd_n),
.ef1(tdc_ef1),
.ef2(tdc_ef2)
);
......@@ -139,30 +205,60 @@ module main;
$display("Un-reset FMCs...");
acc.write('hc2000c, 'h3);
acc.write('hc0100c, 'h3);
#500us;
acc.read('hc40000, d);
acc.read('hc10000, d);
$display("TDC SDB ID : %x", d);
acc.write('hc510a0, 1234); // set UTC
acc.write('hc510fc, 1<<9); // load UTC
acc.write('hc120a0, 1234); // set UTC
acc.write('hc120fc, 1<<9); // load UTC
acc.write('hc52004, 'hf); // enable EIC irq
acc.write('hc13004, 'hf); // enable EIC irq
acc.write('hc51084, 'h1f); // enable all ACAM inputs
acc.write('hc510fc, (1<<0)); // start acquisition
acc.write('hc12084, 'h1f); // enable all ACAM inputs
acc.write('hc120fc, (1<<0)); // start acquisition
acc.write('hc120fc, (1<<0)); // start acquisition
acc.write('hc12090, 2); // thr = 2 ts
acc.write('hc12094, 10); // thr = 10 ms
#300us;
forever begin
tdc_pulse <= 1;
#1000ns;
tdc_pulse <= 0;
#10ns;
end
fork
forever begin
acc.read('hc15000 + `ADDR_TSF_LTSCTL, d);
if(d&1) begin
uint64_t t0,t1,t2,t3;
acc.write('hc15000 + `ADDR_TSF_LTSCTL, 0);
acc.read('hc15000 + `ADDR_TSF_LTS0, t0);
acc.read('hc15000 + `ADDR_TSF_LTS1, t1);
acc.read('hc15000 + `ADDR_TSF_LTS2, t2);
acc.read('hc15000 + `ADDR_TSF_LTS3, t3);
$display("Last: %08x %08x %08x %08x",t0,t1,t2,t3);
end
end
forever begin
$display("Pulse!");
ACAM.pulse(0, 0);
ACAM.pulse(1, 0);
ACAM.pulse(2, 0);
#10us;
end
join
......
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