Specman Notes Specman Elite From Verisity http www

  • Slides: 74
Download presentation
Specman Notes

Specman Notes

Specman Elite From Verisity (http: //www. verisity. com) Presents a high-level language for writing

Specman Elite From Verisity (http: //www. verisity. com) Presents a high-level language for writing test environments n n n Test Benches Coverage Constraint based test generation and checking

Configuration On pitteda 3 or pitteda 4 # Verisity user Environment variables (no newlines)

Configuration On pitteda 3 or pitteda 4 # Verisity user Environment variables (no newlines) setenv SPECMAN_HOME $CAD_DIR/verisity/specman_3. 3. 3/sn_rel 3. 3. 3 setenv PATH {SPECMAN_HOME}/`${SPECMAN_HOME}/bin/sn_arch. sh`: ${SPECM AN_HOME}/bin: ${PATH} setenv SPECMAN_DIR $SPECMAN_HOME/`${SPECMAN_HOME}/bin/sn_arch. sh` setenv VERISITYLD_LICENSE_FILE 5286@pitteda 1. ee. pitt. edu

Files Copy the tutorial tar file Copy the emacs specman-mode file n n If

Files Copy the tutorial tar file Copy the emacs specman-mode file n n If you use emacs If you like language editors Untar the tutorial directories into your own account (. /src and. /gold )

Running (make sure X and DISPLAY are right) specview &

Running (make sure X and DISPLAY are right) specview &

e language Looks like verilog to me… Has support for data types n n

e language Looks like verilog to me… Has support for data types n n With statistical values With constraints (hard and soft) Stimulus Checking Events

On Line Help Verisity has all their help on line n n n e

On Line Help Verisity has all their help on line n n n e language ref Command ref for Specman Elite Usage etc. Tutorial is on OUR web page (large pdf) n n Do not print it, just do it. Its not great

File Format A code segment is enclosed with a begin-code marker <' and an

File Format A code segment is enclosed with a begin-code marker <' and an end-code marker '>. Both the begin-code and the end-code markers must be placed at the beginning of a line (left most), with no other text on that same line (no code and no comments). The following three lines of code form a code segment: <' import cpu_test_env; '> Several code segments can appear in one file. Each code segment consists of one or more statements.

Comments e files begin as a comment which ends when the first begincode marker

Comments e files begin as a comment which ends when the first begincode marker <' is encountered. Comments within code segments can be marked with double dashes (--) or double slashes (//): a = 5; -- This is an inline comment b = 7; // This is also an inline comment The end-code '> and the begin-code <' markers can be used in the middle of code sections, to write several consecutive lines of comment

Pre Defined Constants Constant TRUE FALSE NULL Description For Boolean variables and expressions. For

Pre Defined Constants Constant TRUE FALSE NULL Description For Boolean variables and expressions. For structs, specifies a NULL pointer. For character strings, specifies an empty string. UNDEF indicates NONE where an index is expected. MAX_INT Represents the largest 32 -bit int (231 -1) MIN_INT Represents the smallest 32 -bit int (-231). MAX_UINT Represents the largest 32 -bit uint (232 -1).

Keywords all of all_values and as a as_a assert assume async attribute before bits

Keywords all of all_values and as a as_a assert assume async attribute before bits bool break bytes c export case change check that computed consume continue cover cross cvl callback cvl method cycle default define delay detach do down to dut_error each edges else emit event exec expect extend fail fall file first of force from gen global hdl pathname if #ifdef #ifndef in index

Keywords int is also is c routine is empty is first is inline is

Keywords int is also is c routine is empty is first is inline is instance is not a is not empty is only is undefined item keeping key like line list of matching me nand new nor not in now nxor on only or others pass prev print ranges release repeat return reverse rise routine select session soft start state machine step struct string sync sys that then time to transition true try

Keywords type uint unit until using var verilog code verilog function verilog import verilog

Keywords type uint unit until using var verilog code verilog function verilog import verilog simulator verilog task verilog timescale verilog trace verilog variable vhdl code vhdl driver vhdl function vhdl procedure vhdl driver vhdl simulator vhdl time when while within

Syntactic Elements Statements are top-level constructs and are valid within the begin-code <' and

Syntactic Elements Statements are top-level constructs and are valid within the begin-code <' and end-code '> markers. Statements end with a semicolon ‘; ’ Struct members are second-level constructs and are valid only within a struct definition. Actions are third-level constructs and are valid only when associated with a struct member, such as a method or an event. Expressions are lower-level constructs that can be used only within another e construct. The syntax hierarchy roughly corresponds to the level of indentation shown below: statements struct members actions expressions

Statements are top-level constructs and are valid within thebegin-code <' and end-code '> markers.

Statements are top-level constructs and are valid within thebegin-code <' and end-code '> markers. Key Statement Types: n n Struct – defines a new data structure Type – defines an enumerated/subtype Extend – extends a previously defined struct or type Define – extends language with new commands, actions, expressions w More: import, verilog-x, vhdl-x … n Order is not critical – but imports must be first (after macro defines)

Struct & Struct Members Struct members are second-level constructs and are valid only within

Struct & Struct Members Struct members are second-level constructs and are valid only within a struct definition. struct-type: struct-descriptor [like base-struct-type: struct-descriptor] { [member: struct-member; . . . ]} Example: type packet_kind: [atm, eth]; struct packet { len: int; keep len < 256; kind: packet_kind; };

Struct Members field declaration n Defines a data entity that is a member of

Struct Members field declaration n Defines a data entity that is a member of the enclosing struct and has an explicit data type. method declaration n Defines an operational procedure that can manipulate the fields of the enclosing struct and access run-time values in the DUT. subtype declaration n Defines an instance of the parent struct in which specific struct members have particular values or behavior. (e. g. , when) constraint declaration n Influences the distribution of values generated for data entities and the order in which values are generated. (e. g. , keep) coverage declaration n Defines functional test goals and collects data on how well the testing is meeting those goals. temporal declaration n Defines e events and their associated actions. (e. g. , on, expect, assume)

Fields [!][%] field: field-name[: type] [[min-val: int. . max-val: int]] [((bits | bytes): num:

Fields [!][%] field: field-name[: type] [[min-val: int. . max-val: int]] [((bits | bytes): num: int)] Syntax example: type Network. Type: [IP=0 x 0800, ARP=0 x 8060] (bits: 16); struct header { address: uint (bits: 48); hdr_type: Network. Type; !counter: int; };

Fields ! Ungenerated Fields A field defined as ungenerated (with the “!” option) is

Fields ! Ungenerated Fields A field defined as ungenerated (with the “!” option) is not generated automatically. This is useful for fields that are to be explicitly assigned during the test, or whose values involve computations that cannot be expressed in constraints. Ungenerated fields get default initial values (0 for scalars, NULL for structs, empty list for lists). 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 % Physical Fields A field defined as a physical field (with the “%”

Fields % Physical Fields A field defined as a physical field (with the “%” option) is packed when the struct is packed. Fields that represent data that is to be sent to the HDL device in the simulator or that are to be used for memories in the simulator or in Specman Elite, need to be physical fields. Nonphysical fields are called virtual fields and are not packed automatically when the struct is packed, although they can be packed individually. 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 known width, you must use the (bits | bytes : num) syntax to specify the width.

Actions are third-level constructs and are valid only when associated with a struct member,

Actions are third-level constructs and are valid only when associated with a struct member, such as a method or an event. <' struct packet{ event xmit_ready is rise('top. ready'); on xmit_ready {transmit(); }; transmit() is { out("transmitting packet. . . "); }; }; '>

Actions Creating & modifying variables w var, = , op=, Interacting with the DUT

Actions Creating & modifying variables w var, = , op=, Interacting with the DUT w force, release Flow control n Conditionals w if then else, labeled case, boolean case n Iteratation w While, repeat until, for each, for from-to, for each-line, for each-file-matching n Flow control n break, continue

Actions Invoking methods and routines w method(), tcm(), start tcm(), routine(), compute method(), return

Actions Invoking methods and routines w method(), tcm(), start tcm(), routine(), compute method(), return Performing time consuming actions w emit, sync, wait, all of , first of, state machine Generating data items w gen Detecting/handling errors w check that, dut_error(), assert, warning(), error(), fatal(), try Printing w print, set_config()

Expressions are lower-level constructs that can be used only within another e construct Expressions

Expressions are lower-level constructs that can be used only within another e construct Expressions are constructs that combine operands and operators to represent a value w w w A literal value A constant An e entity, such as a method, field, list, or struct An HDL entity, such as a signal A compound expression applies one or more operators to one or more operands.

Struct Hierarchy global n sys w switch n n n n n ctrl_stub port_stub

Struct Hierarchy global n sys w switch n n n n n ctrl_stub port_stub 1 n sender n listener port_stub 2 port_stub 3 port_stub 4 packing files scheduler simulator session

Implicit Variables it : The implicit variable it always refers to the current item.

Implicit Variables it : The implicit variable it always refers to the current item. for each in sys. packets{ it. len = 5; . good = TRUE; -- it is assumed };

Implicit Variables Me: The implicit variable me refers to the current struct and can

Implicit Variables Me: The implicit variable me refers to the current struct and can be used anywhere in the struct packet { data: uint; stm() is { var tmp: uint; gen tmp keeping {it < me. data}; - - it is tmp print data, tmp using hex; }; };

Implicit Variables result: The result variable returns a value of the method’s return type.

Implicit Variables result: The result variable returns a value of the method’s return type. If no return action is encountered, result is returned by default. The following method returns the sum of “a” and “b”: sum(a: int, b: int): int is { result = a + b; };

Implicit Variables index: The index variable holds the current index of the item referred

Implicit Variables index: The index variable holds the current index of the item referred to by it. The scope of the index variable is limited to the action block. for each in packets do { packets[index]. len = 5; . id = index; };

Operators & Precedence [ ] List indexing (subscripting) [. . ] List slicing [

Operators & Precedence [ ] List indexing (subscripting) [. . ] List slicing [ : ] Bit slicing (selection) f(…) Method and routine calls. Field selection ~ Bitwise not ! (not) Boolean not {; } List concatenation %{…} Bit concatenation + - Unary plus, minus *, /, % Binary multiply, divide, modulus +, - Binary add and subtract >> << Shift right, shift left < <= > >= Comparison is [not] a Subtype identification == != Equality, inequality === !== Verilog four-state comparison ~ !~ String matching in Range list operator & Bitwise AND | Bitwise OR ^ Bitwise XOR && (and) Boolean AND || Boolean or => Boolean implication ? : Conditional operator

Examples num 1 = %{num 2, num 3}; = pack(packing. high, num 2, num

Examples num 1 = %{num 2, num 3}; = pack(packing. high, num 2, num 3); e. g. Num 2 = 0 x 1234; Num 3 = 0 x 7777; Num 1 = %{Num 2, Num 3}; What is Num 3?

Examples var loc 1: list of colors: {red; green; blue}; print loc 1;

Examples var loc 1: list of colors: {red; green; blue}; print loc 1;

Types: Scalars int Represents numeric data, both negative and nonnegative integers. (32 bits) uint

Types: Scalars int Represents numeric data, both negative and nonnegative integers. (32 bits) uint Represents unsigned numeric data, nonnegative integers only. (32 bits) bit An unsigned integer in the range 0– 1. (1 bit) byte An unsigned integer in the range 0– 255. (8 bits) time An unsigned integer in the range 0– 263 -1. ( 64 bits) bool Represents truth (logical) values, TRUE(1) and FALSE(0). (1 bit)

Subtypes By range n int [0. . 100] By width n int (bits: 8)

Subtypes By range n int [0. . 100] By width n int (bits: 8) Named Subtypes n n type int_count : int [0. . 99] (bits: 7); var count : int_count;

Enumerated Types You can define the valid values for a variable or field as

Enumerated Types You can define the valid values for a variable or field as a list of symbolic constants. var kind: [immediate, register]; You can extend the definition: type packet_protocol: []; extend the definition of the type with extend packet_protocol : [Ethernet, IEEE, foreign];

Struct Subtypes type packet_protocol: [Ethernet, IEEE, foreign]; struct packet { protocol: packet_protocol; size: int

Struct Subtypes type packet_protocol: [Ethernet, IEEE, foreign]; struct packet { protocol: packet_protocol; size: int [0. . 1 k]; data[size]: list of byte; legal: bool; }; extend sys { gen_eth_packet () is { var packet: legal Ethernet packet; -- local sub-type gen packet keeping {it. size < 10; }; print packet; }; };

Generate example struct location { address: int; … } gen l keeping {it. address

Generate example struct location { address: int; … } gen l keeping {it. address == 2*i}

Subtypes with extend & when type packet_protocol: [Ethernet, IEEE, foreign]; struct packet { protocol:

Subtypes with extend & when type packet_protocol: [Ethernet, IEEE, foreign]; struct packet { protocol: packet_protocol; size: int [0. . 1 k]; data[size]: list of byte; // when Ethernet packet {e_field: int; -- same as extend below // show() is {out("I am an Ethernet packet") // }; }; extend Ethernet packet { e_field: int; show() is {out("I am an Ethernet packet")}; };

Accessing sub-typed structs type packet_protocol: [Ethernet, IEEE, foreign]; struct packet { protocol: packet_protocol; when

Accessing sub-typed structs type packet_protocol: [Ethernet, IEEE, foreign]; struct packet { protocol: packet_protocol; when IEEE packet { i_val: int; }; }; var pk_inst: IEEE packet; pk_inst. i_val = 1; if pk_inst is a IEEE packet (ip) {ip. i_val = 1; }; pk_list. first(it is a IEEE packet (ip) and ip. i_val == 1);

List functions list. add, list. add 0, list. clear, list. insert, list. delete, list.

List functions list. add, list. add 0, list. clear, list. insert, list. delete, list. first var ilist: list of int; ilist. add(5); var iitem: instr; iitem = instr_list. first(it. op 1 > 15);

List add usage struct p_l { ! packeti : packet ! plst: list of

List add usage struct p_l { ! packeti : packet ! plst: list of packet; mklst() @sysclk is { gen packeti; plst. add(packeti); stop. run(); } }

@ event sim_ready is change(‘topready’) @sim; Simulator object change @sys. any – predefined event

@ event sim_ready is change(‘topready’) @sim; Simulator object change @sys. any – predefined event occurs everytime anyother event occurs extend sys { event clk is rise(‘top. clk’) @sim; }

List types perl-like array/list semantics my_list[0] refers to the first item in the list

List types perl-like array/list semantics my_list[0] refers to the first item in the list var lob: list of byte = {15; 31; 63; 127; 255}; print lob[0. . 2]; No multi-dimensional lists. To create a list with sublists in it, create a struct to contain the sublists

Example type packet_protocol : [Ethernet, IEEE, foreign]; struct packet { protocol: packet_protocol; len: int

Example type packet_protocol : [Ethernet, IEEE, foreign]; struct packet { protocol: packet_protocol; len: int [0. . 10]; }; extend sys { packets[10] : list of packet; do_print() is { var all_lengths: list of packet'len; all_lengths = packets. len; -- multi-element assignment print packets; print all_lengths; }; };

Run system: sys = packets = item type protocol 0. 1. 2. 3. 4.

Run system: sys = packets = item type protocol 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. packet packet packet Ethernet IEEE Ethernet foreign len 10 10 4 0 7 8 8 5 3 6 all_lengths = 0. 10 1. 10 2. 4 3. 0 4. 7 5. 8 6. 8 7. 5 8. 3 9. 6

Keyed Lists A keyed list data type is similar to hash tables or association

Keyed Lists A keyed list data type is similar to hash tables or association lists found in other programming languages. struct person { name: string; id: int; }; struct city { persons: list(key: name) of person; street_names: list(key: it) of string; };

Constraints with Keep keep constraint-bool-exp Syntax example: keep kind != tx or len ==

Constraints with Keep keep constraint-bool-exp Syntax example: keep kind != tx or len == 16; Parameters constraint-bool-exp A simple or a compound Boolean expression. States restrictions on the values generated for fields in the struct or the struct subtree, or describes required relationships between field values and other items in the struct or its subtree. Hard constraints are applied whenever the enclosing struct is generated. For any keep constraint in a generated struct, the generator either meets the constraint or issues a constraint contradiction message. Note If the keep constraint appears under a when construct, the constraint is considered

Keep examples struct pkt { kind: [tx, rx]; len: int; keep kind == tx

Keep examples struct pkt { kind: [tx, rx]; len: int; keep kind == tx => len == 16; // when tx pkt { -- this acts exactly the same way // keep len == 16; // }; }; Both these constraints are identical to the constraint: keep kind != tx or len == 16; Note: this is just the true meaning of “=>” Boolean implication

Keep examples Using the predefined method “is_a_permutation()” struct astr { l_1: list of int;

Keep examples Using the predefined method “is_a_permutation()” struct astr { l_1: list of int; l_2: list of int; keep l_2. is_a_permutation(l_1); }; struct transaction { address: uint; keep soft address == select { -- using keep soft and select 10: [0. . 49]; 60: 50; 30: [51. . 99]; }; };

Keep examples struct transaction { address: uint; keep soft address == select { 10:

Keep examples struct transaction { address: uint; keep soft address == select { 10: [0. . 49]; 60: 50; 30: [51. . 99]; }; }; extend transaction { keep address in [10. . 50]; keep soft address == select { 10: min; 60: others; 30: max; }; }; extend instr { keep soft opcode == select { 40: [ADD, ADDI, SUBI]; 20: [AND, ANDI, XORI]; 10: [JMP, CALL, RET, NOP]; ‘top. carry' * 90: JMPC; }; };

Keep examples type transaction_kind: [good, bad]; struct transaction { kind: transaction_kind; address: uint; length:

Keep examples type transaction_kind: [good, bad]; struct transaction { kind: transaction_kind; address: uint; length: uint; data: list of byte; }; extend transaction { keep length < 24; keep data[0] == 0 x 9 a; keep address in [0 x 100. . 0 x 200]; keep me. kind == good; }; extend sys { t: transaction; keep me. t. length != 0; };

Generation with keep Generation order is important because it influences the distribution of values.

Generation with keep Generation order is important because it influences the distribution of values. For example, in the keep constraint shown below, if “kind” is generated first, “kind” is “tx” about 1/2 the time because there are only two legal values for “kind”: struct packet { kind: [tx, rx]; size: byte; keep size > 15 => kind == rx; }; 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.

Specman Tutorial Example Use src files from tar archive CPU and Testbench are both

Specman Tutorial Example Use src files from tar archive CPU and Testbench are both modeled in specman n No need for nclaunch simulator “easy” high level modeling of CPU Black box testing

CPU_top. e <' // Basic: import CPU_instr, CPU_misc; // Add dut and drive: import

CPU_top. e <' // Basic: import CPU_instr, CPU_misc; // Add dut and drive: import CPU_dut, CPU_drive; // Add Coverage: import CPU_cover; // Add Checking: import CPU_checker; '>

CPU_instr. e <' type cpu_opcode: [ ADD, ADDI, SUBI, ANDI, XORI, JMPC, CALL, RET,

CPU_instr. e <' type cpu_opcode: [ ADD, ADDI, SUBI, ANDI, XORI, JMPC, CALL, RET, NOP ] (bits: 4); type reg : [ REG 0, REG 1, REG 2, REG 3 ] (bits: 2); // Opcodes // Register names

Instruction Formats to test struct instr { %opcode : cpu_opcode ; %op 1 :

Instruction Formats to test struct instr { %opcode : cpu_opcode ; %op 1 : reg ; kind : [imm, reg]; // defines legal opcodes for reg instr keep opcode in [ADD, SUB, AND, XOR, RET, NOP] => kind == reg; // defines 2 nd op of reg instruction when reg instr { %op 2 : reg ; }; // defines legal opcodes for imm instr keep opcode in [ADDI, SUBI, ANDI, XORI, JMPC, CALL] => kind == imm; // defines 2 nd op of imm instruction when imm instr { %op 2 : byte; }; // ensures 4 -bit addressing scheme when imm instr { keep (opcode in [JMP, JMPC, CALL]) => op 2 < 16; }; };

Extend the system struc extend sys { // creates the stream of instructions !instrs:

Extend the system struc extend sys { // creates the stream of instructions !instrs: list of instr; -- don’t pre-generate the list }; '>

CPU_misc. e <' extend global { setup_test() is also { set_config(print, radix, hex); set_config(cover,

CPU_misc. e <' extend global { setup_test() is also { set_config(print, radix, hex); set_config(cover, mode, normal, show_mode, both); set_config(print, items, 100); }; finalize_test() is also{ specman("display print sys. instrs"); }; }; '>

CPU_drive <‘ extend sys { event cpuclk is (fall('top. clk')@sys. any); cpu_env : cpu_env;

CPU_drive <‘ extend sys { event cpuclk is (fall('top. clk')@sys. any); cpu_env : cpu_env; cpu_dut : cpu_dut; //cpu_refmodel : cpu_refmodel; }; struct cpu_env { reset_cpu() @sys. cpuclk is { 'top. rst' = 0; wait [1] * cycle; 'top. rst' = 1; wait [5] * cycle; //sys. cpu_refmodel. reset(); 'top. rst' = 0; }; // reset reference model

CPU_drive_one_instr(instr: instr) @sys. cpuclk is { var fill 0 : uint(bits : 2) =

CPU_drive_one_instr(instr: instr) @sys. cpuclk is { var fill 0 : uint(bits : 2) = 0 b 00; wait until rise('top. fetch 1'); emit instr. start_drv_DUT; if instr. kind == reg then { 'top. data' = pack(packing. high, instr); } else { // immediate instruction 'top. data' = pack(packing. high, instr. opcode, instr. op 1, fill 0); wait until rise('top. fetch 2'); 'top. data' = pack(packing. high, instr. imm'op 2); }; wait until rise('top. exec'); };

CPU_drive !next_instr : instr; num_instrs : uint; keep soft num_instrs in [40. . 60];

CPU_drive !next_instr : instr; num_instrs : uint; keep soft num_instrs in [40. . 60]; gen_and_drive_instrs() @sys. cpuclk is { for i from 0 to num_instrs do { gen next_instr; sys. instrs. add(next_instr); drive_one_instr(next_instr); }; };

CPU_drive_pregen_instrs() @sys. cpuclk is { for i from 0 to sys. instrs. size() -

CPU_drive_pregen_instrs() @sys. cpuclk is { for i from 0 to sys. instrs. size() - 1 { drive_one_instr(sys. instrs[i]); }; }; drive_cpu() @sys. cpuclk is { reset_cpu(); if sys. instrs. size() > 0 then { drive_pregen_instrs(); } else { gen_and_drive_instrs(); }; wait [1] * cycle; stop_run(); };

CPU_drive run() is also { start drive_cpu(); }; }; extend instr { event start_drv_DUT;

CPU_drive run() is also { start drive_cpu(); }; }; extend instr { event start_drv_DUT; }; '>

Test 1. e <' import CPU_top; extend instr { // test constraints keep opcode

Test 1. e <' import CPU_top; extend instr { // test constraints keep opcode in [ADD, ADDI]; keep op 1 == REG 0; when reg instr {keep op 2 == REG 1}; // when reg instr when imm instr {keep op 2 == 0 x 5}; // when imm instr }; extend sys { // generate 5 instructions keep instrs. size() == 5; }; extend sys { post_generate() is also { gen instrs; // start generating stream of instructions }; }; '>

Test 2. e <' import CPU_top; extend instr { keep soft opcode == 30

Test 2. e <' import CPU_top; extend instr { keep soft opcode == 30 : [ADD, 30 : [AND, 10 : [JMP, }; }; '> select { ADDI, SUBI]; ANDI, XORI]; JMPC, CALL, RET, NOP]; // arithmetic operation // Logic operation // Other operation

State Coverage extend cpu_env { event cpu_fsm is @sys. cpuclk; // DUT Coverage: State

State Coverage extend cpu_env { event cpu_fsm is @sys. cpuclk; // DUT Coverage: State Machine and State Machine transition coverage cover cpu_fsm is { item fsm : FSM_type = 'top. cpu. curr_FSM'; transition fsm; }; };

Test 3. e extend instr { keep soft opcode == select { // high

Test 3. e extend instr { keep soft opcode == select { // high weights on arithmetic instructions 40 : [ADD, ADDI, SUBI]; 20 10 : [AND, ANDI, XORI]; // Logic operation : [JMP, CALL, RET, NOP]; // Other operation // generation of JMPC controlled by the carry signal value 'top. carry' * 90 : JMPC ; }; }; extend cpu_env { keep num_instrs == 52; }; extend global { setup_test() is also { set_config(gen, seed, 7); }; };

Checker. e: data checker extend cpu_env { // Data Checker event exec_done is (fall('top.

Checker. e: data checker extend cpu_env { // Data Checker event exec_done is (fall('top. exec') and true('top. rst' == 0))@sys. cpuclk; on_exec_done() is { // Compare PC - program counter check that sys. cpu_dut. pc == sys. cpu_refmodel. pc else dut_error("DATA MISMATCH(pc)"); };

Temporal Checker // Temporal (Protocol) Checker event enter_exec_st is (change('top. cpu. curr_FSM') and true('top.

Temporal Checker // Temporal (Protocol) Checker event enter_exec_st is (change('top. cpu. curr_FSM') and true('top. cpu. curr_FSM' == exec_st))@sys. cpuclk; event fetch 1_assert is (change('top. fetch 1') and true('top. fetch 1' == 1))@sys. cpuclk; // Interface Spec: After entering instruction execution state, fetch 1 // signal must be asserted in the following cycle. expect @enter_exec_st => { @fetch 1_assert}@sys. cpuclk else dut_error("PROTOCOL ERROR"); };

Operation Coverage extend instr { cover start_drv_DUT is { item opcode; item op 1;

Operation Coverage extend instr { cover start_drv_DUT is { item opcode; item op 1; item carry: bit = 'top. carry'; cross opcode, carry; }; };

Reference model struct cpu_refmodel { regs[4] : list of byte; pc : byte; stack

Reference model struct cpu_refmodel { regs[4] : list of byte; pc : byte; stack : list of byte; // Current PC // stack of PC values fetch(r: reg): byte is { return(regs[r. as_a(int)]); }; update(r: reg, val: byte) is { regs[r. as_a(int)] = val; }; // compute an ALU function compare(r: byte, val: byte): bool is { // compare against a reg result = (r == val); if ! result { out("Register has ", r, " While HDL has ", val); }; }; ret

Contd. jump(val: byte) is { pc = val; }; jumpc(cpu_dut: cpu_dut, val: byte) is

Contd. jump(val: byte) is { pc = val; }; jumpc(cpu_dut: cpu_dut, val: byte) is { // cheated a bit here pc = cpu_dut. pc; //if (cpu_dut. carry == 1) then {pc = val)}}; //pc = val; }; call(val: byte) is { stack. add(pc+2); pc = val; };

Reset operation reset() is { for i from 0 to 3 do { regs[i]

Reset operation reset() is { for i from 0 to 3 do { regs[i] = 0; // Initialize Specman reference regs }; pc = 0; };

Example of execution execute(instr: instr, var op 2_val : var reg_instr var imm_instr cpu_dut:

Example of execution execute(instr: instr, var op 2_val : var reg_instr var imm_instr cpu_dut: cpu_dut) is { byte; : reg instr; : imm instr; // compute next PC case instr. opcode { [ADD, SUB, XOR, AND, NOP]: {jump(pc +1); }; [ADDI, SUBI, XORI, ANDI, JMPC]: {jump(pc +2); }; }; if (instr. kind == reg) then{ reg_instr = instr. as_a(reg instr); op 2_val = fetch(reg_instr. op 2); } else { imm_instr = instr. as_a(imm instr); op 2_val = imm_instr. op 2; }; // compute next CPU State