Verilog Simulation Testbench  timing output async events. - Page 1
Forum section: electronics / general

author: BrianHG
author_rank: Super Contributor
timestamp: October 07, 2021, 07:36:28 am
content: Ok, say I have a simulation where I want a few manual 10 MHz clock cycles, I could write:Code:task run ();beginclk = 1 ;#(50);clk = 0 ;out1 = 1;out2 = 1;out3 = 1;#(50);clk = 1 ;#(50);clk = 0 ;out1 = 0;out2 = 0;out3 = 0;#(50);endendtaskNow, say I want to place a few stimulations at specific times inside that cycle, I want the first out1/2/3=1 to be delayed by an additional adjustable parameters, however, I do not want any other timing to change:Code:task run ();beginclk = 1 ;#(50);clk = 0 ;#(oldy_1) out1 = 1;#(odly_2) out2 = 1;#(odly_3) out3 = 1;#(50);clk = 1 ;#(50);clk = 0 ;out1 = 0;out2 = 0;out3 = 0;#(50);endendtaskThe problem with the above code is that the #(oldy_1/2/3) will mess up the clock timing and each one affects the timing of the next, especially if I need odly_2 to be shorter than odly_1.Instead of doing all the math, is there an easy way to specify the #(oldy_1/2/3) as a one-time event to take place at that time after the previous normal #(50), but not mess up the normal #(50) delay events?

author: dtodorov
author_rank: Contributor
timestamp: October 07, 2021, 11:01:38 am
content: fork...join?

author: BrianHG
author_rank: Super Contributor
timestamp: October 07, 2021, 02:23:50 pm
content: Thanks dtodorov, but I ended up making a separate :Code:always #(100) beginif (($time/100)==(etc[ 6]/100)) lZ80_DATA = 8'bzzzzzzzz ;if (($time/100)==(etc/100)) lZ80_DATA = nZ80_DATA ;if (($time/100)==(etc/100)) lZ80_ADDR = nZ80_ADDR ;if (($time/100)==(etc[ 8]/100)) lZ80_MREQ = 0 ;if (($time/100)==(etc/100)) lZ80_MREQ = 1 ;if (($time/100)==(etc/100)) lZ80_WR = 0 ;if (($time/100)==(etc/100)) lZ80_WR = 1 ;if (($time/100)==(etc/100)) lZ80_RD = 0 ;if (($time/100)==(etc/100)) lZ80_RD = 1 ;if (($time/100)==(etc/100)) lZ80_wait_sh = 1 ;if (($time/100)==(etc/100)) lZ80_wait_sh = 0 ;if (($time/100)==(etc/100)) lZ80_read_sh = 1 ;if (($time/100)==(etc/100)) lZ80_read_sh = 0 ;endAnd above in my task code, I have:Code:// Timings found in Zilog Z8400/Z84C00 NMOS/CMOS Z80 CPU Product Specification data sheet.// 4 MHz, 6 MHz, 8 MHz, 10 MHz, 20 MHzlocalparam int tc6 [0:4] = '{ 110000, 90000, 80000, 65000, 57000}; // TdCr(A)localparam int tc8 [0:4] = '{ 85000, 70000, 60000, 55000, 40000}; // TdCf(MREQf)localparam int tc12 [0:4] = '{ 85000, 70000, 60000, 55000, 40000}; // TdCf(MREQr)localparam int tc13 [0:4] = '{ 95000, 80000, 70000, 65000, 40000}; // TdCf(RDf)localparam int tc23 [0:4] = '{ 85000, 70000, 60000, 55000, 40000}; // TdCf(RDr)localparam int tc30 [0:4] = '{ 80000, 70000, 60000, 55000, 40000}; // TdCf(WRf)localparam int tc32 [0:4] = '{ 80000, 70000, 60000, 55000, 40000}; // TdCf(WRr)localparam int tc42 [0:4] = '{ 90000, 80000, 70000, 65000, 40000}; // TdCr(Dz)localparam int tc53 [0:4] = '{ 150000, 130000, 115000, 110000, 75000}; // TdCf(D).....@(posedge Z80_CLK);Z80_CKS_pos = 1 ;lZ80_ADDR = 16'bxxxxxxxxxxxxxxxx;nZ80_ADDR = tx_addr;nZ80_DATA = tx_data ;etc = tc6 + $time ; // Time until the Z80_data bus goes HI-Zetc = tc42 + $time ; // Time until the Z80_data bus address is valid.etc = tc8  + $time + zp ; // Time until the Z80_MREQ goes low.etc = tc53 + $time + zp ; // Time until the Z80 output data is valid. +zp means wait for the falling clock@(posedge Z80_CLK);Z80_CKS_pos = 2 ;etc = $time + zp - tc17 - (FPGA_IO_tsu*1000) ; // Setup time for sampling the 'WAIT' input.etc = tc18 + $time + zp - (FPGA_IO_tsu*1000) ; // Hold time for sampling the 'WAIT' input.etc = tc30 + $time + zp ; // Time until the Z80_WR goes low.@(posedge Z80_CLK);Z80_CKS_pos = 3 ;etc = tc12 + $time + zp ; // Time until the Z80_MREQ goes high.etc = tc32 + $time + zp ; // Time until the Z80_WR goes high.etc = tc23 + $time + zp ; // Time until the Z80_RD goes high.@(negedge Z80_CLK); // Z80_CKS_pos = 5 ;This appears to work fine.It generates a Z80 write bus cycle according to the data-sheet's worst case scenario for a selected MHz model.