Sie sind auf Seite 1von 8

From Verilog to SystemVerilog

• SystemVerilog is the third generation of the


Verilog language standard:
 1st generation standard: Verilog-1995
SystemVerilog – Lecture 1
 2nd generation standard: Verilog-2001.

 3rd generation standard: SystemVerilog.

• SystemVerilog is a significant and important


extension of Verilog-2001, and it includes many
features which are useful for high-level modeling
and verification of large and complex designs.

1 2

Using SystemVerilog With VCS Built-in Data Types


• By convention, SystemVerilog files use the • We'll start with some of the simpler
extension .sv elements of the language and give some
 For example: design examples before moving on to the
design1.sv, tbdesign1.sv more complex features that are available.
• To compile SystemVerilog code with VCS, use
• 4-state data types: (0, 1, x or z values)
the –sverilog flag when compiling.
 reg, logic, integer, wire, wor,
 For example:
wand (logic is identical to reg)
vcs –sverilog design1.sv tbdesign1.sv
./simv • 2-state data types: (only 0 or 1 values)
 bit, byte, shortint, int, longint

3 4

Unsigned and Signed Data Types Assigning the Same Value to all Bits
• Keywords signed and unsigned can be • The common value 0, 1, x or z can be
used to override the default numeric assigned to all bit positions of a vector with
properties: a new and simple syntax:
• logic is unsigned by default:
logic [7:0] a; // a is unsigned my_bus = '0; // fills with all 0
logic signed [7:0] b; // b is signed my_bus = '1; // fills with all 1
• int is 32-bit signed by default: my_bus = 'x; // fills with all x
int c; // c is 32-bit signed my_bus = 'z; // fills with all z
int unsigned d; // 32-bit unsigned

5 6

Module Inputs and Outputs Example: 10-bit Truncated Adder


• Design a ripple-carry adder module for adding two 10-bit signed
• We can specify the direction and the type of numbers by first sign-extending each operand to 11 bits, adding the
the signals going in and out of a module sign-extended values and then returning the 10 most significant bits
(MSBs) of the sum as the output of the module. (Note: This is called
directly in the module statement itself: "Step 1a" of a larger example which will be considered later.)
• Note that you must correctly scale the power-of-two weights of these
module simple (output logic a, b, output bits when interpreting the numerical value that is produced at
the output. Also, note that the truncation may introduce a small error
input logic c, d); compared to the full-precision result.
p[9:0] q[9:0]
...
10-bit truncated adder
endmodule

r[10:1]
7 8
SystemVerilog Code– Part 1 of 1 SystemVerilog Code – cont.
// half adder // 10-bit truncated ripple-carry adder
module half_adder(input logic a, b, module RCA10(input logic [9:0] p, q,
output logic s, cout); output logic [10:1] r);

assign s = a^b; wire lsb_sum, msb_carry;


assign cout = a&b; wire [9:0] carry;

endmodule half_adder ha0(p[0], q[0], lsb_sum, carry[0]);


full_adder fa1(p[1], q[1], carry[0], r[1], carry[1]);
// full addder full_adder fa2(p[2], q[2], carry[1], r[2], carry[2]);
module full_adder(input logic a, b, cin, full_adder fa3(p[3], q[3], carry[2], r[3], carry[3]);
output logic s, cout); full_adder fa4(p[4], q[4], carry[3], r[4], carry[4]);
full_adder fa5(p[5], q[5], carry[4], r[5], carry[5]);
assign s = a^b^cin; full_adder fa6(p[6], q[6], carry[5], r[6], carry[6]);
assign cout = (a&b) | (b&cin) | (a&cin); full_adder fa7(p[7], q[7], carry[6], r[7], carry[7]);
full_adder fa8(p[8], q[8], carry[7], r[8], carry[8]);
endmodule full_adder fa9(p[9], q[9], carry[8], r[9], carry[9]);
full_adder fa10(p[9], q[9], carry[9], r[10], msb_carry);

endmodule

9 10

Testbench (cont. on next page) // exhaustive simulation of all possible cases


