Friday, 10 July 2009

DigitalVerification Blog is noticed by Verification Community

I am glad and thankful to the verification community for appreciating my small contribution towards the verification world. This blog has been noticed by Cadence Team Specman and recoginized as useful resource. also recognized this blog saying "if you live and breathe in this world, here’s an additional resource"
I'll keep posting and contributing to the verification world.

Thursday, 25 June 2009

IntelliGen - Introduction

IntelliGen is around for quite a while, but I've observed that most of the Specman users are less interested in/aware of it. Probably they are very comfortable with old generation engine known as PGen. Even I am quite comfortable with PGen and I am used to think generation in PGen way. But, when I went through IntelliGen, it also looked conviencing. But it will take some time to penetrate and Cadence has to push it hard so that people start thinking about generation IntelliGen way. :)

IntelliGen is a new generation engine introduced in Specman 6.1 version onwards. It is a new generation engine which uses different generation algorithm from Specman's original generation engine PGen. Though PGen remains default generation engine, user can switch to IntelliGen by setting a configuration flag before loading any code.

Specman>config gen -default_generator=IntelliGen

IntelliGen is easier to use as there is no generation dependencies on the fields declaration order. In PGen, fields which are declared first are generated first unless there are specific generation order mentioned using "keep gen before" or "readonly()". With a new and powerful debugger, its very easy to debug generation errors for IntelliGen. The messages which are displayed when any generation errors occur are more informative than whatever is displayed for PGen. Cadence also claims that performance can be increased by 2 to 5 times compared to PGen. IntelliGen solves some constraint more logically and intelligently compared to PGen. We will see all these in few examples.

  • Generation Order Independence
In the code shown below, we want to generate addr based on addr_hi_lo value. So you put constraint over addr_hi_lo and addr. But since addr is declared first, it will be generated first in PGen generation engine. Due to that, there are very little chance that it is either equal to addr_hi or addr_lo. So, either of the constraint on addr_hi_lo does not satisfy and PGen will not be able to solve it. Though the constraint is bidirectional, since addr is declared first, it is generated first and that makes constraint unidirectional.
Same code will not cause any generation error if IntelliGen is used because, there is not generation dependency on declaration order.

define addr_hi 0xFF;
define addr_lo 0x05;
type addr_kind : [LO, HI];
extend sys
addr : list of uint (bits: 8);
addr_hi_lo : addr_kind;
keep addr.size() == 10;
keep for each in (addr)
addr_hi_lo == HI => it == addr_hi;
addr_hi_lo == LO => it == addr_lo;
post_generate() is also { print addr; };

Results with PGen:

*** Error: Contradiction:
A contradiction has occurred when generating sys-@0.addr_hi_lo :
Previous constraints reduced its range of possible values,
then the following constraint contradicted these values:
addr_hi_lo == LO => it == addr_lo; at line 20 in @temp
Reduced: sys-@0.addr_hi_lo into []
To see details, reload and rerun with "collect gen"

Results with IntelliGen:

addr = (10 items, dec):
5 5 5 5 5 5 5 5 5 5 .0

  • Better Solvability
Further to that, IntelliGen takes good care of soft and soft select constraints. When soft select constraints are added for a field which already has soft constraint defined previously, PGen will ignore all the previously defined soft constraints even there are no contradiction between soft and soft select constraints. Whereas IntelliGen takes care of both constraints as long as they do not contradict. If they contradict, then IntelliGen ignores soft constraint over soft select. Take a look at the following example and results generated using PGen and IntelliGen.
type addr_kind : [LO, HI, OTHERS];
struct operation_s
addr_hi_lo : addr_kind;
keep soft addr_hi_lo in [HI, LO];
extend operation_s
keep soft addr_hi_lo == select
10 : LO;
80 : OTHERS;
10 : HI;
extend sys
op : list of operation_s;
keep op.size() == 10;
post_generate() is also { print op; };

