Commit 1da5cbfa authored by Javier Díaz's avatar Javier Díaz Committed by Miguel Jimenez Lopez

new register for controlling pulse_length and trigger ready interrupts

parent 6c4814e0
files = ["wrsw_dio_wb.vhd",
"wrsw_dio.vhd",
"dummy_time.vhd" ]
"wrsw_dio.vhd",
"pulse_gen_pl.vhd",
"immed_pulse_counter.vhd",
"dummy_time.vhd" ]
-------------------------------------------------------------------------------
-- Entity: immed_pulse counter
-- File: immed_pulse counter.vhd
-- Description: a simple synchronous output based on strobe inputs that produces a N-ticks
-- length pulse.
-- Author: Javier Díaz (jdiaz@atc.ugr.es)
-- Date: 9 July 2012
-- Version: 0.01
-- Properties:
-- TBD
-- Todo:
-- TBD
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-- 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;
entity immed_pulse_counter is
generic (
-- reference clock frequency
pulse_length_width : integer := 28
);
port (
clk_i : in std_logic;
rst_n_i : in std_logic; -- asynchronous system reset
pulse_start_i : in std_logic; -- strobe for pulse generation
pulse_length_i : in std_logic_vector(pulse_length_width-1 downto 0);
pulse_output_o : out std_logic
);
end immed_pulse_counter;
architecture rtl of immed_pulse_counter is
-- Internal registers to hold pulse duration
signal counter : unsigned (pulse_length_width-1 downto 0);
-- Signals for states
type counter_state is (WAIT_ST, COUNTING);
signal state : counter_state;
-- Aux
constant zeros : std_logic_vector(pulse_length_width-1 downto 0) := (others=>'0');
begin -- architecture rtl
state_process : process(clk_i, rst_n_i)
begin
if (rst_n_i='0') then
counter <=(others=>'0');
state <=WAIT_ST;
elsif rising_edge(clk_i) then
case state is
when WAIT_ST =>
if pulse_start_i='1' and pulse_length_i/=zeros then
state <=COUNTING;
counter <=unsigned(pulse_length_i)-1;
else
state<=WAIT_ST;
end if;
when COUNTING =>
if (counter=0) then
state <= WAIT_ST;
else
state <= COUNTING;
counter<=counter-1;
end if;
when others =>
state<=WAIT_ST;
end case;
end if;
end process;
output_process:process(counter, state)
begin
if (rst_n_i='0') then
pulse_output_o <='0';
else
case state is
when WAIT_ST =>
pulse_output_o <='0';
when COUNTING =>
pulse_output_o <='1';
when others =>
pulse_output_o <='0';
end case;
end if;
end process;
end architecture rtl;
-------------------------------------------------------------------------------
-- Entity: pulse_gen_pl
-- File: pulse_gen_pl.vhd
-- Description: a pulse generator which produces a N-ticks length pulse in its
-- output when the time passed to it through a vector equals a
-- pre-programmed time.
-- Author: Javier Díaz (jdiaz@atc.ugr.es)
-- Based on the pulse_gen code of Javier Serrano (Javier.Serrano@cern.ch)
-- Date: 6 July 2012
-- Version: 0.02
-- Properties:
-- 1) After arming the trigger, new trigger values are not possible during for 13 clk_sys
-- ticks (208 ns for a 62,5 MHz clock, trig_ready_o<='0') --> not MESURABLE BY PC-SOFTWARE.
-- 2) Minimum of 7 clk_refs ticks are needed between trigger_time and its activation
-- (trig_valid_p1 = 1)
-- Trigger values can be overwritten when trig_ready_o without generate current assigment output
-- Todo: Substitute ready_for_trig process by a state machine.
-- Factor out synchronizer in a separate reusable block.
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-- 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;
entity pulse_gen_pl is
generic (
-- reference clock frequency
g_ref_clk_rate : integer := 125000000);
port (
clk_ref_i : in std_logic; -- timing reference clock
clk_sys_i : in std_logic; -- data output reference clock
rst_n_i : in std_logic; -- system reset
pulse_o : out std_logic; -- pulse output
-------------------------------------------------------------------------------
-- Timing input (from WRPC), clk_ref_i domain
------------------------------------------------------------------------------
-- 1: time given on tm_utc_i and tm_cycles_i is valid (otherwise, don't
-- produce pulses and keep trig_ready_o line permamaently active)
tm_time_valid_i : in std_logic;
-- number of seconds
tm_utc_i : in std_logic_vector(39 downto 0);
-- number of clk_ref_i cycles
tm_cycles_i : in std_logic_vector(27 downto 0);
---------------------------------------------------------------------------
-- Time tag output (clk_sys_i domain)
---------------------------------------------------------------------------
-- 1: input is ready to accept next trigger time tag
trig_ready_o : out std_logic;
-- time at which the pulse will be produced + a single-cycle strobe to
-- latch it in
trig_utc_i : in std_logic_vector(39 downto 0);
trig_cycles_i : in std_logic_vector(27 downto 0);
trig_valid_p1_i : in std_logic;
pulse_length_i : in std_logic_vector(27 downto 0)
);
end pulse_gen_pl;
architecture rtl of pulse_gen_pl is
-- Internal registers to hold trigger time and pulse duration
signal trig_utc, trig_utc_ref : std_logic_vector(39 downto 0);
signal trig_cycles, trig_cycles_ref : std_logic_vector(27 downto 0);
signal pulse_length, pulse_length_ref : std_logic_vector(27 downto 0);
-- Signals for the synchronizer
signal trig_valid_sys_d1, trig_valid_sys_d2 : std_logic;
signal rst_from_sync, rst_from_sync_d1 : std_logic;
signal trig_valid_ref : std_logic_vector(2 downto 0);
signal trig_valid_back : std_logic_vector(2 downto 0);
signal trig_valid_ref_p1 : std_logic;
-- Aux
constant zeros : std_logic_vector(27 downto 0) := (others=>'0');
signal counter : unsigned (27 downto 0);
begin -- architecture rtl
-- Get trigger time into internal registers
trig_regs: process (clk_sys_i) is
begin -- process trig_regs
if clk_sys_i'event and clk_sys_i = '1' then
if rst_n_i='0' then
trig_utc <= (others=>'0');
trig_cycles <= (others=>'0');
pulse_length <= (others=>'0');
elsif trig_valid_p1_i='1' then
if trig_cycles_i=zeros then
-- Delay 1 sys_ref tick time trigger to match pulse generation at exact time
-- (otherwise 1 clock cycle delay is presented)
trig_utc <= std_logic_vector(unsigned(trig_utc_i)-to_unsigned(1,trig_utc'length));
trig_cycles <= (others=>'1');
else
trig_utc <= trig_utc_i;
trig_cycles <= std_logic_vector(unsigned(trig_cycles_i)-to_unsigned(1,trig_cycles'length));
end if;
pulse_length <= pulse_length_i;
end if;
end if;
end process trig_regs;
-- Synchronizer to pass UTC register data to the reference clock domain
-- This synchronizer is made with the following four processes
-- First one FF with async reset, still in the clk_sys_i domain
sync_first_ff: process (clk_sys_i, rst_n_i, rst_from_sync)
begin
if rst_n_i='0' or rst_from_sync='1' then
trig_valid_sys_d1 <= '0';
elsif clk_sys_i'event and clk_sys_i='1' then
if trig_valid_p1_i='1' then
trig_valid_sys_d1 <= '1';
end if;
end if;
end process sync_first_ff;
-- OK this is just for the UTC and cycle registers to have time to settle
-- in the pathological case of a very fast ref clock and very long
-- combinational delays in the UTC and cycle registers
delay_sys: process (clk_sys_i)
begin
if clk_sys_i'event and clk_sys_i='1' then
trig_valid_sys_d2 <= trig_valid_sys_d1;
end if;
end process delay_sys;
-- Then three FFs to take the strobe safely into the clk_ref_i domain
sync_ref: process (clk_ref_i)
begin
if clk_ref_i'event and clk_ref_i='1' then
trig_valid_ref <= trig_valid_ref(1 downto 0) & trig_valid_sys_d2;
trig_valid_ref_p1 <= trig_valid_ref(1) and not trig_valid_ref(2);
end if;
end process sync_ref;
-- And then back into the clk_sys_i domain
sync_sys: process (clk_sys_i)
begin
if clk_sys_i'event and clk_sys_i='1' then
trig_valid_back <= trig_valid_back(1 downto 0) & trig_valid_ref(2);
rst_from_sync <= trig_valid_back(2);
rst_from_sync_d1 <= rst_from_sync;
end if;
end process sync_sys;
-- Now get the trig registers into the clk_ref_i domain
trig_regs_ref: process (clk_ref_i)
begin
if clk_ref_i'event and clk_ref_i='1' then
if trig_valid_ref_p1='1' then
trig_utc_ref <= trig_utc;
trig_cycles_ref <= trig_cycles;
pulse_length_ref <= pulse_length;
end if;
end if;
end process trig_regs_ref;
-- Notify we're ready to receive another trigger time write
-- Having the reset set trig_ready_o to '1' is a kludge.
-- A proper state machine would be better.
ready_for_trig: process (rst_n_i, clk_sys_i)
begin
if rst_n_i='0' then
trig_ready_o <= '1';
elsif clk_sys_i'event and clk_sys_i='1' then
if trig_valid_p1_i='1' then
trig_ready_o <= '0';
elsif rst_from_sync_d1='1' and rst_from_sync='0' then
-- falling edge of reset_from_sync
trig_ready_o <= '1';
end if;
end if;
end process ready_for_trig;
-- Produce output
-- Note rst_n_i is used as an async reset because it comes from the
-- clk_sys_i domain. Not the most elegant but it ensures no glitches
-- in the output after startup.
-- This block actually creates a pulse pulse_length ticks when the programmed
-- time matches the current time.
gen_out: process (rst_n_i, clk_ref_i)
begin
if rst_n_i='0' then
pulse_o <= '0';
elsif clk_ref_i'event and clk_ref_i='1' then
if tm_time_valid_i ='0' then
pulse_o <= '0';
elsif tm_utc_i=trig_utc_ref and tm_cycles_i=trig_cycles_ref and pulse_length_ref/=zeros then
pulse_o <= '1';
counter <=unsigned(pulse_length_ref)-1;
elsif counter/=0 then
counter<=counter-1;
else
pulse_o <= '0';
end if;
end if;
end process gen_out;
end architecture rtl;
This diff is collapsed.
......@@ -6,9 +6,9 @@ peripheral {
hdl_entity="wrsw_dio_wb";
---------------------------------------
-- FIFOS FOR INPUT EVENT TIME STAMPING
---------------------------------------
----------------------------------------------------
-- FIFOS & INTERRUPTS FOR INPUT EVENT TIME STAMPING
----------------------------------------------------
-- CHANNEL 0 INPUT FIFO
......@@ -499,11 +499,14 @@ peripheral {
};
};
-----------------------------------------
-- OUTPUT CONFIGURATION/CONTROL REGISTERS
-----------------------------------------
-- Monostable/Programmable output or GPIO selection
-- Programmable output or GPIO selection
reg {
name = "FMC-DIO output configuration register. ";
description = "It allows to choose a Monostable/programmable output or a standard GPIO output.";
description = "It allows to choose a programmable output or a standard GPIO output.";
prefix = "out";
field {
......@@ -557,7 +560,7 @@ peripheral {
-- seconds trigger ready value. Readable-writable the bus, writable from the device.
reg {
name = "FMC-DIO seconds-based trigger is ready to accept a new trigger generation request";
name = "FMC-DIO time trigger is ready to accept a new trigger generation request";
description = "ready state, waiting new trigger commands for dio output.";
prefix = "trig";
......@@ -572,45 +575,167 @@ peripheral {
};
};
-- DIO CHANNEL 0 trigger ready interrupt
irq {
name = "Channel 0 trigger ready interrupt";
description = "Interrupt active when time-programmable output channels accept new time trigger command.";
prefix = "trigger_ready_0";
trigger = LEVEL_1;
};
-- DIO CHANNEL 1 trigger ready interrupt
irq {
name = "Channel 1 trigger ready interrupt";
description = "Interrupt active when time-programmable output channels accept new time trigger command.";
prefix = "trigger_ready_1";
trigger = LEVEL_1;
};
-- DIO CHANNEL 2 trigger ready interrupt
irq {
name = "Channel 2 trigger ready interrupt";
description = "Interrupt active when time-programmable output channels accept new time trigger command.";
prefix = "trigger_ready_2";
trigger = LEVEL_1;
};
-- DIO CHANNEL 3 trigger ready interrupt
irq {
name = "Channel 3 trigger ready interrupt";
description = "Interrupt active when time-programmable output channels accept new time trigger command.";
prefix = "trigger_ready_3";
trigger = LEVEL_1;
};
-- DIO CHANNEL 4 trigger ready interrupt
irq {
name = "Channel 4 trigger ready interrupt";
description = "Interrupt active when time-programmable output channels accept new time trigger command.";
prefix = "trigger_ready_4";
trigger = LEVEL_1;
};
-- DIO CHANNEL 0: Programmable/immediate output pulse length . Readable-writable the bus, readble from the device.
reg {
name = "fmc-dio channel 0 Programmable/immediate output pulse length";
description = "Number of clk_ref clock ticks that output will be active";
prefix = "prog0_pulse";
field {
name = "number of ticks field for channel 0";
description = "ticks number";
prefix = "length";
type = SLV;
size = 28;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
-- DIO CHANNEL 1: Programmable/immediate output pulse length . Readable-writable the bus, readble from the device.
reg {
name = "fmc-dio channel 1 Programmable/immediate output pulse length";
description = "Number of clk_ref clock ticks that output will be active";
prefix = "prog1_pulse";
field {
name = "number of ticks field for channel 1";
description = "ticks number";
prefix = "length";
type = SLV;
size = 28;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
-- DIO CHANNEL 2: Programmable/immediate output pulse length . Readable-writable the bus, readble from the device.
reg {
name = "fmc-dio channel 2 Programmable/immediate output pulse length";
description = "Number of clk_ref clock ticks that output will be active";
prefix = "prog2_pulse";
field {
name = "number of ticks field for channel 2";
description = "ticks number";
prefix = "length";
type = SLV;
size = 28;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
-- DIO CHANNEL 3: Programmable/immediate output pulse length . Readable-writable the bus, readble from the device.
reg {
name = "fmc-dio channel 3 Programmable/immediate output pulse length";
description = "Number of clk_ref clock ticks that output will be active";
prefix = "prog3_pulse";
field {
name = "number of ticks field for channel 3";
description = "ticks number";
prefix = "length";
type = SLV;
size = 28;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
-- DIO CHANNEL 4: Programmable/immediate output pulse length . Readable-writable the bus, readble from the device.
reg {
name = "fmc-dio channel 4 Programmable/immediate output pulse length";
description = "Number of clk_ref clock ticks that output will be active";
prefix = "prog4_pulse";
field {
name = "number of ticks field for channel 4";
description = "ticks number";
prefix = "length";
type = SLV;
size = 28;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
-----------------------------------------
-- IMMEDIATE OUTPUT REGISTERS
-----------------------------------------
-- Pulse generator.
reg {
name = "Pulse generate immediately";
description = "It is used to generate a pulse immediately";
prefix = "puls_inmed";
prefix = "pulse";
field {
name = "pulse_gen_now_0";
description = "It generates a pulse";
prefix = "pul_inm_0";
prefix = "imm_0";
type = MONOSTABLE;
clock = "clk_asyn_i";
};
field {
name = "pulse_gen_now_1";
description = "It generates a pulse";
prefix = "pul_inm_1";
prefix = "imm_1";
type = MONOSTABLE;
clock = "clk_asyn_i";
};
field {
name = "pulse_gen_now_2";
description = "It generates a pulse";
prefix = "pul_inm_2";
prefix = "imm_2";
type = MONOSTABLE;
clock = "clk_asyn_i";
};
field {
name = "pulse_gen_now_3";
description = "It generates a pulse";
prefix = "pul_inm_3";
prefix = "imm_3";
type = MONOSTABLE;
clock = "clk_asyn_i";
};
field {
name = "pulse_gen_now_4";
description = "It generates a pulse";
prefix = "pul_inm_4";
prefix = "imm_4";
type = MONOSTABLE;
clock = "clk_asyn_i";
};
......
This diff is collapsed.
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