Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
10 years ago

Need help with testbench driving serial data out @ different clock rates, Please :)

TestBench fills an 8 bit by 16 registers array with random numbers then serially shifts it to the TDM serial input. The TDM will be coming from a Sharc DSP @ 8bit x 16 slots and continuous frames and the VHDL will demux it to various ICs. The TestBench also generates clock and frame sync for the TDM input. The 192 & 48 clocks are divided and generated internally by the VHDL code under test. Sending serial data to the TDM input works exactly as I want but I can't figure out how to send the other serial data at different clocks at the same time.

serial data to mpx_sdi @ 2 x TDM clock

serial data to aud_sdi, tnr1_sdi, tnr2_sdi @ 8 x TDM clock

I posted the TestBench code and a diagram, may be it helps.

Also I have neatly separated and colored the waveforms in modelsim for this TestBench, is there a way to save these settings so each time I need to view this particular project, I don't have to set everything each time? Cheers for all, happy Christmas and new year everyone.

library ieee;

use ieee.std_logic_1164.all;

use ieee.numeric_std.all;

use ieee.math_real.all;

entity tdm_tb is

end tdm_tb;

architecture arch_tb of tdm_tb is

constant max_frames : natural := 5;

constant max_slot : natural := 15;

constant max_bits : natural := 7;

type my_data is array (0 to max_slot) of std_logic_vector(max_bits downto 0);

signal my_data_bit : my_data;

signal clk: std_logic;

signal rst: boolean;

signal tdm_sdi, tdm_fsi, tdm_sclki : std_logic;

signal tdm_sdo : std_logic;

signal mpx_sdi : std_logic;

signal mpx_sdo, mpx_sclk, mpx_wco : std_logic;

signal aud_sdi : std_logic;

signal aud_sdo, aud_wco, aud_sclko : std_logic;

signal hdn_sdo, hdn_wco, hdn_sclko : std_logic;

signal tnr1_sdi : std_logic;

signal tnr1_sdo, tnr1_wco, tnr1_sclko : std_logic;

signal tnr2_sdi : std_logic;

signal tnr2_sdo, tnr2_wco, tnr2_sclko : std_logic;

signal rand_num : natural := 0;

constant t_clk : time := 2 ps;

constant t_tdm : time := 3072 ps;

begin

tdm_uut: entity work.zalzett

port map (clk => clk, rst => rst,

tdm_sdi => tdm_sdi, tdm_fsi => tdm_fsi, tdm_sclki => tdm_sclki, tdm_sdo => tdm_sdo,

mpx_sdi => mpx_sdi, mpx_sdo => mpx_sdo, mpx_sclk => mpx_sclk, mpx_wco => mpx_wco,

aud_sdi => aud_sdi, aud_sdo => aud_sdo, aud_wco => aud_wco, aud_sclko => aud_sclko,

hdn_sdo => hdn_sdo, hdn_wco => hdn_wco, hdn_sclko => hdn_sclko,

tnr1_sdo => tnr1_sdo, tnr1_sdi => tnr1_sdi, tnr1_wco => tnr1_wco, tnr1_sclko => tnr1_sclko,

tnr2_sdo => tnr2_sdo, tnr2_sdi => tnr2_sdi, tnr2_wco => tnr2_wco, tnr2_sclko => tnr2_sclko);

clk <= '1' after t_clk/2 when clk = '0' else '0' after t_clk/2; --main clock

tdm_sclki <= not tdm_sclki after t_tdm/2 when rst = FALSE else '0'; -- TDM clock

--------------------random number generator

process

variable seed1, seed2: positive; -- seed values for random generator

variable rand: real; -- random real-number value in range 0 to 1.0

variable range_of_rand : real := 250.0; -- the range of random values created will be 0 to +250.

begin

for i in 0 to max_slot loop

uniform(seed1, seed2, rand); -- generate random number

rand_num <= integer(rand*range_of_rand); -- rescale to 0.250, convert integer part

my_data_bit(i) <= std_logic_vector(to_unsigned(rand_num, max_bits+1));

wait for t_tdm * (max_bits+1); --if I don't do this 'wait', numbers change without control.

