task
in
Verilogtask
KeywordA task
is a
group of statements that would usually appear in an always
block.
If we need to repeat the same statements multiple times, it makes sense
to define them as a task
. Common
examples include simple data format conversions, such as reversing the
bit order in a vector. Say we have an 8-bit vector v
. In some specifications, the Least
Significant Bit (LSB) is on the “right”, i.e. v[0]. In other
specifications, the LSB is on the “left”, i.e. v[7].
For some project, we may need to reverse the bit order of several
vectors. This particularly occurs with filesystem interfaces and data
communication channels. Do do this, we could use for
loops, as
in this code snippet:
input [7:0] a, b;
output reg [7:0] q, w;
integer idx; // Loop Index
always @(a,b) begin
for (idx=0; idx<8; idx=idx+1) begin
[7-idx] = a[idx];
q[7-idx] = b[idx];
wend
end
This seems simple enough, but if we need to do this for many
different signals, in multiple modules, it would make sense to group
these lines into a simpler reusable statement. To accomplish this, we
put the loop into a task
like
this:
task automatic reverse_bits_task;
input [7:0] in;
output [7:0] out;
integer idx;
begin
for (idx=0; idx<8; idx=idx+1) begin
[7-idx] = in[idx];
outend
end
endtask
Then to use the task
, we
reference it within an always
block
like this:
always @(a,b) begin
(.in(a),.out(q));
reverse_bits_task(.in(b),.out(w));
reverse_bits_taskend
The task
definition has to appear inside of the module. The automatic
keyword is usually required; it instructs the simulator to allocate
fresh memory every time the task is evaluated. The default non-automatic
behavior has fewer applications and can create subtle simulation
bugs.
So almost always your tasks should be automatic.
Tasks probably get the most use in testbenches. We’ll start with a
simple example that simulates the reverse_bits_task
shown above. In a
text editor, open the file src/testbench.v
.
At the bottom of the testbench module, place the definition for reverse_bits_task
. Find the always
block
that assigns q
and w
, and change it from for
loops to
task invocations. You should remove or comment out the declaration of
idx
since it is now defined
within the task.
Type make
to run the
simulation. You should see several lines of output reporting a->q and
b->w. Verify that the bits are correctly reversed in each case.
A task can be reused in a variety of different modules and
testbenches. To facilitate this, Verilog has a `include
directive that imports lines
from external files. You can use this to organize reverse_bits_task
in its own file.
Move the reverse_bits_task
definition into a file called inc/reverse_bits_task.v
(remove or comment the task definition in testbench.v
). Then, in the testbench,
add the include directive from inside the module:
`include "inc/reverse_bits_task.v"
Run the test again, you should get the same result.
Next, remove or comment the `include
line in the testbench.v
. Create a new module file
named src/reverse_bits_module.v
,
to act as a “wrapper” for the task:
module reverse_bits_module
(
input [7:0] a,
input [7:0] b,
output reg [7:0] q,
output reg [7:0] w
);
`include "inc/reverse_bits_task.v"
always @(a,b) begin
(a,q);
reverse_bits_task(b,w);
reverse_bits_taskend
endmodule
In the testbench, remove or comment the lines that reference the
reverse_bits_task
, and make an
instance of reverse_bits_module
.
You will need to change q
and
w
to wire
types.
reverse_bits_module
A task is synthesizable if it
Examples of non-synthesizeable statements include:
#N
syntax$display
or
$random
To be synthesizeable, a module needs inputs and outputs, and should be fully defined by synthesizeable statements; non-synthesizeable lines can exist for simulation purposes, but they are ignored during synthesis.
Fortunately for our task
, a for
loop is
synthesizeable. With reverse_bits_module
serving as a top
module, we can synthesize and verify the design on the Basys3 board.
Open reverse_bits.xdc
and
examine the constraints. Input vector a
is mapped to switches 0–7, and input
vector b
is mapped to switches
8–15. Output vector q
is mapped
to LEDs 0–7, and w
is mapped to
8–15. Also notice that there is no clock in this design.
Run make implement
to build
the design. Since there is no clock or other timing constraints in the
design, the timing report is meaningless. The utilization report is more
interesting. Open it and notice that there is no logic utilization –
zero. The reverse_bits_task
is
implemented entirely in routing, i.e. switch
configurations.
If successful, the build process should create reverse_bits.bit
. Program the Basys3
board with this bitstream and verify that the left/right 8-bit groups
are reversed. Verify and photograph the following cases:
a=00010011
,
b=01010101
a=11101100
,
b=01101001
Place photos of the two cases in your working directory, and name
them case1
and case2
(with the appropriate graphics
file extension).
To complete this assignment, commit and push your results to the repository, and indicate on Canvas that it is complete:
git add *.bit *.rpt *.txt inc/ src/*
git commit . -m "Complete."
git push origin main