Results with PGen:

op =
item type addr_hi_lo

0. operation* OTHERS
1. operation* OTHERS
2. operation* OTHERS
3. operation* OTHERS
4. operation* HI
5. operation* OTHERS
6. operation* OTHERS
7. operation* HI
8. operation* HI
9. operation* OTHERS

Results with IntelliGen:

op =
item type addr_hi_lo

0. operation* LO
1. operation* LO
2. operation* HI
3. operation* HI
4. operation* LO
5. operation* HI
6. operation* HI
7. operation* LO
8. operation* LO
9. operation* LO

  • Better Distribution
Because of improved constraint solving ability, IntelliGen gives better distribution of generated values within the range.
define addr_hi 0xFF;
define addr_lo 0x05;
type op_kind : [LO, HI, OTHERS];
struct operation_s
addr : uint (bits: 8);
op_hi_lo : op_kind;
keep op_hi_lo == HI => addr == addr_hi;
keep op_hi_lo == LO => addr == addr_lo;
keep op_hi_lo == OTHERS => addr in [addr_lo+1..addr_hi-1];
extend sys
op : list of operation_s;
keep op.size() == 10;
post_generate() is also { print op; };

Results with PGen:

op =
item type addr op_hi_lo

0. operation* 0x57 OTHERS
1. operation* 0x12 OTHERS
2. operation* 0x80 OTHERS
3. operation* 0xbe OTHERS
4. operation* 0x7f OTHERS
5. operation* 0x64 OTHERS
6. operation* 0x0f OTHERS
7. operation* 0xab OTHERS
8. operation* 0x6e OTHERS
9. operation* 0xcd OTHERS

Results with IntelliGen:

op =
item type addr op_hi_lo

0. operation* 0xff HI
1. operation* 0xc3 OTHERS
2. operation* 0xff HI
3. operation* 0x05 LO
4. operation* 0x05 LO
5. operation* 0x05 LO
6. operation* 0x1d OTHERS
7. operation* 0x6a OTHERS
8. operation* 0x1a OTHERS
9. operation* 0xff HI

  • Better Debug Information
When any generation error occurs, IntelliGen issues elaborated generation error message which is very useful to pin point the problematic area of the code. Look at the below code.
type addr_kind : [LO, HI, OTHERS];
struct operation_s
addr_hi_lo : addr_kind;
keep addr_hi_lo in [HI, LO];
extend sys
op : list of operation_s;
keep op.size() == 10;
keep for each in (op)
index in [0] => it.addr_hi_lo == LO;
index in [1..8] => it.addr_hi_lo == OTHERS;
index in [9] => it.addr_hi_lo == HI;
post_generate() is also { print op; };

Error Message with PGen:

*** Error: ERR_GEN_OR_WITH_NO_GEN_ALT: After static analysis, the following constraint
consists of non-enforceable constraints only:
index in [1..8] => it.addr_hi_lo == OTHERS; at line 19 in @temp

Error Message with IntelliGen:

*** Error: Contradiction when generating sys

No set of values exists for:

that obey the constraints:
keep addr_hi_lo in [0x0..0x1] at line 7 in @temp ,
index in [0x1..0x8] => it.addr_hi_lo == OTHERS at line 19 in @temp

with the input:
index = 0x1

By now, you might have realized the improvement of IntelliGen over PGen. I hope this is useful basic information about IntelliGen. I'll cover IntelliGen Technical Concepts in my next post.

Monday, 15 June 2009

Specman/Verification Books

Specman Books

Design Verification with e
Author : Samir Palnitkar
ISBN 0131413090
Publisher Prentice Hall Professional Technical Reference
Publish Date Auguts, 2003
Page 416
The e-Hardware Verification Language
Author : Sasan Iman and Sunita Joshi
ISBN 1402080239
Publisher Kluwer Academic Publishers
Publish Date May, 2004
Page 349
Aspect-Oriented Programming with the e Verification Language: A Pragmatic Guide for Testbench Developers
Author : David Robinson
ISBN 0123742102
Publisher Morgan Kaufmann Publishers
Publish Date August, 2007
Page 244

