Showing posts with label Sample Codes. Show all posts
Showing posts with label Sample Codes. Show all posts

Tuesday, 27 October 2015

Einstein’s Five House Riddle - Solution in 'e'

Over the weekend, I came across this riddle and thought of solving it using ‘e’. Later on I challenged our team members over the WhatsApp and they took up the challenge. They came up with their version of solution in SV and SVA. I thought of sharing this solution to show how constraints solver engine can solve these kind of riddles. During the course of solution, I observed specifics about constraint solving technology of Specman. But before that, let’s look at the riddle. It is called with different names like Zebra Riddle or Einstein’s Riddle. This riddle has different version of stories and none of it has any solid proof to prove its origin. I’ve taken this riddle from one of the student’s home page from Stanford University website. Here is his version of the riddle which we tried to solve.

Let us assume that there are five houses of different colors next to each other on the same road. In each house lives a man of a different nationality. Every man has his different favorite drink, his different favorite brand of cigarettes, and keeps different pets of a particular kind.
  1. The Englishman lives in the red house.
  2. The Swede keeps dogs.
  3. The Dane drinks tea.
  4. The green house is just to the left of the white one.
  5. The owner of the green house drinks coffee.
  6. The Pall Mall smoker keeps birds.
  7. The owner of the yellow house smokes Dunhills.
  8. The man in the center house drinks milk.
  9. The Norwegian lives in the first house.
  10. The Blend smoker has a neighbor who keeps cats.
  11. The man who smokes Blue Masters drinks bier.
  12. The man who keeps horses lives next to the Dunhill smoker.
  13. The German smokes Prince.
  14. The Norwegian lives next to the blue house.
  15. The Blend smoker has a neighbor who drinks water.
The question to be answered is: Who keeps fish?
Now to solve this riddle, I started thinking these clues as constraints in ‘e’. Let’s go step by step how I approached this problem.

Here, we have 5 men who has different characteristics like they live in specific house number which has specific color. Each one has unique nationality, favorite drink, favorite brand of cigarettes and pet. So, based on these attributes, we can create a struct which can have these 5 attributes. These five attributes can be enumerated and ‘man’ struct can be defined as shown below.

type nationality_t : [english, swede, dane, norweigian, german];
type house_color_t : [red, green, yellow, blue, white];
type cigarette_t : [dunhill, blend, blue_masters, prince, pall_mall];
type pet_t : [dog, bird, cat, horse, fish];
type drink_t : [tea, coffee, milk, bier, water];

struct man {
   nationality : nationality_t;
   house_color : house_color_t;
   cigarette   : cigarette_t;
   pet         : pet_t;
   drink       : drink_t;
};

Here, I’ve not captured the house number as an attribute since I thought I can create list of struct which automatically will fix the house number of each object.
Now, I’ve categorized the clues in 2 category. One category which does not have house number order dependency and the other category which has house number dependency. Like, clue number 1 “The Englishman lives in red house” does not have any reference to the number of house, whereas clue no. 4 “The gree house is just to the left of the white one” has reference to the house number order. Since I have not captured the house number as an attribute, I’ve to split the clues into two different categories of constraints. One without the reference of the house number can be part of the original struct definition. One with the house number dependency can go to the place where list of struct is created so that we have notion of the house orders using index number of the list.

Let’s first capture the clues without house number ordering as global constraints as part of struct declaration. Here is what I’ve captured.

extend man {
      //Englishman lives in the red house
      keep nationality == english      => house_color == red;

      //Swede keeps dog
      keep nationality == swede        => pet         == dog;

      //dane drinks tea
      keep nationality == dane         => drink       == tea;

      //owner of the green house drinks coffee
      keep house_color == green        => drink       == coffee;

      //Pall Mall smoker keeps bird
      keep cigarette   == pall_mall    => pet         == bird;

      //owner of the yellow house smokes dunhill
      keep house_color == yellow       => cigarette   == dunhill;

      //Man who smokes Blue Masters drinks bier
      keep cigarette   == blue_masters => drink       == bier;

      //German smokes prince
      keep nationality == german       => cigarette   == prince;

};

Now let’s move on to declaring this struct as 5 objects as shown below.

extend sys
{
   men : list of man;
     keep men.size() == 5;
};

Now over here, we can capture the clues with house number ordering as different constraints involving different objects. Here, we’ll go by clues.

