cycle
interface is typically implemented by
processors, but can be implemented by other objects as well. Its purpose is
to handle events based on time. The cycle queue has a cycle as the smallest
time unit. The cycle queue also has an associated frequency which makes it
possible to define events based on seconds or picoseconds.
The get_frequency function returns the frequency in Hertz for
the queue. Most objects implementing cycle
also
have a notification mechanism for frequency changes through the
simple_dispatcher
interface in the cpu_frequency
port. It is recommended that such a notification mechanism is used to get
updates rather than polling with get_frequency.
The current number of cycles executed by the queue is returned by get_cycle_count. Time elapsed since the queue was created is returned by get_time (in seconds) and get_time_in_ps (in picoseconds); this will be equal to the value returned by get_cycle_count divided by the value returned by get_frequency if the frequency has been constant since time zero.
The cycles_delta function returns the highest number of cycles obj can run before it passes the absolute local time when, assuming no frequency change occurs in the meantime. Note that cycles_delta can raise an exception if when was too far ahead in the future. The cycles_delta_from_ps function performs the same function, for an absolute local time expressed in picoseconds.
The post_cycle function will schedule an event that will occur after cycles counted from local current time at queue. The post_time function is similar but takes seconds as argument, while post_time_in_ps takes a number of picoseconds. The arguments cycles, seconds and picoseconds must be nonnegative.
An event previously posted can be removed by calling cancel. The
cancel function takes a function pred as argument
which is called when a matching event is found. The event is only removed if
pred returns 1
.
The find_next_cycle, find_next_time and
find_next_time_as_ps functions take the same arguments as
cancel but only return the number of cycles, seconds or
picoseconds before the event occur. The evclass is the event
class, obj is the object posting the event, and
user_data is pointer to data used as a parameter when calling
the callback function defined in the evclass.
If no matching event was found, find_next_cycle and
find_next_time return −1;
find_next_time_as_ps returns ILLEGAL_DURATION
.
The events method returns a list of all pending events in expiration order. Each element is a four-element list containing the event object, the event class name, the expiration time counted in cycles as an integer and the event description as given by the event class describe method, or NIL for events whose event class does not define that method.
What happens to already posted events when a frequency change occurs is implementation dependent. Simics processors will scale the cycle queue to keep the time left before triggering events equal across the frequency change. Note that the new times will be rounded to entire cycles during the scaling, so approximations may occur when switching between high and low frequencies.
Objects implementing the cycle interface are usually meant to be scheduled by Simics itself. For this to happen, a number of conditions must be fulfilled:
cycle
interface
must be controlled by an object implementing the execute
interface. It can be the same object that implements the
execute
interface. The object implementing the
execute
interface points to the object implementing the
cycle
interface via its queue attribute.cycle
interface
must inform Simics about changes in frequency by calling the
VT_clock_frequency_change function. That also applies to the
initial frequency set when the object is created.cycle
interface must be
registered with SIM_register_clock, which will also add some
Simics specific attributes to the corresponding class. Beyond those, the
implementor of the cycle
can use any checkpoint
representation. The name field in the event class data
structure is unique, and the attribute setter function for checkpoint restore
can use VT_get_event_class to get the event class structure
corresponding to an event class name.SIM_INTERFACE(cycle) { cycles_t (*get_cycle_count)(conf_object_t *queue); double (*get_time)(conf_object_t *queue); cycles_t (*cycles_delta)(conf_object_t *NOTNULL clock, double when); uint64 (*get_frequency)(conf_object_t *queue); void (*post_cycle)( conf_object_t *NOTNULL queue, event_class_t *NOTNULL evclass, conf_object_t *NOTNULL obj, cycles_t cycles, lang_void *user_data); void (*post_time)( conf_object_t *NOTNULL queue, event_class_t *NOTNULL evclass, conf_object_t *NOTNULL obj, double seconds, lang_void *user_data); void (*cancel)( conf_object_t *NOTNULL queue, event_class_t *NOTNULL evclass, conf_object_t *NOTNULL obj, int (*pred)(lang_void *data, lang_void *match_data), lang_void *match_data); cycles_t (*find_next_cycle)( conf_object_t *NOTNULL queue, event_class_t *NOTNULL evclass, conf_object_t *NOTNULL obj, int (*pred)(lang_void *data, lang_void *match_data), lang_void *match_data); double (*find_next_time)( conf_object_t *NOTNULL queue, event_class_t *NOTNULL evclass, conf_object_t *NOTNULL obj, int (*pred)(lang_void *data, lang_void *match_data), lang_void *match_data); attr_value_t (*events)(conf_object_t *NOTNULL obj); /* new picoseconds based functions */ local_time_t (*get_time_in_ps)(conf_object_t *queue); cycles_t (*cycles_delta_from_ps)(conf_object_t *NOTNULL clock, local_time_t when); void (*post_time_in_ps)( conf_object_t *NOTNULL queue, event_class_t *NOTNULL evclass, conf_object_t *NOTNULL obj, duration_t picoseconds, lang_void *user_data); duration_t (*find_next_time_in_ps)( conf_object_t *NOTNULL queue, event_class_t *NOTNULL evclass, conf_object_t *NOTNULL obj, int (*pred)(lang_void *data, lang_void *match_data), lang_void *match_data); }; #define CYCLE_INTERFACE "cycle"