initial begin
// initialize the counter variables
• Construct a testbench to perform exhaustive testing of this module to num_correct = 0; num_wrong = 0;
prove that your design code is correct. Note that the check value // loop through all possible cases and record the results
calculated in the testbench should correctly model the truncation and for (i = 0; i < 1024; i = i + 1) begin
x = i;
scaling process used in the design. for (j = 0; j < 1024; j = j + 1) begin
y = j;
check = x + y;
module tbstep1; // testbench for adder of Step 1a. // adjust check value for truncation
// exhaustive checking of all 1024*1024 possible if (((check % 2) == 1) || ((check % 2) == -1))
check = check - 1;
cases
// compute and check the sum
logic signed [9:0] x, y; // 10-bit signed inputs #10 sval = s*2;
if (sval == check)
logic signed [9:0] s; // 10-bit sum output of the adder num_correct = num_correct + 1;
integer sval; // scaled value of the sum else
integer check; // value used to check correctness num_wrong = num_wrong + 1;
integer i, j; // loop variables // following line is commented out, but is useful for debugging
integer num_correct; // counter to keep track of num. correct // $display($time, " %d + %d = %d (%d)", x, y, sval, check);
integer num_wrong; // counter to keep track of num. wrong end
end

// instantiate the adder // print the final counter values


RCA10 adder_instance(x, y, s); $display("num_correct = %d, num_wrong = %d", num_correct, num_wrong);
end

endmodule
11 12

Testbench Results Carry Look-Ahead (CLA) Adders


• The results from compiling and running the design and testbench are: • Given two multi-bit operands A and B, we define the functions Pi (propagate), Gi
(generate) and Psumi (partial sum) at each bit position as follows: (Note that some
num_correct = 1048576, num_wrong = 0 references define propagate using the exclusive OR function.)
Pi = A i + B i , Gi = A iB i , Psum i = A i ⊕ B i
• Assume that the carry into bit position i is Ci. Then, the sum at bit position i, Si, and
• If the debug statement is not commented out, then a portion of the carry into the next higher bit position, Ci+1, are given by:
output looks as follows (notice the truncation): S i = Psum i ⊕ C i , C i+1 = G i + PiC i
• A CLA adder uses the fact that these functions can be computed at all bit positions in
102000 9 + -41 = -32 ( -32) parallel, and this information can be used to speed up the carry (and hence the sum)
102010 9 + -40 = -32 ( -32) computations.
102020 9 + -39 = -30 ( -30)
102030 9 + -38 = -30 ( -30) C 1 = G 0 + P0 C 0
102040 9 + -37 = -28 ( -28) C 2 = G 1 + P1C1 = G 1 + P1 ( G 0 + P0 C 0 ) = G 1 + P1G 0 + P1 P0 C 0
102050 9 + -36 = -28 ( -28)
C 3 = G 2 + P2 C 2 = G 2 + P2 ( G 1 + P1G 0 + P1 P0 C 0 )
102060 9 + -35 = -26 ( -26)
102070 9 + -34 = -26 ( -26) = G 2 + P2 G 1 + P2 P1G 0 + P2 P1 P0 C 0
102080 9 + -33 = -24 ( -24) C 4 = G 3 + P3C 3 = G 3 + P3 ( G 2 + P2 G 1 + P2 P1G 0 + P2 P1 P0 C 0 )
102090 9 + -32 = -24 ( -24)
= G 3 + P3G 2 + P3 P2 G 1 + P3 P2 P1G 0 + P3 P2 P1 P0 C 0
13 14

