2

This is a follow up question from my previous question (Difference between "new" and "gen").

Is there a way to pass dependencies into a struct before generation occurs?

I'm interested in trying to write my code in a way which is easily tested. Currently, our codebase uses get_enclosing_unit() frequently to acquire pointers to helper structs such as a translator/params. This causes there to be lots of bidirectional dependencies in our codebase. This means it is hard to test pieces independent of the other structs.

Here is an example of what I am trying to avoid.

pregenerate() is also {
  var translator : my_translator_s = get_enclosing_unit(some_enclosing_unit).get_translator_pointer();
};

I'm trying to avoid depending on some_enclosing_unit since it doesn't relate to my struct and gets in the way of unit testing

With the lack of a constructor in e, I'm lost as to how to pass a dependency in from the calling unit/struct without using get_enclosing_unit(). "new... with" seems like it might be able to help, but as I learned in my last question, it doesn't generate underlying fields and "gen...keeping" doesn't set my generation needed dependencies until after generation has been completed.

Community
  • 1
  • 1
qzcx
  • 361
  • 1
  • 12

1 Answers1

2

There is no easy answer because your architecture seems to be entangled already. You are right in being suspicious about these bi-directional, vertical dependencies in your instance tree. In general, one should follow the constraints-from-above (CFA) strategy where you pass dependencies down the hierarchy like in

unit child_u {
    p_tr: translator_s;
    keep soft p_tr == NULL; // safety catch, in case you forget to constrain it
};

unit parent_u {
  tr: translator_s;
  child: child_u is instance;
  keep child.p_tr == tr;
};

Also, I recommend to not have generation dependencies between units. This way you can keep all your pointers to units non-generatable and connect them in the connect_pointers() method of a unit which is called after generation (see documentation).

extend child_u {
  !p_parent: parent_u;
}
extend parent_u {
  connect_pointers() is also {
    child.p_parent = me;
  };
};

But then of course you can't have constraints in child that point to parent. In the case where you absolutely need a generated pointer, use keep soft <ptr> == NULL to provoke failure in case you forgot to constrain it.

Just my 2cents.

Thorsten
  • 710
  • 8
  • 17
  • Yeah, the codebase is currently a little entangled. I'm new to Specman and the team, but would like to help the team do better in this area. I'll look for ways to apply this advice. Thanks! – qzcx Jul 01 '15 at 16:25
  • 1
    Also, if you avoid the constraint solver for simple things like connecting pointers, it can greatly speed up generation for very large testbenches. The constraint solver is a really, really big gun. Any time you can avoid it ( within reason), you will reduce the cost of running Specman. In my experience, using `connect_pointers()` as much as possible and other procedural phases can make Specman run much, much faster. Speed may or may not be a consideration for a given project, depending on the DUT and testbench size. – Ross Rogers Jul 06 '15 at 22:22
  • 1
    @RossRogers that was true, until Cadence introduced the compilation of simple generation actions - meaning things like `keep a==10` get translated to procedural code. Assuming this is complete of course. I think that was introduced with 14.x. – Thorsten Jul 07 '15 at 14:07