Let’s look at the first constraint which has dependency on the house number ordering. This clue is clue number 4 “The green house is just to the left of the white one”. This can be captured as shown below. Here I’ve assumed house numbers starts from 0 to 4 runs from left to right. Due to this assumption, house number 0 does not have any house on left side of it.

extend sys {
   //The green house is just to the left of the white one.
   keep men[1].house_color == white => men[0].house_color == green;
   keep men[2].house_color == white => men[1].house_color == green;
   keep men[3].house_color == white => men[2].house_color == green;
   keep men[4].house_color == white => men[3].house_color == green;
};

Next clue which has dependency on the house number ordering is clue number 8 “The man in the center house drinks milk”. This can be captured easily as we know the house number 2 is in center.

extend sys {
   //The man in the center house drinks milk.
   keep men[2].drink       == milk;
};

Next such clue is clue number 9 “The Norwegian lives in the first house”. Again it is simple to capture.

extend sys {
   //Norweigian lives in the first house
   keep men[0].nationality == norweigian;
};

Next such clue is clue number 10 “The Blend smoker has a neighbor who keeps cats”. This is how I captured it. It is obvious that man staying in house 0 or 4 have only one neighbor and rest men have 2 neighbour.

extend sys {
   //The Blend smoker has a neighbor who keeps cats.
   keep men[0].pet         == cat   => men[1].cigarette == blend;
   keep men[1].pet         == cat => men[0].cigarette == blend or men[2].cigarette == blend;
   keep men[2].pet         == cat => men[1].cigarette == blend or men[3].cigarette == blend;
   keep men[3].pet         == cat => men[2].cigarette == blend or men[4].cigarette == blend;
   keep men[4].pet         == cat => men[3].cigarette == blend;
};

Next clue is clue number 12 “The man who keeps horses lives next to the Dunhill smoker”. Again it is captured just like the above constraints for clue number 10.

extend sys {
   //The man who keeps horses lives next to the Dunhill smoker.
   keep men[0].pet         == horse => men[1].cigarette == dunhill;
   keep men[1].pet         == horse => men[0].cigarette == dunhill or men[2].cigarette == dunhill;
   keep men[2].pet         == horse => men[1].cigarette == dunhill or men[3].cigarette == dunhill;
   keep men[3].pet         == horse => men[2].cigarette == dunhill or men[4].cigarette == dunhill;
   keep men[4].pet         == horse => men[3].cigarette == dunhill;
};

Next clue in this category is clue number 14 “The Norwegian lives next to the blue house”.  Since it is already declared in clue number 9 “The Norwegian lives in the first house”, it is obvious that the blue house is house number 1. The Here is how I’ve captured it.

extend sys {
   //The Norwegian lives next to the blue house.
   keep men[1].house_color == blue;
};

If we do not want to capture it by interpreting it by ourselves and want tool to interpret for us, we can capture it just like we captured clue number 10 and 12. Here is how clue number 14 can be captured in alternate way.

extend sys {
   //The Norwegian lives next to the blue house.
   keep men[0].nationality == norweigian => men[1].house_color == blue;
   keep men[1].nationality == norweigian => men[0].house_color == blue or men[2].house_color == blue;
   keep men[2].nationality == norweigian => men[1].house_color == blue or men[3].house_color == blue;
   keep men[3].nationality == norweigian => men[2].house_color == blue or men[4].house_color == blue;
   keep men[4].nationality == norweigian => men[2].house_color == blue or men[4].house_color == blue;
};

Last clue that is clue number 15 “The Blend smoker has a neighbor who drinks water” is again captured the way we have captured clue number 10 and 12.

extend sys {
   //The Blend smoker has a neighbor who drinks water.
   keep men[0].cigarette   == blend => men[1].drink == water;
   keep men[1].cigarette   == blend => men[0].drink == water or men[2].drink == water;
   keep men[2].cigarette   == blend => men[1].drink == water or men[3].drink == water;
   keep men[3].cigarette   == blend => men[2].drink == water or men[4].drink == water;
   keep men[4].cigarette   == blend => men[3].drink == water;
};

Now we have captured all the clues as constraints. But when we load this file into Specman and try to solve it, we get constraint error. The reason is that we have not capture an important piece of information into this solution, that is each man has unique values of each 5 attributes. Now capturing this and informing Specman to generate uniq values for all 5 objects of man struct is bit tricky in ‘e’. In system Verilog, randc operator helps us capture it very easily, but in ‘e’ we have to do it with lot of codes. Here is how I’ve done it.

