1
votes

I have a Verilog testbench for a FIFO and I think using tasks to perform push and pop would be more effective than what I am doing now. Currently, I use a sequence of repeat (ticks) @ (negedge clk) statements to push, pop or push and pop in a long initial begin/end block.

This makes the code ugly and difficult to read. I would rather have a task, push_task(ticks), that I can call. Something like this -

initial begin
    task_push(5);
    task_pop(2);
    task_push(10);
    ...
end

The problem is, if I write my push_task like this -

task push_task;
    input [31:0] ticks;
    repeat (ticks) begin
            push <= 1'b1;
            push_data <= $random % (2**DATA_WIDTH);
            @ (negedge clk);
            push <= 1'b0;
        end
    end
endtask

and I have a similar pop_task, then I can either push or pop but not both at the same time. How do I get both to either execute at the same time or sequentially depending on what I want to do?

One obvious way is to create a third task that does both. Another way is to have a singe task with three inputs, ticks, push and pop and have push and pop be asserted based on whether the inputs to the task are asserted or not.

Does anyone have another (better?) way of doing this? I can find plenty of information online about what the syntax of tasks is and how to write them. Not much about what the correct way of using them is.

1

1 Answers

1
votes

Use fork-join for parallel operations, begin-end for sequential. Nesting is allowed.

Ex:

initial begin
  task_push(10);
  fork // parallel operations
    task_push(4);
    task_pop(7);
  join
  // back to sequential
  fork // another parallel operation
    task_push(6);
    begin // sequential within parallel
      task_pop(2);
      @(negedge clk); // no pop for one cycle
      task_pop(3);
    end
  join
end

FYI I will suggest changing your tasks to be more like the following. The header is more conventional; a IEEE1364-2001 & above and IEEE1800 style instead of the legacy IEEE1364-1995 style. Moving the assignments to push outside the loop will save some CPU cycles in simulation. Your CPU time is probably nothing, but something to consider when scaling up to significantly larger project.

task push_task(input [31:0] ticks);
begin
  push <= 1'b1;
  repeat (ticks) begin
    push_data <= $random % (2**DATA_WIDTH);
    @(negedge clk);
  end
  push <= 1'b0;
end
endtask