There are two ways in e to define an event to be sensitive to a change of value in the simulator:
1. Use simple_port and bind it to the HDL object. Then create an event that will be sensitive to rise/fall/change of that port value with the @sim sampling event:
sig_p : inout simple_port of bit is instance;
keep sig_p.hdl_path() == "sig";
event sig_e is rise/fall/change (sig_p$)@sim;
2. Use an event_port and define its edge() attribute to reflect the sensitivity:
sig_ep : in event_port is instance;
keep sig_ep.hdl_path() == "sig";
keep sig_p.edge() == rise/fall/change;
This blog post discusses the differences between those two approaches.
Let's divide the difference into several aspects:
1. Performance
2. Functionality
3. Synchronization
1. Performance Is probably the most important of them all.
We have 2 main usages:
- A standard usage, i.e. get a single event with a specific edge whenever a value is changed in the simulator (clock would be the most common usage)
- An enhanced usage that needs two (or more) events on different edges of the simulator object.
For both usages we would prefer an event_port .
The reason for that is that event_port saves calls to the Specman tick since the edge transition condition is checked before the Specman tick.
The edge() attribute of an event_port can take only one value, so multiple edges will require multiple event_ports, while one simple_port can define as many events on different edges of the value change as required. But an event_port will still run faster.
2. Functionality:
- Variation of ports as an argument in the event expression.
We have to differentiate between two main options:
(1) Not using the edge() attribute (sensitivity is ‘any change')
The main power of an event_port is the sensitivity to a change. In fact, without specifying any edge(), the default will be a "change". So if you use an event_port without an edge (i.e. sensitive to ‘any change') it will be able to detect a change on Types bigger than 32 bit.
Since the argument to change|fall|rise in the event expression
e.g. (event ev is change|fall|rise (<argument>) @sim)
for simple_port has to be less than or equal to 32 bit, event_port with no edge() has a big advantage on these cases, as it can connect with HDL signals bigger than 32-bit
(2) Using the edge() attribute
When we need a different edge() than a change (rise,fall, MVL transitions) than we lose the advantages of event_port mentioned above, because event_port with an edge() specified can take only a single-bit HDL object.
Simple_port will detect those edges for multi-bit HDL objects as well (as mentioned - non part-select and smaller than 32 bits) but will operate only on the LSB of the port. For example : 1010101 -> 1111110 is considered a fall.
- Reading the value
Unlike a simple_port, an event port does not store the value of the sampling HDL signal it is connected to. It just emits itself at every sampling point (edge) and in turn it activates the TCMs depending upon it. Thus you can't print or use the values of event port itself using ‘$' suffix etc. Please also see the outlined limitations at the end of the document for event ports.
On the other hand simple_port stores the value of the sampling HDL signal it is connected to. Thus you can print or use the values of simple port itself using ‘$' suffix.
- Ability to disable/enable the port (From SN 12.1)
Another advantage of using event_port over simple_port would be the disable()/enable() feature that is available from Specman version 12.1. This gives you an option to deactivate the port for a period of time in your simulation, and then activate it back if needed. Let's say you have a reset procedure, in which you don't want to keep getting events from the event_port that is connected to your clock. You simply disable the event_port at the beginning of the reset procedure, and enable it back at the end.
- Transition of MVLs
When you want to detect a transition in Multi Value Logic values, Using event_port's edge() attribute with the MVL_X_to_0, MVL_Z_to_1 options allows you this functionality without specifying or dealing with MVL conversion methods, or MVL types for the port itself.
3. Synchronization:
- Event_port works through glitches
Event_ports are able to catch the desired edge() even in case of glitches. Event_port will detect every change, and when the Specman tick occurs it will issue the correct event (rise, fall ,change - according to edge() attribute). It still holds the current value after every change, so it will be able to calculate any further change yet to come. So we can say that if we have glitches in our design, event port will detect all zero time changes.
Do we want that?
That's specific for a design...
Here is an example:
As you can see there is a glitch on clk2 at time 50ns. The signal ‘clk2' asserted at 50(2)ns and de-asserted at 50(3)ns causing a glitch. The event port connected to ‘clk2' emits the event at clk 0->1 and also it keeps on monitoring ‘clk2' to for any further changes in same simulation cycle. Thus at the end of simulation time 50ns it would know the value of clk2 as 0.
- Simple_port will ignore the glitch (and will miss next event)
When combining simple_port with @sim event, Specman will detect the change and will sample the value at the next Specman tick. The problem with this approach is that the value might change several times in that time period (between the change and the sampling) and the values in between are not seen by simple_port. This might cause unexpected results when glitches are encountered. Specman samples the attached HDL signal in a particular tick and compares it with the value that was sampled in the previous tick. So if there are any glitches in same simulation time, it will miss the changed value. This causes incorrect sampling in subsequent cycle. So we can say that if we have glitches in our design, simple_port will simply "ignore" all subsequent changes between ticks, hence ignoring the glitch.
Let us take the same example:
As you can see there is a glitch on clk2 at time 50ns. The signal ‘clk2' asserted at 50(2)ns and de-asserted at 50(3)ns causing a glitch. The simple port connected to ‘clk2' samples it as clk2 0->1 and then does not sample ‘clk2' to for any further changes (1 -> 0) in same simulation cycle until next tick, in which the value is 1 again. Thus at the end of simulation time 50ns, unlike event port, it would NOT see the change of value in ‘clk2'.
So to summarize:
- event_ports have many advantages when we need an event that creates a callback from the simulator, especially performance wise, and we would usually prefer using it as the "clock" event.
- When we have multiple bits signals in HDL that we need a more complex edge than just ‘any_change', and we would have benefit in holding the actual value of the signal - we would usually prefer using the simple_port with @sim event.
- When we have glitches in our design, it depends whether we want Specman to detect all changes in 0 time (event_port) or ignore changes in the same tick (simple_port)
Appendix:
Other limitations of event ports (Just for the completeness, taken from documentation):
- The ‘on' struct member for event ports is supported only from 11.1
- Coverage on event ports is not supported.
- The ‘echo event' command is not supported for event ports.
- You cannot specify a temporal formula (like "event_port is ...") for the definition of an out event port.
Avi Farjoun
Mahesh Soni