how do we test it? process/cmu... · white box testing white box testing access through ports and...

Post on 26-Jan-2020

1 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Many elements © Don Thomas, 2014, used with permission

!

18-545 — Advanced Digital Design ECE Department

Lecture

How do we test it?

08

with

cre

dit t

o G

. Lar

son

What’s up?

❏ Better yet, what’s not up? ❏ What you know

◆ Lots about how to write Verilog descriptions of designs ❏ What you don’t know

◆ Techniques and strategies to use for debugging and validating a design

◆ Most design time is spent here — more than designing it in the first place

◆ Validation Engineering — It’s often the first job/internship you will get in digital electronic system design

❏ So, how have you debugged your descriptions? ◆ Probably in haphazard ways!

Today's Agenda

❏ Theory of Testbenches ❏ FSM Testbenches (review) ❏ Randomization in Testbenches ❏ Testbench Potpourri

❏ Classes ❏ Tasks, Functions (again) ❏ Hierarchical Names ❏ Force/Release ❏ $display, $monitor, $strobe ❏ File I/O ❏ Foreach ❏ Finally!

Some common approaches…❏ Smoke test

◆ Let ‘er rip, watch the system crash and burn, even in the simulator ❏ Ask the TAs

◆ Assuring yourself that the testbench must be wrong ❏ Shoot some test vectors into the design

◆ Direct: Specific vector sequences even for something simple ◆ Random: Any number will do, just try something

❏ Check the pieces first ◆ Then check on piece integration next

❏ Indirect test ◆ Model checking — assertions

❏ Boot the OS ◆ That should check lots of stuff

❏ OK, these are some ways, but let’s step back a little…

How has Digital Design Changed?

❏ Majorly: TTL Handbooks — ABEL/ Verilog/VHDL — Cadence tools — Synopsys Synthesis — …

How has system debug changed?

System-on-Chip (or board)

❏ Virtual design methods are more widely used ◆ Language-based (model-driven)

simulation and synthesis ❏ Pre-Silicon validation

◆ Simulation ◆ Assertion based validation

❏ Post-Silicon validation ◆ Embedded hardware and software are

now being more widely used ◆ Components testing themselves and

other components — using both hardware and software

Why is this important?

❏ Software and validation are about 80% of total SoC development cost — about equally split

◆ Software — OS, middleware, firmware, drivers ◆ (Recent semi-quote from Lip-Bu Tan, CEO of Cadence) ◆ 40% each is high, more than twice the design costs

❏ If an SoC doesn’t work, you can’t sell it ◆ Not even in a garage sale ◆ Re-spins are in the 10s of millions of dollars for ASICs ◆ Less pricey for FPGAs but there are still NRE design

costs ❏ The validation aspect

◆ Do the design’s pieces work together? ◆ Not just “running some testbench vectors through”

Validation Engineer

❏ A designer who knows enough to realize what might be wrong or missed

◆ Can create a fault model listing what could be wrong ❏ A designer who can create a testbench to test against the fault

model ◆ Either a hardware or software testbench

❏ A designer who can measure how much of the fault model has been covered

◆ Functional coverage ❏ A designer who can “think different” ❏ Building a Verification Mindset

◆ In industry, there are teams of validation engineers ◆ Waking up every morning knowing there are bugs to find

❏ Aha! and embarrass the designers

Building a Validation Mindset

There’s a bug in the offense’s plan!

At 10K feet

❏ Pieces ◆ Device under test (“dut”) — what’s being tested – duh ◆ Stimulus generator — figures out what test vectors (stimulus)

to present to the dut ◆ Monitor and check — checks certain features and logs outputs ◆ Scoreboard — A check-off list of what still needs (to be)

tested. Figures out what needs closer testing

Design under test

Stimulus generator

Monitor and

checker

ScoreboardThe Testbench

A lot more smarts

❏ These elements imply a lot of smarts behind them ◆ a plan for the testing and validation ◆ a fault model — a list of faults that are to be checked ◆ a measure of functional coverage —the percent of faults checked ◆ a dynamically reactive capability — change the stimulus generator

to focus on remaining faults

The Testbench

Design under test

Stimulus generator

Monitor and

checker

ScoreboardThe Testbench

The next step in testbench building

❏ There are teams of verification engineers who build testbenches ◆ Playing defense ◆ Knowing there is a bug in the design somewhere and they’ll

find it (break anything!) and embarrass the designers ❏ Verification/validation engineering generalizes on this

◆ i.e., this structure (or similar) could be applied to any dut ◆ we won’t go there — at least not too far