extend sys {
   //Let us assume that there are five houses of different colors next to each other on the same road. In each house lives a man of a different nationality. Every man has his favorite drink, his favorite brand of cigarettes, and keeps pets of a particular kind.
   //Unique nationality, house_color, cigarette, pet and drink
   keep men[0].nationality != men[1].nationality;
   keep men[0].nationality != men[2].nationality;
   keep men[0].nationality != men[3].nationality;
   keep men[0].nationality != men[4].nationality;
   keep men[0].house_color != men[1].house_color;
   keep men[0].house_color != men[2].house_color;
   keep men[0].house_color != men[3].house_color;
   keep men[0].house_color != men[4].house_color;
   keep men[0].cigarette   != men[1].cigarette;
   keep men[0].cigarette   != men[2].cigarette;
   keep men[0].cigarette   != men[3].cigarette;
   keep men[0].cigarette   != men[4].cigarette;
   keep men[0].pet         != men[1].pet;
   keep men[0].pet         != men[2].pet;
   keep men[0].pet         != men[3].pet;
   keep men[0].pet         != men[4].pet;
   keep men[0].drink       != men[1].drink;
   keep men[0].drink       != men[2].drink;
   keep men[0].drink       != men[3].drink;
   keep men[0].drink       != men[4].drink;

   keep men[1].nationality != men[2].nationality;
   keep men[1].nationality != men[3].nationality;
   keep men[1].nationality != men[4].nationality;
   keep men[1].house_color != men[2].house_color;
   keep men[1].house_color != men[3].house_color;
   keep men[1].house_color != men[4].house_color;
   keep men[1].cigarette   != men[2].cigarette;
   keep men[1].cigarette   != men[3].cigarette;
   keep men[1].cigarette   != men[4].cigarette;
   keep men[1].pet         != men[2].pet;
   keep men[1].pet         != men[3].pet;
   keep men[1].pet         != men[4].pet;
   keep men[1].drink       != men[2].drink;
   keep men[1].drink       != men[3].drink;
   keep men[1].drink       != men[4].drink;

   keep men[2].nationality != men[3].nationality;
   keep men[2].nationality != men[4].nationality;
   keep men[2].house_color != men[3].house_color;
   keep men[2].house_color != men[4].house_color;
   keep men[2].cigarette   != men[3].cigarette;
   keep men[2].cigarette   != men[4].cigarette;
   keep men[2].pet         != men[3].pet;
   keep men[2].pet         != men[4].pet;
   keep men[2].drink       != men[3].drink;
   keep men[2].drink       != men[4].drink;

   keep men[3].nationality != men[4].nationality;
   keep men[3].house_color != men[4].house_color;
   keep men[3].cigarette   != men[4].cigarette;
   keep men[3].pet         != men[4].pet;
   keep men[3].drink       != men[4].drink;
};

Now we are ready to solve it. Let’s add some debug and solution print statements.

extend {
   post_generate() is also
   {
      for i from 0 to 4 {
         outf ("\n");
         outf ("men[%d].nationality = %s\n", i, men[i].nationality);
         outf ("men[%d].house_color = %s\n", i, men[i].house_color);
         outf ("men[%d].cigarette   = %s\n", i, men[i].cigarette  );
         outf ("men[%d].pet         = %s\n", i, men[i].pet        );
         outf ("men[%d].drink       = %s\n", i, men[i].drink      );
      };

      outf ("===================================\n");
      for i from 0 to 4 {
         if (men[i].pet == fish)
         {
            outf ("\nAnswer to the quesiton 'Who keeps fish?' is %s who lives in house no %d with house color %s and smokes %s and drinks %s has %s as pet...\n", men[i].nationality, i, men[i].house_color, men[i].cigarette, men[i].drink, men[i].pet);
            outf ("\n");
            outf ("men[%d].nationality = %s\n", i, men[i].nationality);
            outf ("men[%d].house_color = %s\n", i, men[i].house_color);
            outf ("men[%d].cigarette   = %s\n", i, men[i].cigarette  );
            outf ("men[%d].pet         = %s\n", i, men[i].pet        );
            outf ("men[%d].drink       = %s\n", i, men[i].drink      );

         };
      };
   }; //post_generate() is also
}; //extend sys

After loading it into Specman and solving it, we get following output.

Loading einsteins_puzle.e ...

Doing setup ...
Generating the test with IntelliGen using seed 1966611192...

men[0].nationality = norweigian
men[0].house_color = yellow
men[0].cigarette   = dunhill
men[0].pet         = cat
men[0].drink       = water

