Sie sind auf Seite 1von 15

System Tasks

System tasks are built-in commands for simulation and system


functions such as printing messages, reading and writing files,
monitoring and displaying simulation time and the signal
values at a specific simulation time. All system task keywords
start with $.

The Verilog standard permits EDA tool vendors to define


system tasks unique to their particular tool using the
Programming Language Interface (PLI).

To maintain portability between EDA tools, it is


recommended to use only the standard system tasks defined as
part of the Verilog language.

Some of the more common system tasks are listed below:

$display $write $stop $finish

$fopen $fclose $fwrite $monitor

$display is most useful for displaying values of variables or


strings or expressions. It has the following syntax.
$display(arg1, arg2, ..., argN);
arg1, arg2, ..., argN can be a mixture of strings, variables or
expressions. A $display inserts a newline at the end of the
string. A $display without any arguments produces a newline.

$write is similar to $display except that $write does not put a


newline at the end of a string by default.

$monitor has the following syntax.


$monitor(arg1, arg2, ..., argN);

arg1, arg2, ..., argN can be variables, signal names or strings.


$monitor is used to print the values of the variable or signal
as they change.

Only one monitoring list can be active at a time. If there is


more than one $monitor in your code, the last $monitor will
be the active one.

Monitoring can be turned on or off during simulation using


$monitoron and $monitoroff respectively. Monitoring is
turned on by default at the beginning of the simulation.

$stop causes the simulation to suspend temporarily. The


designer can then examine the values of signals or debug the
design in an interactive mode.
$finish terminates the simulation.

To open a file, we write the following:


file_handle = $fopen(“filename”);

Each successive call to $fopen returns a 32-bit value (called

multichannel descriptor). A bit is set in the descriptor to

represent a file that has been opened. As files are opened, bit 1

is set, bit 2 is set, and so on, up to bit 30 set, respectively.

$fopen returns a 0 if the file could not opened.

$fdisplay , $fmonitor, $fwrite, and $fstrobe are used to write


to files. For example, $fdisplay has the following syntax.

$fdisplay(file_descriptor, arg1, arg2, ..., argN);

arg1, arg2, ..., argN can be variables, signal names or strings.

The file_descriptor can be a file handle or a bitwise


combination of file handles (to write to more than one file at
the same time). Verilog will write the output to files that have
a 1 set in the bit position of the file descriptor.

The command to close a file is $fclose(file_handler);


Behavioral Modelling of Hardware

Behavioural models describe functionality of a hardware


system in an algorithmic manner independent of technology.

The models describe the functional relationship between the


inputs and outputs of a logic circuit, but do not model the
physical properties such as propagation delays (which depend
on the technology that produced the hardware).

Design work is more effective through the use of behavioral


models, and a synthesis tool can then be used to develop the
physical implementation, rather than design at the gate level.

A behavioral or algorithmic model therefore looks like a


computer program that describes the behavior of the system.

Verilog provides two different control structures to allow


designers to describe model behavior in a computer-program
manner:
• case statement.
• if statement (also known as conditional statement).
if Statement

There are three types of if statement.


Example: Type 1 if statement.
// If the expression is evaluated to true (1 or non-zero value),
// then execute the statements, otherwise
// statements are skipped.
if(expression) begin
statement1;
statement2;
end

Example: Type 2 if-else statement.


if(expression) begin
// If the expression is evaluated to true (1 or non-zero value),
// then execute the following.
statement1;
statement2;
end
else
// If the expression is evaluated to false (x or zero), then
// execute the following.
statement3;

Example: Type 3 nested if-else statement.


if(expression1)
statement1;
else if(expression2)
statement2;
else if(expression3)
statement3;
else
statement4;
case Statement

This is an alternative to type 3 of if statement (nested if-else).

When the number of expressions is large, use of if statement


becomes cumbersome. A better way is to use case statement.

Example:
//***********************************
case(expression)
item1: statement1;

item2: begin
statement2;
statement3;
end

// More codes...

default: default_statement;
endcase

The case statement searches from top to bottom to find a


match between the case expression and a case item. The case
expression and a case item are compared bit by bit.

If their widths do not match, the shorter one is zero filled to


match the wider one. When the first match is found, the
remaining case items are not considered. The case statement
can be nested.
Example:
Model a 4-to-1 multiplexer using case statement.

//###########################################
// 4-to-1 multiplexer.
module mux4to1
(output out,
input ip_data3, ip_data2, ip_data1, ip_data0,
input ip_s1, ip_s0);

//***********************************
// Recompute the signal out if any input signal changes.
// All input signals that cause a recomputation of op_out to
// occur must go into the always @(...)

always @(ip_s1, ip_s0, ip_data3, ip_data2, ip_data1,


ip_data0) begin
case ({ip_s1, ip_s0})
2'b00: out = ip_data0;
2'b01: out = ip_data1;
2'b10: out = ip_data2;
2'b11: out = ip_data3;
// for cases where s0 or s1 is x or z
default: out = 1'bx;
endcase
end

endmodule
casex and casez Statements

There are two variations of the case statement.


• In casex, the x and z values in the case item are treated as
don’t-care.
• In casez, z values in the case item are treated as don’t-care.

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


or non-z positions when matching the case expression with
the case items: x and z positions are not compared at all.

Example:
Write the code for a 16-bit loadable up/down counter. The
counter has a load signal and a reset signal, both active on the
rising edge of the clock. The reset signal has priority over the
load signal. If the load signal is not active, then the counter
counts up or down depending on the state of the up signal.

