Sie sind auf Seite 1von 31

SystemVerilog Lecture 1

From Verilog to SystemVerilog


SystemVerilog is the third generation of the Verilog language standard: 1st generation standard: Verilog-1995 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.

Using SystemVerilog With VCS


By convention, SystemVerilog files use the extension .sv

For example:
design1.sv, tbdesign1.sv

To compile SystemVerilog code with VCS, use the sverilog flag when compiling.

For example:
vcs sverilog design1.sv tbdesign1.sv ./simv

Built-in Data Types


We'll start with some of the simpler

elements of the language and give some design examples before moving on to the more complex features that are available. 4-state data types: (0, 1, x or z values)
reg, logic, integer, wire, wor, wand (logic is identical to reg)

2-state data types: (only 0 or 1 values)


bit, byte, shortint, int, longint
4

Unsigned and Signed Data Types


Keywords signed and unsigned can be

used to override the default numeric properties: logic is unsigned by default:


logic [7:0] a; // a is unsigned logic signed [7:0] b; // b is signed

int is 32-bit signed by default:


int c; // c is 32-bit signed int unsigned d; // 32-bit unsigned
5

Assigning the Same Value to all Bits


The common value 0, 1, x or z can be

assigned to all bit positions of a vector with a new and simple syntax:
my_bus my_bus my_bus my_bus = = = = '0; '1; 'x; 'z; // // // // fills fills fills fills with with with with all all all all 0 1 x z

Module Inputs and Outputs


We can specify the direction and the type of

the signals going in and out of a module directly in the module statement itself:
module simple (output logic a, b, input logic c, d); ... endmodule

Example: 10-bit Truncated Adder

Design a ripple-carry adder module for adding two 10-bit signed numbers by first sign-extending each operand to 11 bits, adding the 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 "Step 1a" of a larger example which will be considered later.) Note that you must correctly scale the power-of-two weights of these output bits when interpreting the numerical value that is produced at the output. Also, note that the truncation may introduce a small error compared to the full-precision result.

p[9:0]

q[9:0]

10-bit truncated adder

r[10:1]

SystemVerilog Code Part 1 of 1


// half adder module half_adder(input logic a, b, output logic s, cout); assign s = a^b; assign cout = a&b; endmodule // full addder module full_adder(input logic a, b, cin, output logic s, cout); assign s = a^b^cin; assign cout = (a&b) | (b&cin) | (a&cin); endmodule

SystemVerilog Code cont.


// 10-bit truncated ripple-carry adder module RCA10(input logic [9:0] p, q, output logic [10:1] r); wire wire lsb_sum, msb_carry; [9:0] carry; ha0(p[0], q[0], lsb_sum, carry[0]); fa1(p[1], q[1], carry[0], r[1], carry[1]); fa2(p[2], q[2], carry[1], r[2], carry[2]); fa3(p[3], q[3], carry[2], r[3], carry[3]); fa4(p[4], q[4], carry[3], r[4], carry[4]); fa5(p[5], q[5], carry[4], r[5], carry[5]); fa6(p[6], q[6], carry[5], r[6], carry[6]); fa7(p[7], q[7], carry[6], r[7], carry[7]); fa8(p[8], q[8], carry[7], r[8], carry[8]); fa9(p[9], q[9], carry[8], r[9], carry[9]); fa10(p[9], q[9], carry[9], r[10], msb_carry);

half_adder full_adder full_adder full_adder full_adder full_adder full_adder full_adder full_adder full_adder full_adder endmodule

10

Testbench (cont. on next page)

Construct a testbench to perform exhaustive testing of this module to prove that your design code is correct. Note that the check value calculated in the testbench should correctly model the truncation and scaling process used in the design.
module tbstep1; // testbench for adder of Step 1a. // exhaustive checking of all 1024*1024 possible cases logic signed [9:0] x, y; logic signed [9:0] s; integer sval; integer check; integer i, j; integer num_correct; integer num_wrong; // // // // // // // 10-bit signed inputs 10-bit sum output of the adder scaled value of the sum value used to check correctness loop variables counter to keep track of num. correct counter to keep track of num. wrong

