0% found this document useful (0 votes)
52 views

Module 4 VHDL

- Behavioral modeling in Verilog represents a circuit at a high level of abstraction and resembles C programming more than digital circuit design. - Verilog uses always and initial statements to define structured procedures, with always representing continuous activity and initial representing activity that occurs once at time 0. - Verilog supports both blocking and non-blocking procedural assignments, with non-blocking assignments useful for modeling concurrent processes.

Uploaded by

Hemanth Kumar
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
52 views

Module 4 VHDL

- Behavioral modeling in Verilog represents a circuit at a high level of abstraction and resembles C programming more than digital circuit design. - Verilog uses always and initial statements to define structured procedures, with always representing continuous activity and initial representing activity that occurs once at time 0. - Verilog supports both blocking and non-blocking procedural assignments, with non-blocking assignments useful for modeling concurrent processes.

Uploaded by

Hemanth Kumar
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 114

Behavioral Modeling

•Module 4
• Verilog provides designers the ability to describe design
functionality in an algorithmic manner.

• Behavioral modeling represents the circuit at a very high level


of abstraction.

• Design at this level resembles C programming more than it


resembles digital circuit design.

• Verilog is rich in behavioral constructs that provide the designer


with a great amount of flexibility.
Structured Procedures
• There are two structured procedure statements in Verilog: always and
initial.

• All other behavioral statements can appear only inside these structured
procedure statements.

• Verilog is a concurrent programming language unlike the C


programming language, which is sequential in nature.

• Activity flows in Verilog run in parallel rather than in sequence.

• Each always and initial statement represents a separate activity flow in


Verilog. Each activity flow starts at simulation time 0.

• The statements always and initial cannot be nested.


initial Statement
• All statements inside an initial statement constitute an initial block.

• An initial block starts at time 0, executes exactly once during a simulation,


and then does not execute again.

• If there are multiple initial blocks, each block starts to execute


concurrently at time 0. Each block finishes execution independently of
other blocks.

• Multiple behavioral statements must be grouped, typically using the


keywords begin and end.

• If there is only one behavioral statement, grouping is not necessary. This is


similar to the begin-end blocks in Pascal programming language or the { }
grouping in the C programming language.
The initial blocks are typically used for initialization, monitoring, waveforms
and other processes that must be executed only once during the entire
simulation run.
Combined Variable Declaration
and Initialization
• Variables can be initialized when they are declared.
Combined Port/Data Declaration
and Initialization
• The combined port/data declaration can also be combined with
an initialization.
always Statement

• All behavioral statements inside an always statement constitute


an always block.

• The always statement starts at time 0 and executes the


statements in the always block continuously in a looping
fashion.

• This statement is used to model a block of activity that is


repeated continuously in a digital circuit.
• the always statement starts at time 0 and executes the statement
clock = ~clock every 10 time units.

• Notice that the initialization of clock has to be done inside a


separate initial statement. If we put the initialization of clock
inside the always block, clock will be initialized every time the
always is entered.

• The simulation must be halted inside an initial statement. If


there is no $stop or $finish statement to halt the simulation, the
clock generator will run forever.

• The activity is stopped only by power off ($finish) or by an


interrupt ($stop).
Procedural Assignments
• Procedural assignments update values of reg, integer, real, or
time variables.

• The value placed on a variable will remain unchanged until


another procedural assignment updates the variable with a
different value.
• The left-hand side of a procedural assignment <lvalue> can be
one of the following:

• A reg, integer, real, or time register variable or a memory


element

• A bit select of these variables (e.g., addr[0])

• A part select of these variables (e.g., addr[31:16])

• A concatenation of any of the above


• There are two types of procedural assignment statements:
blocking and nonblocking.

Blocking Assignments

• Blocking assignment statements are executed in the order they


are specified in a sequential block.

• A blocking assignment will not block execution of statements


that follow in a parallel block.

• The = operator is used to specify blocking assignments.


• In Example , the statement y = 1 is executed only after x = 0 is executed.

• The behavior in a particular block is sequential in a begin-end block if blocking


statements are used, because the statements can execute only in sequence.