//#############################################
module counter
(output reg [15:0] op_count, // Count.
input [15:0] ip_data, // Data.
input ip_load, // Parallel load.
input ip_updown, // Count up.
input ip_clock, // Clock signal.
input ip_reset); // Active-high synchronous
// reset signal.
//***********************************
always @(posedge ip_clock)
casex({ip_reset, ip_load, ip_updown})
// casex means that x and z are treated as don’t-care.

3'b1xx : op_count <= 16'h0000;

// ip_reset has priority over ip_load and ip_updown.


// ip_load and ip_updown are not compared at all due to the x’s
// in the case item.

3'b01x : op_count <= ip_data;

3'b001 : op_count <= op_count + 16'h0001;

3'b000 : op_count <= op_count - 16'h0001;

default : op_count <= 16'bx;

endcase
endmodule

Note that because of the way the signals over-ride, it is


actually easier to write the counter using if statements, as
shown below.

always @(posedge ip_clock)


if(ip_reset)
op_count <= 16'h0000;

else if(ip_load)
op_count <= ip_data;

else if(ip_updown)
op_count <= op_count + 16'h0001;

else
op_count <= op_count - 16'h0001;
Loops

There are four types of loops:


for repeat while forever

All loops must appear inside a procedural block. Loops can


contain delay expressions. Loops can be disabled using the
keyword disable

for is generally used when there is a fixed beginning and end


to the loop.

Example:
// Increment and display count from 0 to 127 using for loop.
module counter_for;
//***********************************
integer i_count;
//***********************************
initial
for(i_count = 0; i_count < 128; i_count = i_count + 1)
$display("Count = %d", i_count);
endmodule

The repeat construct executes the loop a fixed number of


times. It cannot be used to loop on a general logical
expression (must be a number that is a constant, variable or
signal. x and z are treated as zero).

Example:
// Increment and display count from 0 to 127 using repeat loop.
module counter_repeat;
//***********************************
integer i_count;
//***********************************
initial begin
i_count = 0;
repeat(128) begin
$display("Count = %d", i_count);
i_count = i_count + 1;
end
end
endmodule

while are used if the loop is simply looping on a condition. As


long as the expression is evaluated to true, the statements in
the while loop will be executed.

Example:
// Increment and display count from 0 to 127 using while loop.
module counter_while;
//***********************************
integer i_count;
//***********************************
initial begin
i_count = 0;
while (i_count < 128) begin
$display("Count = %d", i_count);
i_count = i_count + 1;
end
end
endmodule

forever Loop does not contain any expression and executes

forever until the $stop is encountered.


Example:
module clock_gen
(output reg op_clock1,
output reg op_clock2);
//***********************************
initial begin
op_clock1 = 1'b0;
forever #10 op_clock1 = ~op_clock1; // Clock with period 20
end
endmodule

generate Statement

The generate statement allows Verilog codes to be generated


dynamically (before the simulation begins).

It is used to replicate independent copies of the following


Verilog codes: net declarations, register variable declarations,
parameter redefinitions, continuous assignments, always
block, initial block, tasks and functions.

For example, a parameterised module can be instantiated


repeatedly for different bit lengths.

There are three variants of generate statement.


• generate-for block.
• generate-if block.
• generate-case block.
generate-for Block

A generate-for block allows the following constructs to be


instantiated multiple times using a for loop:
Variable declarations, Modules, User defined primitives
(UDPs) and gate primitives, Continuous assignments,
and initial and always blocks.

We shall only look at this form of generate block as the other


2 types are very similar to it.

Example:
Given the following 8-bit adder module definition, develop a
24-bit adder using the generate statement.
Suppose the 8-bit adder has the following port declaration:
module add8
(output [7:0] op8_sum,
output op8_cout,
input [7:0] ip8_a, ip8_b,
input ip8_cin);

Then a 24-bit adder can be generated with:


module add24_rca
(output [23:0] op24_sum,
output op24_cout,
input [23:0] ip24_a, ip24_b,
input ip24_cin);

//***********************************
// Interconnects.
wire [3:0] w_carry;

//***********************************
assign w_carry[0] = ip24_cin;
assign op24_cout = w_carry[3];

//***********************************
// Generate the required number of instance.
generate
genvar k; // k is the adder stage number: stage 0, stage 1...

for(k = 0; k <= 2; k = k + 1) begin: LEVEL


add8 ADD
(.op8_sum (op24_sum[((k+1)*8 - 1) : k*8]),
// [7:0], [15:8], [23:16]
.op8_cout (w_carry[k+1]), // [1], [2], [3]
.ip8_a (ip24_a[((k+1)*8 - 1) : k*8]),
.ip8_b (ip24_b[((k+1)*8 - 1) : k*8]),
.ip8_cin (w_carry[k])); // [0], [1], [2]
end
endgenerate
endmodule

Prior to simulation, the simulator reads the code in the


generate blocks. The generate blocks are simply a
convenient way to replace multiple repetitive Verilog
statements with a single statement inside a loop.

genvar is used to declare a nonnegative integer that is used


only in the evaluation of the generate-for block.
The model generates a 24-bit adder from 3 copies of an 8-bit
adder, with instance names LEVEL[0].ADD,
LEVEL[1].ADD and LEVEL[2].ADD.

Das könnte Ihnen auch gefallen