// instantiate the adder RCA10 adder_instance(x, y, s);

11

// exhaustive simulation of all possible cases initial begin // initialize the counter variables num_correct = 0; num_wrong = 0; // loop through all possible cases and record the results for (i = 0; i < 1024; i = i + 1) begin x = i; for (j = 0; j < 1024; j = j + 1) begin y = j; check = x + y; // adjust check value for truncation if (((check % 2) == 1) || ((check % 2) == -1)) check = check - 1; // compute and check the sum #10 sval = s*2; if (sval == check) num_correct = num_correct + 1; else num_wrong = num_wrong + 1; // following line is commented out, but is useful for debugging // $display($time, " %d + %d = %d (%d)", x, y, sval, check); end end // print the final counter values $display("num_correct = %d, num_wrong = %d", num_correct, num_wrong); end endmodule

12

Testbench Results

The results from compiling and running the design and testbench are:
num_correct = 1048576, num_wrong = 0

If the debug statement is not commented out, then a portion of the output looks as follows (notice the truncation):
102000 102010 102020 102030 102040 102050 102060 102070 102080 102090 9 9 9 9 9 9 9 9 9 9 + + + + + + + + + + -41 -40 -39 -38 -37 -36 -35 -34 -33 -32 = = = = = = = = = = -32 -32 -30 -30 -28 -28 -26 -26 -24 -24 ( ( ( ( ( ( ( ( ( ( -32) -32) -30) -30) -28) -28) -26) -26) -24) -24)
13

Carry Look-Ahead (CLA) Adders


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 references define propagate using the exclusive OR function.)
Pi = A i + B i , G i = 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 carry into the next higher bit position, Ci+1, are given by:
S i = Psum i C i , C i +1 = G i + Pi C i

A CLA adder uses the fact that these functions can be computed at all bit positions in parallel, and this information can be used to speed up the carry (and hence the sum) computations.

C1 = G 0 + P0 C 0 C 2 = G 1 + P1C1 = G 1 + P1 ( G 0 + P0 C 0 ) = G 1 + P1G 0 + P1P0 C 0 C 3 = G 2 + P2 C 2 = G 2 + P2 (G 1 + P1G 0 + P1P0 C 0 ) = G 2 + P2 G 1 + P2 P1G 0 + P2 P1 P0 C 0 C 4 = G 3 + P3C 3 = G 3 + P3 ( G 2 + P2 G 1 + P2 P1G 0 + P2 P1P0 C 0 ) = G 3 + P3G 2 + P3 P2 G 1 + P3 P2 P1G 0 + P3 P2 P1P0 C 0
14

Carry Look-Ahead (CLA) Adders Cont.


The previous equations determine the first four carries in parallel. While the previous set of substitutions could be continued to higher-order carries, they become impractical due to the the large number of terms involved and large fan-in gates that would be required. One alternative is to construct a hierarchical structure consisting of groups, blocks and sections. For example, we can define the group generate and propagate functions as:

G 3:0 = G 3 + P3 G 2 + P3 P2 G 1 + P3 P2 P1G 0 , P3:0 = P3 P2 P1 P0


Using these functions, the equation for C4 can be written as follows:

C 4 = G 3:0 + P3:0 C 0
Similarly, we can define group generate and propagate functions for other, nonoverlapping 4-bit groups:

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 Pi + 3:i = Pi + 3 Pi + 2 Pi +1 Pi

15

Carry Look-Ahead (CLA) Adders Cont.


Given the definitions of these group generate and propagate functions, we can create the following group carries:

