Task synthesis in verilog

If I am writing a “task” or a “function” in verilog and calling that “task” or “function” in the same module where I have written task then how will it be synthesized? How my hardware will look?
Suppose I am calling that “task” on every positive edge of clock then will the hardware of task repeat as many times as it is called?
I am confused!!

In reply to Payal_Ashar:

The task or function gets in-lined, meaning the code inside the routine gets inserted at the place where it was called. Pretty much the same as if you used a text macro.

The task or function gets in-lined, meaning the code inside the routine gets inserted at the place where it was called.

Hello Dave,
I am a newbie here both on this forum and with Verilog as well. You are a professional in this field, I have no doubts, but this statement about Tasks does not seem to be right. Please help. I am trying to grasp Tasks, I have been reading about them for days now and I still do not get it. They do not work as expected by what I have read so far. Here is my code that I ran in my simulator:


module alma();

reg clk = 0;
always  #1 clk <= !clk;

reg [3:0] yt_in = 1;  // yt = yes task
reg [3:0] yt_out;
reg [3:0] yt_cc = 0;

reg [3:0] nt_in = 1;   // nt = no task
reg [3:0] nt_out;
reg [3:0] nt_cc = 0;

task count (input [3:0] in, output [3:0] out );      
begin
    out <= in + 1;
end
endtask

always @(posedge clk)
begin
   yt_cc <= yt_cc + 1;  // cc = cycle counter
   count(yt_in, yt_out);
end

always @(posedge clk)
begin
   nt_cc  <= nt_cc + 1;  // cc = cycle counter
   nt_out <= nt_in + 1;
end

endmodule

My yt_out signal gets assigned one clock cycle later than nt_out. Is this ok? Is this how Tasks supposed to work? (My two cycle counters run parallel, their values are equal, no problem.)
(Unfortunately the picture insertion button here works the same way as the link button right next to it, it is a bug, so I cannot insert the simulation waveform screenshot.)

Thank you very much
Miklos

In reply to mbence76:

The issue you have discovered is that using non-blocking assignments to the output argument of a task/function gives you unexpected results. Input arguments get copied upon entry, and output arguments get copied upon exit of the routine. When using a non-blocking assignment to the output argument, the “old” value gets copied out. The next time you call your task, the output argument has the “new” value from the non-blocking assignment.

So you can change your task to assign yt_out directly

task count (input [3:0] in);      
begin
    yt_out <= in + 1;
end
endtask

Or use an intermediate variable

task count (input [3:0] in, output [3:0] out );      
begin
    out = in + 1;
end
end task
reg [3:0] temp;
always @(posedge clk)
begin
   
   yt_cc <= yt_cc + 1;  // cc = cycle counter
   count(yt_in, temp);
    yt_out <= temp;
end

See this discussion for more info.

In reply to dave_59:

Hi Dave, thanks for your explanation and the options how to modify the code.

But if we use a blocking assignment and an intermediate variable, then the Task becomes kindof a function in the sense that it will have no temporal dimension. In the above example it does not matter, but where I came to this question in the first place was actually to kickoff a Task (like sending out a UART character) while the other parts of the always block can continue. But it turned out that Tasks first have to “return” to where they were called. No problem. The rest can wait. But what I wonder now is, can you put any kind of potential blocking event in a Task at all? The tutorials say yes. But maybe they all think of simulation and not synthesis. You said in many posts that most synthesizers accept only one blocking event (usually a posedge clk), and if a Task is like in-line code then it cannot have a potential blocking event, can it?

(By the way, what language construct would suit me in activating a UART process?)

Thank you.

Miklos

In reply to mbence76:

You are correct, a task without any blocking statements is essentially a function. Verilog requires functions to have return values and only be part of an expression. But SystemVerilog added void functions that you would use instead and guarantee that they have no blocking statements.

You are also correct that for RTL synthesis you can only have one blocking event. There have been other behavioral synthesis tools that did accept more than one, but they have not been very successful.

In reply to dave_59:

OK, then - for synthesis - Tasks had better use blocking assignments only (or assign the signal in the calling block itself) and thus they behave like any other “one line” non-blocking assignement in the always block. Therefore Task are not intended to be very complex, their sole purpose is to save typing for repetitive structures, to make the code less redundant, but their purpose is not to break down the design into independent units. I guess it makes little sense to call an (automatic) Task only once within an always block (within the same cycle) bacause then it will not save any redundant typing. Am I right about that?

Then if I am not mistaken events (to sync processes) are not for synthesis either (exept for the posedge clk).

Do you think the iff keyword could be what I am looking for (to kick off a process by enabling it and then to make it stop when it is finished) ?

In reply to mbence76:

Tasks are NOT normally used in synthesis - for the basic reason (As Dave stated) that synthesis tools generally only recognize the ONE blocking event - i.e the always @( posedge clk ) at the beginning of the procedural block.

So, for synthesis, one cannot add any more blocking events in a task - so it’s pointless to use a task. Use functions instead.

The iff keyword is not synthesizable under any tools that I know of, so that’s not useful. I’m not sure what your intent is with using it either. The phrase “make it stop when it is finished” is NOT a hardware concept. The hardware is there or it isn’t. If you want to “make it stop” you’re now describing stateful behavior - you should be coding a state machine. “Make it stop” => “Return to idle state”.

Regards,

Mark

In reply to Mark Curry:

Hello Mark,

thank you for your reply. Ok, now I understand. Where I said I want my process “to stop when it is finished”, I was thinking of stopping in an idle state, and not ticking anymore. Turning clock off. Of course you need an enable signal to make it tick again. I was hoping the “iff enable” would do that, but it does not synthesize as you said. (Unfortunately my synthesizer did not stop with a failure message, but it “synthesized” my code into some wierd nonsense. :( )

Miklos