• The statement count = count + 1 is executed last. The simulation times at which the
statements are executed are as follows:
All statements x = 0 through reg_b = reg_a are executed at time 0
Statement reg_a[2] = 0 at time = 15
Statement reg_b[15:13] = {x, y, z} at time = 25
Statement count = count + 1 at time = 25
Since there is a delay of 15 and 10 in the preceding statements, count = count + 1 will be
executed at time = 25 units

• Note that for procedural assignments to registers, if the right-hand side has more bits
than the register variable, the right-hand side is truncated to match the width of the
register variable. The least significant bits are selected and the most significant bits
are discarded. If the right-hand side has fewer bits, zeros are filled in the most
significant bits of the register variable.
Nonblocking Assignments
• Nonblocking assignments allow scheduling of assignments
without blocking execution of the statements that follow in a
sequential block.

• A <= operator is used to specify nonblocking assignments.

• This operator has the same symbol as a relational operator,


less_than_equal_to. The operator <= is interpreted as a relational
operator in an expression and as an assignment operator in the
context of a nonblocking assignment.
• To illustrate the behavior of nonblocking statements and its
difference from blocking statements
• In this example, the statements x = 0 through reg_b = reg_a are executed sequentially at
time 0. Then the three nonblocking assignments are processed at the same simulation
time.

• reg_a[2] = 0 is scheduled to execute after 15 units (i.e., time = 15)

• reg_b[15:13] = {x, y, z} is scheduled to execute after 10 time units (i.e., time = 10)

• count = count + 1 is scheduled to be executed without any delay (i.e., time = 0)

• Thus, the simulator schedules a nonblocking assignment statement to execute and


continues to the next statement in the block without waiting for the nonblocking
statement to complete execution.

• nonblocking assignment statements are executed last in the time step in which they are
scheduled, that is, after all the blocking assignments in that time step are executed.

• it is recommended that blocking and nonblocking assignments not be mixed in the same
always block.
Application of nonblocking
assignments
• They are used as a method to model several concurrent data
transfers that take place after a common event.
• At each positive edge of clock, the following sequence takes place for the nonblocking
assignments.

• A read operation is performed on each right-hand-side variable, in1, in2, in3, and reg1, at
the positive edge of clock. The right-hand-side expressions are evaluated, and the results
are stored internally in the simulator.

• The write operations to the left-hand-side variables are scheduled to be executed at the
time specified by the intra-assignment delay in each assignment, that is, schedule "write"
to reg1 after 1 time unit, to reg2 at the next negative edge of clock, and to reg3 after 1
time unit.

• The write operations are executed at the scheduled time steps. The order in which the
write operations are executed is not important because the internally stored right-hand-
side expression values are used to assign to the left-hand-side values. For example, note
that reg3 is assigned the old value of reg1 that was stored after the read operation, even if
the write operation wrote a new value to reg1 before the write operation to reg3 was
executed.

• Thus, the final values of reg1, reg2, and reg3 are not dependent on the order in which the
assignments are processed.
• In Illustration 1, there is a race condition when blocking statements are used.

• Either a = b would be executed before b = a, or vice versa, depending on the


simulator implementation. Thus, values of registers a and b will not be swapped.

• Instead, both registers will get the same value (previous value of a or b), based on
the Verilog simulator implementation.

• In Illustration 2 , eliminates the race condition.

• At the positive edge of clock, the values of all right-hand-side variables are "read,"
and the right-hand-side expressions are evaluated and stored in temporary variables.

• During the write operation, the values stored in the temporary variables are
assigned to the left-handside variables. Separating the read and write operations
ensures that the values of registers a and b are swapped correctly, regardless of the
order in which the write operations are performed.
Implementing Nonblocking Assignments using Blocking
Assignments
• For digital design, use of nonblocking assignments in place of blocking
assignments is highly recommended in places where concurrent data
transfers take place after a common event.

• In such cases, blocking assignments can potentially cause race conditions


because the final result depends on the order in which the assignments are
evaluated.

• Nonblocking assignments can be used effectively to model concurrent data


transfers because the final result is not dependent on the order in which the
assignments are evaluated.

• Typical applications of nonblocking assignments include pipeline modeling