Verification Books

Metric Driven Design Verification: An Engineer's and Executive's Guide to First Pass Success
Author : Hamilton B. Carter; Shankar G. Hemmady
ISBN 0387381511
Publisher Springer Verlag
Publish Date May, 2007
Page 361
Writing Testbenches: Functional Verification of HDL Models
Author : Janick Bergeron
ISBN 1402074018
Publisher Kluwer Academic Publishers
Publish Date February, 2003
Page 512
Effective Functional Verification: Principles and Processes
Author : Srivatsa Vasudevan
ISBN 0387286012
Publisher Springer Verlag
Publish Date June, 2006
Page 256
Principles of Functional Verification
Author : Andrea S. Meyer
ISBN 0750676175
Publisher Newnes
Publish Date November, 2003
Page 240

SystemVerilog Books

Step-by-step Functional Verification with SystemVerilog and OVM
Author : Sasan Iman
ISBN 0981656218
Publisher Hansen Brown Publishing
Publish Date May, 2008
Page 520
SystemVerilog for Verification: A Guide to Learning the Testbench Language Features
Author : Spear, Chris
ISBN 0387270361
Publisher Springer
Publish Date June, 2007
Page 429
Verification Methodology Manual For Systerm Verilog
Author : Andy Nightingale, Alan Hunter, Eduard Cerny and Janick Bergeron
ISBN 0387255389
Publisher Springer-Verlag New York Inc
Publish Date 2005
Page 503
Writing Testbenches Using SystemVerilog
Author : Janick Bergeron
ISBN 0387292217
Publisher Springer-Verlag New York Inc
Publish Date 2006
Page 412
A Practical Guide for System Verilog Assertions
Author : Srikanth Vijayaraghavan and Meyyappan Ramanathan
ISBN 0387260498
Publisher Springer Verlag
Publish Date 2005
Page 334
Hardware Verification With SystemVerilog: An Object-oriented Framework
Author : Mike Mintz and Robert Ekendahl
ISBN 0387717382
Publisher Springer
Publish Date May, 2007
Page 314

Monday, 25 May 2009

randc kind of implementation in e

When I went through SystemVerilog constructs, one of the unique construct I found out was randc. Cyclic randomization sometimes helps you generating all unique combinations before repeating it. One classic usage example of randc is to inject all the sequences into DUT at least once without repeating it again. So, I was wondering if it is possible to implement it in e. I realized that though you can not generate the item based on its previously generated values, you can have some workaround for that using list psudo methods. There are all_values() and is_a_permutation() psudo methods which can be used for this purpose.

Let me explain the logic to implement that classic usage example to inject all the sequences into DUT without repeating it. If we somehow generate a list of unique sequence kinds randomly, we can take that list items one-by-one and generate the sequence based on that kind. So, to generate the unique yet random list of sequence kind, we can use above mentioned two list psudo methods. Take a look at the following code snippet.

type seq_type_t : [SEQ_A, SEQ_B, SEQ_C, SEQ_D, SEQ_E, SEQ_F, SEQ_G];
extend MAIN my_sequence_s
seq_randc : list of seq_type_t;
keep seq_randc.is_a_permutation(all_values(seq_type_t));
!seq : my_sequence_s;
body() @driver.clock is only
for i from 0 to seq_randc.size() - 1
do seq { keeping .kind == seq_randc[i]; }

all_values(seq_type_t) statement will return a list which will have all the unique values of scaler type seq_type_t. is_a_permutation() will make sure that seq_ranc list has random but all the fields of the list returned by all_values(seq_type_t) statement. Thus, we have a list which has all the random values of the sequence kind. Now, we can loop through this list one by one and generate a seq and push it to the DUT.