Carry Look-Ahead (CLA) Adders – Cont. Carry Look-Ahead (CLA) Adders – Cont.
• The previous equations determine the first four carries in parallel. While the previous • Given the definitions of these group generate and propagate functions, we can create
set of substitutions could be continued to higher-order carries, they become impractical the following group carries:
due to the the large number of terms involved and large fan-in gates that would be C 8 = G 7:4 + P7:4 C 4 = G 7:4 + P7:4 (G 3:0 + P3:0 C 0 )
required.
• One alternative is to construct a hierarchical structure consisting of groups, blocks and = G 7:4 + P7:4 G 3:0 + P7:4 P3:0 C 0
sections. For example, we can define the group generate and propagate functions as: C12 = G 11:8 + P11:8 C 8 = G 11:8 + P11:8 (G 7:4 + P7:4 G 3:0 + P7:4 P3:0 C 0 )
G 3:0 = G 3 + P3 G 2 + P3 P2 G 1 + P3 P2 P1G 0 , P3:0 = P3 P2 P1 P0
= G 11:8 + P11:8 G 7:4 + P11:8 P7:4 G 3:0 + P11:8 P7:4 P3:0 C 0
• Using these functions, the equation for C4 can be written as follows: C16 = G 15:12 + P15:12 C 12

C 4 = G 3:0 + P3:0 C 0 = G 15:12 + P15:12 ( G 11:8 + P11:8 G 7:4 + P11:8 P7:4 G 3:0 + P11:8 P7:4 P3:0 C 0 )
= G 15:12 + P15:12 G 11:8 + P15:12 P11:8 G 7:4
• Similarly, we can define group generate and propagate functions for other, non-
overlapping 4-bit groups: + P15:12 P11:8 P7:4 G 3:0 + P15:12 P11:8 P7:4 P3:0 C 0
G i + 3:i = G i + 3 + Pi + 3 G i + 2 + Pi + 3 Pi + 2 G i +1 + Pi + 3 Pi + 2 Pi +1G i
• This can be extended to another level of hierarchy (i.e., blocks) by forming block
Pi + 3:i = Pi + 3 Pi + 2 Pi +1 Pi generate and propagate functions, which allows us to get block carries. For example:
G 15:0 = G 15:12 + P15:12 G 11:8 + P15:12 P11:8 G 7:4 + P15:12 P11:8 P7:4 G 3:0
P15:0 = P15:12 P11:8 P7:4 P3:0 ⇒ C 16 = G 15:0 + P15:0 C 0

15 16
Parallel Prefix Adders Kogge-Stone (KS) Architecture
• Parallel prefix adders make use of recursive relations between group propagate and • The n-bit KS design achieves the minimum logical depth of log2n levels. It combines
generate functions. Consider 3 bit positions i, m and j, where i > m > j: values at spans of distance 20, 21, 22, … , 2n-1. The 8-bit KS design is:
Pi: j = (Pi Pi −1 L Pm )(Pm−1Pm− 2 L Pj ) = Pi:m Pm−1: j

Gi: j = (Gi + Pi Gi −1 + Pi Pi −1Gi − 2 +L+ Pi Pi −1 L Pm+1Gm ) + (Pi Pi −1 L Pm )Gm −1: j


= Gi:m + Pi:mGm −1: j
• Define an operator “o” which implements the recursive relations for Pi:j and Gi:j, i.e.:

( Pi:m , G i:m ) o ( Pm−1: j , G m −1; j ) = ( Pi:m Pm −1: j , G i:m + Pi:m G m−1; j )


= ( Pi: j , G i: j )

• This operator is associative (i.e., a series of o operators can be evaluated in any order).
This provides a great deal of flexibility in devising various parallel prefix adder
architectures, as illustrated on the following pages.
• Also, by definition, note that: Pi:i = Pi and Gi:i = Gi

Simon Knowles, “A Family of Adders,” 15th IEEE Symposium on Computer Arithmetic, pp. 277-284, 2001.
17 18

SystemVerilog Code for Kogge-Stone SystemVerilog Code for Kogge-Stone


Adder – Part 1 of 4 Adder – Part 2 of 4
module opo(input bit p1, g1, p2, g2, // form the propagate, generate and psum signals from the input operands
or(p[0], a[0], b[0]);
output bit p3, g3); // operator "o" or(p[1], a[1], b[1]);
or(p[2], a[2], b[2]);
or(p[3], a[3], b[3]);
assign p3 = p1 & p2; or(p[4], a[4], b[4]);
or(p[5], a[5], b[5]);
assign g3 = g1 | (p1 & g2); or(p[6], a[6], b[6]);
or(p[7], a[7], b[7]);