and modeling of several mutually exclusive data transfers.

• Nonblocking assignments can potentially cause a degradation in the


simulator performance and increase in memory usage.
Timing Controls
• In Verilog, if there are no timing control statements, the simulation
time does not advance.

• Timing controls provide a way to specify the simulation time at


which procedural statements will execute.

• There are three methods of timing control:

A. delay-based timing control

B. event-based timing control

C. level-sensitive timing control.


Delay-Based Timing Control

• Delay-based timing control in an expression specifies the time duration


between when the statement is encountered and when it is executed.

• Delays are specified by the symbol #.

• There are three types of delay control for procedural assignments:

A. regular delay control

B. intra-assignment delay control

C. zero delay control.


Regular delay control
• Regular delay control is used when a non-zero delay is specified to the
left of a procedural assignment.
<statement>
= <delay_control> <statement_or_null>
<delay_control>
# <NUMBER>
# <identifier>
# ( <mintypmax_expression> )
Intra-assignment delay control

• Instead of specifying delay control to the left of the assignment,


it is possible to assign a delay to the right of the assignment
operator.

• Such delay specification alters the flow of activity in a different


manner.
Zero delay control
• Procedural statements in different always-initial blocks may be evaluated
at the same simulation time.

• The order of execution of these statements in different always-initial


blocks is nondeterministic.

• Zero delay control is a method to ensure that a statement is executed last,


after all other statements in that simulation time are executed.

• This is used to eliminate race conditions.

• If there are multiple zero delay statements, the order between them is
nondeterministic.
• In Example, four statements x = 0, y = 0, x = 1, y = 1 are to be executed at simulation
time 0.
• However, since x = 1 and y = 1 have #0, they will be executed last. Thus, at the end of
time 0, x will have value 1 and y will have value 1.
• The order in which x = 1 and y = 1 are executed is not deterministic.
• using #0 is not a recommended practice.
Event-Based Timing Control
• An event is the change in the value on a register or a net.

• Events can be utilized to trigger execution of a statement or a block of


statements.

• There are four types of event-based timing control:

regular event control

named event control

event OR control

levelsensitive timing control.


Regular event control
• The @ symbol is used to specify an event control.

• Statements can be executed on changes in signal value or at a


positive or negative transition of the signal value.

• The keyword posedge is used for a positive transition.


Named event control
• Verilog provides the capability to declare an event and then
trigger and recognize the occurrence of that event.

• The event does not hold any data.

• A named event is declared by the keyword event.

• An event is triggered by the symbol ->.

• The triggering of the event is recognized by the symbol @.


Event OR Control
• Sometimes a transition on any one of multiple signals or events
can trigger the execution of a statement or a block of statements.

• This is expressed as an OR of events or signals. The list of


events or signals expressed as an OR is also known as a
sensitivity list.

• The keyword OR is used to specify multiple triggers


• Sensitivity lists can also be specified using the "," (comma)
operator instead of the or operator.

• Comma operators can also be applied to sensitivity lists that


have edge-sensitive triggers.
• When the number of input variables to a combination logic
block are very large, sensitivity lists can become very
cumbersome to write.

• if an input variable is missed from the sensitivity list, the block


will not behave like a combinational logic block.

• To solve this problem, Verilog HDL contains two special


symbols: @* and @(*). Both symbols exhibit identical
behavior.

• These special symbols are sensitive to a change on any signal


that may be read by the statement group that follows this
symbol.
Level-Sensitive Timing Control
• Event control discussed earlier waited for the change of a signal value or the
triggering of an event.

• The symbol @ provided edge-sensitive control. Verilog also allows levelsensitive


timing control, that is, the ability to wait for a certain condition to be true before a
statement or a block of statements is executed.

• The keyword wait is used for levelsensitive constructs.

• always wait (count_enable) #20 count = count + 1;

• In the above example, the value of count_enable is monitored continuously. If


count_enable is 0, the statement is not entered. If it is logical 1, the statement count
= count + 1 is executed after 20 time units. If count_enable stays at 1, count will be
incremented every 20 time units.
Conditional Statements
• Conditional statements are used for making decisions based upon certain conditions.

