cpu: implement a bi-mode branch predictor
[gem5.git] / src / cpu / base.hh
index 8557b5bd5eca86c17cb9036c830aaec4b2ec5c42..cc3f861cca93583fd66f19d7f82597204bff1b52 100644 (file)
@@ -1,4 +1,16 @@
 /*
+ * Copyright (c) 2011-2013 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
  * Copyright (c) 2002-2005 The Regents of The University of Michigan
  * Copyright (c) 2011 Regents of the University of California
  * All rights reserved.
 
 #include <vector>
 
+// Before we do anything else, check if this build is the NULL ISA,
+// and if so stop here
+#include "config/the_isa.hh"
+#if THE_ISA == NULL_ISA
+#include "arch/null/cpu_dummy.hh"
+#else
+#include "arch/interrupts.hh"
 #include "arch/isa_traits.hh"
 #include "arch/microcode_rom.hh"
 #include "base/statistics.hh"
-#include "config/full_system.hh"
-#include "config/the_isa.hh"
+#include "mem/mem_object.hh"
 #include "sim/eventq.hh"
+#include "sim/full_system.hh"
 #include "sim/insttracer.hh"
-#include "mem/mem_object.hh"
-
-#if FULL_SYSTEM
-#include "arch/interrupts.hh"
-#endif
+#include "sim/system.hh"
 
-class BaseCPUParams;
-class BranchPred;
+struct BaseCPUParams;
 class CheckerCPU;
 class ThreadContext;
-class System;
-class Port;
-
-namespace TheISA
-{
-    class Predecoder;
-}
 
 class CPUProgressEvent : public Event
 {
@@ -85,8 +92,7 @@ class CPUProgressEvent : public Event
 class BaseCPU : public MemObject
 {
   protected:
-    // CPU's clock period in terms of the number of ticks of curTime.
-    Tick clock;
+
     // @todo remove me after debugging with legion done
     Tick instCnt;
     // every cpu has an id, put it in the base cpu
@@ -95,37 +101,93 @@ class BaseCPU : public MemObject
     // therefore no setCpuId() method is provided
     int _cpuId;
 
+    /** Each cpu will have a socket ID that corresponds to its physical location
+     * in the system. This is usually used to bucket cpu cores under single DVFS
+     * domain. This information may also be required by the OS to identify the
+     * cpu core grouping (as in the case of ARM via MPIDR register)
+     */
+    const uint32_t _socketId;
+
+    /** instruction side request id that must be placed in all requests */
+    MasterID _instMasterId;
+
+    /** data side request id that must be placed in all requests */
+    MasterID _dataMasterId;
+
+    /** An intrenal representation of a task identifier within gem5. This is
+     * used so the CPU can add which taskId (which is an internal representation
+     * of the OS process ID) to each request so components in the memory system
+     * can track which process IDs are ultimately interacting with them
+     */
+    uint32_t _taskId;
+
+    /** The current OS process ID that is executing on this processor. This is
+     * used to generate a taskId */
+    uint32_t _pid;
+
+    /** Is the CPU switched out or active? */
+    bool _switchedOut;
+
+    /** Cache the cache line size that we get from the system */
+    const unsigned int _cacheLineSize;
+
   public:
+
+    /**
+     * Purely virtual method that returns a reference to the data
+     * port. All subclasses must implement this method.
+     *
+     * @return a reference to the data port
+     */
+    virtual MasterPort &getDataPort() = 0;
+
+    /**
+     * Purely virtual method that returns a reference to the instruction
+     * port. All subclasses must implement this method.
+     *
+     * @return a reference to the instruction port
+     */
+    virtual MasterPort &getInstPort() = 0;
+
     /** Reads this CPU's ID. */
-    int cpuId() { return _cpuId; }
+    int cpuId() const { return _cpuId; }
+
+    /** Reads this CPU's Socket ID. */
+    uint32_t socketId() const { return _socketId; }
+
+    /** Reads this CPU's unique data requestor ID */
+    MasterID dataMasterId() { return _dataMasterId; }
+    /** Reads this CPU's unique instruction requestor ID */
+    MasterID instMasterId() { return _instMasterId; }
+
+    /**
+     * Get a master port on this CPU. All CPUs have a data and
+     * instruction port, and this method uses getDataPort and
+     * getInstPort of the subclasses to resolve the two ports.
+     *
+     * @param if_name the port name
+     * @param idx ignored index
+     *
+     * @return a reference to the port with the given name
+     */
+    BaseMasterPort &getMasterPort(const std::string &if_name,
+                                  PortID idx = InvalidPortID);
+
+    /** Get cpu task id */
+    uint32_t taskId() const { return _taskId; }
+    /** Set cpu task id */
+    void taskId(uint32_t id) { _taskId = id; }
+
+    uint32_t getPid() const { return _pid; }
+    void setPid(uint32_t pid) { _pid = pid; }
 
