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