• These conditions are used to decide whether or not a statement should be executed.

• Keywords if and else are used for conditional statements.

• There are three types of conditional statements.


Multiway Branching
• there were many alternatives, from which one was chosen.

• The nested if-else-if can become unwieldy if there are too many
alternatives. A shortcut to achieve the same result is to use the case
statement.
• Each of statement1, statement2 , default_statement can be a single
statement or a block of multiple statements.

• A block of multiple statements must be grouped by keywords begin


and end.

• The expression is compared to the alternatives in the order they are


written. For the first alternative that matches, the corresponding
statement or block is executed.

• If none of the alternatives matches, the default_statement is


executed. The default_statement is optional.

• Placing of multiple default statements in one case statement is not


allowed. The case statements can be nested.
• The case statement compares 0, 1, x, and z values in the
expression and the alternative bit for bit.

• If the expression and the alternative are of unequal bit width,


they are zero filled to match the bit width of the widest of the
expression and the alternative.
casex, casez Keywords
• There are two variations of the case statement. They are denoted by
keywords, casex and casez.

• casez treats all z values in the case alternatives or the case


expression as don't cares. All bit positions with z can also
represented by ? in that position.

• casex treats all x and z values in the case item or the case expression
as don't cares.

• The use of casex and casez allows comparison of only non-x or -z


positions in the case expression and the case alternatives.
Loops
• There are four types of looping statements in Verilog: while, for,
repeat, and forever.

• The syntax of these loops is very similar to the syntax of loops


in the C programming language.

• All looping statements can appear only inside an initial or


always block. Loops may contain delay expressions.
While Loop

• The keyword while is used to specify this loop.

• The while loop executes until the while-expression is not true.

• Each expression can contain the operators .Any logical


expression can be specified with these operators.

• If multiple statements are to be executed in the loop, they must


be grouped typically using keywords begin and end.
For Loop
• The keyword for is used to specify this loop. The for loop contains three parts:

• An initial condition

• A check to see if the terminating condition is true

• A procedural assignment to change value of the control variable

• The initialization condition and the incrementing procedural assignment are included
in the for loop and do not need to be specified separately. Thus, the for loop provides a
more compact loop structure than the while loop.

• the while loop is more general-purpose than the for loop. The for loop cannot be used
in place of the while loop in all situations.

• for loops are generally used when there is a fixed beginning and end to the loop. If the
loop is simply looping on a certain condition, it is better to use the while loop.
Repeat Loop
• The keyword repeat is used for this loop.

• The repeat construct executes the loop a fixed number of times.

• A repeat construct cannot be used to loop on a general logical


expression. A while loop is used for that purpose.

• A repeat construct must contain a number, which can be a


constant, a variable or a signal value. However, if the number is
a variable or signal value, it is evaluated only when the loop
starts and not during the loop execution.
Forever loop
• The keyword forever is used to express this loop.

• The loop does not contain any expression and executes forever until the
$finish task is encountered.

• The loop is equivalent to a while loop with an expression that always


evaluates to true, e.g., while (1).

• A forever loop can be exited by use of the disable statement.

• A forever loop is typically used in conjunction with timing control constructs.

• If timing control constructs are not used, the Verilog simulator would execute
this statement infinitely without advancing simulation time and the rest of the
design would never be executed.
Sequential and Parallel Blocks
• Block statements are used to group multiple statements to act
together as one.

• we use keywords begin and end to group multiple statements.

• Thus, we used sequential blocks where the statements in the


block execute one after another.

• There are two types of blocks: sequential blocks and parallel


blocks.
Sequential blocks
• The keywords begin and end are used to group statements into
sequential blocks. Sequential blocks have the following
characteristics:

• The statements in a sequential block are processed in the order they


are specified. A statement is executed only after its preceding
statement completes execution (except for nonblocking
assignments with intra-assignment timing control).

• If delay or event control is specified, it is relative to the simulation


time when the previous statement in the block completed
execution.
Parallel blocks
• Parallel blocks, specified by keywords fork and join, provide interesting simulation
features. Parallel blocks have the following characteristics:

