- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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;Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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;
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page