C8 = G 7:4 + P7:4 C 4 = G 7:4 + P7:4 (G 3:0 + P3:0 C 0 ) = G 7:4 + P7:4 G 3:0 + P7:4 P3:0 C 0 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 11:8 + P11:8 G 7:4 + P11:8 P7:4 G 3:0 + P11:8 P7:4 P3:0 C 0 C16 = G 15:12 + P15:12 C12 = 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 + P15:12 P11:8 P7:4 G 3:0 + P15:12 P11:8 P7:4 P3:0 C 0
This can be extended to another level of hierarchy (i.e., blocks) by forming block 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
16

Parallel Prefix Adders


Parallel prefix adders make use of recursive relations between group propagate and generate functions. Consider 3 bit positions i, m and j, where i > m > j:

Pi: j = (Pi Pi 1 L Pm )(Pm 1Pm2 L Pj ) = Pi:m Pm1: 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
17

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

Kogge-Stone (KS) Architecture


The n-bit KS design achieves the minimum logical depth of log2n levels. It combines values at spans of distance 20, 21, 22, , 2n-1. The 8-bit KS design is:

18

SystemVerilog Code for Kogge-Stone Adder Part 1 of 4


module opo(input bit p1, g1, p2, g2, output bit p3, g3); // operator "o" assign p3 = p1 & p2; assign g3 = g1 | (p1 & g2); endmodule module kogge_stone(input input output output wire wire bit [7:0] a, b, bit c0, bit [7:0] s, bit c8);

[7:0] p, g, psum; c1, c2, c3, c4, c5, c6, c7;

19

SystemVerilog Code for Kogge-Stone Adder Part 2 of 4


// form the propagate, generate and psum signals from the input operands or(p[0], a[0], b[0]); or(p[1], a[1], b[1]); or(p[2], a[2], b[2]); or(p[3], a[3], b[3]); or(p[4], a[4], b[4]); or(p[5], a[5], b[5]); or(p[6], a[6], b[6]); or(p[7], a[7], b[7]); and(g[0], and(g[1], and(g[2], and(g[3], and(g[4], and(g[5], and(g[6], and(g[7], a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], b[0]); b[1]); b[2]); b[3]); b[4]); b[5]); b[6]); b[7]); b[0]); b[1]); b[2]); b[3]); b[4]); b[5]); b[6]); b[7]);