men[1].nationality = dane
men[1].house_color = blue
men[1].cigarette   = blend
men[1].pet         = horse
men[1].drink       = tea

men[2].nationality = english
men[2].house_color = red
men[2].cigarette   = pall_mall
men[2].pet         = bird
men[2].drink       = milk

men[3].nationality = german
men[3].house_color = green
men[3].cigarette   = prince
men[3].pet         = fish
men[3].drink       = coffee

men[4].nationality = swede
men[4].house_color = white
men[4].cigarette   = blue_masters
men[4].pet         = dog
men[4].drink       = bier
===================================

Answer to the quesiton 'Who keeps fish?' is german who lives in house no 3 with house color green and smokes prince and drinks coffee has fish as pet...

men[3].nationality = german
men[3].house_color = green
men[3].cigarette   = prince
men[3].pet         = fish
men[3].drink       = coffee

Starting the test ...
Running the test ...
No actual running requested.
Checking the test ...
Checking is complete - 0 DUT errors, 0 DUT warnings.

So the answer is “German keeps the Fish”. Now try to solve this solution multiple times with random seed and you will get the same answer. That way we can be sure that the constraints we’ve captured are correct.

One last observation I’ve made is that this solution can be solved in IntelliGen Specman solver only. It does not work with PGen Specman solver engine. The reason is quiet obvious. PGen depends on the order of constraints declaration whereas IntelliGen is truly bi-directional constraints solver which is natural way of solving all the constraints at the same time.

Hope you like this riddle and the solution. I am sure this is not the optimal way of solving the problem, but it’s my lazy weekend stuff, so I wrote whatever came to my mind first without thinking much about optimizing it. If you have any suggestion to improve it, please do comment. If you have solutions in other forms (XLS, Perl, tcl, python, C, C++, VB, PHP or any other your favorite language) then please do post it in the comment.

Wednesday, 29 February 2012

Automatic Coverage Weight Calculator Utility

If you want to get Specman coverage number in linear fashion (i.e. coverage numbers = (total buckets hit) / (total buckets in valid space) ), then you need to set the weight of individual items and coverage groups properly. Updating the code for proper weights to each item and cover group is tedious and error prone task. Maintaining the code is also a problem. What if you can do it automatically by using Coverage API? I hope people, who are looking such kind of solution will benefit from this post.

Specman overall coverage grade is calculated in hierarchical manner by default. It means that coverage is calculated from leaf level to the top level in following manner. I've assumed that weight is not set manually and default weight value 1 is applied here.

  1. Individual item grade is calculated by dividing buckets hit by total bucket for that item.
  2. Individual cover group grade is calculated by dividing total of all items grade by total number of items
  3. Overall coverage grade is calculated by dividing total of all cover groups graade by total number of cover groups

Take a look at the following example code.

<'
extend sys
{
config : config_s;
};
struct config_s
{
a : uint(bits: 3);
b : uint(bits: 3);
c : bool;
event cov1_e;
event cov2_e;
cover cov1_e is
{
item a using ignore = (a in [0, 1, 7, 8]);
item b using ignore = (b in [0, 1, 7, 8]);
cross a, b using
ignore =
(a in [2] and b in [4]) or
(a in [4] and b in [2] );
};
cover cov2_e is
{
item a using ignore = (a in [0, 1, 7, 8]);
item c using ignore = (c == TRUE);
cross a, c;
};
keep soft a == select
{
40 : 2;
10 : 3;
40 : 4;
10 : 5;
10 : 6;
};
keep soft b == select
{
40 : 2;
10 : 3;
40 : 4;
10 : 5;
10 : 6;
};
keep soft c == TRUE;
run() is also
{
for i from 1 to 10
{
gen a; gen b; gen c;
emit cov1_e;
emit cov2_e;
outf ("a=%d b=%d c=%s\n", a, b, c);
};
};
};
'>


When you run the above code with Intelligen with seed 1, Specman generates following combinations of a, b and c.

a=4 b=4 c=TRUE
a=4 b=4 c=TRUE
a=4 b=3 c=TRUE
a=2 b=2 c=TRUE
a=6 b=2 c=TRUE
a=2 b=4 c=TRUE
a=2 b=2 c=TRUE
a=2 b=4 c=TRUE
a=2 b=2 c=TRUE
a=4 b=6 c=TRUE

Let's analyze the coverage now.

ItemHitValid SpaceGrade
a3560.00% (hit/valid space)
b4580.00% (hit/valid space)
cross_a_b52321.74% (hit/valid space)