-//    Tick currentTick;
-    inline Tick frequency() const { return SimClock::Frequency / clock; }
-    inline Tick ticks(int numCycles) const { return clock * numCycles; }
-    inline Tick curCycle() const { return curTick() / clock; }
-    inline Tick tickToCycles(Tick val) const { return val / clock; }
     inline void workItemBegin() { numWorkItemsStarted++; }
     inline void workItemEnd() { numWorkItemsCompleted++; }
     // @todo remove me after debugging with legion done
     Tick instCount() { return instCnt; }
 
-    /** The next cycle the CPU should be scheduled, given a cache
-     * access or quiesce event returning on this cycle.  This function
-     * may return curTick() if the CPU should run on the current cycle.
-     */
-    Tick nextCycle();
-
-    /** The next cycle the CPU should be scheduled, given a cache
-     * access or quiesce event returning on the given Tick.  This
-     * function may return curTick() if the CPU should run on the
-     * current cycle.
-     * @param begin_tick The tick that the event is completing on.
-     */
-    Tick nextCycle(Tick begin_tick);
-
     TheISA::MicrocodeRom microcodeRom;
 
-#if FULL_SYSTEM
   protected:
     TheISA::Interrupts *interrupts;
 
@@ -142,7 +204,8 @@ class BaseCPU : public MemObject
     postInterrupt(int int_num, int index)
     {
         interrupts->post(int_num, index);
-        wakeup();
+        if (FullSystem)
+            wakeup();
     }
 
     void
@@ -160,7 +223,7 @@ class BaseCPU : public MemObject
     bool
     checkInterrupts(ThreadContext *tc) const
     {
-        return interrupts->checkInterrupts(tc);
+        return FullSystem && interrupts->checkInterrupts(tc);
     }
 
     class ProfileEvent : public Event
@@ -174,11 +237,9 @@ class BaseCPU : public MemObject
         void process();
     };
     ProfileEvent *profileEvent;
-#endif
 
   protected:
     std::vector<ThreadContext *> threadContexts;
-    std::vector<TheISA::Predecoder *> predecoders;
 
     Trace::InstTracer * tracer;
 
@@ -193,28 +254,31 @@ class BaseCPU : public MemObject
     /// Notify the CPU that the indicated context is now active.  The
     /// delay parameter indicates the number of ticks to wait before
     /// executing (typically 0 or 1).
-    virtual void activateContext(int thread_num, int delay) {}
+    virtual void activateContext(ThreadID thread_num, Cycles delay) {}
 
     /// Notify the CPU that the indicated context is now suspended.
-    virtual void suspendContext(int thread_num) {}
+    virtual void suspendContext(ThreadID thread_num) {}
 
     /// Notify the CPU that the indicated context is now deallocated.
-    virtual void deallocateContext(int thread_num) {}
+    virtual void deallocateContext(ThreadID thread_num) {}
 
     /// Notify the CPU that the indicated context is now halted.
-    virtual void haltContext(int thread_num) {}
+    virtual void haltContext(ThreadID thread_num) {}
 
    /// Given a Thread Context pointer return the thread num
    int findContext(ThreadContext *tc);
 
    /// Given a thread num get tho thread context for it
-   ThreadContext *getContext(int tn) { return threadContexts[tn]; }
+   virtual ThreadContext *getContext(int tn) { return threadContexts[tn]; }
+
+   /// Get the number of thread contexts available
+   unsigned numContexts() { return threadContexts.size(); }
 
   public:
     typedef BaseCPUParams Params;
     const Params *params() const
     { return reinterpret_cast<const Params *>(_params); }
-    BaseCPU(Params *params);
+    BaseCPU(Params *params, bool is_checker = false);
     virtual ~BaseCPU();
 
     virtual void init();
@@ -225,13 +289,56 @@ class BaseCPU : public MemObject
 
     void registerThreadContexts();
 
-    /// Prepare for another CPU to take over execution.  When it is
-    /// is ready (drained pipe) it signals the sampler.
+    /**
+     * Prepare for another CPU to take over execution.
+     *
+     * When this method exits, all internal state should have been
+     * flushed. After the method returns, the simulator calls
+     * takeOverFrom() on the new CPU with this CPU as its parameter.
+     */
     virtual void switchOut();
 
-    /// Take over execution from the given CPU.  Used for warm-up and
-    /// sampling.
-    virtual void takeOverFrom(BaseCPU *, Port *ic, Port *dc);
+    /**
+     * Load the state of a CPU from the previous CPU object, invoked
+     * on all new CPUs that are about to be switched in.
+     *
+     * A CPU model implementing this method is expected to initialize
+     * its state from the old CPU and connect its memory (unless they
+     * are already connected) to the memories connected to the old
+     * CPU.
+     *
+     * @param cpu CPU to initialize read state from.
+     */
+    virtual void takeOverFrom(BaseCPU *cpu);
+
+    /**
+     * Flush all TLBs in the CPU.
+     *
+     * This method is mainly used to flush stale translations when
+     * switching CPUs. It is also exported to the Python world to
+     * allow it to request a TLB flush after draining the CPU to make
+     * it easier to compare traces when debugging
+     * handover/checkpointing.
+     */
+    void flushTLBs();
+
+    /**
+     * Determine if the CPU is switched out.
+     *
+     * @return True if the CPU is switched out, false otherwise.
+     */
+    bool switchedOut() const { return _switchedOut; }
+
+    /**
+     * Verify that the system is in a memory mode supported by the
+     * CPU.
+     *
+     * Implementations are expected to query the system for the
+     * current memory mode and ensure that it is what the CPU model
+     * expects. If the check fails, the implementation should
+     * terminate the simulation using fatal().
+     */
+    virtual void verifyMemoryMode() const { };
 
     /**
      *  Number of threads we're actually simulating (<= SMT_MAX_THREADS).
@@ -255,31 +362,87 @@ class BaseCPU : public MemObject
 
     System *system;
 
-    Tick phase;
+    /**
+     * Get the cache line size of the system.
+     */
+    inline unsigned int cacheLineSize() const { return _cacheLineSize; }
 
