[sv-bc] Enumerate Extensions examples and usage models

From: Alsop, Thomas R <thomas.r.alsop@intel.com>
Date: Tue May 24 2011 - 10:53:43 PDT

Hi,

I was asked to gather feedback on enumerate extension. What are the needs from Intel's perspective, what types of usage models exist, and can we provide examples. I heard back from 3 verification experts. Our disclaimer on the following examples and discussion is only this. We understand that there may be other ways to do these examples, but we do not want end users to have to deal with the complexities and maintenance of these other solution styles. Enumerate extension will greatly simplify their usage models and will in many ways help the ongoing UVM effort (see discussions below).

Please read through the examples below and let's discuss them. My expectation is now to bring an enum extension proposal to either the sv-bc or sv-ec as soon as I can.

Here is a summary of this feedback.

First usage example:

Say that I have a package which contains base virtual classes from which I will create all of the BFMs in my environment (OVM, UVM or even CGFramework). In that base package, I would like to be able to specify and manipulate some generic elements such as command and message, without getting into the specifics of the exact commands and messages that are allowed. The commands and messages will vary per interface. So my library might have a class like this:

virtual class xaction;
  typedef enum {READ, WRITE, MSG} command_t;
  typedef enum {INT, ATTN, PWR} message_t;

  command_t command;
  message_t message;

  virtual function void print();
    $display("command: %s, message: %s", command.name(), message.name());
  endfunction
endclass

In use, what I've seen is that the BFM owner will extend the xaction class and create their own fields, for example "cmd" and "msg" which creates confusion, and then they re-define the print function to refer to those new variables. What would be preferable is to be able to extend the enumerated types, and allow "virtual" type of inheritance behavior of the enumeration to be usable in the display function above. So the code might change to something like this:

virtual class Xaction;
  typedef virtual enum {READ, WRITE, MSG} command_t;
  typedef virtual enum {INT, ATTN, PWR} message_t;

  command_t command;
  message_t message;

  virtual function void print();
    $display("command: %s, message: %s", command.name(), message.name());
  endfunction
endclass

class PCIeXaction extends Xaction;
  extends enum {CFGREAD, CFGWRITE, IOREAD0, IOWRITE0, IOREAD1, IOWRITE1} command_t;
  extends enum {INTA, INTB, INTC, INTD, ATTN_BUTTON_PRESSED, PWR_BUTTON_PRESSED} message_t;
endclass PCIeXaction

I leave it to discussion if the above implementation example is reasonable or too limiting for other uses. The idea is that now PCIeXaction implicitly has its own typedef enum PCIeXaction::command_t which is an extension of Xaction::command_t. The command field declared in class Xaction when inherited in class PCIeXaction implicitly of the enumerated type PCIeXaction::command_t which includes the new additional commands.

What I show above is a greatly limited approach to extending typedef'd enumerated types (the parent typedef enum must be declared as "virtual" inside of a parent class and can only be extended in a descendent class). However, I had a case which would require a much more relaxed ability to extend an enumeration. Say that we have the following:

virtual class Xaction;
  typedef enum {MEMORY, IO, CONFIG} destination_type_t;
  typedef enum {HIGH_MEM, LOW_MEM, HIGH_IO, LOW_IO, HIGH_CFG, LOW_CFG} destination_t;

  rand destination_typet_t destination_t;
  rand destination_t destination;

  constraint memory_destination_c {
    (destination_type_t == MEMORY) => (destination_t inside {HIGH_MEM, LOW_MEM});
  }

  constraint config_destination_c {
    (destination_type_t == CONFIG) => (destination_t inside {HIGH_CFG, LOW_CFG});
  }

  constraint io_destination_c {
    (destination_type_t == IO) => (destination_t inside {HIGH_IO, LOW_IO});
  }
endclass