❏ What we’ll do ◆ Consider ways to build the stimulus generator and monitor/

checker ◆ SV constructs and kernel stuff to support testbenches

Black box testing

❏ Black box testing ◆ Only have access

to the ports ◆ No (little)

knowledge of internal structures

❏ How come? ◆ Synthesis

generated the internals — don’t know what optimizations were used

◆ Tests can be used across parts in a family

testbench design

top

Normal port connections

White box testing

❏ White box testing ◆ Access through

ports and hierarchical naming

◆ Can see lots of internal structures

❏ How come? ◆ Can test lots more

of the details ◆ Good but doesn’t

necessarily cross to new versions of a system

testbench design

top

Normal port connections

Gray box testing

❏ Gray box testing ◆ Somewhere in the

middle between black and white

testbench design

top

Normal port connections

Styles of checking: Direct

❏ Direct — apply vectors, check results (maybe some time later)

❏ Think of something that might go wrong

◆ Aha! The ALU carry chain might not work

❏ Think of how to test for that specific problem

◆ What values can I add to check that it works: -1 + 1

❏ Just two values? or all pairs? or just some? — then which?

◆ Select specific values — typically specific corner cases

◆ Select random values — typically general case

design

testbench

Expected results

Actual results

OK

Test vectors

It’s never quite this clean…

Styles of checking: Indirect

❏ Model Checking ◆ A piece of the design is checked

against a model while other tests are being run

◆ Sometimes called assertion-based ❏ Typically a general check

◆ Assert that “a always equals b + c” ◆ If it doesn’t, report an error!

❏ How’s it work? ◆ You’re testing other things and,

oops, the alu screwed up! ❏ This would be part of the monitor

box in earlier diagram

design

testbench

Expected results

Actual results

OK

Test vectors

assert property (a == b + c)

Testbench Stuff

❏ The testbench includes ◆ how you want to test your system

❏ reset, reading in data files, printing stuff, logs, … ◆ the rest of the world — the environment surrounding your design

❏ clocks, other designs not yet completed, upstream/downstream systems

❏ It’s not synthesizable, it’s just time-based behavior ◆ just about anything — programming-wise — goes

❏ Today, just some basics ◆ fault models — what types of things can go wrong? ◆ random test generation and constraints

❏ Other important concepts for the future ◆ assertions — what things should always be true? ◆ object-oriented subset of the language

SVbook 7.3

Testbench

❏ Basic organizations

top

tb design top

tb code

design

top

tb code1

design

tb code2

top

tb code

design

tb code

instantiated module

Today's Agenda

❏ Theory of Testbenches ❏ FSM Testbenches (review) ❏ Randomization in Testbenches ❏ Testbench Potpourri

❏ Classes ❏ Tasks, Functions (again) ❏ Hierarchical Names ❏ Force/Release ❏ $display, $monitor, $strobe ❏ File I/O ❏ Foreach ❏ Finally!

0 0 0 1

1 0

A

C

B

R 1/00

1/10

0/010/01

s1 s0Legend

i/a,b

x/00

Testing an FSM

❏ Reset the system, and follow a sequence of states ◆ These should lead your design through

a path of its own states ◆ Do this multiple times, following

different paths (eventually all paths) ◆ You will probably want to be able to

reset the design under test (“dut”) without resetting your testbench

❏ The answer is no. What’s missing? ◆ …

Is this path a complete check?

0 0 0 1

1 0

A

C

B

R 1/00

1/10

0/010/01

s1 s0Legend

i/a,b

x/00

How does the sequence happen?

❏ Testbench has to generate the right inputs (i for this FSM) plus clock, reset ◆ … in the right sequence

❏ Implicit FSM ◆ This is a style of writing a SystemVerilog

description ◆ More abstract, less error-prone than with

all the details — no modules to instantiate or wire

◆ More amenable to making inline checks

Big idea: Testbench must be an FSM!

Implicit FSM — How?

❏ Write a state machine procedurally ◆ use “@(posedge ck)” for testing FSMs

❏ Defining a state ◆ Each “@posedge clock” defines a new state and what values

should appear ◆ The code after the @posedge clock is what executes and updates

at the clock edge ❏ just like when writing a dFF

◆ outputs of the FSM use non-blocking assignments (<=) ❏ After all, it’s another FSM, just written in a different style

The beginning of an implicit FSM

module TB; initial begin clock = 0; forever #5 clock = ~clock; end

initial begin $monitor (blah blah); // only one of these reset_l = 0;