endmodule and(g[0], a[0], b[0]);


and(g[1], a[1], b[1]);
and(g[2], a[2], b[2]);
module kogge_stone(input bit [7:0] a, b, and(g[3], a[3], b[3]);
and(g[4], a[4], b[4]);
input bit c0, and(g[5], a[5], b[5]);
and(g[6], a[6], b[6]);
output bit [7:0] s, and(g[7], a[7], b[7]);
output bit c8);
xor(psum[0], a[0], b[0]);
xor(psum[1], a[1], b[1]);
wire [7:0] p, g, psum; xor(psum[2], a[2], b[2]);
xor(psum[3], a[3], b[3]);
wire c1, c2, c3, c4, c5, c6, c7; xor(psum[4], a[4], b[4]);
xor(psum[5], a[5], b[5]);
xor(psum[6], a[6], b[6]);
xor(psum[7], a[7], b[7]);

19 20

SystemVerilog Code for Kogge-Stone SystemVerilog Code for Kogge-Stone


Adder – Part 3 of 4 Adder – Part 4 of 4
// first level of operator o // form the carry signals
opo opo01(p[7], g[7], p[6], g[6], p76, g76); assign c1 = g[0] | (p[0] & c0);
opo opo02(p[6], g[6], p[5], g[5], p65, g65); assign c2 = g10 | (p10 & c0);
opo opo03(p[5], g[5], p[4], g[4], p54, g54); assign c3 = g20 | (p20 & c0);
opo opo04(p[4], g[4], p[3], g[3], p43, g43); assign c4 = g30 | (p30 & c0);
opo opo05(p[3], g[3], p[2], g[2], p32, g32); assign c5 = g40 | (p40 & c0);
opo opo06(p[2], g[2], p[1], g[1], p21, g21); assign c6 = g50 | (p50 & c0);
opo opo07(p[1], g[1], p[0], g[0], p10, g10); assign c7 = g60 | (p60 & c0);
assign c8 = g70 | (p70 & c0);
// second level of operator o
opo opo08(p76, g76, p54, g54, p74, g74); // form the sum signals
opo opo09(p65, g65, p43, g43, p63, g63); xor(s[0], psum[0], c0);
opo opo10(p54, g54, p32, g32, p52, g52); xor(s[1], psum[1], c1);
opo opo11(p43, g43, p21, g21, p41, g41); xor(s[2], psum[2], c2);
opo opo12(p32, g32, p10, g10, p30, g30); xor(s[3], psum[3], c3);
opo opo13(p21, g21, p[0], g[0], p20, g20); xor(s[4], psum[4], c4);
xor(s[5], psum[5], c5);
// third level of operator o xor(s[6], psum[6], c6);
opo opo14(p74, g74, p30, g30, p70, g70); xor(s[7], psum[7], c7);
opo opo15(p63, g63, p20, g20, p60, g60);
opo opo16(p52, g52, p10, g10, p50, g50); endmodule
opo opo17(p41, g41, p[0], g[0], p40, g40);

21 22

A Testbench for the Kogge-Stone Adder Part of the Testbench Output


module tb1ks; // random unsigned inputs, decimal values including a check 10 36 + 129 + 1 = 166 (166)
logic [7:0] a, b; // 8-bit inputs (to be chosen randomly) 20 99 + 13 + 1 = 113 (113)
logic c0; // carry input (to be chosen randomly)
wire [7:0] s; // 8-bit sum output 30 101 + 18 + 1 = 120 (120)
wire c8; // carry out of the MSB position
40 13 + 118 + 1 = 132 (132)
reg [8:0] check; // 9-bit sum value used to check correctness
50 237 + 140 + 1 = 378 (378)
// instantiate the 8-bit Kogge-Stone adder
kogge_stone ks1(a, b, c0, s, c8); 60 198 + 197 + 0 = 395 (395)

// simulation of 50 random addition operations 70 229 + 119 + 0 = 348 (348)


