Forum Discussion

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

Using tasks with wait segments in Verilog

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.

3 Replies

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

    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.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    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
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    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