• Statements in a parallel block are executed concurrently.

• Ordering of statements is controlled by the delay or event control assigned to each


statement.

• If delay or event control is specified, it is relative to the time the block was entered.

• All statements in a parallel block start at the time when the block was entered. Thus, the
order in which the statements are written in the block is not important.

• The keyword fork can be viewed as splitting a single flow into independent flows. The
keyword join can be seen as joining the independent flows back into a single flow.
Independent flows operate concurrently.
Special Features of Blocks
• three special features available with block statements: nested blocks,
named blocks, and disabling of named blocks.

Nested blocks

• Blocks can be nested. Sequential and parallel blocks can be mixed


Named blocks
• Blocks can be given names.

• Local variables can be declared for the named block.

• Named blocks are a part of the design hierarchy. Variables in a


named block can be accessed by using hierarchical name
referencing.

• Named blocks can be disabled, i.e., their execution can be


stopped.
Disabling named blocks
• The keyword disable provides a way to terminate the execution of a
named block.

• disable can be used to get out of loops, handle error conditions, or


control execution of pieces of code, based on a control signal.

• Disabling a block causes the execution control to be passed to the


statement immediately succeeding the block.

• For C programmers, this is very similar to the break statement used to


exit a loop. The difference is that a break statement can break the
current loop only, whereas the keyword disable allows disabling of any
named block in the design.
Generate Blocks
• Generate statements allow Verilog code to be generated dynamically at
elaboration time before the simulation begins.

• This facilitates the creation of parametrized models.

• Generate statements are particularly convenient when the same operation


or module instance is repeated for multiple bits of a vector, or when certain
Verilog code is conditionally included based on parameter definitions.

• Generate statements allow control over the declaration of variables,


functions, and tasks, as well as control over instantiations.

• All generate instantiations are coded with a module scope and require the
keywords generate - endgenerate.
• Generated instantiations can be one or more of the following
types:

• Modules

• User defined primitives

• Verilog gate primitives

• Continuous assignments

• initial and always blocks


• Generated declarations and instantiations can be conditionally instantiated into
a design.

• Generated instances have unique identifier names and can be referenced


hierarchically.

• To support interconnection between structural elements and/or procedural


blocks, generate statements permit the following Verilog data types to be
declared within the generate scope:

• net, reg

• integer, real, time, realtime

• event .

• Generated data types have unique identifier names and can be referenced
hierarchically.
• Parameter redefinition using ordered or named assignment or a
defparam statement can be declared with the generate scope.

• A defparam statement within a generate scope is allowed to


modify the value of a parameter only in the same generate scope
or within the hierarchy instantiated within the generate scope.

• Task and function declarations are permitted within the generate


scope but not within a generate loop. Generated tasks and
functions have unique identifier names and can be referenced
hierarchically.
• Some module declarations and module items are not permitted in a generate
statement. They include:

• parameters, local parameters

• input, output, inout declarations

• specify blocks Connections to generated module instances are handled in the


same way as with normal module instances.

• There are three methods to create generate statements:

• Generate loop

• Generate conditional

• Generate case
Generate Loop
• A generate loop permits one or more of the following to be
instantiated multiple times using a for loop:

• Variable declarations

• Modules

• User defined primitives, Gate primitives

• Continuous assignments

• initial and always blocks


Some interesting observations for Example are listed below.

• Prior to the beginning of the simulation, the simulator elaborates (unrolls) the code in the
generate blocks to create a flat representation without the generate blocks. The unrolled code is
then simulated. Thus, generate blocks are simply a convenient way of replacing multiple
repetitive Verilog statements with a single statement inside a loop.

• genvar is a keyword used to declare variables that are used only in the evaluation of generate
block. Genvars do not exist during simulation of the design.

• The value of a genvar can be defined only by a generate loop.

• Generate loops can be nested. However, two generate loops using the same genvar as an index
variable cannot be nested.

• The name xor_loop assigned to the generate loop is used for hierarchical name referencing of
the variables inside the generate loop. Therefore, the relative hierarchical names of the xor gates
will be xor_loop[0].g1, xor_loop[1].g1, ......., xor_loop[31].g1.