i = 0 reset_l <= #1 1;

@(posedge clock); //any statement here will execute at time 5 i <= 1;

@(posedge clock); // time 15 i <= 0;

@(posedge clock); … $finish;

end

endmodule

clock

0 5 10 15

0 0 0 1

1 0

A

C

B

R 1/00

1/10

0/010/01

s1 s0Legend

i/a,b

x/00

i equals 1

Timing between testbench and designmodule TB; initial begin clock = 0; forever #5 clock = ~clock; end initial begin $monitor (blah blah); // only one of these reset_l = 0;

i = 0 reset_l <= #1 1;

@(posedge clock); //any statement here will execute at time 5 i <= 1;

@(posedge clock); // time 15 i <= 0;

@(posedge clock); …

end

endmodule

module explicitFSM (output logic a, b, input ck, r_l, i); // output logic not shown always_comb case (state) A: nextState = (i) ? B : A; B: nextState = C; C: nextState = (~i): A : C; default: nextState = A; endcase always_ff @(posedge ck, negedge r_l) if (~r_l) state <= A; else state <= nextState; endmodule: explicitFSM

What happens simultaneously

with this?

0 0 0 1

1 0

A

C

B

R 1/00

1/10

0/010/01

s1 s0Legend

i/a,b

x/00

0

0

0

i

state

nextState

5 15

A

B

A

A

B

C

What this boils down to

module TB; initial begin clock = 0; forever #5 clock = ~clock; end initial begin $monitor (blah blah); // only one of these reset_l = 0;

i = 0 reset_l <= #1 1;

@(posedge clock); //any statement here will execute at time 5 i <= 1;

@(posedge clock); // time 15 i <= 0;

@(posedge clock); …

end

endmodule

module explicitFSM (output logic a, b, input ck, r_l, i); // output logic not shown always_comb case (state) A: nextState = (i) ? B : A; B: nextState = C; C: nextState = (~i): A : C; default: nextState = A; endcase always_ff @(posedge ck, negedge r_l) if (~r_l) state <= A; else state <= nextState; endmodule: explicitFSM

clock

D Q

D Q i1 (or 0)

nextState state

TB

FSM

What happens at the clock edge?

there’s a clock edge at time 5

clk becomes 1, always_FF and initial run,

evaluates state and i, schedules non-blocking

update.

all within time 5

module explicitFSM (output logic a, b, input ck, r_l, i); … always_comb case (state) A: nextState = (i) ? B : A; B: nextState = C; C: nextState = (~i): A : C; default: nextState = A; endcase always_ff @(posedge ck, negedge r_l) if (~r_l) state <= A; else state <= nextState; endmodule: explicitFSM

both always_comb

blocks execute, in

arbitrary order

module TB; initial begin clock = 0; forever #5 clock = ~clock; end initial begin @(posedge clock);

//any statement here will execute at time 5 i <= 1;

Nothing else to do, state and i are updated simultaneously

Oh my, what about this?

module TB; initial begin clock = 0; forever #5 clock = ~clock; end initial begin $monitor (blah blah); // only one of these reset_l = 0;

i = 0 reset_l <= #1 1;

@(posedge clock); //any statement here will execute at time 5 i = 1;

@(posedge clock); // time 15 i = 0;

@(posedge clock); …

end

endmodule

module explicitFSM (output logic a, b, input ck, r_l, i); // output logic not shown always_ff @(posedge ck, negedge r_l) if (~r_l) state <= A; else state <= i; endmodule: explicitFSM

What could happen?

clock

D Q

D Q i1 (or 0)

i state

?

Note, the design changed for this

illustration

Consider the situation where the simulator updates i first and state second… (not simultaneously)

TB

FSM

How do you check the output’s value?module TB; initial begin clock = 0; forever #5 clock = ~clock; end initial begin $monitor (blah blah); // only one of these reset_l = 0;

i = 0 reset_l <= #1 1;

@(posedge clock); //any statement here will execute at time 5 i <= 1; #1 if (a != 1’b0) $display (“oops”);

@(posedge clock); // time 15 i <= 0;

@(posedge clock); …

end

endmodule

module explicitFSM (output logic a, b, input ck, r_l, i); // output logic not shown always_comb case (state) A: nextState = (i) ? B : A; B: nextState = C; C: nextState = (~i): A : C; default: nextState = A; endcase always_ff @(posedge ck, negedge r_l) if (~r_l) state <= A; else state <= nextState; endmodule: explicitFSM

0 0 0 1

1 0

A

C

