Verilog · Chapter 15.5 · Tasks & Functions
Tasks & Functions Advanced in Verilog — Synthesis Rules & Patterns
This lesson closes the chapter with the synthesis rules and practical patterns for tasks and functions. The synthesis boundary is simple to state. A function is always synthesizable because it is combinational, while a task is synthesizable only when it contains no timing, since a timed task is simulation only. Functions slot into continuous assignments and always blocks as reusable combinational computation, and tasks structure procedures and timed stimulus in testbenches. You will also learn the patterns worth knowing, including passing arrays and producing several outputs from one task, the rule that a function may call other functions but never a task, and how tasks and functions compose into clean, reusable behavioural code. Working through these rules leaves you able to reuse logic confidently while staying on the synthesizable side of the line.
Foundation10 min readVerilogTasksFunctionsSynthesisReuse
Chapter 15 · Section 15.5 · Tasks & Functions
1. The Engineering Problem
Using tasks and functions well means knowing the synthesis boundary and the composition rules:
A function is synthesizable (combinational); a task is synthesizable only without timing. Functions go in expressions/
always; tasks structure procedures. A function can't call a task; tasks compose freely.
This page drills the advanced rules and patterns.
2. Synthesis Rules
The synthesizability of tasks and functions:
- Functions are synthesizable — they are combinational (no timing, one return), so synthesis inlines them as logic at each call site.
- Tasks are synthesizable only without timing — a task with no
#/@/waitis inlinable logic; a timed task is simulation-only. - Same timing boundary as procedural code — timing belongs in testbenches; synthesizable tasks/functions are timing-free.
function [7:0] saturate; // synthesizable (combinational)
input [8:0] sum;
saturate = sum[8] ? 8'hFF : sum[7:0];
endfunction
assign result = saturate(a + b); // function in a continuous assignment
task automatic clamp; // synthesizable task (no timing)
input [8:0] in;
output [7:0] out;
out = in[8] ? 8'hFF : in[7:0];
endtaskA function used in an assign (saturate) and a timing-free task (clamp) are both synthesizable combinational reuse.
3. Functions in Assignments and always Blocks
Functions slot anywhere a value is needed:
assign p = parity(data); // continuous assignment
always @(*) y = saturate(a + b); // combinational always
always @(posedge clk) q <= encode(state); // function value registeredA function returns a value usable in continuous assignments, combinational always blocks, and even as the right-hand side of a non-blocking assignment in a clocked block (the function computes combinationally; the result is registered). This makes functions clean reusable computation across all of behavioural code.
4. Multiple Outputs and Passing Arrays
A task produces multiple outputs via output arguments, and tasks/functions can pass arrays:
// a task with multiple outputs:
task divmod;
input [7:0] num, den;
output [7:0] quot, rem;
begin
quot = num / den;
rem = num % den;
end
endtask
// call: divmod(a, b, q, r); // q and r receive both outputsWhen you need more than one result, a task with several output arguments is the construct (a function returns only one value). Tasks and functions can also take array arguments for bulk operations. This is the everyday pattern for multi-result reusable operations.
Visual A — synthesis boundary
Tasks & functions — synthesis boundary
data flow5. Composition Rules
- A function can call only functions (not tasks — tasks may have timing, functions can't).
- A task can call tasks and functions.
- Tasks and functions compose — a task can use functions for its computations, functions can call helper functions — to build clean, layered reusable code.
6. Common Mistakes
- Timed task in synthesizable design — only timing-free tasks synthesize (§2).
- Function calling a task — illegal; functions call only functions (§5).
- Function for multiple outputs — use a task with output args (§4).
7. Interview Q&A
8. Exercises
Exercise 1 — Function in an assign
Write a function clog2-style bits_needed (for a constant) and use it to size a register width.
Exercise 2 — Multiple outputs
Write a task that returns both the min and max of two inputs.
Exercise 3 — Synthesizable?
Which synthesize: (a) a function computing a CRC; (b) a task with @(posedge clk); (c) a task with no timing returning two outputs?
9. Summary
Advanced tasks and functions:
- Synthesis — functions are always synthesizable (combinational); tasks only without timing (timed tasks are testbench-only).
- Functions slot into continuous assignments and
alwaysblocks (combinational reuse, even registered). - Multiple outputs — a task with several
outputargs (functions return one value). - Composition — functions call only functions; tasks call both; they compose into layered reusable code.
Tasks & functions complete
This closes Chapter 15 Tasks & Functions — functions (15.1), tasks (15.2), static/automatic storage (15.3), re-entrancy (15.4), and these advanced rules (15.5). You can now factor repeated computation into functions and repeated procedures into tasks, with automatic for recursion and concurrency — behavioural reuse that complements the structural reuse of modules.
The remaining chapters are advanced/reference: Chapter 16 User-Defined Primitives (UDPs), 17 Delay Modeling, 18 Timing Checks, and 19 Timing Regions — the lower-level and signoff-adjacent topics that round out the language.
Related Tutorials
- Re-entrant Tasks & Functions — Chapter 15.4; recursion and concurrency.
- Function — Chapter 15.1; the value-returning construct.
- Task — Chapter 15.2; the procedure construct.
- Tasks & Functions — Chapter 15 overview; function vs task.