initial repeat (50) begin
80 143 + 242 + 0 = 385 (385)
// get new operand values and compute a check value
a = $random; b = $random; c0 = $random; 90 232 + 197 + 0 = 429 (429)
check = a + b + c0;
100 189 + 45 + 1 = 235 (235)
// compute and display the sum every 10 time units
#10 $display($time, " %d + %d + %d = %d (%d)", a, b, c0, {c8, s}, ...
check);
end
23 24
Ladner-Fischer (LF) Architecture Knowles Architecture
• The n-bit LF design also achieves the minimum logical depth of log 2n levels. It uses • Knowles has shown that the KS and LF designs are limiting cases of a set of minimum-
higher fan-out configurations. The 8-bit LF design is shown below: depth designs. There are 3 other possible 8-bit designs, such as:

25 26

Han-Carlson (HC) Architecture Post-/Pre- Inc./Dec. Operators


• One additional stage at the end is used, but it has low fanout and few devices.
• post-increment Example: n=k++;
 The value of k is assigned to n and then k is
incremented.
• pre-increment Example: n=++k;
 First, k is incremented. Then, the new value of k is
assigned to n.
• post-decrement Example: n=k--;
 The value of k is assigned to n and then k is
decremented.
• pre-decrement Example: n=--k;
 First, k is decremented. Then, the new value of k is
assigned to n.
27 28

Compound Assignment Operators Declaring Local Loop Variables


• += operator: • In a for loop, we need a variable which keeps track of the
number of iterations which have been executed. In
 y += x; is equiv. to: y = y + x; Verilog, this variable is declared outside of the loop, so it is
• -= operator: not local to the loop:
// Verilog example
 y -= x; is equiv. to: y = y - x;
int i;
• *= operator: ...
 y *= x; is equiv. to: y = y * x; for (i = 0; i < 16; i = i + 1)
• /= operator: ...
• SystemVerilog allows declaration of a local loop variable:
 y /= x; is equiv. to: y = y / x;
for (int i = 0; i < 16; i++)
• etc. (%=, &=, |=, ^=, ... ) ...
29 30

User-Defined Data Types Structures: The struct keyword


• The typedef keyword is used. Example: • Similar to structures in C.
typdef reg [127:0] wide_word; • Useful for grouping together a set of signals
• It can be applied for either a single module which have different data types.
or for several different modules: • An example is as follows:
 Local declaration: If typedef is used inside of struct {
a module, then it is only visible within that logic a, b, c;
module. int d, e, f;
 External declaration: If typedef is used bit [3:0] g, h;
outside of any module, then it can be visible } my_structure;
within several modules.
31 32
Structures – cont. Initialization of Structures
• Use the "dot notation" to access a particular • Initial values can be specified within curly
element of a structure. For example: braces by listing them in the order that they
my_structure.a = 1'b1; are declared within the structure:
typedef struct {
• We can also combine struct and typedef to logic a, b, c;
create new data types: int d, e, f;
typedef struct { bit [3:0] g, h;
logic a, b, c; } my_new_type;
int d, e, f;
bit [3:0] g, h; my_new_type var1 = {1'b0, 1'b1, 1'b0,
} my_new_type; 5, 6, 7, 4'hA, 4'hB};
33 34

Structures Passed Through Module Ports Example: A struct through a Module Port
• In order to be able to pass structures • First, use a typedef struct statement outside
through the ports of a module, do the of the module. Then, the module can declare one
or more of its ports to be of that type.
following:
 Place the typedef struct statement
typedef struct {
outside of the module. logic [15:0] a, b;
 Then, you can pass variables of that type int c;
into and out of the module. } simple;
module example (input simple r, s);
• Similarly, you can pass arguments to
...
functions and tasks which are structures. endmodule

35 36

Packed Structures Unions


• You can declare a struct to be packed. This • Similar to unions in C.
means that all of the elements in the struct are • A union represents a single unit of storage, but
stored as contiguous bits which are stored as a having more than one representation.
vector:  Each representation may be of a different data
 First element in the struct is the left-most element of
type.
the vector.
 In a typical application of a union, sometimes
 Last element in the struct is the right-most element of
