Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)
17256 Discussions

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

Altera_Forum
Honored Contributor II
2,894 Views

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;
0 Kudos
5 Replies
Altera_Forum
Honored Contributor II
2,155 Views

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.
0 Kudos
Altera_Forum
Honored Contributor II
2,155 Views

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

0 Kudos
Altera_Forum
Honored Contributor II
2,155 Views

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;
0 Kudos
Altera_Forum
Honored Contributor II
2,155 Views

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

0 Kudos
Altera_Forum
Honored Contributor II
2,155 Views

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.

0 Kudos
Reply