B

R 1/00

1/10

0/010/01

s1 s0Legend

i/a,b

x/00

0

0

0

i

state

nextState

5 15

A

B

A

A

B

C

Here

Thought you said not to put #1 in your code — something must be wrong! For checking, this is OK.

There are better ways (see SVbook)

Today's Agenda

❏ Theory of Testbenches ❏ FSM Testbenches (review) ❏ Randomization in Testbenches ❏ Testbench Potpourri

❏ Classes ❏ Tasks, Functions (again) ❏ Hierarchical Names ❏ Force/Release ❏ $display, $monitor, $strobe ❏ File I/O ❏ Foreach ❏ Finally!

A random slide

❏ Random numbers are widely used in testing ◆ Shown to be as good as any for general situations

❏ Could have used randoms instead of 1s and 0s in previous algorithm

◆ Have seen $urandom previously, returns a random value ◆ $urandom_range(1049, 17) returns value in the range

❏ Can declare SV types to take on random values ◆ rand — declares a variable that when randomized will take on

one of the 2n possible values, with replacement. ❏ each next value is chose from the whole range of 2n values

◆ randc — declares a variable that when randomized will take on one of the 2n possible values, without replacement

❏ think of drawing from a deck of cards ◆ No x or z values ◆ Synthesizable? Ha! Not at all

◆ Where would the RNG hardware be?

rand bit [3:0] val;

randc bit [4:0] valB;

Setting up an example

❏ We have a memory controller with 256 pages of 256 16-bit words

◆ We only have one memory (256 words) in the system

module memController #(parameter logic [7:0] page = 8'h02) (inout tri [15:0] addrData, input logic addrValid, rw, clk, reset);

During read, addrData driven

by memController in states B-E

During write, addrData driven by processor in

states B-E

Testbench needed

❏ Our testbench uses random numbers to determine: ◆ The address to write to and the values to write ◆ When to read or write, and whether to try the wrong page

❏ Start with a class definition — SV has classes! ◆ If there are rand(c) variables in the class, a randomize method is

available

class memPkt;rand bit [7:0] TBaddr;rand bit [15:0] TBvalue[4];randc bit [3:0] coinFlip;

constraint A {TBaddr inside {[0:252]};}endclass

memPkt pkt = new;

A random address to read/write

An array of 4 values to write

readwrite coin flip

You know, like in

software

A Constraint specification❏ Uses a set operator

◆ inside {…} ◆ What’s specified is a range [0:252] ◆ Could have specified {3, 17, [35:44]} as an alternate

❏ When the random numbers are generated, the constraint(s) is applied ◆ Why 252? So that an address doesn’t cross a page boundary

class memPkt;rand bit [7:0] TBaddr;rand bit [15:0] TBvalue[4];randc bit [3:0] coinFlip;

constraint A {TBaddr inside {[0:252]};}endclass

memPkt pkt = new;A set

operatorThe set

Our write_memory task (sort of)

task wMem;logic [7:0] myAD, i, pageNum;if (~pkt.randomize())