-#if FULL_SYSTEM
     /**
      * Serialize this object to the given output stream.
+     *
+     * @note CPU models should normally overload the serializeThread()
+     * method instead of the serialize() method as this provides a
+     * uniform data format for all CPU models and promotes better code
+     * reuse.
+     *
      * @param os The stream to serialize to.
      */
     virtual void serialize(std::ostream &os);
 
     /**
      * Reconstruct the state of this object from a checkpoint.
+     *
+     * @note CPU models should normally overload the
+     * unserializeThread() method instead of the unserialize() method
+     * as this provides a uniform data format for all CPU models and
+     * promotes better code reuse.
+
      * @param cp The checkpoint use.
-     * @param section The section name of this object
+     * @param section The section name of this object.
      */
     virtual void unserialize(Checkpoint *cp, const std::string &section);
 
-#endif
+    /**
+     * Serialize a single thread.
+     *
+     * @param os The stream to serialize to.
+     * @param tid ID of the current thread.
+     */
+    virtual void serializeThread(std::ostream &os, ThreadID tid) {};
 
     /**
-     * Return pointer to CPU's branch predictor (NULL if none).
-     * @return Branch predictor pointer.
+     * Unserialize one thread.
+     *
+     * @param cp The checkpoint use.
+     * @param section The section name of this thread.
+     * @param tid ID of the current thread.
      */
-    virtual BranchPred *getBranchPred() { return NULL; };
+    virtual void unserializeThread(Checkpoint *cp, const std::string &section,
+                                   ThreadID tid) {};
 
-    virtual Counter totalInstructions() const = 0;
+    virtual Counter totalInsts() const = 0;
+
+    virtual Counter totalOps() const = 0;
+
+    /**
+     * Schedule an event that exits the simulation loops after a
+     * predefined number of instructions.
+     *
+     * This method is usually called from the configuration script to
+     * get an exit event some time in the future. It is typically used
+     * when the script wants to simulate for a specific number of
+     * instructions rather than ticks.
+     *
+     * @param tid Thread monitor.
+     * @param insts Number of instructions into the future.
+     * @param cause Cause to signal in the exit event.
+     */
+    void scheduleInstStop(ThreadID tid, Counter insts, const char *cause);
+
+    /**
+     * Schedule an event that exits the simulation loops after a
+     * predefined number of load operations.
+     *
+     * This method is usually called from the configuration script to
+     * get an exit event some time in the future. It is typically used
+     * when the script wants to simulate for a specific number of
+     * loads rather than ticks.
+     *
+     * @param tid Thread monitor.
+     * @param loads Number of load instructions into the future.
+     * @param cause Cause to signal in the exit event.
+     */
+    void scheduleLoadStop(ThreadID tid, Counter loads, const char *cause);
 
     // Function tracing
   private:
@@ -291,25 +454,35 @@ class BaseCPU : public MemObject
     void enableFunctionTrace();
     void traceFunctionsInternal(Addr pc);
 
-  protected:
+  private:
+    static std::vector<BaseCPU *> cpuList;   //!< Static global cpu list
+
+  public:
     void traceFunctions(Addr pc)
     {
         if (functionTracingEnabled)
             traceFunctionsInternal(pc);
     }
 
-  private:
-    static std::vector<BaseCPU *> cpuList;   //!< Static global cpu list
-
-  public:
     static int numSimulatedCPUs() { return cpuList.size(); }
-    static Counter numSimulatedInstructions()
+    static Counter numSimulatedInsts()
     {
         Counter total = 0;
 
         int size = cpuList.size();
         for (int i = 0; i < size; ++i)
-            total += cpuList[i]->totalInstructions();
+            total += cpuList[i]->totalInsts();
+
+        return total;
+    }
+
+    static Counter numSimulatedOps()
+    {
+        Counter total = 0;
+
+        int size = cpuList.size();
+        for (int i = 0; i < size; ++i)
+            total += cpuList[i]->totalOps();
 
         return total;
     }
@@ -321,4 +494,6 @@ class BaseCPU : public MemObject
     Stats::Scalar numWorkItemsCompleted;
 };
 
+#endif // THE_ISA == NULL_ISA
+
 #endif // __CPU_BASE_HH__