Add timetagger logic
This commit is contained in:
parent
21da05d6cd
commit
96090ac31e
|
@ -161,6 +161,7 @@ begin
|
|||
-- Detect overflow of external data buffer.
|
||||
if (r.out_valid = '1') and (out_ready = '0') then
|
||||
v.overflow := '1';
|
||||
v.out_valid := '0';
|
||||
end if;
|
||||
|
||||
-- If there is a pending overflow, discard data until the buffer
|
||||
|
|
|
@ -158,7 +158,8 @@ begin
|
|||
inst_fifo: entity work.simple_fifo
|
||||
generic map (
|
||||
data_width => 64,
|
||||
fifo_depth_bits => queue_size_bits )
|
||||
fifo_depth_bits => queue_size_bits,
|
||||
block_ram => true )
|
||||
port map (
|
||||
clk => clk,
|
||||
reset => s_fifo_reset,
|
||||
|
|
|
@ -75,6 +75,16 @@ package puzzlefw_pkg is
|
|||
constant reg_adc1_minmax: natural := 16#000294#;
|
||||
constant reg_adc2_minmax: natural := 16#000298#;
|
||||
constant reg_adc3_minmax: natural := 16#00029c#;
|
||||
constant reg_tt_addr_start: natural := 16#000300#;
|
||||
constant reg_tt_addr_end: natural := 16#000304#;
|
||||
constant reg_tt_addr_limit: natural := 16#000308#;
|
||||
constant reg_tt_addr_intr: natural := 16#00030c#;
|
||||
constant reg_tt_addr_ptr: natural := 16#000310#;
|
||||
constant reg_tt_dma_ctrl: natural := 16#000314#;
|
||||
constant reg_tt_intr_ctrl: natural := 16#000318#;
|
||||
constant reg_tt_dma_status: natural := 16#00031c#;
|
||||
constant reg_timetagger_en: natural := 16#000320#;
|
||||
constant reg_timetagger_mark: natural := 16#000324#;
|
||||
constant reg_dig_simulate: natural := 16#000330#;
|
||||
constant reg_dig_sample: natural := 16#000338#;
|
||||
constant reg_led_state: natural := 16#000404#;
|
||||
|
@ -84,7 +94,7 @@ package puzzlefw_pkg is
|
|||
-- Firmware info word.
|
||||
constant fw_api_version: natural := 1;
|
||||
constant fw_version_major: natural := 0;
|
||||
constant fw_version_minor: natural := 4;
|
||||
constant fw_version_minor: natural := 6;
|
||||
constant fw_info_word: std_logic_vector(31 downto 0) :=
|
||||
x"4a"
|
||||
& std_logic_vector(to_unsigned(fw_api_version, 8))
|
||||
|
@ -92,9 +102,11 @@ package puzzlefw_pkg is
|
|||
& std_logic_vector(to_unsigned(fw_version_minor, 8));
|
||||
|
||||
-- Data stream.
|
||||
constant msg_adc_data: std_logic_vector(7 downto 0) := x"01";
|
||||
constant msg_trigger: std_logic_vector(7 downto 0) := x"02";
|
||||
constant msg_overflow: std_logic_vector(7 downto 0) := x"10";
|
||||
constant msg_adc_data: std_logic_vector(7 downto 0) := x"10";
|
||||
constant msg_trigger: std_logic_vector(7 downto 0) := x"11";
|
||||
constant msg_timetagger_data: std_logic_vector(7 downto 4) := x"2";
|
||||
constant msg_marker: std_logic_vector(7 downto 0) := x"30";
|
||||
constant msg_overflow: std_logic_vector(7 downto 0) := x"40";
|
||||
|
||||
-- Control registers: read/write access by processor, output signals to FPGA.
|
||||
type registers_control is record
|
||||
|
@ -124,6 +136,16 @@ package puzzlefw_pkg is
|
|||
trig_ext_falling: std_logic;
|
||||
trigger_delay: std_logic_vector(15 downto 0);
|
||||
adc_range_clear: std_logic;
|
||||
tt_addr_start: std_logic_vector(31 downto 7);
|
||||
tt_addr_end: std_logic_vector(31 downto 7);
|
||||
tt_addr_limit: std_logic_vector(31 downto 7);
|
||||
tt_addr_intr: std_logic_vector(31 downto 3);
|
||||
tt_dma_en: std_logic;
|
||||
tt_dma_init: std_logic; -- single cycle
|
||||
tt_intr_en: std_logic;
|
||||
tt_intr_clear: std_logic; -- single cycle
|
||||
timetagger_en: std_logic_vector(7 downto 0);
|
||||
timetagger_mark: std_logic; -- single cycle
|
||||
dig_simulate: std_logic;
|
||||
dig_sim_state: std_logic_vector(3 downto 0);
|
||||
led_state: std_logic_vector(7 downto 0);
|
||||
|
@ -133,7 +155,7 @@ package puzzlefw_pkg is
|
|||
|
||||
-- Status registers: input signals from FPGA, read-only access by processor.
|
||||
type registers_status is record
|
||||
irq_pending: std_logic_vector(0 downto 0);
|
||||
irq_pending: std_logic_vector(1 downto 0);
|
||||
dma_busy: std_logic;
|
||||
dma_err_read: std_logic;
|
||||
dma_err_write: std_logic;
|
||||
|
@ -146,6 +168,8 @@ package puzzlefw_pkg is
|
|||
adc_sample: adc_data_array(0 to 3);
|
||||
adc_min_value: adc_data_array(0 to 3);
|
||||
adc_max_value: adc_data_array(0 to 3);
|
||||
tt_addr_ptr: std_logic_vector(31 downto 3);
|
||||
tt_dma_busy: std_logic;
|
||||
dig_sample: std_logic_vector(3 downto 0);
|
||||
end record;
|
||||
|
||||
|
@ -176,6 +200,16 @@ package puzzlefw_pkg is
|
|||
trig_ext_falling => '0',
|
||||
trigger_delay => (others => '0'),
|
||||
adc_range_clear => '0',
|
||||
tt_addr_start => (others => '0'),
|
||||
tt_addr_end => (others => '0'),
|
||||
tt_addr_limit => (others => '0'),
|
||||
tt_addr_intr => (others => '0'),
|
||||
tt_dma_en => '0',
|
||||
tt_dma_init => '0',
|
||||
tt_intr_en => '0',
|
||||
tt_intr_clear => '0',
|
||||
timetagger_en => (others => '0'),
|
||||
timetagger_mark => '0',
|
||||
dig_simulate => '0',
|
||||
dig_sim_state => (others => '0'),
|
||||
led_state => (others => '0'),
|
||||
|
|
|
@ -58,7 +58,7 @@ entity puzzlefw_top is
|
|||
dac_pwm_o: out std_logic_vector(3 downto 0); -- PWM DAC
|
||||
exp_p_io: inout std_logic_vector(7 downto 0); -- extension I/O pos
|
||||
exp_n_io: inout std_logic_vector(7 downto 0); -- extension I/O neg
|
||||
led_o: inout std_logic_vector(7 downto 0) -- LEDs
|
||||
led_o: out std_logic_vector(7 downto 0) -- LEDs
|
||||
);
|
||||
|
||||
end puzzlefw_top;
|
||||
|
@ -132,7 +132,7 @@ architecture arch of puzzlefw_top is
|
|||
signal s_axi_rready: std_logic;
|
||||
|
||||
-- Interrupts.
|
||||
signal s_irq_pending: std_logic_vector(0 downto 0);
|
||||
signal s_irq_pending: std_logic_vector(1 downto 0);
|
||||
signal s_irq_f2p: std_logic_vector(7 downto 0);
|
||||
|
||||
-- Registers.
|
||||
|
@ -140,19 +140,24 @@ architecture arch of puzzlefw_top is
|
|||
signal s_reg_status: registers_status;
|
||||
|
||||
-- DMA write channel control.
|
||||
signal s_dma_write_cmd_addr: dma_address_array(0 downto 0);
|
||||
signal s_dma_write_cmd_length: dma_burst_length_array(0 to 0);
|
||||
signal s_dma_write_cmd_valid: std_logic_vector(0 downto 0);
|
||||
signal s_dma_write_cmd_ready: std_logic_vector(0 downto 0);
|
||||
signal s_dma_write_data: dma_data_array(0 downto 0);
|
||||
signal s_dma_write_data_ready: std_logic_vector(0 downto 0);
|
||||
signal s_dma_write_finished: std_logic_vector(0 downto 0);
|
||||
signal s_dma_write_cmd_addr: dma_address_array(0 to 1);
|
||||
signal s_dma_write_cmd_length: dma_burst_length_array(0 to 1);
|
||||
signal s_dma_write_cmd_valid: std_logic_vector(1 downto 0);
|
||||
signal s_dma_write_cmd_ready: std_logic_vector(1 downto 0);
|
||||
signal s_dma_write_data: dma_data_array(0 to 1);
|
||||
signal s_dma_write_data_ready: std_logic_vector(1 downto 0);
|
||||
signal s_dma_write_finished: std_logic_vector(1 downto 0);
|
||||
|
||||
signal s_acq_dma_valid: std_logic;
|
||||
signal s_acq_dma_ready: std_logic;
|
||||
signal s_acq_dma_empty: std_logic;
|
||||
signal s_acq_dma_data: dma_data_type;
|
||||
|
||||
signal s_tt_dma_valid: std_logic;
|
||||
signal s_tt_dma_ready: std_logic;
|
||||
signal s_tt_dma_empty: std_logic;
|
||||
signal s_tt_dma_data: dma_data_type;
|
||||
|
||||
signal s_timestamp: std_logic_vector(timestamp_bits - 1 downto 0);
|
||||
signal s_adc_data: adc_data_array(0 to 1);
|
||||
signal s_adc_sample: adc_data_array(0 to 1);
|
||||
|
@ -161,13 +166,20 @@ architecture arch of puzzlefw_top is
|
|||
signal s_dig_deglitch: std_logic_vector(3 downto 0);
|
||||
signal s_dig_sample: std_logic_vector(3 downto 0);
|
||||
|
||||
-- TODO
|
||||
signal r_mhz_cnt: unsigned(7 downto 0);
|
||||
signal r_khz_cnt: unsigned(9 downto 0);
|
||||
signal r_blink_mhz: std_logic;
|
||||
signal r_blink_mhz_d: std_logic;
|
||||
signal r_blink_khz: std_logic;
|
||||
|
||||
begin
|
||||
|
||||
-- Drive LEDs.
|
||||
led_o(0) <= r_adcclk_led; -- blinking LED, 1 Hz
|
||||
led_o(1) <= s_reg_control.acquisition_en; -- acquisition enabled
|
||||
led_o(2) <= s_reg_status.trig_waiting; -- waiting for trigger
|
||||
-- TODO: led_o(3) <= timetagger_en
|
||||
led_o(3) <= or_reduce(s_reg_control.timetagger_en); -- timetagger enabled
|
||||
led_o(7 downto 4) <= s_reg_control.led_state(7 downto 4);
|
||||
|
||||
-- Enable ADC clock duty cycle stabilizer.
|
||||
|
@ -184,10 +196,39 @@ begin
|
|||
dac_rst_o <= '0';
|
||||
dac_pwm_o <= (others => 'Z');
|
||||
|
||||
-- Use extension I/O pins as inputs.
|
||||
exp_p_io <= (others => 'Z');
|
||||
-- Use extension I/O pins as inputs only.
|
||||
-- TODO -- temporary test pulse generator
|
||||
exp_p_io <= (2 => r_blink_khz, 3 => r_blink_khz, 4 => r_blink_mhz, 5 => r_blink_mhz, 6 => r_blink_mhz_d, 7 => r_blink_mhz_d, others => 'Z');
|
||||
exp_n_io <= (others => 'Z');
|
||||
|
||||
-- TODO
|
||||
process (clk_adc) is
|
||||
begin
|
||||
if rising_edge(clk_adc) then
|
||||
if r_mhz_cnt < 124 then
|
||||
r_mhz_cnt <= r_mhz_cnt + 1;
|
||||
else
|
||||
r_mhz_cnt <= (others => '0');
|
||||
if r_khz_cnt < 999 then
|
||||
r_khz_cnt <= r_khz_cnt + 1;
|
||||
else
|
||||
r_khz_cnt <= (others => '0');
|
||||
end if;
|
||||
end if;
|
||||
if r_mhz_cnt < 62 then
|
||||
r_blink_mhz <= '0';
|
||||
else
|
||||
r_blink_mhz <= '1';
|
||||
end if;
|
||||
r_blink_mhz_d <= r_blink_mhz;
|
||||
if r_khz_cnt < 500 then
|
||||
r_blink_khz <= '0';
|
||||
else
|
||||
r_blink_khz <= '1';
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- Differential clock input for ADC clock.
|
||||
inst_ibuf_adc_clk: IBUFDS
|
||||
port map (
|
||||
|
@ -300,7 +341,7 @@ begin
|
|||
inst_axi_master: entity work.dma_axi_master
|
||||
generic map (
|
||||
num_read_channels => 0,
|
||||
num_write_channels => 1 )
|
||||
num_write_channels => 2 )
|
||||
port map (
|
||||
clk => clk_adc,
|
||||
reset => s_reset,
|
||||
|
@ -366,7 +407,7 @@ begin
|
|||
m_axi_rready => s_axi_rready
|
||||
);
|
||||
|
||||
-- DMA Write Channel
|
||||
-- DMA write channel for analog acquisition
|
||||
inst_acq_dma: entity work.dma_write_channel
|
||||
generic map (
|
||||
transfer_size_bits => 4,
|
||||
|
@ -398,6 +439,38 @@ begin
|
|||
write_data_ready => s_dma_write_data_ready(0),
|
||||
write_finished => s_dma_write_finished(0) );
|
||||
|
||||
-- DMA write channel for time tagger
|
||||
inst_tt_dma: entity work.dma_write_channel
|
||||
generic map (
|
||||
transfer_size_bits => 4,
|
||||
queue_size_bits => 10,
|
||||
idle_timeout => 256 )
|
||||
port map (
|
||||
clk => clk_adc,
|
||||
reset => s_reset,
|
||||
channel_en => s_reg_control.tt_dma_en,
|
||||
channel_busy => s_reg_status.tt_dma_busy,
|
||||
channel_init => s_reg_control.tt_dma_init,
|
||||
addr_start => s_reg_control.tt_addr_start,
|
||||
addr_end => s_reg_control.tt_addr_end,
|
||||
addr_limit => s_reg_control.tt_addr_limit,
|
||||
addr_interrupt => s_reg_control.tt_addr_intr,
|
||||
addr_pointer => s_reg_status.tt_addr_ptr,
|
||||
intr_en => s_reg_control.tt_intr_en,
|
||||
intr_clear => s_reg_control.tt_intr_clear,
|
||||
intr_out => s_irq_pending(1),
|
||||
in_valid => s_tt_dma_valid,
|
||||
in_ready => s_tt_dma_ready,
|
||||
in_empty => s_tt_dma_empty,
|
||||
in_data => s_tt_dma_data,
|
||||
write_cmd_addr => s_dma_write_cmd_addr(1),
|
||||
write_cmd_length => s_dma_write_cmd_length(1),
|
||||
write_cmd_valid => s_dma_write_cmd_valid(1),
|
||||
write_cmd_ready => s_dma_write_cmd_ready(1),
|
||||
write_data => s_dma_write_data(1),
|
||||
write_data_ready => s_dma_write_data_ready(1),
|
||||
write_finished => s_dma_write_finished(1) );
|
||||
|
||||
-- Timestamp generator.
|
||||
inst_timestamp_gen: entity work.timestamp_gen
|
||||
port map (
|
||||
|
@ -470,7 +543,7 @@ begin
|
|||
trig_ext_falling => s_reg_control.trig_ext_falling,
|
||||
timestamp_in => s_timestamp,
|
||||
adc_data_in => s_adc_sample,
|
||||
trig_ext_in => "0000", -- TODO
|
||||
trig_ext_in => s_dig_sample,
|
||||
trig_waiting => s_reg_status.trig_waiting,
|
||||
out_valid => s_acq_dma_valid,
|
||||
out_ready => s_acq_dma_ready,
|
||||
|
@ -518,7 +591,19 @@ begin
|
|||
-- Monitor digital signal state.
|
||||
s_reg_status.dig_sample <= s_dig_sample;
|
||||
|
||||
-- TODO : time tagger
|
||||
-- Time tagger.
|
||||
inst_timetagger: entity work.timetagger
|
||||
port map (
|
||||
clk => clk_adc,
|
||||
reset => s_reset,
|
||||
channel_en => s_reg_control.timetagger_en,
|
||||
marker => s_reg_control.timetagger_mark,
|
||||
timestamp_in => s_timestamp,
|
||||
dig_sample => s_dig_sample,
|
||||
out_valid => s_tt_dma_valid,
|
||||
out_ready => s_tt_dma_ready,
|
||||
out_empty => s_tt_dma_empty,
|
||||
out_data => s_tt_dma_data );
|
||||
|
||||
-- Collect interrupt signals from peripherals and generate interrupt to PS.
|
||||
s_reg_status.irq_pending <= s_irq_pending;
|
||||
|
|
|
@ -76,6 +76,9 @@ begin
|
|||
v.reg_control.acq_intr_clear := '0';
|
||||
v.reg_control.trig_force := '0';
|
||||
v.reg_control.adc_range_clear := '0';
|
||||
v.reg_control.tt_dma_init := '0';
|
||||
v.reg_control.tt_intr_clear := '0';
|
||||
v.reg_control.timetagger_mark := '0';
|
||||
|
||||
-- Respond to each APB access on the next clock cycle (no wait states).
|
||||
v.pready := apb_psel and (not apb_penable);
|
||||
|
@ -90,7 +93,7 @@ begin
|
|||
case to_integer(unsigned(apb_paddr and reg_addr_mask)) is
|
||||
when reg_info => v.prdata := fw_info_word;
|
||||
when reg_irq_enable => v.prdata(0) := r.reg_control.irq_enable;
|
||||
when reg_irq_pending => v.prdata(0 downto 0) := reg_status.irq_pending;
|
||||
when reg_irq_pending => v.prdata(1 downto 0) := reg_status.irq_pending;
|
||||
when reg_dma_en => v.prdata(0) := r.reg_control.dma_en;
|
||||
when reg_dma_status =>
|
||||
v.prdata(0) := reg_status.dma_busy;
|
||||
|
@ -105,8 +108,7 @@ begin
|
|||
when reg_acq_addr_limit => v.prdata(31 downto 7) := r.reg_control.acq_addr_limit;
|
||||
when reg_acq_addr_intr => v.prdata(31 downto 3) := r.reg_control.acq_addr_intr;
|
||||
when reg_acq_addr_ptr => v.prdata(31 downto 3) := reg_status.acq_addr_ptr;
|
||||
when reg_acq_dma_ctrl =>
|
||||
v.prdata(0) := r.reg_control.acq_dma_en;
|
||||
when reg_acq_dma_ctrl => v.prdata(0) := r.reg_control.acq_dma_en;
|
||||
when reg_acq_intr_ctrl => v.prdata(0) := r.reg_control.acq_intr_en;
|
||||
when reg_acq_dma_status => v.prdata(0) := reg_status.acq_dma_busy;
|
||||
when reg_acquisition_en => v.prdata(0) := r.reg_control.acquisition_en;
|
||||
|
@ -141,6 +143,15 @@ begin
|
|||
when reg_adc3_minmax =>
|
||||
v.prdata(adc_data_bits - 1 downto 0) := reg_status.adc_min_value(3);
|
||||
v.prdata(adc_data_bits + 15 downto 16) := reg_status.adc_max_value(3);
|
||||
when reg_tt_addr_start => v.prdata(31 downto 7) := r.reg_control.tt_addr_start;
|
||||
when reg_tt_addr_end => v.prdata(31 downto 7) := r.reg_control.tt_addr_end;
|
||||
when reg_tt_addr_limit => v.prdata(31 downto 7) := r.reg_control.tt_addr_limit;
|
||||
when reg_tt_addr_intr => v.prdata(31 downto 3) := r.reg_control.tt_addr_intr;
|
||||
when reg_tt_addr_ptr => v.prdata(31 downto 3) := reg_status.tt_addr_ptr;
|
||||
when reg_tt_dma_ctrl => v.prdata(0) := r.reg_control.tt_dma_en;
|
||||
when reg_tt_intr_ctrl => v.prdata(0) := r.reg_control.tt_intr_en;
|
||||
when reg_tt_dma_status => v.prdata(0) := reg_status.tt_dma_busy;
|
||||
when reg_timetagger_en => v.prdata(7 downto 0) := r.reg_control.timetagger_en;
|
||||
when reg_dig_simulate =>
|
||||
v.prdata(8) := r.reg_control.dig_simulate;
|
||||
v.prdata(3 downto 0) := r.reg_control.dig_sim_state;
|
||||
|
@ -185,6 +196,18 @@ begin
|
|||
v.reg_control.trig_force := apb_pwdata(8);
|
||||
when reg_trigger_delay => v.reg_control.trigger_delay := apb_pwdata(15 downto 0);
|
||||
when reg_adc_range_clear => v.reg_control.adc_range_clear := apb_pwdata(0);
|
||||
when reg_tt_addr_start => v.reg_control.tt_addr_start := apb_pwdata(31 downto 7);
|
||||
when reg_tt_addr_end => v.reg_control.tt_addr_end := apb_pwdata(31 downto 7);
|
||||
when reg_tt_addr_limit => v.reg_control.tt_addr_limit := apb_pwdata(31 downto 7);
|
||||
when reg_tt_addr_intr => v.reg_control.tt_addr_intr := apb_pwdata(31 downto 3);
|
||||
when reg_tt_dma_ctrl =>
|
||||
v.reg_control.tt_dma_en := apb_pwdata(0);
|
||||
v.reg_control.tt_dma_init := apb_pwdata(1);
|
||||
when reg_tt_intr_ctrl =>
|
||||
v.reg_control.tt_intr_en := apb_pwdata(0);
|
||||
v.reg_control.tt_intr_clear := apb_pwdata(1);
|
||||
when reg_timetagger_en => v.reg_control.timetagger_en := apb_pwdata(7 downto 0);
|
||||
when reg_timetagger_mark => v.reg_control.timetagger_mark := apb_pwdata(0);
|
||||
when reg_dig_simulate =>
|
||||
v.reg_control.dig_simulate := apb_pwdata(8);
|
||||
v.reg_control.dig_sim_state := apb_pwdata(3 downto 0);
|
||||
|
|
|
@ -21,7 +21,10 @@ entity simple_fifo is
|
|||
data_width: integer range 1 to 1024;
|
||||
|
||||
-- Size of FIFO as 2-log of the number of words.
|
||||
fifo_depth_bits: integer range 2 to 16
|
||||
fifo_depth_bits: integer range 2 to 16;
|
||||
|
||||
-- True to use block RAM, False to let the synthesizer choose.
|
||||
block_ram: boolean
|
||||
);
|
||||
|
||||
port (
|
||||
|
@ -75,6 +78,16 @@ architecture arch of simple_fifo is
|
|||
signal s_ram_wen: std_logic;
|
||||
signal s_ram_ren: std_logic;
|
||||
|
||||
-- Determine the value of the MEMORY_PRIMITIVE attribute.
|
||||
function choose_memory_primitive return string is
|
||||
begin
|
||||
if block_ram then
|
||||
return "block";
|
||||
else
|
||||
return "auto";
|
||||
end if;
|
||||
end function;
|
||||
|
||||
begin
|
||||
|
||||
--
|
||||
|
@ -92,7 +105,7 @@ begin
|
|||
MEMORY_INIT_FILE => "none",
|
||||
MEMORY_INIT_PARAM => "0",
|
||||
MEMORY_OPTIMIZATION => "true",
|
||||
MEMORY_PRIMITIVE => "block",
|
||||
MEMORY_PRIMITIVE => choose_memory_primitive,
|
||||
MEMORY_SIZE => data_width * 2**fifo_depth_bits,
|
||||
MESSAGE_CONTROL => 0,
|
||||
READ_DATA_WIDTH_B => data_width,
|
||||
|
|
|
@ -0,0 +1,293 @@
|
|||
--
|
||||
-- Time tagger logic.
|
||||
--
|
||||
-- The time tagger assigns timestamps to events on the digital inputs.
|
||||
-- It produces a stream of event records to the DMA write channel.
|
||||
--
|
||||
-- Output record format:
|
||||
-- bits 63 : 60 = record type
|
||||
-- bits 59 : 56 = channel index (only for event record)
|
||||
-- bits 55 : 52 = 0000
|
||||
-- bits 51 : 48 = digital signal state (or 0 for overflow record)
|
||||
-- bits 47 : 0 = timestamp (or 0 for overflow record)
|
||||
--
|
||||
-- Channel index:
|
||||
-- Even channel index (2*k) represents a rising edge on channel k.
|
||||
-- Odd channel index (2*k+1) represents a falling edge on channel k.
|
||||
--
|
||||
-- Joris van Rantwijk 2024
|
||||
--
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.std_logic_misc.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
use work.puzzlefw_pkg.all;
|
||||
|
||||
|
||||
entity timetagger is
|
||||
|
||||
port (
|
||||
-- Main clock, active on rising edge.
|
||||
clk: in std_logic;
|
||||
|
||||
-- Reset, active high, synchronous to main clock.
|
||||
reset: in std_logic;
|
||||
|
||||
-- Channel enable mask.
|
||||
channel_en: in std_logic_vector(7 downto 0);
|
||||
|
||||
-- High to emit a marker record.
|
||||
-- An arbitrary delay may pass between a marker request and actual
|
||||
-- emitting of the marker record.
|
||||
marker: in std_logic;
|
||||
|
||||
-- Global timestamp counter.
|
||||
timestamp_in: in std_logic_vector(timestamp_bits - 1 downto 0);
|
||||
|
||||
-- Digital input signals.
|
||||
dig_sample: in std_logic_vector(3 downto 0);
|
||||
|
||||
-- Output data stream.
|
||||
out_valid: out std_logic;
|
||||
out_ready: in std_logic;
|
||||
out_empty: in std_logic;
|
||||
out_data: out dma_data_type
|
||||
);
|
||||
|
||||
end entity;
|
||||
|
||||
architecture arch of timetagger is
|
||||
|
||||
type regs_type is record
|
||||
overflow: std_logic;
|
||||
marker_pending: std_logic;
|
||||
marker_holdoff: std_logic;
|
||||
prev_sample: std_logic_vector(3 downto 0);
|
||||
pending_events: std_logic_vector(3 downto 0);
|
||||
fifo_in_valid: std_logic;
|
||||
fifo_in_evmask: std_logic_vector(3 downto 0);
|
||||
out_valid: std_logic;
|
||||
out_data: dma_data_type;
|
||||
end record;
|
||||
|
||||
constant regs_init: regs_type := (
|
||||
overflow => '0',
|
||||
marker_pending => '0',
|
||||
marker_holdoff => '0',
|
||||
prev_sample => (others => '0'),
|
||||
pending_events => (others => '0'),
|
||||
fifo_in_valid => '0',
|
||||
fifo_in_evmask => (others => '0'),
|
||||
out_valid => '0',
|
||||
out_data => (others => '0')
|
||||
);
|
||||
|
||||
signal r: regs_type := regs_init;
|
||||
signal rnext: regs_type;
|
||||
|
||||
signal s_fifo_in_ready: std_logic;
|
||||
signal s_fifo_in_data: std_logic_vector(55 downto 0);
|
||||
signal s_fifo_out_valid: std_logic;
|
||||
signal s_fifo_out_ready: std_logic;
|
||||
signal s_fifo_out_data: std_logic_vector(55 downto 0);
|
||||
|
||||
-- Return the index of the first active channel.
|
||||
function find_first_active_channel(ev: std_logic_vector; st: std_logic_vector)
|
||||
return std_logic_vector
|
||||
is
|
||||
constant x: std_logic_vector(ev'length - 1 downto 0) := ev;
|
||||
constant y: std_logic_vector(st'length - 1 downto 0) := st;
|
||||
variable r: std_logic_vector(3 downto 0) := "0000";
|
||||
begin
|
||||
for i in 0 to x'high loop
|
||||
if x(i) = '1' then
|
||||
r(3 downto 1) := std_logic_vector(to_unsigned(i, 3));
|
||||
r(0) := not y(i);
|
||||
exit;
|
||||
end if;
|
||||
end loop;
|
||||
return r;
|
||||
end function;
|
||||
|
||||
-- Clear the least significant non-zero bit.
|
||||
function clear_first_nonzero(ev: std_logic_vector)
|
||||
return std_logic_vector
|
||||
is
|
||||
variable r: std_logic_vector(ev'length - 1 downto 0);
|
||||
begin
|
||||
r := ev;
|
||||
for i in 0 to r'high loop
|
||||
if r(i) = '1' then
|
||||
r(i) := '0';
|
||||
exit;
|
||||
end if;
|
||||
end loop;
|
||||
return r;
|
||||
end function;
|
||||
|
||||
begin
|
||||
|
||||
-- Small FIFO buffer for events.
|
||||
-- A single entry in this buffer may expand into multiple event records
|
||||
-- thus taking up multiple clock cycles.
|
||||
inst_event_fifo: entity work.simple_fifo
|
||||
generic map (
|
||||
data_width => 56,
|
||||
fifo_depth_bits => 4,
|
||||
block_ram => false )
|
||||
port map (
|
||||
clk => clk,
|
||||
reset => reset,
|
||||
in_valid => r.fifo_in_valid,
|
||||
in_ready => s_fifo_in_ready,
|
||||
in_data => s_fifo_in_data,
|
||||
out_valid => s_fifo_out_valid,
|
||||
out_ready => s_fifo_out_ready,
|
||||
out_data => s_fifo_out_data,
|
||||
queue_length => open );
|
||||
|
||||
-- Drive data to FIFO.
|
||||
-- bits 55 : 52 = mask of active channels
|
||||
-- bits 51 : 48 = new input state after events
|
||||
-- bits 47 : 0 = timestamp
|
||||
s_fifo_in_data <= r.fifo_in_evmask & r.prev_sample & timestamp_in;
|
||||
|
||||
-- Read from FIFO if we can produce an output record and there
|
||||
-- are no pending events.
|
||||
s_fifo_out_ready <= out_ready and (not or_reduce(r.pending_events));
|
||||
|
||||
-- Drive output ports.
|
||||
out_valid <= r.out_valid;
|
||||
out_data <= r.out_data;
|
||||
|
||||
--
|
||||
-- Combinatorial process.
|
||||
--
|
||||
process (all) is
|
||||
variable v: regs_type;
|
||||
begin
|
||||
-- Load current register values.
|
||||
v := r;
|
||||
|
||||
-- Latch marker request.
|
||||
if marker = '1' then
|
||||
v.marker_pending := '1';
|
||||
end if;
|
||||
|
||||
-- Hold off marker record emission during the cycle following insertion
|
||||
-- of an event into the FIFO. This prevents the marker record from
|
||||
-- cutting in line and appearing before an event record with an
|
||||
-- earlier timestamp.
|
||||
v.marker_holdoff := r.fifo_in_valid;
|
||||
|
||||
--
|
||||
-- Detect events and write to FIFO.
|
||||
---
|
||||
|
||||
-- Hold previous input state.
|
||||
v.prev_sample := dig_sample;
|
||||
|
||||
-- Detect events on enabled channels.
|
||||
for i in 0 to 3 loop
|
||||
v.fifo_in_evmask(i) :=
|
||||
(channel_en(2*i) and (not r.prev_sample(i)) and dig_sample(i))
|
||||
or (channel_en(2*i+1) and r.prev_sample(i) and (not dig_sample(i)));
|
||||
end loop;
|
||||
|
||||
-- Write changes to FIFO.
|
||||
if (r.overflow = '0') and (or_reduce(v.fifo_in_evmask) = '1') then
|
||||
v.fifo_in_valid := '1';
|
||||
else
|
||||
v.fifo_in_valid := '0';
|
||||
end if;
|
||||
|
||||
-- Detect FIFO overflow.
|
||||
if (r.fifo_in_valid = '1') and (s_fifo_in_ready = '0') then
|
||||
v.overflow := '1';
|
||||
v.fifo_in_valid := '0';
|
||||
end if;
|
||||
|
||||
--
|
||||
-- Read from FIFO and generate event records.
|
||||
--
|
||||
|
||||
if out_ready = '1' then
|
||||
|
||||
-- By default, do not generate a new record.
|
||||
v.out_valid := '0';
|
||||
|
||||
if or_reduce(r.pending_events) = '1' then
|
||||
|
||||
-- Emit the next event of a series of simultaneous events.
|
||||
v.out_valid := '1';
|
||||
v.out_data(59 downto 56) := find_first_active_channel(
|
||||
r.pending_events,
|
||||
r.out_data(51 downto 48));
|
||||
|
||||
v.pending_events := clear_first_nonzero(r.pending_events);
|
||||
|
||||
elsif s_fifo_out_valid = '1' then
|
||||
|
||||
-- Got digital events from FIFO.
|
||||
-- Emit the first event. Keep any other events.
|
||||
v.out_valid := '1';
|
||||
v.out_data(63 downto 60) := msg_timetagger_data;
|
||||
v.out_data(59 downto 56) := find_first_active_channel(
|
||||
s_fifo_out_data(55 downto 52),
|
||||
s_fifo_out_data(51 downto 48));
|
||||
v.out_data(55 downto 52) := "0000";
|
||||
v.out_data(51 downto 48) := s_fifo_out_data(51 downto 48);
|
||||
v.out_data(47 downto 0) := s_fifo_out_data(47 downto 0);
|
||||
|
||||
v.pending_events := clear_first_nonzero(s_fifo_out_data(55 downto 52));
|
||||
|
||||
elsif r.overflow = '1' then
|
||||
|
||||
-- Wait until output buffer empty, then emit overflow record.
|
||||
v.out_data(63 downto 56) := msg_overflow;
|
||||
v.out_data(55 downto 0) := (others => '0');
|
||||
if out_empty = '1' then
|
||||
v.out_valid := '1';
|
||||
v.overflow := '0';
|
||||
end if;
|
||||
|
||||
elsif (r.marker_pending = '1') and (r.marker_holdoff = '0') then
|
||||
|
||||
-- Emit marker record.
|
||||
v.out_valid := '1';
|
||||
v.out_data(63 downto 56) := msg_marker;
|
||||
v.out_data(55 downto 52) := "0000";
|
||||
v.out_data(51 downto 48) := r.prev_sample;
|
||||
v.out_data(47 downto 0) := timestamp_in;
|
||||
|
||||
v.marker_pending := '0';
|
||||
|
||||
end if;
|
||||
|
||||
end if;
|
||||
|
||||
--
|
||||
-- Synchronous reset.
|
||||
--
|
||||
if reset = '1' then
|
||||
v := regs_init;
|
||||
end if;
|
||||
|
||||
-- Drive new register values to synchronous process.
|
||||
rnext <= v;
|
||||
|
||||
end process;
|
||||
|
||||
--
|
||||
-- Synchronous process.
|
||||
--
|
||||
process (clk) is
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
r <= rnext;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end architecture;
|
|
@ -37,6 +37,7 @@ read_vhdl -vhdl2008 ../rtl/shift_engine.vhd
|
|||
read_vhdl -vhdl2008 ../rtl/syncdff.vhd
|
||||
read_vhdl -vhdl2008 ../rtl/simple_fifo.vhd
|
||||
read_vhdl -vhdl2008 ../rtl/timestamp_gen.vhd
|
||||
read_vhdl -vhdl2008 ../rtl/timetagger.vhd
|
||||
read_vhdl -vhdl2008 ../rtl/trigger_detector.vhd
|
||||
read_vhdl -vhdl2008 ../rtl/puzzlefw_top.vhd
|
||||
|
||||
|
|
|
@ -59,6 +59,16 @@
|
|||
#define REG_ADC1_MINMAX 0x0294
|
||||
#define REG_ADC2_MINMAX 0x0298
|
||||
#define REG_ADC3_MINMAX 0x029c
|
||||
#define REG_TT_ADDR_START 0x0300
|
||||
#define REG_TT_ADDR_END 0x0304
|
||||
#define REG_TT_ADDR_LIMIT 0x0308
|
||||
#define REG_TT_ADDR_INTR 0x030c
|
||||
#define REG_TT_ADDR_PTR 0x0310
|
||||
#define REG_TT_DMA_CTRL 0x0314
|
||||
#define REG_TT_INTR_CTRL 0x0318
|
||||
#define REG_TT_DMA_STATUS 0x031c
|
||||
#define REG_TIMETAGGER_EN 0x0320
|
||||
#define REG_TIMETAGGER_MARK 0x0324
|
||||
#define REG_DIG_SIMULATE 0x0330
|
||||
#define REG_DIG_SAMPLE 0x0338
|
||||
#define REG_LED_STATE 0x0404
|
||||
|
@ -635,6 +645,33 @@ static void show_status(struct puzzlefw_context *ctx)
|
|||
v = puzzlefw_read_reg(ctx, REG_DIG_SAMPLE);
|
||||
printf(" digital input = %d %d %d %d\n",
|
||||
(v >> 3) & 1, (v >> 2) & 1, (v >> 1) & 1, v & 1);
|
||||
|
||||
v = puzzlefw_read_reg(ctx, REG_TT_ADDR_START);
|
||||
printf(" tt_addr_start = 0x%08x\n", v);
|
||||
|
||||
v = puzzlefw_read_reg(ctx, REG_TT_ADDR_END);
|
||||
printf(" tt_addr_end = 0x%08x\n", v);
|
||||
|
||||
v = puzzlefw_read_reg(ctx, REG_TT_ADDR_LIMIT);
|
||||
printf(" tt_addr_limit = 0x%08x\n", v);
|
||||
|
||||
v = puzzlefw_read_reg(ctx, REG_TT_ADDR_INTR);
|
||||
printf(" tt_addr_intr = 0x%08x\n", v);
|
||||
|
||||
v = puzzlefw_read_reg(ctx, REG_TT_ADDR_PTR);
|
||||
printf(" tt_addr_ptr = 0x%08x\n", v);
|
||||
|
||||
v = puzzlefw_read_reg(ctx, REG_TT_DMA_CTRL);
|
||||
printf(" tt_dma_ctrl = 0x%08x\n", v);
|
||||
|
||||
v = puzzlefw_read_reg(ctx, REG_TT_DMA_STATUS);
|
||||
printf(" tt_dma_status = 0x%08x\n", v);
|
||||
|
||||
v = puzzlefw_read_reg(ctx, REG_TT_INTR_CTRL);
|
||||
printf(" tt_intr_ctrl = 0x%08x\n", v);
|
||||
|
||||
v = puzzlefw_read_reg(ctx, REG_TIMETAGGER_EN);
|
||||
printf(" timetagger_en = 0x%08x\n", v);
|
||||
}
|
||||
|
||||
|
||||
|
@ -775,10 +812,15 @@ static int send_all(int conn, const void *buf, size_t len)
|
|||
static int wait_dma_data(
|
||||
struct puzzlefw_context *ctx,
|
||||
int conn,
|
||||
int timetagger,
|
||||
uint32_t read_pointer,
|
||||
uint32_t wait_avail,
|
||||
int timeout_ms)
|
||||
{
|
||||
const uint32_t reg_addr_ptr = timetagger ? REG_TT_ADDR_PTR : REG_ACQ_ADDR_PTR;
|
||||
const uint32_t reg_addr_intr = timetagger ? REG_TT_ADDR_INTR : REG_ACQ_ADDR_INTR;
|
||||
const uint32_t reg_intr_ctrl = timetagger ? REG_TT_INTR_CTRL : REG_ACQ_INTR_CTRL;
|
||||
|
||||
assert(wait_avail > 0);
|
||||
assert(wait_avail % ctx->dma_transfer_size == 0);
|
||||
|
||||
|
@ -787,20 +829,20 @@ static int wait_dma_data(
|
|||
if (addr_intr >= ctx->dma_buf_size) {
|
||||
addr_intr -= ctx->dma_buf_size;
|
||||
}
|
||||
puzzlefw_write_reg(ctx, REG_ACQ_ADDR_INTR, addr_intr);
|
||||
puzzlefw_write_reg(ctx, REG_ACQ_INTR_CTRL, 3);
|
||||
puzzlefw_write_reg(ctx, reg_addr_intr, addr_intr);
|
||||
puzzlefw_write_reg(ctx, reg_intr_ctrl, 3);
|
||||
|
||||
// Check if data are already available.
|
||||
// This is necessary to prevent a race condition when data becomes
|
||||
// available just before the interrupt is enabled.
|
||||
uint32_t write_pointer = puzzlefw_read_reg(ctx, REG_ACQ_ADDR_PTR);
|
||||
uint32_t write_pointer = puzzlefw_read_reg(ctx, reg_addr_ptr);
|
||||
uint32_t navail =
|
||||
(write_pointer >= read_pointer) ?
|
||||
(write_pointer - read_pointer) :
|
||||
(ctx->dma_buf_size + write_pointer - read_pointer);
|
||||
if (navail >= wait_avail) {
|
||||
// Data already available; disable DMA writer interrupts.
|
||||
puzzlefw_write_reg(ctx, REG_ACQ_INTR_CTRL, 2);
|
||||
puzzlefw_write_reg(ctx, reg_intr_ctrl, 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -821,7 +863,7 @@ static int wait_dma_data(
|
|||
}
|
||||
|
||||
// Disable DMA writer interrupt and clear pending interrupt.
|
||||
puzzlefw_write_reg(ctx, REG_ACQ_INTR_CTRL, 2);
|
||||
puzzlefw_write_reg(ctx, reg_intr_ctrl, 2);
|
||||
|
||||
if ((fds[0].revents & POLLIN) != 0) {
|
||||
// Interrupt occurred.
|
||||
|
@ -847,7 +889,7 @@ static int wait_dma_data(
|
|||
*
|
||||
* Keep running until the TCP connection is closed.
|
||||
*/
|
||||
int transmit_dma_data(struct puzzlefw_context *ctx, int conn)
|
||||
int transmit_dma_data(struct puzzlefw_context *ctx, int conn, int timetagger)
|
||||
{
|
||||
// Maximum block size per TCP send() call.
|
||||
const uint32_t send_max_block = 65536;
|
||||
|
@ -861,6 +903,15 @@ int transmit_dma_data(struct puzzlefw_context *ctx, int conn)
|
|||
// Reserve this number of bytes in the buffer to avoid ambiguous pointers.
|
||||
const uint32_t pointer_margin = 4096;
|
||||
|
||||
const uint32_t reg_dma_ctrl = timetagger ? REG_TT_DMA_CTRL : REG_ACQ_DMA_CTRL;
|
||||
const uint32_t reg_dma_status = timetagger ? REG_TT_DMA_STATUS : REG_ACQ_DMA_STATUS;
|
||||
const uint32_t reg_addr_start = timetagger ? REG_TT_ADDR_START : REG_ACQ_ADDR_START;
|
||||
const uint32_t reg_addr_end = timetagger ? REG_TT_ADDR_END : REG_ACQ_ADDR_END;
|
||||
const uint32_t reg_addr_limit = timetagger ? REG_TT_ADDR_LIMIT : REG_ACQ_ADDR_LIMIT;
|
||||
const uint32_t reg_addr_ptr = timetagger ? REG_TT_ADDR_PTR : REG_ACQ_ADDR_PTR;
|
||||
const uint32_t reg_intr_ctrl = timetagger ? REG_TT_INTR_CTRL : REG_ACQ_INTR_CTRL;
|
||||
|
||||
|
||||
assert(ctx->dma_buf_size >= 2 * wait_block_size);
|
||||
assert(send_max_block % ctx->dma_transfer_size == 0);
|
||||
assert(wait_block_size % ctx->dma_transfer_size == 0);
|
||||
|
@ -870,16 +921,15 @@ int transmit_dma_data(struct puzzlefw_context *ctx, int conn)
|
|||
puzzlefw_write_reg(ctx, REG_DMA_EN, 0);
|
||||
|
||||
// Disable DMA write channel.
|
||||
puzzlefw_write_reg(ctx, REG_ACQ_DMA_CTRL, 0);
|
||||
puzzlefw_write_reg(ctx, reg_dma_ctrl, 0);
|
||||
|
||||
// Initialize DMA write buffer.
|
||||
puzzlefw_write_reg(ctx, REG_ACQ_ADDR_START, 0);
|
||||
puzzlefw_write_reg(ctx, REG_ACQ_ADDR_END, ctx->dma_buf_size);
|
||||
puzzlefw_write_reg(ctx, REG_ACQ_ADDR_LIMIT,
|
||||
ctx->dma_buf_size - pointer_margin);
|
||||
puzzlefw_write_reg(ctx, reg_addr_start, 0);
|
||||
puzzlefw_write_reg(ctx, reg_addr_end, ctx->dma_buf_size);
|
||||
puzzlefw_write_reg(ctx, reg_addr_limit, ctx->dma_buf_size - pointer_margin);
|
||||
|
||||
// Disable DMA writer interrupts; clear interrupt status.
|
||||
puzzlefw_write_reg(ctx, REG_ACQ_INTR_CTRL, 2);
|
||||
puzzlefw_write_reg(ctx, reg_intr_ctrl, 2);
|
||||
|
||||
// Clear AXI DMA state.
|
||||
puzzlefw_write_reg(ctx, REG_DMA_CLEAR, 1);
|
||||
|
@ -888,10 +938,10 @@ int transmit_dma_data(struct puzzlefw_context *ctx, int conn)
|
|||
puzzlefw_write_reg(ctx, REG_DMA_EN, 1);
|
||||
|
||||
// Initialize DMA writer.
|
||||
puzzlefw_write_reg(ctx, REG_ACQ_DMA_CTRL, 2);
|
||||
puzzlefw_write_reg(ctx, reg_dma_ctrl, 2);
|
||||
|
||||
// Enable DMA writer.
|
||||
puzzlefw_write_reg(ctx, REG_ACQ_DMA_CTRL, 1);
|
||||
puzzlefw_write_reg(ctx, reg_dma_ctrl, 1);
|
||||
|
||||
uint32_t read_pointer = 0;
|
||||
int ret;
|
||||
|
@ -899,7 +949,7 @@ int transmit_dma_data(struct puzzlefw_context *ctx, int conn)
|
|||
while (1) {
|
||||
|
||||
// Check DMA status.
|
||||
uint32_t status = puzzlefw_read_reg(ctx, REG_DMA_STATUS);
|
||||
uint32_t status = puzzlefw_read_reg(ctx, reg_dma_status);
|
||||
if ((status & 0x1e) != 0) {
|
||||
// DMA error.
|
||||
fprintf(stderr, "ERROR: DMA error, status=0x%08x\n", status);
|
||||
|
@ -908,7 +958,7 @@ int transmit_dma_data(struct puzzlefw_context *ctx, int conn)
|
|||
}
|
||||
|
||||
// Determine number of bytes available.
|
||||
uint32_t write_pointer = puzzlefw_read_reg(ctx, REG_ACQ_ADDR_PTR);
|
||||
uint32_t write_pointer = puzzlefw_read_reg(ctx, reg_addr_ptr);
|
||||
uint32_t navail = (write_pointer >= read_pointer) ?
|
||||
(write_pointer - read_pointer) :
|
||||
(ctx->dma_buf_size + write_pointer - read_pointer);
|
||||
|
@ -916,6 +966,7 @@ int transmit_dma_data(struct puzzlefw_context *ctx, int conn)
|
|||
// Wait for enough data in the buffer, or timeout.
|
||||
if (navail < wait_block_size) {
|
||||
ret = wait_dma_data(ctx, conn,
|
||||
timetagger,
|
||||
read_pointer,
|
||||
wait_block_size,
|
||||
timeout_ms);
|
||||
|
@ -928,7 +979,7 @@ int transmit_dma_data(struct puzzlefw_context *ctx, int conn)
|
|||
break;
|
||||
}
|
||||
|
||||
write_pointer = puzzlefw_read_reg(ctx, REG_ACQ_ADDR_PTR);
|
||||
write_pointer = puzzlefw_read_reg(ctx, reg_addr_ptr);
|
||||
}
|
||||
|
||||
// Determine number of bytes available.
|
||||
|
@ -958,8 +1009,7 @@ int transmit_dma_data(struct puzzlefw_context *ctx, int conn)
|
|||
// Update read pointer and update DMA writer limit.
|
||||
read_pointer += block_size;
|
||||
if (read_pointer > pointer_margin) {
|
||||
puzzlefw_write_reg(ctx, REG_ACQ_ADDR_LIMIT,
|
||||
read_pointer - pointer_margin);
|
||||
puzzlefw_write_reg(ctx, reg_addr_limit, read_pointer - pointer_margin);
|
||||
}
|
||||
|
||||
navail -= block_size;
|
||||
|
@ -985,10 +1035,10 @@ int transmit_dma_data(struct puzzlefw_context *ctx, int conn)
|
|||
puzzlefw_write_reg(ctx, REG_DMA_EN, 0);
|
||||
|
||||
// Disable DMA write channel.
|
||||
puzzlefw_write_reg(ctx, REG_ACQ_DMA_CTRL, 0);
|
||||
puzzlefw_write_reg(ctx, reg_dma_ctrl, 0);
|
||||
|
||||
// Disable DMA writer interrupts; clear interrupt status.
|
||||
puzzlefw_write_reg(ctx, REG_ACQ_INTR_CTRL, 2);
|
||||
puzzlefw_write_reg(ctx, reg_intr_ctrl, 2);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -997,9 +1047,9 @@ int transmit_dma_data(struct puzzlefw_context *ctx, int conn)
|
|||
/*
|
||||
* Run TCP server.
|
||||
*/
|
||||
int run_server(struct puzzlefw_context *ctx)
|
||||
int run_server(struct puzzlefw_context *ctx, int timetagger)
|
||||
{
|
||||
const int tcp_port = 5001;
|
||||
const int tcp_port = timetagger ? 5002 : 5001;
|
||||
|
||||
// Create server socket.
|
||||
int srv_sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
@ -1038,7 +1088,7 @@ int run_server(struct puzzlefw_context *ctx)
|
|||
|
||||
close(srv_sock);
|
||||
|
||||
int ret = transmit_dma_data(ctx, conn);
|
||||
int ret = transmit_dma_data(ctx, conn, timetagger);
|
||||
|
||||
close(conn);
|
||||
|
||||
|
@ -1064,7 +1114,9 @@ int main(int argc, char **argv)
|
|||
int acqoff = 0;
|
||||
int trigger = 0;
|
||||
int trigauto = 0;
|
||||
int trigext = 0;
|
||||
int trignone = 0;
|
||||
int trigfall = 0, trigrise = 0;
|
||||
int set_trigdelay = 0, trigdelay = 0;
|
||||
int set_reclen = 0, reclen = 0;
|
||||
int set_decimate = 0, decimate = 0;
|
||||
|
@ -1073,6 +1125,9 @@ int main(int argc, char **argv)
|
|||
int simon = 0, simoff = 0;
|
||||
int rangeclear = 0;
|
||||
int set_digsim = 0, digsim = 0;
|
||||
int set_timetagger = 0, timetagger_en = 0;
|
||||
int marker = 0;
|
||||
int ttserver = 0;
|
||||
|
||||
if (argc == 2 && strcmp(argv[1], "show") == 0) {
|
||||
show = 1;
|
||||
|
@ -1098,8 +1153,14 @@ int main(int argc, char **argv)
|
|||
trigger = 1;
|
||||
} else if (argc == 2 && strcmp(argv[1], "trigauto") == 0) {
|
||||
trigauto = 1;
|
||||
} else if (argc == 2 && strcmp(argv[1], "trigext") == 0) {
|
||||
trigext = 1;
|
||||
} else if (argc == 2 && strcmp(argv[1], "trignone") == 0) {
|
||||
trignone = 1;
|
||||
} else if (argc == 2 && strcmp(argv[1], "trigfall") == 0) {
|
||||
trigfall = 1;
|
||||
} else if (argc == 2 && strcmp(argv[1], "trigrise") == 0) {
|
||||
trigrise = 1;
|
||||
} else if (argc == 3 && strcmp(argv[1], "trigdelay") == 0) {
|
||||
set_trigdelay = 1;
|
||||
trigdelay = atoi(argv[2]);
|
||||
|
@ -1129,8 +1190,15 @@ int main(int argc, char **argv)
|
|||
} else {
|
||||
digsim = atoi(argv[2]);
|
||||
}
|
||||
} else if (argc == 3 && strcmp(argv[1], "timetagger") == 0) {
|
||||
set_timetagger = 1;
|
||||
timetagger_en = atoi(argv[2]);
|
||||
} else if (argc == 2 && strcmp(argv[1], "marker") == 0) {
|
||||
marker = 1;
|
||||
} else if (argc == 2 && strcmp(argv[1], "server") == 0) {
|
||||
server = 1;
|
||||
} else if (argc == 2 && strcmp(argv[1], "ttserver") == 0) {
|
||||
ttserver = 1;
|
||||
} else {
|
||||
printf(
|
||||
"Usage:\n"
|
||||
|
@ -1170,9 +1238,18 @@ int main(int argc, char **argv)
|
|||
" testje trigauto\n"
|
||||
" Enable continuous triggering.\n"
|
||||
"\n"
|
||||
" testje trigext\n"
|
||||
" Enable external trigger.\n"
|
||||
"\n"
|
||||
" testje trignone\n"
|
||||
" Disable triggering.\n"
|
||||
"\n"
|
||||
" testje trigrise\n"
|
||||
" Trigger on rising edge.\n"
|
||||
"\n"
|
||||
" testje trigfall\n"
|
||||
" Trigger on falling edge.\n"
|
||||
"\n"
|
||||
" testje trigdelay N\n"
|
||||
" Set trigger delay N cycles.\n"
|
||||
"\n"
|
||||
|
@ -1200,11 +1277,20 @@ int main(int argc, char **argv)
|
|||
" testje rangeclear\n"
|
||||
" Clear min/max ADC sample monitor.\n"
|
||||
"\n"
|
||||
" testje digsim N/'off'\n"
|
||||
" testje digsim N|'off'\n"
|
||||
" Set simulated digital input.\n"
|
||||
"\n"
|
||||
" testje timetagger MASK\n"
|
||||
" Specify set of enabled time tagger channels.\n"
|
||||
"\n"
|
||||
" testje marker\n"
|
||||
" Emit a marker in the time tagger stream.\n"
|
||||
"\n"
|
||||
" testje server\n"
|
||||
" Open TCP port 5001 to stream DMA data.\n"
|
||||
" Open TCP port 5001 to stream ADC data.\n"
|
||||
"\n"
|
||||
" testje ttserver\n"
|
||||
" Open TCP port 5002 to stream time tagger data.\n"
|
||||
"\n");
|
||||
if (argc > 1) {
|
||||
fprintf(stderr, "ERROR: Invalid command\n");
|
||||
|
@ -1266,10 +1352,22 @@ int main(int argc, char **argv)
|
|||
puzzlefw_set_trigger_mode(&ctx, TRIG_AUTO);
|
||||
}
|
||||
|
||||
if (trigext) {
|
||||
puzzlefw_set_trigger_mode(&ctx, TRIG_EXTERNAL);
|
||||
}
|
||||
|
||||
if (trignone) {
|
||||
puzzlefw_set_trigger_mode(&ctx, TRIG_NONE);
|
||||
}
|
||||
|
||||
if (trigrise) {
|
||||
puzzlefw_set_trigger_ext_falling(&ctx, 0);
|
||||
}
|
||||
|
||||
if (trigfall) {
|
||||
puzzlefw_set_trigger_ext_falling(&ctx, 1);
|
||||
}
|
||||
|
||||
if (set_trigdelay) {
|
||||
puzzlefw_write_reg(&ctx, REG_TRIGGER_DELAY, trigdelay);
|
||||
}
|
||||
|
@ -1314,8 +1412,20 @@ int main(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
|
||||
if (set_timetagger) {
|
||||
puzzlefw_write_reg(&ctx, REG_TIMETAGGER_EN, timetagger_en);
|
||||
}
|
||||
|
||||
if (marker) {
|
||||
puzzlefw_write_reg(&ctx, REG_TIMETAGGER_MARK, 1);
|
||||
}
|
||||
|
||||
if (server) {
|
||||
run_server(&ctx);
|
||||
run_server(&ctx, 0);
|
||||
}
|
||||
|
||||
if (ttserver) {
|
||||
run_server(&ctx, 1);
|
||||
}
|
||||
|
||||
puzzlefw_close(&ctx);
|
||||
|
|
Loading…
Reference in New Issue