$display("oops, bad random numbers");if (pkt.coinFlip > 4'b0011)

pageNum = 8'h02;else pageNum = pkt.coinFlip;

Get a new set of random

numbers for all values above

class memPkt;rand bit [7:0] TBaddr;rand bit [15:0] TBvalue[4];randc bit [3:0] coinFlip;

constraint A {TBaddr inside {[0:252]};}

Most of the time access

page 2

Otherwise access pages 3-15 randomly

write_memory task, continued

❏ This could also keep track of what’s written ◆ Check if correct when read back ◆ Reads and writes randomly

❏ But what does it check? ◆ Go back to slide “What might go wrong here”

@(posedge clk);busDrive <= 1;ad <= { pageNum, pkt.TBaddr };addrValid <= 1;rw <= 0;

@(posedge clk);for (int i = 0 ; i < 4; i++) begin

addrValid <= 0;ad <= pkt.TBvalue[i];@(posedge clk);

end …

send address, including the

random address in first step of

protocol

then send the four data elements

Yet another random slide

❏ Can constrain random variables at each usage

◆ Here’s where randomize could fail

class vectors rand bit [3:0] valA; randc bit [4:0] valB; endclass

vectors tv = new; … if (~tv.randomize() with {valB < valA}) $display (“OOPS, randomize didn’t work”);

valB must take on all values, some aren’t less than

valA

“with” allows you to add constraints to those specified in the class

Multiple series of random numbersmodule randStuff (); bit [3:0] myT, myR; class TimeGen; rand bit [3:0] numWaits; constraint EVEN {numWaits[0] == 0;} function [3:0] getT (TimeGen T); if (T.randomize() == 1) getT = T.numWaits; else $display("Randomize had constraint problems."); endfunction

endclass initial begin TimeGen T = new, R = new; repeat (16) begin myT = T.getT(T); myR = R.getT(R); $display ("time = %d, %d", myT, myR); end end endmodule

time = 14, 6 time = 2, 0 time = 4, 12 time = 8, 0 time = 2, 14 time = 6, 10 time = 4, 4 time = 2, 8 time = 12, 2 time = 6, 6 time = 2, 14 time = 4, 8 time = 12, 12 time = 0, 2 time = 6, 8 time = 14, 14

Two series of random numbers

Random with enumerate

❏ Picks labels out of enumerations

typedef enum bit[2:0] {R, O, Y, G, B, I, V} roy_g_biv_t;

class greatColors; rand roy_g_biv myRainbow; endclass

greatColors gc = new;

Now when you call randomize, it will pick from

the enumerated labels

Today's Agenda

❏ Theory of Testbenches ❏ FSM Testbenches (review) ❏ Randomization in Testbenches ❏ Testbench Potpourri

❏ Classes ❏ Tasks, Functions (again) ❏ Hierarchical Names ❏ Force/Release ❏ $display, $monitor, $strobe ❏ File I/O ❏ Foreach ❏ Finally!

Testbenches for FSM-Ds

❏Tests ◆ not typically

characterized by single test vectors

❏Need to ◆ Send packets of info ◆ Follow protocols

❏ Use the old standby ◆ Assert go ◆ Send data to add ◆ When data == 0, set

done

Random info to send to sumItUp

❏Need to create packets of numbers to add ◆ This will send between 2 and 10 items to add ◆ and generate the values in array item[ ]

class sumPkt;rand bit [15:0] howMany;rand bit [15:0] item[];

constraint N {howMany inside {[2:10]};}

constraint arraySize {item.size == howMany;}endclass

A class with methods (tasks, fns)class testSumThread;

local bit unsigned [15:0] total;local sumPkt pkt = new;

task sendPktToThread; total = 0;if (~pkt.randomize()) $display("oops");for (byte i = 0; i < pkt.howMany; i++) begin

@(posedge ck);inA <= pkt.item[i];total += pkt.item[i];go_l <= (i == 0) ? 0 : 1;

end@(posedge ck);inA <= 0;

endtask

function checkTotal (bit unsigned [15:0] value);return value == total;

endfunctionendclass

Create instance of pkt to send

Fill in random numbers

Send values, keep track of total

Send 0 at end

Here’s a way to check the FSM-D

❏ Instantiate instance of testSumThread ◆ Send 100 packets to it – call sendPktToThread ◆ Check if total is correct

initial begin testSumThread t = new;for (int i = 0; i < 100; i++) begin

t.sendPktToThread();wait (done);if(~t.checkTotal(sum))

$display("OOPS"); end$finish;

end

Tasks and functions — revisited

❏ Both are subroutines ◆ Tasks can have timing operators

(#, @, wait), functions cannot ❏ Basic operations

◆ Arguments can be defined ◆ When called, inputs and inouts are copied into the

task/function ◆ On return, outputs and inouts are copied back to

calling site ◆ Function return value can be used

in an expression (e.g., in assign = …) ❏ Functions

◆ function type name (args)…endfunction ◆ If recursive, include “automatic” before type ◆ Functions can access vars not in port list (ouch, ugly

side effects!)

function bit[2:0] incB(input bit [2:0] b);incB = b + 1;

endfunction

return type name

value returned

assign a = incB(y) + z;

Tasks and functions — revisited

❏ Tasks don’t return a value ◆ except through output or inout arguments

❏ Since tasks can have timing operators… ◆ a single task can be called from more than one

process (initial block) ◆ In this case, they would share any variables

declared in the task ◆ A task can be declared as automatic

❏ Then each process has its own variables ❏ Inputs can be declared as ref

◆ Like passing a pointer to the function or task ◆ No difference at calling site ◆ function or task can change the variable by

reference too ◆ often used to pass arrays

task name (args);…

endtask

function bit[2:0] incB(input ref bit [2:0] b);incB = b + 1;

endfunction

b is passed by reference (pointer)

“automatic”

Hierarchical name refs

Hierarchical Names

❏ White box testing ◆ You can see

inside ❏ It’s all there but how

to access? ❏ Hierarchical name

references ◆ You can directly

access the leaf cells

◆ Can search “up” and then back “down”

◆ Lots of details left out

testbench design

top

Normal port connections

logic a

a

b

c

$display (“aDownThere=%h”, top.design.a.b.c.a);

display(…);

You can do more than just print

❏ You can actually override values within the design

❏ Called force and release

❏ Use with hierarchical names to debug pieces

testbench design

top

Normal port connections

Debugging with Force/Release

❏ These are used to temporarily override a net or register ◆ If sum is a “wire”, e.g., output of a gate primitive, assign, or

always_comb ❏ then force overrides the other drivers of the wire are

ignored after the force. ❏ When release is executed, the other drivers take over

◆ If sum is a “register,” e.g., output of an always_ff ❏ then force causes sum to hold the new forced value. It

can’t be overwritten by = or <=. ❏ When release is executed, this new value is held until

the register is written again. Acts like an async reset in a typical always_ff initial begin

… force sum = 0; … release sum; end

Debugging with Force/Release

❏ Can do this in “procedural continuous assign”

◆ That is, using assign in procedural block ◆ You may have accidentally tried this ◆ Essentially acts like force and release ◆ Don’t ! ◆ Will probably be deprecated in the future.

❏ Details — Back to force and release ◆ Force and release are procedural

❏ found in initial blocks of TBs only ◆ Can reference hierarchical names

❏ override anything anywhere! ◆ They are not synthesizable ◆ Can be executed on some simulator

command lines

initial begin … assign sum = q + r; … deassign sum; end

always_comb begin … sum = a + b; … end

Force/Release Scenario❏ Instead of injecting faults, isolate logic

◆ Isolate some logic without having to figure out how to set some of the other logic.

◆ e.g., it may be difficult to figure out the inputs needed to set B, and C to these values. — so just do it with force/release

◆ Debugging only — these don’t synthesize

logic

Lots of ugly logic logic

A B C

Many layers of instantiationmodule testbench initial begin… force B = 1; force C = 1; … // now A and // inputSig control // “logic”; … release B; release C; …

inputSig

Displaying information

Printing task When it prints$display Right now, with the values of the vars

currently existing$monitor At the end of the time step after all

values have settled to their final value$strobe Called like $display — from in any

procedural context — but prints after values have settled to their final value. (at the “monitor events” time)

always_ff @(posedge clk) begin a <= a + b; $display (“a=%h, b=%h, a, b); $strobe (“a=%h, b=%h, a, b); end

prints value before non-blocking

update

prints value of a after non-blocking

assignment resolved

File I/O

❏ Looks a lot like file I/O in C ◆ Although has a multichannel file descriptor, not shown here ◆ Some in book, all in manual

int fileDescriptor;

initial begin fileDescriptor = $fopen(“file.txt”, “w”); if (fileDescriptor == 0) $display(“oops, disk crashed, your files gone, ha ha!”); … $fdisplay (fileDescriptor, “a=%h, b=%d”, a, b); // could also $fmonitor (), $fstrobe () … $fclose (fileDescriptor); end

foreach loops

❏ Who needs counter variables? (who hates to type?) ◆ foreach — used to iterate over array elements ◆ Can be multidimensional

module tryForeach; string speak [2] = '{ "hello", "logic"}; logic [13:0] tvectors [2] = ' {14'b11110000111100, 14'b00001111000011}; logic [13:0] dutInput;

initial begin $monitor ($stime, " dutInput = %b", dutInput);

foreach (speak [j]) $display(speak[j]);

foreach (tvectors [i]) begin dutInput = tvectors[i]; #1; end for (int j = 0; j <= 1; j++) $display(speak[j]); end endmodule: tryForeach

hello logic 0 dutInput = 11110000111100 1 dutInput = 00001111000011 hello logic

final block

❏ It runs after everything else has finished, or $finish has been called

❏ Like an always_x or initial block, introduces procedural context ❏ Simulation only — all must finish in a single simulation cycle

◆ i.e., no #, @, or wait

final begin //print summary data $display (“executed %d instructions”, numInst); … //do other cleanup things like: $fclose (fileDescriptor); end

Today's Agenda

❏ Theory of Testbenches ❏ FSM Testbenches (review) ❏ Randomization in Testbenches ❏ Testbench Potpourri

❏ Classes ❏ Tasks, Functions (again) ❏ Hierarchical Names ❏ Force/Release ❏ $display, $monitor, $strobe ❏ File I/O ❏ Foreach ❏ Finally!

top related