end loop;

end process;

--main process

process

variable frame_cnt : natural range 0 to max_frames := 0;

variable slot_cnt : natural range 0 to max_slot := 0;

variable bit_cnt : natural range 0 to max_bits := max_bits;

begin

-----resetting the system

rst <= TRUE; tdm_fsi <= '0'; tdm_sdi <= '0'; wait for 5 ps;

rst <= FALSE;

-----new tdm frame sync

wait until rising_edge(tdm_sclki); tdm_fsi <= '1';

wait until rising_edge(tdm_sclki);

tdm_fsi <= '0';

for i in 0 to max_frames loop --frame loop

for j in 0 to max_slot loop --slot loop

for k in max_bits downto 0 loop --bit loop

tdm_sdi <= my_data_bit(j)(k);

wait until rising_edge(tdm_sclki);

if bit_cnt = 0 then

bit_cnt := max_bits;

tdm_fsi <= '0';

else

bit_cnt := bit_cnt -1;

if slot_cnt = (max_slot) and bit_cnt = 0 then

tdm_fsi <= '1';

end if;

end if;

end loop;

if slot_cnt = (max_slot) then

slot_cnt := 0;

else

slot_cnt := slot_cnt +1;

end if;

end loop;

frame_cnt := frame_cnt +1;

end loop;

wait until rising_edge(tdm_sclki);

wait until rising_edge(tdm_sclki);

wait until rising_edge(tdm_sclki);

wait until rising_edge(tdm_sclki);

end process;

end arch_tb;

5 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Ok, my comments on the existing code.

    1. Why is the clock period 2 ps? the default modelsim resultion is 100ps and anything less than this will probably round to nearest? this models a 500 GHz clock (i know it doesnt really matter, because it's event driven). But wouldnt it be better to have some more-realistic or easier to read clock (like 10 ns)?

    2. The data should be generated in the main process, not in a separate process. You should just generate words as you need them and then loop through the word to send it over the sdi. Generating the data as you need it will give you more freedom to input data at different speeds. You can have as many sets of seeds as you want to control the different input frames.

    3. With VHDL 2008 you have hierarchical signal referencing, so you can access the internal clocks from your testbench. The easiest way would be to alias the internal signal and then use it locally:

    alias internal_192khz : std_logic is <<signal tdm_uut.some_ent1.some_ent2.clk_192khz : std_logic >>;

    This way you can ensure the data is properly aligned with the clock.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi there, thanks for your reply. I did 2ns so I don't have to press a lot of F9 to run the simulation. Don't know if it makes any sense, any how. I didn't quite understand the second and third points. Please bear in mind that the data needs to go to each sdi @ different clock rates simultaneously. I would appreciate a sample code just to know from where to start. Cheers

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    You can run the simulation for as long as you want typing:

    run X ns/us/ms/s

    or even

    run -all

    (runs until all transactions are complete or simulation is forced to stop)

    Into the console.eg:

    run 100 us

    runs for 100 micro seconds.

    as for an example - how about this?:

    
    data_48khz_proc : process
        variable seed1, seed2 : positive;
        variable rand         : real;
        alias internal_48khz  : std_logic is <<signal tdm_uut.some_ent1.some_ent2.clk_192khz : std_logic >>;
        
        variable rnd_val      : std_logic_vector(7 downto 0);
        
    begin
        
        for bitcnt in 0 to 7 begin
            if bitcnt = 0 then
                uniform(seed1, seed2, rand); -- generate random number
                rand_num <= integer(rand*range_of_rand); -- rescale to 0.250, convert integer part 
                rnd_val <= std_logic_vector(to_unsigned(rand_num, max_bits+1));            
            end if;
            
            input <= rnd_val(bit_cnt);
            wait until rising_edge(internal_48khz);
            
        end loop;
    end process;
    
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi Tricky, Thanks for the replies. I haven't experimented with alias yet. So I don't really know how it works. But I shall read about it more and try to experiment a better test bench. Will alias solve the problem of sending serial data at different clock speed simultaneously in one process though? Thanks

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    An alias will do nothing on its own. You can only write the data at the correct rates it's you write the code to do so.