Friday, 22 May 2009

Less known and less used Specman commands

There are quite a few Specman commands which are handy when it comes to debugging. Here I tried to summarize few less known but useful Specman commands. Here we go.
  1. If you have verification environment loaded on Specman and one method is extended in multiple files and you want to see all the extension of that method in a single place, "collect" command is what you are looking for.

  2. Specman> collect sys.mystruct.monitor
    Specman> collect

    File temp.erld - created by collecting: (after module specman)
    ----------------------- Reset
    extend sys {
    ) is as was after specman;
    ----------------------- From temp.e at line 6:
    extend sys {
    run() is also
    var x : mystruct_s;
    gen x;
    ----------------------- End of

  3. If you want to debug temporal expression, you would like to visualise how different events are triggered. Event chart is basic but sometimes useful for debugging temporal expressions. To see the events you first have to collect events you are interested in by using "collect events" Specman command.

  4. Specman> collect events *.*
    Specman> collect events sys.mystruct.* //collects all events for the instance sys.mystruct
    Specman> collect events mystruct_s.* //collects all the events of struct mystruct_s

  5. If you want to see the events triggered during simulation, you can use Specman command "show events" after collecting the events as mentioned above.

  6. Specman> show events
    Specman> show events 100 //This command shows events since time 100
    Specman> show events 100..150 //This command shows events in the time range 100..150
    Specman> show events -chart //Pops up event chart

  7. If you want to have a summarized report about the events count, if it is associated with cover group, its source etc, you can use "show events def" command.

  8. Specman> show events def sys.any

    count echo col covr name source
    0 10000 FALSE TRUE FALSE sys.any @sn_te_tick

  9. Executing actions on command line. You can define variables or call methods or start a TCMs. (you can not call a TCM on command line). Remember, you can not give "gen" action on command line, but you can call a method which has gen action in it.

  10. Specman> var x : uint(bits: 4) = 5;
    Specman> var y : uint = x + 10;
    Specman> print x + y;
    Specman> sys.non_tcm()
    Specman> start sys.tcm()
    Specman> sys.non_tcm_with_arg(4, TRUE)

  11. You can search/grep within the loaded files using "search" command

  12. Specman> search mystruct_s

  13. You can open a file (known as "module" in Specman terms) in source browser by using "source" command. It will open a source browser with that perticular line number into focus.

  14. syntax: source

    Specman> source mystruct.e 50

  15. You can run unix commands using "shell" command.

  16. syntax: shell

    Specman> shell echo $SPECMAN_PATH
    Specman> shell pwd

  17. You can also get the value of define by issuing "show define" command.

  18. syntax: show define [-v] [-e]

    Specman> show define -v "*WIDTH*"

  19. If you want to know what are the modules that are loaded you can use "show modules" command.

  20. Specman> show modules

  21. You can get unix environment variables value within your e code by using get_symbol() method.

  22. my_method() is
    outf ("SPECMAN_PATH=%s",get_symbol("SPECMAN_PATH"));

  23. 12. If you wish to execute specman command in e code, then you can use specman() method as shown below.

  24. pre_generate() is
    specman("break on error");

  25. If you wish to execute unix command from your e code, you can use output_from() method.

  26. my_method() is
    var list_of_files: string;
    list_of_files = output_from("ls");
    print list_of_files;

  27. If you want to uderstand port binding in Specman, use "show ports" command.

  28. You can use "trace bind' to follow the binding process

  29. If you have executed a set of commands and want to see the history of executed commands, you can use "show redo" command.

  30. Specman> show redo
    show redo
    The redo buffer (default is 'redo 0..') =
    0. "restore specman.esv"
    1. "load temp.e"
    2. "test"
    3. "clear screen; restore; reload; test"

  31. Once you know the hisotry of executed command, you can reexecute them by issueing "redo" Specman command.

  32. Specman> redo 3 //this will execute command 3 (clear screen; restore; reload; test)
    Specman> redo 0..2 //this will execute command 0 to 2 (restore specman.esv, load temp.e, test)

  33. If you have wave command executed to view e fields into waveform and want to dump all these wave tracing commands into a file, you can use "write wave" command.

  34. syntax: write wave to

    Specman> write wave to trace_wave.ecom

    19. To debug, packing and unpacking, you can use "show pack" and "show unpack" command as shown below.

    Specman> var x : uint (bits: 3) = 3
    Specman> var y : uint (bits: 7) = 5
    Specman> show pack(packing.low, x, y);

    |9 8 7 6 5 4 3|2 1 0| +0
    |0 0 0 0 1 0 1|0 1 1|
    |y |x |

    Specman> var x : packet_s
    Specman> var data : list of bit = {1;1;0;1;0;0;0;1;1;1;0;1}
    Specman> show unpack(packing.low, data, x)

    |1 0 9 8 7 6 5 4|3 2 1 0| +0
    |1 0 1 1 1 0 0 0|1 0 1 1|
    |x.addr |x.len |

Thursday, 21 May 2009

Debugging packing and unpacking in Specman

Hello readers, I am back after a loooooong break. It has been quite a some time since I posted something here as I was too busy with my personal life and responsibilities. I try to be regular now. So with this note, let me start something from today itself.

While using packing/unpacking in your environment, you might have gone through some debugging troubles due to silly mistakes. So here are few tips to avoid errors for packing and unpacking.
So starting with Unpacking, there can be 2 kind of problems you may face while unpacking a list into struct
  • You run out of data while unpacking (i.e. list is shorter than total length of physical fields of a struct)
  • Unpacking is finished but you have bits/bytes left over (i.e. list is bigger than total length of physical fields of struct)
If you have situation 1, it will be flagged as run-time error by Specman. But, if you have situation 2, you might not even aware of it as Specman does not issue even a warning for this. For situation 1, if you want to suppress run-time error, you can use 'try' action.

tcm() @clk is {
try {
unpack(packing.low, my_list, my_struct);
} else {
message (LOW, "Unpacking failed");

To debug packing/unpacking issues, you can use Specman command 'trace packing'. It shows how packing/unpacking is performed. Following example shows the result of 'trace packing' command performed for unpacking.

Following example shows the result of 'trace packing' command performed for packing

If unpacking is unsuccessful (ran out of data in the list), you normally get following message on Specman STDOUT.

*** Error: Ran out of data while trying to unpack (use 'trace packing' for further details)
at line 19 in @packing_unpacking_debug
unpack(packing.low, lob_u, x);

But if you use 'trace packing' Specman command, you see where unpacking stopped.

> ----- Starting an unpack() at line 19 in @packing_unpacking_debug ----

> ----------- Unpacking 'x': x_s
> Unpacking 'x.a': uint (bits: 4)
8 .0
> 'x.a': uint (bits: 4) = 8
> Unpacking 'x.b': uint (bits: 8)
0 5 .0
> 'x.b': uint (bits: 8) = 5
> Unpacking 'x.c': list of byte
*** Error: Ran out of data while trying to unpack into 'x.c'
at line 19 in @packing_unpacking_debug
unpack(packing.low, lob_u, x);

One of the very common cause of the unpacking failure is the unsized list. If the target struct has unsized list as a physical field, all the bits/bytes of the source list will be absorbed by this unsized list and there will be no data left for the next physical field and Specaman will issue an error. So it is always advisable not to have unsized list in the target struct.

Another reason for unpacking failure could be subtype physical fields. If you have few physical fields defined under 'when' subtype of a struct, your need to make sure which subtype to pick while unpacking.

One more reason for the unpacking to give errorneous result is the order of the physical fields in a struct. If physical fields of a struct is defined in the multiple files, then import order of that file becomes crucial because based on the order, physical fields will be treated differently during unpacking. Take a look at the following example.