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

Using tasks with wait segments in Verilog

Altera_Forum
Honored Contributor II
3,416 Views

Hello, 

 

I have a problem with using wait segments in my task. I am trying to test a deserializer, that has to work with a specific format. I want to give the full byte to send to the task, then it transforms it to the format the deserializer, and in the end I check whether the input corresponds to the output.  

My code for the task is: 

 

task send_8bit; input reg Y8bit; input reg C8bit; output reg rx_in; integer counter; reg PIXEL_IN_Y1; reg PIXEL_IN_Y2; reg PIXEL_IN_C1; reg PIXEL_IN_C2; begin // Data protocol: // Y1: Y6 Y5 Y4 Y3 Y2 Y1 Y0 // Y2: 0 0 0 X X X Y7 // C1: C6 C5 C4 C3 C2 C1 C0 // C2: 0 0 0 0 0 C6 C7 PIXEL_IN_Y1=Y8bit; PIXEL_IN_Y2=Y8bit; PIXEL_IN_C1=C8bit; PIXEL_IN_C2=C8bit; PIXEL_IN_C2=C8bit; PIXEL_IN_Y2=6'b000XXX; PIXEL_IN_C2=5'b00000; Y8bit_debug=Y8bit; C8bit_debug=C8bit; for(counter = 6; counter >=0; counter = counter - 1) begin # 1924 //length of 1 data period in ps rx_in= PIXEL_IN_Y1; rx_in= PIXEL_IN_Y2; rx_in= PIXEL_IN_C1; rx_in= PIXEL_IN_C2; end end endtask 

 

However, the code does not work, it seems it only assigns the values once. I simply want to have the option to write send_8bit(MYBYTE1,MYBYTE2,OUTPUT);, have rx_in appear on OUTPUT at the right times and be done with it.
0 Kudos
3 Replies
Altera_Forum
Honored Contributor II
1,770 Views

In Verilog, input arguments get copied upon entry, and output arguments get copied upon exit of a task or function. If you use Systemverilog, you can change the last argument to a ref, which means rx_in will be a reference to the actual argument instead of a value that gets copied to it. 

task automatic send_8bit( input reg Y8bit, input reg C8bit, ref reg rx_in ); 

Most tools now support SystemVerilog just by changing the file extension from *.v to *.SystemVerilog . Note that the task needs to have an automatic lifetime to use the ref argument.  

 

If you are not able to do this, your only other option is for the task to directly modify OUPUT instead of passing it in as an argument to the task.
0 Kudos
Altera_Forum
Honored Contributor II
1,770 Views

Thank you, it works now. 

 

For anyone stumbling upon this question, note that the task must be automatic; so the working code is: 

 

task automatic send_8bit; input reg Y8bit; input reg C8bit; ref reg rx_in; integer counter; reg PIXEL_IN_Y1; reg PIXEL_IN_Y2; reg PIXEL_IN_C1; reg PIXEL_IN_C2; begin // Data protocol for the Tamron camera: // Y1: Y6 Y5 Y4 Y3 Y2 Y1 Y0 // Y2: 0 0 0 X X X Y7 // C1: C6 C5 C4 C3 C2 C1 C0 // C2: 0 0 0 0 0 C6 C7 PIXEL_IN_Y1=Y8bit; PIXEL_IN_Y2=Y8bit; PIXEL_IN_C1=C8bit; PIXEL_IN_C2=C8bit; PIXEL_IN_C2=C8bit; PIXEL_IN_Y2=6'b000XXX; PIXEL_IN_C2=5'b00000; Y8bit_debug=Y8bit; C8bit_debug=C8bit; for(counter = 6; counter >=0; counter = counter - 1) begin # 1924 //length of 1 data period in ps rx_in= PIXEL_IN_Y1; rx_in= PIXEL_IN_Y2; rx_in= PIXEL_IN_C1; rx_in= PIXEL_IN_C2; end end endtask
0 Kudos
Altera_Forum
Honored Contributor II
1,770 Views

The use of 'automatic' means the verilog compiler/simulator must make the task re-entrant, so it must copy all input/outputs to temp variables during execution. So this probably means you are calling the task multiple times in parallel, while older invocations are still executing, because of your builtin time delays. 

 

As an example, in old style verilog, I have the task just reference the module signals in its called context, and not pass everything as arguments. I also don't call the task again until I know the existing call has finished (which in my case calling it multiple times in parallel does not make any sense). 

 

Example: 

 

reg sd_dat_adr = 0; reg sd_dat_wen = 0; reg sd_dat_din = 0; wire sd_dat_dout; task rd_buf; input fradr; input toadr; integer i; begin @(posedge clk)# TPD ; $write("\n"); for (i = fradr; i <= toadr; i = i+1) begin sd_dat_adr = i; sd_dat_wen = 0; sd_dat_din = 0; @(posedge clk)# TPD ; @(posedge clk)# TPD ; @(posedge clk)# TPD ; if (sd_dat_adr % 16 == 0) $write("%h:", sd_dat_adr); $write(" %h", sd_dat_dout); if (sd_dat_adr % 16 == 15) $write("\n"); end @(posedge clk)# TPD ; $write("\n"); end endtask // rd_buf  

 

And then in my testbench I just call the task when needed: 

 

initial begin init_card(10); rd_buf(0,511); delay(250); $finish; end
0 Kudos
Reply