So, cov1_e cover group's grade = (grade of item a*weight + grade of item b*weight + grade of item cross_a_b*weight)/3 = 1.6174/3 = 53.91 %

ItemHitValid SpaceGrade
a3560.00% (hit/valid space)
c11100.00% (hit/valid space)
cross_a_c3560.00% (hit/valid space)

So, cov2_e cover group's grade = (grade of item a + grade of item c + grade of item cross_a_c)/3 = 2.20/3 = 73.33 %

So, overall grade = (cov1_e grade + cov2_grade)/2 = 1.2725/2 = 63.62 %

But, if you need the linear coverage, it should be
(Total number of hit buckets) / (Total number of buckets in valid space) = ((3+4+5) + (3+1+3))/((5+5+23) + (5+1+5)) = 43.18 %

This can be achieved by adjusting the weitage of individual item and cover group. If you set the weight of each item equal to the total number of valid buckets, linear coverage is achieved. Let's see how it works.

ItemHitValid SpaceWeightGrade
a35560.00 % (hit/valid space)
b45580.00 % (hit/valid space)
cross_a_b5232321.74 % (hit/valid space)

So, cov1_e cover group's grade = (grade of item a*weight + grade of item b*weight + grade of item cross_a_b*weight)/(weight of a + weight of b + weight of cross_a_b) = (3 + 4 + 5) / (5 + 5 + 23) = 36.36 %

ItemHitValid SpaceWeightGrade
a35560.00 % (hit/valid space)
c11180.00 % (hit/valid space)
cross_a_c35521.74 % (hit/valid space)

So, cov2_e cover group's grade = (grade of item a*weight + grade of item c*weight + grade of item cross_a_c*weight)/(weight of a + weight of c + weight of cross_a_c) = (3 + 1 + 3) / (5 + 1 + 5) = 63.64 %

So, overall grade = (cov1_e grade*weight + cov2_grade*weight)/(weight of cov1_e + weight of cov2_e) = (12+7)/(33+11) = 43.18%

This number looks linear as we can see we've calculated the coverage based on the number of buckets hit divided by total number of bucket for whole of the coverage space. So, setting the weight of the items based its number of buckets, it gives us the correct result.

Setting the weight manually is tedious process as you need to check the exact number of valid buckets of each item and coverage groups by keeping ignores and ranges into the mind. And even you do that, if you want to change the coverage model again, you might need to calculate the valid space again which is tedious and error prone. So, why not automate it using Coverage API calls?

You can use this small utility which uses coveage API to change the weight of all the items and cover group. It gives you the linear overall grade which is total number of buckets hit in valid coverage space divided by total number of buckets in valid coverage space. This utility can also be used in the post processing of coverage database. This utility uses coverage API to recursively parse the whole coverage space of a given unit which can be sys. It counts the total number of buckets of each item and coverage group and uses covers.set_weight() to set the weight of items and cover groups recursively.

You can use it after loading the linear_coverage.e. It defines a specman command using "define as" macro. Example is given below

Specman>load linear_coverage.e
Specman>adjust weight sys (for whole coverage space)
Specman>adjust weight config_s (for coverage space defined in config_s struct)


I hope this will help you. Your comments and thoughts are welcome.

-------------------------------------------
liner_coverage.e
-------------------------------------------
<'
define "adjust weight " as {
sys.adjust_weight = new;
sys.adjust_weight.main("<1>");
};

struct cover_info
{
item_name : string;
num_of_buckets: uint;
weight : uint;
};

