
Next: Fetch Stage Up: Out of Order Processor Previous: Introduction Contents
Subsections
The out of order core is spread across several source files:
- ooocore.cpp contains control logic, the definition of the OutOfOrderMachine class and its functions (see Section 15.3), the top-level pipeline control functions, all event printing logic (Section 16.1) and miscellaneous code.
- ooopipe.cpp contains all pipeline stages, except for execution stages and functional units.
- oooexec.cpp contains the functional units, load/store unit, issue queues, replay control and exception handling.
- ooocore.h defines all structures and lists easy to configure parameters.
The OutOfOrderMachine structure is divided into an array of one or more OutOfOrderCore structures (by default, one per VCPU). The OutOfOrderMachine::init() function creates contextcount cores and binds one per-VCPU Context structure to each core. The init() function is declared in ooocore.h, since some user configurable state is set up at this point.
The OutOfOrderMachine::run() function first flushes the pipeline in each core, using core.flush_pipeline() to copy state from the corresponding Context structure into the physical register file and other per-core structures (see Section 24.6 for details).
The run() function then enters a loop with one iteration per simulated cycle:
- update_progress() prints the current performance information (cycles, committed instructions and simulated cycles/second) to the console and/or log file.
- inject_events() injects any pending interrupts and outside events into the processor; these will be processed at the next x86 instruction boundary. This function only applies to full system PTLsim/X.
- The OutOfOrderCore::runcycle() function is called for each core in sequence, to step its entire state machine forward by one cycle (see below for details). If a given core is blocked (i.e. paused while waiting for some outside event), its Context.running field is zero; in this case, the core's handle_interrupt() method may be called to wake it up (see below).
- Any global structures (like memory controllers or interconnect networks) are clocked by one cycle using their respective clock() methods.
- check_for_async_sim_break() checks if the user has requested the simulation stop or switch back to native mode. This function only applies to full system PTLsim/X.
- The global cycle counter and other counters are incremented.
The OutOfOrderCore::runcycle() function is where the majority of the work in PTLsim's out of order model occurs. This function, in ooocore.cpp, runs one cycle in the core by calling functions to implement each pipeline stage, the per-core data caches and other clockable structure. If the core's commit stage just encountered a special event (e.g. barrier, microcode assist request, exception, interrupt, etc.), the appropriate action is taken at the cycle boundary.
In the following chapters, we describe every pipeline stage and structure in detail.
Every structure in the out of order model can obtain a reference to its parent OutOfOrderCore structure by calling its own getcore() method. Similarly, getcore().ctx returns a reference to the Contextstructure for that core.
Event Log Ring Buffer
Section 10.5 describes PTLsim's event log ring buffer system, in which the simulator can log all per-cycle events to a circular ring buffer when the -ringbuf option is given. The ring buffer can help developers look backwards in time from when an undesirable event occurs (for instance, as specified by -ringbuf-trigger-rip), allowing much easier debugging and experimentation.
In the out of order core, the EventLog structure provides this ring buffer. The buffer consists of an array of OutOfOrderCoreEvent structures (in ooocore.h); each structure contains a fixed header with subject information common to all events (e.g. the cycle, uuid, RIP, uop, ROB slot, and so forth), plus a union with sub-structures for each possible event type. The actual events are listed in an enum above this structure.
The EventLog class has various functions for quickly adding certain types of events and filling in their special fields. Specifically, calling one of the EventLog::add() functions allocates a new record in the ring buffer and returns a pointer to it, allowing additional event-specific fields to be filled in if needed. The usage of these functions is very straightforward and documented by example in the various out of order core source files.
In ooocore.cpp, the OutOfOrderCoreEvent::print() method lists all event types and gives code to nicely format the recorded event data. The eventlog.print() function prints every event in the ring buffer; this function can be called from anywhere an event backtrace is needed.

Next: Fetch Stage Up: Out of Order Processor Previous: Introduction Contents
Matt T Yourst 2007-09-26