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:
op[0x0..0xffffffff].addr_hi_lo

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.

7 comments:

Nishith said...

Very Good Sandeep. It's very nicely explained. I would like to look forward explanation/examples for various Linting errors associated with Igen..

Avidan said...

Hi Sandeep,
An interesting overview. Thanks. Generation order was a patch right from the start, and its good news that it is finally removed.

One thing I've noticed is that the results of your first example from intelligen, look a bit strangs - i.e. all addr elements are 5, whereis I would expect some of them to be FF. Any idea why?

Avidan said...

Hi Sandeep. A good overview. Generation order was a patch right from the start so its good news to hear that's gone now.

One thing I've noticed is that the results of your first example look a bit strange - i.e - all address elements get the value of 5 whereis I would expect some of them to be 99. Any idea why?

Sandeep Gor said...

Hi Avidan,

Thanks for your comment. The reason why all address elements are having value 0x05 is that addr_hi_lo is generated only once. After it is generated, it decides if all address elements need to be 0x05 or 0xFF. So, if you load the same code with different seed, you will find all address elements will be either 0x05 or 0xFF. Other way of looking at it is like addr_hi_lo field corresponds to the whole address list and not each element of address list. If you want one to one relation between address and addr_hi_lo field, you can place them in a struct and then instead of having a list of address, you can have list of that struct. I hope it clears your doubt.

-Sandeep

Avidan Efody said...

Ah yes, obviously you're right... stupid me, I thought the addr_hi_lo field was a list as well :-(...

JL Gray said...

Excellent article, Sandeep. Thanks!

JL

Anonymous said...

Very nice article, but in case of better solvability example code, it seems that igen ignores soft select constraint over soft when it resolves.