struct bucket_cover_struct like user_cover_struct
{
collect: bool; // flag to skip specific item
cover_info : list (key: item_name) of cover_info;

main(items: string) is
{
if scan_cover(items) == 0 {
error("Adjust Weight Error: no cover items matching ", items," exist");
};
};

scan_bucket() is
{
if ((collect) and (cross_level == sub_items.size()-1)) then
{
var full_item_name := appendf ("%s.%s.%s", struct_name, group_name, item_name);
if (status in [hole, normal])
{
if cover_info.key_exists(full_item_name)
{
cover_info.first(.item_name == full_item_name).num_of_buckets = cover_info.first(.item_name == full_item_name).num_of_buckets + 1;
}
else
{
var temp_cov_info : cover_info = new;
temp_cov_info.item_name = full_item_name;
temp_cov_info.num_of_buckets = 1;
cover_info.add(temp_cov_info);
};
};
};
};

// Output a line of text for item:
end_item() is
{
if collect then
{
var full_item_name := appendf ("%s.%s.%s", struct_name, group_name, item_name);
var num_of_buckets := cover_info.first(.item_name == full_item_name).num_of_buckets;
outf ("%s - %d (weight=%d)\n", full_item_name, num_of_buckets, item_weight);
covers.set_weight(full_item_name, num_of_buckets, FALSE);
};
};

start_group() is
{
collect = (struct_name != "session");//skip session struct
if collect then
{
outf ("\n------------------------------------\n");
};
};

end_group() is
{
if collect then
{
var group_total : uint;
for each (cov_info) in (cover_info)
{
group_total = group_total + cov_info.num_of_buckets;
};
outf ("------------------------------------\n");
outf ("Group and Total Buckets ---> %s - %d (weight=%d)\n", group_name, group_total, group_weight);
covers.set_weight(appendf("%s.%s", struct_name, group_name), group_total, FALSE);
outf ("------------------------------------\n");
cover_info.clear();
};
};
};

// Define an instance of bucket_cover_struct:
extend sys
{
!adjust_weight: bucket_cover_struct;
init() is also { adjust_weight = new; };
setup() is also { set_config(cover, show_sub_holes, TRUE); };
};

'>

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
{
gen_seq_randc();
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.

Monday, 24 December 2007

Raised Objection Report

Any raised objection will prohibit your simulation to stop. And In large environments, it may be painfull to find the one objection still raised using the SN commands 'show objections' or 'trace objections'.

You may just load follwoing e-code in your test and you'll be able to get a short report of all raised objections by typing 'sys.report_raised_objections(TEST_DONE)'


<'
extend sys
{
report_raised_objections(kind : objection_kind) is
{
// usage: sys.report_raised_objections(TEST_DONE)
var obj_units : list of any_unit = get_all_units(any_unit).all(.get_objection_counter(kind) > 0);
outf("-----------------------------------------------\n");
outf("Objection Report:\n");
outf("Counter Total Env e path\n");
outf("------- ----- ---- ------\n");
for each (u) in obj_units
{
outf("%-7d %-5s %-7s \n", u.get_objection_counter(kind), u is an any_env ? u.short_name() : "", u.e_path());
};
};
// just to print the command in the sn window
run() is also
{
outf("-----------------------------------------------\n");
outf("REPORT_RAISED_OBJECTIONS loaded\n");
outf("usage: sys.report_raised_objections(TEST_DONE)\n");
outf("------------------------------------------------\n");
};
};
'>

Thursday, 13 December 2007

eToolkit from Verilab

Here is a very useful toolkit from Verilab to understand somebody else's e environment. It is especially useful when you want to have an overview and detailed view of the e code.

http://www.verilab.com/resources/e-toolkit/

Using this toolkit, you can find like inheritance hierarchy of classes and also find declaration and extension of classes, enumtypes, methods and coverage groups.

Tuesday, 11 December 2007

Access Multi Language Signals using Ports

Ever came across the issue where one unit's signal map uses different signals from multi language design (VHDL and Verilog)? Take following example.

As shown in the diagram, top_wrapper is in vhdl and DUT is in verilog. Corresponding to this design, in e domain, two units are defined, one is top_wrapper_u and another dut_u.





Now, somewhere in dut_u unit, if you want to use clk from dut (verilog) and reset_n from top_wrapper (vhdl ), you can not do it using computed names (using strings). To achieve this, you have to use e external ports. Once ports are defined, using .agent() attribute of the units and ports, you can define, which unit/port is belonged to which design unit (vhdl/verilog).

As shown in the following code, refer the last line. reset_n.agent() is constrained to vhdl so that reset_n will be taken from vhdl module and rest of the ports in the dut_u will be taken from verilog module as dut_u.agent() is constrained to verilog.


<' unit dut_u
{
clk : in simple_port of bit is instance;
reset_n : in simple_port of bit is instance;

keep bind (clk, external);
keep bind (reset_n, external);


keep clk.hdl_path = "clk";
keep reset_n.hdl_path = "reset_n";


};



unit top_wrapper_u
{
dut : dut_u is instance;
};



extend sys
{
top : top_wrapper_u is instance;

keep top.hdl_path() == "~/top_wrapper";
keep top.dut.hdl_path() == "~/top_wrapper/dut";


keep top.agent() == "vhdl";
keep top.dut.agent() == "verilog";
keep top.dut.reset_n.agent() == "vhdl";


};
'>