Hi,
this is the pulse train producer I used in my master thesis. I needed to solve a
variable modulo problem in VHDL for this. By introducing an estimator I was able to do it.
Pulse train producer
--DESCRIPTION
--This entity takes three parameters once it detects a edge on edge_in
--afterwards, it will produce a pulse train in accordance with these parameters
--the ratio between the high speed clock and the low speed clock is 8
--tested with a 800MHz high speed clock
-- DELAY:
-- cycles before it starts producing the pulse train, 0-2**8-1
-- as this entity most likely will run with a faster clockj then the rest, I added
-- this parameter so you can sync stuff up beween the state machines clock cycles.
-- eg:
-- ___|^|_|^|_|^|____ (ch1)
--________|^|________ (ch2)
-- cannot be done without the delay parameter as |^| has a lenfth of about 1.25ns (800MHz clock) while minimal reaction time
-- for the state machine is 100ns (running at 10Mhz right now)
-- LENGTH:
-- width of the pulses to be produced, 1-2**8
-- eg:
-- ___|^^|____ (ch1) -> length = 2
-- ___|^|_____ (ch2) -> length = 1
-- COUNT:
-- number of pulses to be procuded, 1-2**8
-- This is needed if you want to have a pulse train.
-- Pulses will always be symmetric (so _|^|_|^|_ or _|^^^|___|^^^|___ but never _|^|___|^|___)
-- Reminder:
-- all values must be below their max values, either 0-2**8-1 or 1-2**8
LIBRARY IEEE ;
USE IEEE . STD_LOGIC_1164 . ALL ;
USE IEEE . NUMERIC_STD . ALL ;
LIBRARY UNISIM ;
USE UNISIM . VCOMPONENTS . ALL ;
ENTITY pulser_generic IS
PORT (
clk_in : IN STD_LOGIC ;
clk_high_speed_in : IN STD_LOGIC ;
edge_in : IN STD_LOGIC ;
rst_in : IN STD_LOGIC ;
length_in : IN Integer RANGE 1 TO 2 ** 8 ;
count_in : IN Integer RANGE 1 TO 2 ** 8 ;
delay_in : IN Integer RANGE 0 TO 2 ** 8-1 ;
pulse_out : OUT STD_LOGIC ;
finished_out : OUT STD_LOGIC
);
END pulser_generic ;
ARCHITECTURE main OF pulser_generic IS
SIGNAL edge_in_old : STD_LOGIC ;
SIGNAL serdes_input : STD_LOGIC_VECTOR ( 7 DOWNTO 0 );
SIGNAL estimator : INTEGER RANGE 0 TO 2 ** 8-1 ;
SIGNAL estimator_increase : INTEGER RANGE 1 TO 4 ;
SIGNAL chunk_counter : INTEGER RANGE -2 ** 5 TO 2 ** 14 ;
SIGNAL length_act : INTEGER RANGE 1 TO 2 ** 8 ;
SIGNAL count_act : INTEGER RANGE 1 TO 2 ** 8 ;
SIGNAL delay_act : INTEGER RANGE 0 TO 7 ;
SIGNAL running : STD_LOGIC ;
BEGIN
OSERDES2_inst : OSERDESE2
GENERIC MAP (
TBYTE_CTL => "FALSE" ,
TBYTE_SRC => "FALSE" ,
DATA_RATE_OQ => "SDR" ,
DATA_RATE_TQ => "SDR" ,
DATA_WIDTH => 8 ,
INIT_OQ => '0' ,
INIT_TQ => '0' ,
SERDES_MODE => "MASTER" ,
SRVAL_OQ => '0' ,
SRVAL_TQ => '0' ,
TRISTATE_WIDTH => 1
)
PORT MAP (
OFB => open ,
OQ => pulse_out ,
SHIFTOUT1 => open ,
SHIFTOUT2 => open ,
TBYTEOUT => open ,
TFB => open ,
TQ => open ,
CLK => clk_high_speed_in ,
CLKDIV => clk_in ,
D1 => serdes_input ( 0 ),
D2 => serdes_input ( 1 ),
D3 => serdes_input ( 2 ),
D4 => serdes_input ( 3 ),
D5 => serdes_input ( 4 ),
D6 => serdes_input ( 5 ),
D7 => serdes_input ( 6 ),
D8 => serdes_input ( 7 ),
OCE => '1' ,
RST => rst_in ,
SHIFTIN1 => '0' ,
SHIFTIN2 => '0' ,
T1 => '0' ,
T2 => '0' ,
T3 => '0' ,
T4 => '0' ,
TBYTEIN => '0' ,
TCE => '0'
);
finished_out <= NOT running ;
PROCESS ( clk_in )
BEGIN
IF RISING_EDGE ( clk_in ) THEN
edge_in_old <= edge_in ;
serdes_input <= ( '0' , '0' , '0' , '0' , '0' , '0' , '0' , '0' );
IF rst_in = '1' THEN
running <= '0' ;
ELSIF running = '1' AND chunk_counter * 8 >= 2 * length_act * count_act + delay_act THEN
running <= '0' ;
ELSIF edge_in_old = '0' AND edge_in = '1' AND running = '0' THEN
running <= '1' ;
length_act <= length_in ;
count_act <= count_in ;
delay_act <= delay_in MOD 8 ;
chunk_counter <= - delay_act / 8 ;
estimator <= 0 ;
CASE length_in IS
WHEN 1 => estimator_increase <= 4 ;
WHEN 2 | 3 => estimator_increase <= 2 ;
WHEN OTHERS => estimator_increase <= 1 ;
END CASE ;
ELSE
IF estimator * 2 * length_act + delay_act < 8 * chunk_counter THEN
estimator <= estimator + estimator_increase ;
END IF ;
chunk_counter <= chunk_counter + 1 ;
FOR i IN 0 TO 7 LOOP
IF chunk_counter * 8 + i < 2 * length_act * count_act + delay_act AND (
--we should only have 4 here but somewhere is a "one-off"-error and I just cannot find it right now
--the problem is that the estimator is being counted up one to early but I do not see why this is.
--test with delay_act = 7 and delay_act = 0 to see this error
(( 2 * estimator - 2 ) * length_act + delay_act <= chunk_counter * 8 + i AND chunk_counter * 8 + i < ( 2 * estimator - 2 + 1 ) * length_act + delay_act ) OR
(( 2 * estimator + 0 ) * length_act + delay_act <= chunk_counter * 8 + i AND chunk_counter * 8 + i < ( 2 * estimator + 0 + 1 ) * length_act + delay_act ) OR
(( 2 * estimator + 2 ) * length_act + delay_act <= chunk_counter * 8 + i AND chunk_counter * 8 + i < ( 2 * estimator + 2 + 1 ) * length_act + delay_act ) OR
(( 2 * estimator + 4 ) * length_act + delay_act <= chunk_counter * 8 + i AND chunk_counter * 8 + i < ( 2 * estimator + 4 + 1 ) * length_act + delay_act ) OR
(( 2 * estimator + 6 ) * length_act + delay_act <= chunk_counter * 8 + i AND chunk_counter * 8 + i < ( 2 * estimator + 6 + 1 ) * length_act + delay_act )) THEN
serdes_input ( i ) <= running ;
END IF ;
--alternative version but did not generate optimized code
--variable tmp: std_logic;
--tmp:= '0';
--FOR j IN -1 TO 3 LOOP
-- tmp:= tmp and '1' IF ((2*estimator + 2*j)*length_act + delay_act <= chunk_counter * 8 + i AND chunk_counter * 8 + i < (2*estimator + 2*j + 1)*length_act + delay_act) ELSE '0';
--END LOOP;
--IF tmp = '1' THEN
-- serdes_input(i) <= running;
--END if;
END LOOP ;
END IF ;
END IF ;
END PROCESS ;
END main ;