The above class would be used by all of the BFMs in my environment. In my testbench/test I'd specify additional enumerated values for destination, and then override the constraints in the Xaction class to clarify the relationship between destination_type_t and destination. In order to make use of that, I would need to not only be able to extend the enumerated type for destination_t, but I would also need to be able to do something with constraint composition to override the constraints in class Xaction with my new relationships between destination_type and my new destination values. (I'd also use constraint composition to define relationships between destination and address).

Second usage discussion from an 'e' user

I think there are 2 main buckets of reasons for the enum extension:

- General extensibility benefits partly discussed already and that I'll touch on more below

- To support the "when extension" form of AOP that exists in e which enables some level of randomization of the actual class sub-type of an object when the object is randomized. I don't expect this to show up in SVTB so I won't mention it more.

First I'll mention the key problems I see with using the custom class approach:

- You don't get any compile time checking of the validity of "values" in code. Thinking about having to do this makes me feel like I'm reverting to our Perl/Mace days where we used strings all over the place and wouldn't find simple typo problems until way into the simulation. In our current large super-cluster/fullchip DUTs where it can take multiple hours just to get through reset and start executing most of the TE/test code, this can be a real issue.

- The other consistency/usability/maintenance issues Tom mentions:

o It runs slower

o It is more complicated and requires someone to write, maintain, and understand their complexity.

o It's not user friendly. You have to teach the test bench writers how to use it when they already know how to use enums.

o It's not standardized and therefore not IP re-use friendly. Many different incantations will evolve.

Some statistics for user defined enum types in our test environments:

- Total user defined enum types: 902

- User enum types with extensions: 72 (~8%)

I think this is a fairly large number of enumerated types compared to what I've seen in other non-e code. I expect that if e didn't have enum type extension support then the total number enum types would decrease by more than the number of enum types that actually have extensions (out of concern for potential need for "extension" support).

I expect if you look at the existing UVM SVTB infrastructure there are probably a decent number of examples where if enum type extensions existed then some functions/tasks could have used enum types for inputs instead of either: a) strings or b) integers that are paired with parameters/defines for each supported value. They key advantage the enums would have provided is the compile time checking (and debug-ability when replacing integers). Some specific examples that quickly popped into my head where enum types may have been usable (I don't have strong SVTB knowledge):

- Some of the sequence interface methods where "kind" is a string

- The factory by-name methods where the class name is passed as a string

- Some of the by-name register package methods (such as the field names)

Third usage discussion:

Here are two examples I can think of [for enumerate extension]:

1) Extend enum tied with extending/overloading functions. This is just a common/generic problem I cannot have a limited number of examples.

Class X has enum list A and function with arg of type A
Subclass Y inherits X but wants to extend the same function and handle extended definition of A

Workaround: implement new function, accept new enum type B, accept integer instead of enum. All of which are just defect possibilities from a maintenance perspective

Think certain sequence could fill in a particular cmd field of type A with any of options defined by A. As different designs being worked on in parallel add different options to A you can have derived sequences with overloaded methods to implement the new options (I can think of interrupt types, error injection choices, power management states, and so on)

2) Full/partial template specialization. This is mainly a C++ concept. You have a template method/class and for particular parameter you should be able to fully specialize the implementation (define something different from the generalized template definition). Similarly in 'e' is runtime when inheritance where I could not touch a lot of legacy code in [projectX] that assumed things about system agent unit bindings and hierarchy. So I extended an existing enum and used when inheritance to redefine how the unit works when data member is selected to be the new option.

I think SV has parameterized functions. If it has the ability to specialize them, then with enumerate extension you have the ability to extend enum and have full/partial specialization. Once again another generic example I use heavily in class specialization.

In general this extension capability will reduce a lot of pain for both OOP and AOP and making sure developers don't fallback to plain integers when they could be defining and extending compiler-checked value set.

I can see this being controversial in terms of how to extend (add to end, add to start, fully redefine the list, redefine value of existing label). So it needs to be worked carefully at least introducing syntax that can grow to other future cases.

-- 
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.
Received on Tue May 24 10:54:37 2011

This archive was generated by hypermail 2.1.8 : Tue May 24 2011 - 10:55:04 PDT