the vector. the data is needed in one representation, while
 The number of bits in the vector is equal to the sum of at other times it is needed in a different
the number of bits needed to hold each individual representation.
element of the struct. • Packed unions are synthesizable, but unpacked
unions are not synthesizable.
37 38

Example of a Packed Union Example of a Union – Continued


• In the example below, we want to be able to module tbu; // testbench for the union
represent the information as either a signed or an union packed {
unsigned quantity: logic [3:0] u;
logic signed [3:0] s;
} info;
union packed {
initial begin
logic [3:0] u;
info.s = -3;
logic signed [3:0] s; $display("signed info: %d", info.s);
} info; $display("unsigned info: %d", info.u);
end
endmodule

39 40
Example of a Union – Continued Arrays
• The output from executing the previous code: • Multi-dimensional arrays are allowed.
• For example, a 3-dimensional array of integers of
signed info: -3 size 16x8x4 can be declared as:
unsigned info: 13 int my_array[0:15][0:7][0:3];
• The same array can also be declared as follows:
• Note that the value -3 is represented as a 4-bit int my_array[16][8][4];
signed binary number by: 1101 • To assign a value to a specific array element, just
specify each of its index values. For example:
• When this 4-bit pattern is interpreted as an my_array[4][3][2] = 55;
unsigned number, its value is 8+4+1=13.
41 42

Initializing Array Elements Assigning Multiple Values to Arrays


• The construction '{ , ... , } is called an • We can also use array literals and the replication
array literal. It can be used to initialize an array: operator to assign constant values to arrays which
int a[5] = '{10, 20, 30, 40, 50}; have already been declared:
int b[2][4] = '{'{0, 0, 0, 0}, int d[5];
'{1, 1, 1, 1}}; int e[2][4];
• We can also use the replication operator: int f[100];
int c[100] = '{100{0}}; // all 0s initial begin
d = '{10, 20, 30, 40, 50};
• Alternatively , we can use the default keyword: e = '{'{0, 0, 0, 0},'{1, 1, 1, 1}};
int c[100] = '{default:0}; f = '{100{0}};
43
end 44

Using for Loops with Arrays Using foreach Loops with Arrays
• Some features of SystemVerilog make using for • A foreach loop automatically goes through each
loops with arrays easier than in Verilog: possible index value in an array.
 Declare the loop index directly in the loop. • The previous example can be coded as:
 Use the ++ increment operator
 Use the $size function (returns the number of array
int arr[10];
elements)
int arr[10]; initial begin
initial begin foreach (arr[i])
for (int i = 0; i < $size(arr); i++) arr[i] = 3*i;
arr[i] = 3*i; end
end
45 46

foreach with Multidimensional Arrays Arrays of Structures


• The syntax is a little unusual when using • We can form an array in which each element is a
foreach with a multidimensional array. We use structure:
[i, ..., k] rather than [i] ... [k] in the // create the structure
foreach statement: typedef struct {
int a, b, c;
int g[10][10]; logic [15:0] d, e, f;
initial begin } collection;
foreach (g[i, j])
g[i][j] = i + j; // now, form an array of 50 of these
end collection coll_arr[50];
47 48
Structures Containing Arrays Enumerated Names and Data Types
• It is also possible to include one or more arrays as • Useful for abstract system modeling.
part of a structure, as in the following type • The enum keyword is used, followed by a
definition:
list of the allowed values, followed by the
name of the variable. For example:
// this contains 3 10-element arrays
typedef struct { enum {Shanghai, Beijing, Nanjing} city;
int a[10], b[10], c[10];
logic [15:0] d, e, f; • Can also use it together with a typedef:
} new_collection;
typedef enum {add, sub, mul} instruction;

49 50

Values of Enumerated Type Variables Procedural Blocks: Problem with always


• By default, the actual values used internally • In Verilog, an always block can be used to model
to represent the different enumerated either combinational logic or sequential logic.
names are 32-bit 2-state values, which • The designer must observe a set of rules order to
corresponds to the int data type. specify if the block will generate combinational
logic, latches or flip-flops when it is synthesized:
 The first name listed gets the value 0.
 signals and qualifiers in the sensitivity list
 The second name listed gets the value 1, etc.  statements within the body of the always block