• Generate loops are fairly flexible. Various Verilog constructs can be used inside the generate
loops.
Generate Conditional
• A generate conditional is like an if-else-if generate construct that
permits the following Verilog constructs to be conditionally
instantiated into another module based on an expression that is
deterministic at the time the design is elaborated:

• Modules

• User defined primitives, Gate primitives

• Continuous assignments

• initial and always blocks


• Example shows the implementation of a parametrized multiplier. If either
a0_width or a1_width parameters are less than 8 bits, a carry-look-ahead (CLA)
multiplier is instantiated. If both a0_width or a1_width parameters are greater
than or equal to 8 bits, a tree multiplier is instantiated.

module multiplier (product, a0, a1);


parameter a0_width = 8; // 8-bit bus by default
parameter a1_width = 8; // 8-bit bus by default
localparam product_width = a0_width + a1_width;
output [product_width -1:0] product;
input [a0_width-1:0] a0;
input [a1_width-1:0] a1;
generate if (a0_width <8) || (a1_width < 8)
cla_multiplier #(a0_width, a1_width) m0 (product, a0, a1);
else
tree_multiplier #(a0_width, a1_width) m0 (product, a0, a1);
endgenerate //end of the generate block
endmodule
Generate Case
• A generate case permits the following Verilog constructs to be
conditionally instantiated into another module based on a select-
one-of-many case construct that is deterministic at the time the
design is elaborated:

• Modules

• User defined primitives, Gate primitives

• Continuous assignments

• initial and always blocks


Example Generate Case Example— This module generates an N-bit adder

module adder(co, sum, a0, a1, ci);


parameter N = 4;
output [N-1:0] sum;
output co;
input [N-1:0] a0, a1;
input ci;

generate case (N)

1: adder_1bit adder1(c0, sum, a0, a1, ci); //1-bit implementation

2: adder_2bit adder2(c0, sum, a0, a1, ci); //2-bit implementation

default: adder_cla #(N) adder3(c0, sum, a0, a1, ci);


endcase
endgenerate
endmodule
4-to-1 Multiplexer with the behavioral case statement.
4-bit Counter by using behavioral statements.
Traffic Signal Controller

Consider a controller for traffic at the intersection of a main highway and a country
road.

• The traffic signal for the main highway gets highest priority because cars are continuously
present on the main highway. Thus, the main highway signal remains green by default.

• Occasionally, cars from the country road arrive at the traffic signal. The traffic signal for the
country road must turn green only long enough to let the cars on the country road go.

• As soon as there are no cars on the country road, the country road traffic signal turns yellow
and then red and the traffic signal on the main highway turns green again.

• There is a sensor to detect cars waiting on the country road. The sensor sends a signal X as
input to the controller. X = 1 if there are cars on the country road; otherwise, X= 0.

• There are delays on transitions from S1 to S2, from S2 to S3, and from S4 to S0.

• The delays must be controllable.


Tasks and Functions

• Differences between tasks and functions, declaration,


invocation, automatic tasks and functions.
Differences between Tasks and
Functions
• Both tasks and functions must be defined in a module and are local to the module.

• Tasks are used for common Verilog code that contains delays, timing, event
constructs, or multiple output arguments.

• Functions are used when common Verilog code is purely combinational, executes in
zero simulation time, and provides exactly one output.

• Functions are typically used for conversions and commonly used calculations.

• Tasks can have input, output, and inout arguments; functions can have input
arguments. In addition, they can have local variables, registers, time variables,
integers, real, or events.

• Tasks or functions cannot have wires.

• Tasks and functions contain behavioral statements only.

• Tasks and functions do not contain always or initial statements but are called from
always blocks, initial blocks, or other tasks and functions.
Tasks
• Tasks are declared with the keywords task and endtask. Tasks must be used if any one of the following
conditions is true for the procedure:

• There are delay, timing, or event control constructs in the procedure.

• The procedure has zero or more than one output arguments.

• The procedure has no input arguments.

• Task Declaration and Invocation


• I/O declarations use keywords input, output, or inout, based on the type of argument
declared.

• Input and inout arguments are passed into the task.

• Input arguments are processed in the task statements.

