Professional Documents
Culture Documents
Specman Elite: From Verisity Presents A High-Level Language For Writing Test Environments
Specman Elite: From Verisity Presents A High-Level Language For Writing Test Environments
1
Pre Defined Constants Keywords
Constant Description all of bytes default fail
TRUE For Boolean variables and expressions. all_values c export define fall
and case delay file
FALSE For Boolean variables and expressions.
as a change detach first of
NULL For structs, specifies a NULL pointer. For as_a check that do for
character strings, specifies an empty string. assert compute down to force
UNDEF UNDEF indicates NONE where an index is assume computed dut_error from
expected. async consume each gen
MAX_INT Represents the largest 32-bit int (231 -1) attribute continue edges global
before cover else hdl pathname
MIN_INT Represents the smallest 32-bit int (-231).
bit cross emit if
MAX_UINT Represents the largest 32-bit uint (232-1). bits cvl call event #ifdef
bool cvl callback exec #ifndef
break cvl method expect in
byte cycle extend index
Keywords Keywords
int key or soft
is a like others start type vhdl code
is also line pass state machine uint vhdl driver
is c routine list of prev step unit vhdl function
is empty matching print struct until vhdl procedure
is first me range string using
vhdl driver
is inline nand ranges sync var
vhdl simulator
is instance new release sys verilog code
vhdl time
is not a nor repeat that verilog function
is not empty not return then verilog import when
is only not in reverse time verilog simulator while
is undefined now rise to verilog task with
item nxor routine transition verilog time within
keep on select true verilog timescale
keeping only session try verilog trace
verilog variable
2
Struct & Struct Members Struct Members
field declaration
Struct members are second-level constructs and ! Defines a data entity that is a member of the enclosing struct and has an
explicit data type.
are valid only within a struct definition. method declaration
! Defines an operational procedure that can manipulate the fields of the
enclosing struct and access run-time values in the DUT.
struct struct-type: struct-descriptor [like base-struct-type: struct-descriptor]
{ subtype declaration
[member: struct-member; ...]} ! Defines an instance of the parent struct in which specific struct members
Example: have particular values or behavior. (e.g., when)
type packet_kind: [atm, eth]; constraint declaration
struct packet { ! Influences the distribution of values generated for data entities and the
order in which values are generated. (e.g., keep)
len: int;
keep len < 256; coverage declaration
kind: packet_kind; ! Defines functional test goals and collects data on how well the testing is
meeting those goals.
};
temporal declaration
! Defines e events and their associated actions.(e.g., on, expect, assume)
Fields Fields
[!][%] field: field-name[: type: type] [[min-val: int .. max-val: int]] ! Ungenerated Fields
[((bits | bytes):num: int)] A field defined as ungenerated (with the “!” option) is not generated
automatically.
Syntax example:
This is useful for fields that are to be explicitly assigned during the
type NetworkType: [IP=0x0800, ARP=0x8060] (bits: 16); test, or whose values involve computations that cannot be expressed in
struct header { constraints.
address: uint (bits: 48); Ungenerated fields get default initial values (0 for scalars, NULL for
hdr_type: NetworkType; structs, empty list for lists).
!counter: int; An ungenerated field whose value is a range (such as [0..100]) gets the
}; first value in the range.
If the field is a struct, it will not be allocated and none of the fields in it
will be generated.
Fields Actions
% Physical Fields Actions are third-level constructs and are valid
A field defined as a physical field (with the “%” option) is packed
when the struct is packed.
only when associated with a struct member, such
Fields that represent data that is to be sent to the HDL device in the as a method or an event.
simulator or that are to be used for memories in the simulator or in <'
Specman Elite, need to be physical fields.
struct packet{
Nonphysical fields are called virtual fields and are not packed
automatically when the struct is packed, although they can be packed event xmit_ready is rise('top.ready');
individually. on xmit_ready {transmit();};
If no range is specified, the width of the field is determined by the
field’s type. For a physical field, if the field’s type does not have a transmit() is {
known width, you must use the (bits | bytes : num) syntax to specify out("transmitting packet...");
the width.
};
};
'>
3
Actions Actions
Creating & modifying variables Invoking methods and routines
" var, = , op=, " method(), tcm(), start tcm(), routine(), compute method(),
return
Interacting with the DUT
" force, release Performing time consuming actions
" emit, sync, wait, all of , first of, state machine
Flow control
! Conditionals Generating data items
" gen
" if then else, labeled case, boolean case
! Iteratation Detecting/handling errors
" While, repeat until, for each, for from-to, for each-line, for " check that, dut_error(), assert, warning(), error(), fatal(),
each-file-matching try
! Flow control Printing
! break, continue " print, set_config()
! port_stub2
" A literal value
! port_stub3
" A constant ! port_stub4
" An e entity, such as a method, field, list, or struct ! packing
" An HDL entity, such as a signal ! files
" A compound expression applies one or more operators to one ! scheduler
or more operands. ! simulator
! session
4
Implicit Variables Implicit Variables
result:The result variable returns a value index: The index variable holds the
of the method’s return type. If no return current index of the item referred to by it.
action is encountered, result is returned by The scope of the index variable is limited
default. The following method returns the to the action block.
sum of “a” and “b”: for each in packets do {
sum(a: int, b: int): int is { packets[index].len = 5;
result = a + b; .id = index;
}; };
5
Struct Subtypes Subtypes with extend & when
type packet_protocol: [Ethernet, IEEE, foreign]; type packet_protocol: [Ethernet, IEEE, foreign];
struct packet { struct packet {
protocol: packet_protocol; protocol: packet_protocol;
size: int [0..1k];
size: int [0..1k];
data[size]: list of byte;
data[size]: list of byte;
// when Ethernet packet {e_field: int; -- same as extend below
legal: bool; // show() is {out("I am an Ethernet packet")
}; // };
extend sys { };
gen_eth_packet () is { extend Ethernet packet {
var packet: legal Ethernet packet; -- local sub-type e_field: int;
gen packet keeping {it.size < 10;}; show() is {out("I am an Ethernet packet")};
print packet; };
};
};
6
Keyed Lists Constraints with Keep
keep constraint-bool-exp
A keyed list data type is similar to hash Syntax example:
tables or association lists found in other keep kind != tx or len == 16;
programming languages. Parameters
struct person { constraint-bool-exp A simple or a compound Boolean expression.
name: string; States restrictions on the values generated for fields in the struct or the
id: int; struct subtree,or describes required relationships between field values
}; and other items in the struct or its subtree.
struct city { Hard constraints are applied whenever the enclosing struct is
persons: list(key: name) of person; generated. For any keep constraint in a generated struct, the generator
street_names: list(key: it) of string; either meets the constraint or issues a constraint contradiction message.
}; Note If the keep constraint appears under a when construct, the
constraint is considered
7
Generation with keep Events --
Generation order is important because it influences the The e language provides temporal
distribution of values. For example, in the keep constraint
shown below, if “kind” is generated first, “kind” is “tx” constructs for specifying and verifying
about 1/2 the time because there are only two legal values behavior over time.
for “kind”:
struct packet { All e temporal language features depend on
kind: [tx, rx];
size: byte;
the occurrence of events, which are used to
keep size > 15 => kind == rx; synchronize activity with a simulator and
};
within Specman Elite.
On the other hand, if “size” is generated first, there is only
a 1 in 16 chance that “size” will be less than or equal to 15,
so “kind” will be “tx” about 1/16 of the time.
8
Callbacks: from simulator and
emit Emit example
struct sys_ready { <' run() is also {
event sim_ready is change('top/ready') @sim; // callback struct xmit_recv { start transmit();
event rec_ev;
bar() @sys.clk is { start receive();
transmit() @sys.clk is {
while TRUE { wait cycle; };
wait until @sys.ok; emit rec_ev; };
wait [1] *cycle; out("rec_ev emitted"); extend sys {
};
emit sim_ready; // force the event event clk is @sys.any;
receive() @sys.clk is {
}; wait until @rec_ev;
xmtrcv_i: xmit_recv;
}; out("rec_ev occurred"); '>
}; stop_run();
};
Configuration Files
On pitteda3 or pitteda4
# Verisity user Environment variables (no newlines) Copy the tutorial tar file
setenv SPECMAN_HOME
$CAD_DIR/verisity/specman_3.3.3/sn_rel3.3.3
Copy the emacs specman-mode file
setenv PATH ! If you use emacs
{SPECMAN_HOME}/`${SPECMAN_HOME}/bin/sn_arch.sh`:${SPECM
AN_HOME}/bin:${PATH} ! If you like language editors
setenv SPECMAN_DIR
$SPECMAN_HOME/`${SPECMAN_HOME}/bin/sn_arch.sh` Untar the tutorial directories into your own
setenv VERISITYLD_LICENSE_FILE account ( ./src and ./gold )
5286@pitteda1.ee.pitt.edu
9
Running Specman Tutorial Example
(make sure X and DISPLAY are right) Use src files from tar archive
CPU and Testbench are both modeled in
specview & specman
! No need for modelsim simulator
! “easy” high level modeling of CPU
! Black box testing
CPU_top.e CPU_instr.e
<' <'
// Basic: type cpu_opcode: [ // Opcodes
import CPU_instr, CPU_misc; ADD, ADDI, SUB, SUBI,
AND, ANDI, XOR, XORI,
// Add dut and drive:
JMP, JMPC, CALL, RET,
import CPU_dut, CPU_drive;
NOP
] (bits: 4);
// Add Coverage:
import CPU_cover; type reg : [ // Register names
REG0, REG1, REG2, REG3
// Add Checking: ] (bits: 2);
import CPU_checker;
'>
// defines 2nd op of reg instruction // defines legal opcodes for imm instr
when reg instr { keep opcode in [ADDI, SUBI, ANDI, };
%op2 : reg ; XORI, JMP, JMPC, CALL]
}; => kind == imm;
'>
// defines 2nd op of imm instruction // ensures 4-bit addressing scheme
when imm instr { when imm instr {
%op2 : byte; keep (opcode in [JMP, JMPC,
CALL]) => op2 < 16;
};
};
};
10
CPU_misc.e CPU_drive
<‘
<' extend sys {
extend global { event cpuclk is (fall('top.clk')@sys.any);
cpu_env : cpu_env;
setup_test() is also { cpu_dut : cpu_dut; //cpu_refmodel : cpu_refmodel;
set_config(print,radix,hex);
set_config(cover,mode,normal,show_mode,both); };
set_config(print, items, 100); struct cpu_env {
reset_cpu() @sys.cpuclk is {
}; 'top.rst' = 0;
finalize_test() is also{ wait [1] * cycle;
specman("display print sys.instrs"); 'top.rst' = 1;
wait [5] * cycle;
}; //sys.cpu_refmodel.reset(); // reset reference model
}; 'top.rst' = 0;
'> };
CPU_drive CPU_drive
drive_one_instr(instr: instr) @sys.cpuclk is { !next_instr : instr;
var fill0 : uint(bits : 2) = 0b00; num_instrs : uint;
wait until rise('top.fetch1');
keep soft num_instrs in [40..60];
emit instr.start_drv_DUT;
if instr.kind == reg then {
'top.data' = pack(packing.high, instr); gen_and_drive_instrs() @sys.cpuclk is {
} else { for i from 0 to num_instrs do {
// immediate instruction
gen next_instr;
'top.data' = pack(packing.high, instr.opcode, instr.op1, fill0);
wait until rise('top.fetch2');
sys.instrs.add(next_instr);
'top.data' = pack(packing.high, instr.imm'op2); drive_one_instr(next_instr);
}; };
wait until rise('top.exec'); };
};
CPU_drive CPU_drive
drive_pregen_instrs() @sys.cpuclk is { run() is also {
for i from 0 to sys.instrs.size() - 1 { start drive_cpu();
drive_one_instr(sys.instrs[i]);
};
};
}; };
drive_cpu() @sys.cpuclk is { extend instr {
reset_cpu(); event start_drv_DUT;
if sys.instrs.size() > 0 then {
};
drive_pregen_instrs();
} else {
'>
gen_and_drive_instrs();
};
wait [1] * cycle;
stop_run();
};
11
Test1.e
<'
Calc 1 – from IBM
import CPU_top;
extend instr { // test constraints This testbench provides the basic structure
keep opcode in [ADD, ADDI];
keep op1 == REG0;
to the calc1 design.
when reg instr {keep op2 == REG1}; // when reg instr
when imm instr {keep op2 == 0x5}; // when imm instr
It is only set to test ADD operations on port
}; 1.
extend sys {
// generate 5 instructions Your exercise is to test the other ports and
keep instrs.size() == 5;
};
operations.
extend sys {
post_generate() is also {
gen instrs; // start generating stream of instructions
};
};
'>
12
Calc1.e: main test loop Calc1.e: extend system for
struct test {
event clk is fall('~/demo_top/c_clk')@sim;
test
event resp is change('~/demo_top/out_resp1')@sim; extend global {
body () @clk is { run_test() is also { -- Called from "test" after generation.
for each command (cmd) in sys.cmds do { -- run the initialization function
force '~/demo_top/req1_cmd_in'= pack(NULL, cmd.cmd_in);
var i: init = new;
force '~/demo_top/req1_data_in'= pack(NULL, cmd.din1);
i.initvals();
wait cycle;
force '~/demo_top/req1_cmd_in'= 0000; -- start the testing function
force '~/demo_top/req1_data_in'= pack(NULL, cmd.din2); var w: test = new;
wait @resp; -- wait for the response start w.body();
cmd.resp = '~/demo_top/out_resp1'; -- run the simulator until the tests are done
cmd.dout = '~/demo_top/out_data1'; simulator_command("run -all");
check that cmd.resp == 01; }; // run_test()
check that cmd.dout == (cmd.din1 + cmd.din2);
}; // extend global
wait cycle;
'>
}; // for each command
wait cycle;
stop_run();
}; // body
}; // struct test
13