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;

Published

Category

snippets

Tags