• Output and inout argument values are passed back to the variables in the task
invocation statement when the task is completed.

• Tasks can invoke other tasks or functions.

• Although the keywords input, inout, and output used for I/O arguments in a task are
the same as the keywords used to declare ports in modules, there is a difference.

• Ports are used to connect external signals to the module.

• I/O arguments in a task are used to pass values to and from the task.
Consider a task called bitwise_oper, which computes the bitwise and, bitwise
or, and bitwise ex-or of two 16-bit numbers. The two 16-bit numbers a and b
are inputs and the three outputs are 16bit numbers ab_and, ab_or, ab_xor. A
parameter delay is also used in the task.
• In the above task, the input values passed to the task are A and B.

• Hence, when the task is entered, a = A and b = B. The three output values are
computed after a delay.

• This delay is specified by the parameter delay, which is 10 units for this example.

• When the task is completed, the output values are passed back to the calling output
arguments.

• Therefore, AB_AND = ab_and, AB_OR = ab_or, and AB_XOR = ab_xor when the
task is completed.
Asymmetric Sequence
Generator

• Tasks can directly operate on reg variables defined in the


module.

• Example directly operates on the reg variable clock to


continuously produce an asymmetric sequence.

• The clock is initialized with an initialization sequence.


Automatic (Re-entrant) Tasks
• Tasks are normally static in nature.

• All declared items are statically allocated and they are shared across all uses of the task executing
concurrently.

• Therefore, if a task is called concurrently from two places in the code, these task calls will operate
on the same task variables.

• It is highly likely that the results of such an operation will be incorrect.

• To avoid this problem, a keyword automatic is added in front of the task keyword to make the tasks
re-entrant. Such tasks are called automatic tasks.

• All items declared inside automatic tasks are allocated dynamically for each invocation.

• Each task call operates in an independent space. Thus, the task calls operate on independent copies
of the task variables.

• This results in correct operation. It is recommended that automatic tasks be used if there is a chance
that a task might be called concurrently from two locations in the code.
Functions
• Functions are declared with the keywords function and endfunction.

• Functions are used if all of the following conditions are true for the
procedure:

• There are no delay, timing, or event control constructs in the


procedure.

• The procedure returns a single value.

• There is at least one input argument.

• There are no output or inout arguments.

• There are no nonblocking assignments.


Function Declaration and
Invocation
• There are some peculiarities of functions. When a function is declared, a register with
name function_identifer is declared implicitly inside Verilog.

• The output of a function is passed back by setting the value of the register
function_identifer appropriately.

• The function is invoked by specifying function name and input arguments.

• At the end of function execution, the return value is placed where the function was
invoked.

• The optional range_or_type specifies the width of the internal register. If no range or
type is specified, the default bit width is 1.

• Functions are very similar to FUNCTION in FORTRAN.

• Notice that at least one input argument must be defined for a function.

• There are no output arguments for functions because the implicit register
function_identifer contains the output value.

• Also, functions cannot invoke other tasks. They can invoke only other functions.
Function Examples-Parity calculation
• Let us discuss a function that calculates the parity of a 32-bit address and returns the value. We assume even parity.

• Note that in the first invocation of calc_parity, the returned value was used to set the reg parity. In the second invocation, the
value returned was directly used inside the $display task. Thus, the returned value is placed wherever the function was invoked.
Automatic (Recursive)
Functions
• Functions are normally used non-recursively .

• If a function is called concurrently from two locations, the results are non-
deterministic because both calls operate on the same variable space.

• However, the keyword automatic can be used to declare a recursive (automatic)


function where all function declarations are allocated dynamically for each
recursive calls.

• Each call to an automatic function operates in an independent variable space.

• Automatic function items cannot be accessed by hierarchical references.

• Automatic functions can be invoked through the use of their hierarchical name.
Constant Functions
• A constant function is a regular Verilog HDL function, but with certain restrictions.

• These functions can be used to reference complex values and can be used instead of constants.

• Example 8-11 shows how a constant function can be used to compute the width of the address bus in
a module.
Signed Functions
• Signed functions allow signed operations to be performed on the
function return values.

You might also like