xor(psum[0], xor(psum[1], xor(psum[2], xor(psum[3], xor(psum[4], xor(psum[5], xor(psum[6], xor(psum[7],

a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7],

20

SystemVerilog Code for Kogge-Stone Adder Part 3 of 4


// first level of operator o opo opo01(p[7], g[7], p[6], g[6], opo opo02(p[6], g[6], p[5], g[5], opo opo03(p[5], g[5], p[4], g[4], opo opo04(p[4], g[4], p[3], g[3], opo opo05(p[3], g[3], p[2], g[2], opo opo06(p[2], g[2], p[1], g[1], opo opo07(p[1], g[1], p[0], g[0], p76, p65, p54, p43, p32, p21, p10, g76); g65); g54); g43); g32); g21); g10);

// second level of operator o opo opo08(p76, g76, p54, g54, p74, g74); opo opo09(p65, g65, p43, g43, p63, g63); opo opo10(p54, g54, p32, g32, p52, g52); opo opo11(p43, g43, p21, g21, p41, g41); opo opo12(p32, g32, p10, g10, p30, g30); opo opo13(p21, g21, p[0], g[0], p20, g20); // third level opo opo14(p74, opo opo15(p63, opo opo16(p52, opo opo17(p41, of operator o g74, p30, g30, p70, g70); g63, p20, g20, p60, g60); g52, p10, g10, p50, g50); g41, p[0], g[0], p40, g40);

21

SystemVerilog Code for Kogge-Stone Adder Part 4 of 4


// form the assign c1 = assign c2 = assign c3 = assign c4 = assign c5 = assign c6 = assign c7 = assign c8 = carry signals g[0] | (p[0] & c0); g10 | (p10 & c0); g20 | (p20 & c0); g30 | (p30 & c0); g40 | (p40 & c0); g50 | (p50 & c0); g60 | (p60 & c0); g70 | (p70 & c0);

// form the sum signals xor(s[0], psum[0], c0); xor(s[1], psum[1], c1); xor(s[2], psum[2], c2); xor(s[3], psum[3], c3); xor(s[4], psum[4], c4); xor(s[5], psum[5], c5); xor(s[6], psum[6], c6); xor(s[7], psum[7], c7); endmodule

22

A Testbench for the Kogge-Stone Adder


module tb1ks; // random unsigned inputs, decimal values including a check logic [7:0] a, b; logic c0; wire [7:0] s; wire c8; reg [8:0] check; // // // // // 8-bit carry 8-bit carry 9-bit inputs (to be chosen randomly) input (to be chosen randomly) sum output out of the MSB position sum value used to check correctness

// instantiate the 8-bit Kogge-Stone adder kogge_stone ks1(a, b, c0, s, c8); // simulation of 50 random addition operations initial repeat (50) begin // get new operand values and compute a check value a = $random; b = $random; c0 = $random; check = a + b + c0; // 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

Part of the Testbench Output


10 36 + 129 + 1 = 166 (166) 20 30 40 50 60 70 80 90 100 99 + 101 + 13 + 1 = 113 (113) 18 + 1 = 120 (120)

13 + 118 + 1 = 132 (132) 237 + 140 + 1 = 378 (378) 198 + 197 + 0 = 395 (395) 229 + 119 + 0 = 348 (348) 143 + 242 + 0 = 385 (385) 232 + 197 + 0 = 429 (429) 189 + ... 45 + 1 = 235 (235)

24

Ladner-Fischer (LF) Architecture


The n-bit LF design also achieves the minimum logical depth of log2n levels. It uses higher fan-out configurations. The 8-bit LF design is shown below:

25

Knowles Architecture
Knowles has shown that the KS and LF designs are limiting cases of a set of minimumdepth designs. There are 3 other possible 8-bit designs, such as:

26

Han-Carlson (HC) Architecture


One additional stage at the end is used, but it has low fanout and few devices.

27

Post-/Pre- Inc./Dec. Operators


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. Example: n=k--; The value of k is assigned to n and then k is decremented. Example: n=--k; First, k is decremented. Then, the new value of k is assigned to n.
28

post-decrement

pre-decrement

Compound Assignment Operators


+= operator:
y += x; is equiv. to: is equiv. to: is equiv. to: is equiv. to: y = y + x; y = y - x; y = y * x; y = y / x;

-= operator:
y -= x;

*= operator:
y *= x;

/= operator:
y /= x;

etc. (%=, &=, |=, ^=, ... )


29

Declaring Local Loop Variables


In a for loop, we need a variable which keeps track of the number of iterations which have been executed. In Verilog, this variable is declared outside of the loop, so it is not local to the loop: // Verilog example

int i; ... for (i = 0; i ...

< 16; i = i + 1)

SystemVerilog allows declaration of a local loop variable: for (int i = 0; i < 16; i++) ...
30

User-Defined Data Types


The typedef keyword is used. Example:

typdef reg [127:0] wide_word;


It can be applied for either a single module

or for several different modules:


Local declaration: If typedef is used inside of a module, then it is only visible within that module. External declaration: If typedef is used outside of any module, then it can be visible within several modules.
31

Structures: The struct keyword


Similar to structures in C. Useful for grouping together a set of signals

which have different data types. An example is as follows:


struct { logic a, b, c; int d, e, f; bit [3:0] g, h; } my_structure;

32

Structures cont.
Use the "dot notation" to access a particular element of a structure. For example:
my_structure.a = 1'b1;

We can also combine struct and typedef to create new data types:
typedef struct { logic a, b, c; int d, e, f; bit [3:0] g, h; } my_new_type;
33

Initialization of Structures
Initial values can be specified within curly

braces by listing them in the order that they are declared within the structure:
typedef struct { logic a, b, c; int d, e, f; bit [3:0] g, h; } my_new_type; my_new_type var1 = {1'b0, 1'b1, 1'b0, 5, 6, 7, 4'hA, 4'hB};
34

Structures Passed Through Module Ports


In order to be able to pass structures

through the ports of a module, do the following: Place the typedef struct statement outside of the module. Then, you can pass variables of that type into and out of the module. Similarly, you can pass arguments to functions and tasks which are structures.
35

Example: A struct through a Module Port


First, use a typedef struct statement outside of the module. Then, the module can declare one or more of its ports to be of that type.
typedef struct { logic [15:0] a, b; int c; } simple; module example (input simple r, s); ... endmodule
36

Packed Structures
You can declare a struct to be packed. This means that all of the elements in the struct are stored as contiguous bits which are stored as a vector:
First element in the struct is the left-most element of the vector. Last element in the struct is the right-most element of the vector. The number of bits in the vector is equal to the sum of the number of bits needed to hold each individual element of the struct.

37

Unions
Similar to unions in C. A union represents a single unit of storage, but having more than one representation. Each representation may be of a different data type. In a typical application of a union, sometimes the data is needed in one representation, while at other times it is needed in a different representation. Packed unions are synthesizable, but unpacked unions are not synthesizable.
38

Example of a Packed Union


In the example below, we want to be able to represent the information as either a signed or an unsigned quantity:

union packed { logic [3:0] u; logic signed [3:0] s; } info;

39

Example of a Union Continued


module tbu; // testbench for the union union packed { logic [3:0] u; logic signed [3:0] s; } info; initial begin info.s = -3; $display("signed info: %d", info.s); $display("unsigned info: %d", info.u); end endmodule
40

Example of a Union Continued


The output from executing the previous code:

signed info: unsigned info: 13

-3

Note that the value -3 is represented as a 4-bit signed binary number by: 1101 When this 4-bit pattern is interpreted as an unsigned number, its value is 8+4+1=13.
41

Arrays
Multi-dimensional arrays are allowed. For example, a 3-dimensional array of integers of size 16x8x4 can be declared as: int my_array[0:15][0:7][0:3]; The same array can also be declared as follows: int my_array[16][8][4]; To assign a value to a specific array element, just specify each of its index values. For example: my_array[4][3][2] = 55;

42

Initializing Array Elements


The construction '{ , ... , } is called an array literal. It can be used to initialize an array: int a[5] = '{10, 20, 30, 40, 50}; int b[2][4] = '{'{0, 0, 0, 0}, '{1, 1, 1, 1}}; We can also use the replication operator: int c[100] = '{100{0}}; // all 0s Alternatively , we can use the default keyword: int c[100] = '{default:0};
43

Assigning Multiple Values to Arrays


We can also use array literals and the replication operator to assign constant values to arrays which have already been declared: int d[5]; int e[2][4]; int f[100]; initial begin d = '{10, 20, 30, 40, 50}; e = '{'{0, 0, 0, 0},'{1, 1, 1, 1}}; f = '{100{0}}; end 44

Using for Loops with Arrays


Some features of SystemVerilog make using for loops with arrays easier than in Verilog:
Declare the loop index directly in the loop. Use the ++ increment operator Use the $size function (returns the number of array elements)

int arr[10]; initial begin for (int i = 0; i < $size(arr); i++) arr[i] = 3*i; end
45

Using foreach Loops with Arrays


A foreach loop automatically goes through each possible index value in an array. The previous example can be coded as:

int arr[10]; initial begin foreach (arr[i]) arr[i] = 3*i; end


46

foreach with Multidimensional Arrays


The syntax is a little unusual when using foreach with a multidimensional array. We use [i, ..., k] rather than [i] ... [k] in the foreach statement:

int g[10][10]; initial begin foreach (g[i, j]) g[i][j] = i + j; end


47

Arrays of Structures
We can form an array in which each element is a structure: // create the structure typedef struct { int a, b, c; logic [15:0] d, e, f; } collection;

// now, form an array of 50 of these collection coll_arr[50];


48

Structures Containing Arrays


It is also possible to include one or more arrays as part of a structure, as in the following type definition:

// this contains 3 10-element arrays typedef struct { int a[10], b[10], c[10]; logic [15:0] d, e, f; } new_collection;

49

Enumerated Names and Data Types


Useful for abstract system modeling. The enum keyword is used, followed by a

list of the allowed values, followed by the name of the variable. For example:
enum {Shanghai, Beijing, Nanjing} city;

Can also use it together with a typedef:


typedef enum {add, sub, mul} instruction;
50

Values of Enumerated Type Variables


By default, the actual values used internally

to represent the different enumerated names are 32-bit 2-state values, which corresponds to the int data type.
The first name listed gets the value 0. The second name listed gets the value 1, etc.

If desired, it is possible to override this

default value assignment process.

51

Procedural Blocks: Problem with always


In Verilog, an always block can be used to model either combinational logic or sequential logic. The designer must observe a set of rules order to specify if the block will generate combinational logic, latches or flip-flops when it is synthesized:
signals and qualifiers in the sensitivity list statements within the body of the always block

However, the rules are complex and the designer can easily make a mistake. Also, it is difficult for other people reading the code to determine what the designer intended.
52

Expressing Combinational Logic: always_comb


The always_comb statement expresses the designer's intent to create a combinational logic block. Synthesis tools can issue a warning message if the code generates any sequential elements. You do not include a sensitivity list! (The sensitivity list is "inferred" to include all the necessary signals in the block.)

Thus, the block will be evaluated whenever any input signal to the block changes. This corresponds to the way in which a combinational logic block operates. The block is also evaluated once at simulation time 0 so that the combinational logic block is properly initialized.
53

always_comb Example
A 2-to-1 MUX with data inputs in0 and

in1, select signal select and output mux_out can be modeled as follows (the inferred sensitivity list includes in0, in1 and select): always_comb if (select) mux_out = in1; else mux_out = in0;
54

Expressing Edge-Triggered Logic: always_ff


The always_ff statement expresses the designer's intent to create an edge-triggered sequential logic block. Synthesis tools can issue a warning message if the code generates any other type of block. You do include a sensitivity list. Every signal in this list must be qualified by the keyword posedge or negedge. Example (a rising edge triggered D-type flip-flop with an active-low asynchronous reset) :

always_ff @(posedge clk or negedge rst) if (rst == 0) Q <= 0; else Q <= D;


55

Expressing Latched Logic: always_latch


The always_latch statement expresses the designer's intent to create a latched (i.e., level-sensitive) sequential logic block. Synthesis tools can issue a warning message if the code generates any other type of block. You do not include a sensitivity list! (The sensitivity list is "inferred" to include all the necessary signals in the block.)

Thus, the block will be evaluated whenever any input signal to the block changes. This corresponds to the way in which a latched logic block operates. The block is also evaluated once at simulation time 0 so that the latched logic block is properly initialized.
56

always_latch Example
A D-type latch which is transparent when the clock is high can be expressed as:

always_latch if (clock) Q <= D;


Note that this uses an "incompletely specified" if statement since there is no else clause. This will synthesize a latch, which is consistent with the designers intent as expressed by the always_latch keyword.
57

Functions
begin ... end is not required in functions containing multiple statements. Those statements will be executed sequentially. The blocking assignment = must be used in each of the statements. As in Verilog, you can assign the value to be returned to the name of the function. Alternatively, you can use a return statement to return a value.
58

Example of Using return


A simple example using the return statement:
// perform a multiply-add operation function int mul_add (input int a, b, c); return(a*b + c); endfunction

Same result using the Verilog-style assignment:


// equivalent operation function int mul_add (input int a, b, c); mul_add = a*b + c; endfunction
59

Placement of the return Statement


The return statement does not have to be placed at the end of the function. It is also OK to have more than one return statement. This provides an efficient way to have several different exit paths from the function, depending on the desired behavior. If a return statement is executed, the function is terminated at that point. (In other words, depending on the placement of the return, not all statements in the function may be executed.)
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