• If desired, it is possible to override this • However, the rules are complex and the designer
default value assignment process. can easily make a mistake.
• Also, it is difficult for other people reading the
code to determine what the designer intended.
51 52

Expressing Combinational Logic:


always_comb always_comb Example
• The always_comb statement expresses the designer's • A 2-to-1 MUX with data inputs in0 and
intent to create a combinational logic block.
in1, select signal select and output
• Synthesis tools can issue a warning message if the code
generates any sequential elements. mux_out can be modeled as follows (the
• You do not include a sensitivity list! (The sensitivity list is inferred sensitivity list includes in0, in1
"inferred" to include all the necessary signals in the block.) and select):
 Thus, the block will be evaluated whenever any input

signal to the block changes.


always_comb
 This corresponds to the way in which a combinational
if (select)
logic block operates. mux_out = in1;
• The block is also evaluated once at simulation time 0 so else
that the combinational logic block is properly initialized.
mux_out = in0;
53 54

Expressing Edge-Triggered Logic: Expressing Latched Logic:


always_ff always_latch
• The always_ff statement expresses the designer's • The always_latch statement expresses the designer's
intent to create an edge-triggered sequential logic block. intent to create a latched (i.e., level-sensitive) sequential
• Synthesis tools can issue a warning message if the code logic block.
generates any other type of block. • Synthesis tools can issue a warning message if the code
• You do include a sensitivity list. Every signal in this list generates any other type of block.
must be qualified by the keyword posedge or negedge. • You do not include a sensitivity list! (The sensitivity list is
• Example (a rising edge triggered D-type flip-flop with an "inferred" to include all the necessary signals in the block.)
active-low asynchronous reset) :  Thus, the block will be evaluated whenever any input
signal to the block changes.
always_ff @(posedge clk or negedge rst)  This corresponds to the way in which a latched logic

if (rst == 0) Q <= 0; block operates.


else Q <= D; • The block is also evaluated once at simulation time 0 so
that the latched logic block is properly initialized.
55 56
always_latch Example Functions
• A D-type latch which is transparent when the • begin ... end is not required in functions
clock is high can be expressed as: containing multiple statements.
 Those statements will be executed

always_latch sequentially.
if (clock) Q <= D;  The blocking assignment = must be used in

each of the statements.


• Note that this uses an "incompletely specified" if • As in Verilog, you can assign the value to be
statement since there is no else clause. returned to the name of the function.
• Alternatively, you can use a return statement to
• This will synthesize a latch, which is consistent
with the designers intent as expressed by the return a value.
always_latch keyword.
57 58

Example of Using return Placement of the return Statement


• A simple example using the return statement: • The return statement does not have to be
// perform a multiply-add operation placed at the end of the function.
function int mul_add (input int a, b, c); • It is also OK to have more than one return
return(a*b + c); statement.
endfunction • This provides an efficient way to have several
different exit paths from the function, depending
• Same result using the Verilog-style assignment: on the desired behavior.
// equivalent operation • If a return statement is executed, the function is
function int mul_add (input int a, b, c); terminated at that point. (In other words,
mul_add = a*b + c; depending on the placement of the return, not
endfunction all statements in the function may be executed.)
59 60

References
• IEEE Standard for SystemVerilog— Unified Hardware
Design, Specification, and Verification Language, IEEE,
IEEE Std 1800TM -2005, 22 November 2005.
• S. Sutherland, S. Davidmann and P. Flake, SystemVerilog
for Design, Kluwer Academic Publishers, 2004.
• C. Spear, SystemVerilog for Verification, Springer, 2006.
• SystemVerilog Tutorials, Doulos Ltd.,
http://www.doulos.com/knowhow/sysverilog/tutorial/
• SystemVerilog Tutorial, electroSofts.com,
http://electrosofts.com/systemverilog/

61

Das könnte Ihnen auch gefallen