From a4d7bb113aa4ed398a2ec7f6fb01b6d866fba60c Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Wed, 12 May 2004 15:49:01 -0400 Subject: Make a new stat type of Value which is a scalar stat that proxies for a real C/C++ scalar value or scalar functor. This replaces the scalar() and functor() terms that were previously used in formulas. This helps when dumping statistics because the formulas are not supposed to change. cpu/base_cpu.cc: Add a number of cycles stat to the cpu object that tracks the number of cycles that the cpu has executed. This starts to pave the way for cpu cycles being different from event ticks. cpu/base_cpu.hh: provide a functor for calculating all simulated instructions of all CPUs and a virtual function for determining that number. To deal with the change from functor() to Value::functor() cpu/simple_cpu/simple_cpu.cc: simTicks -> numCycles numInsts is now a real Scalar stat, not a Formula cpu/simple_cpu/simple_cpu.hh: numInsts is now a real Scalar stat, not a Formula count all instructions sim/stat_control.cc: simInsts, simTicks, hostMemory, and hostSeconds are no longer Statistics::Formula but rather Statistics::Value add new stat for tick frequency sim/stats.hh: don't need everything to be extern. test/Makefile: Make stuff work a tad bit better test/stattest.cc: test out Statistics::Value --HG-- extra : convert_revision : c812e8baa2b17c08abf3a68ed1e1125dc6f2cfb4 --- base/statistics.hh | 218 +++++++++++++++++++++++-------------------- cpu/base_cpu.cc | 7 ++ cpu/base_cpu.hh | 20 +++- cpu/simple_cpu/simple_cpu.cc | 5 +- cpu/simple_cpu/simple_cpu.hh | 7 +- sim/stat_control.cc | 26 ++++-- sim/stats.hh | 6 +- test/Makefile | 12 ++- test/stattest.cc | 10 +- 9 files changed, 183 insertions(+), 128 deletions(-) diff --git a/base/statistics.hh b/base/statistics.hh index e7fc18d74..ee09cc622 100644 --- a/base/statistics.hh +++ b/base/statistics.hh @@ -139,11 +139,13 @@ struct StatData static bool less(StatData *stat1, StatData *stat2); }; -struct ScalarData : public StatData +class ScalarData : public StatData { + public: virtual Counter value() const = 0; virtual Result result() const = 0; virtual Result total() const = 0; + virtual void visit(Visit &visitor) { visitor.visit(*this); } }; template @@ -162,8 +164,6 @@ class ScalarStatData : public ScalarData virtual Result total() const { return s.total(); } virtual void reset() { s.reset(); } virtual bool zero() const { return s.zero(); } - - virtual void visit(Visit &visitor) { visitor.visit(*this); } }; struct VectorData : public StatData @@ -394,6 +394,16 @@ class Wrap : public Child return ptr; } + protected: + /** + * Copy constructor, copies are not allowed. + */ + Wrap(const Wrap &stat); + /** + * Can't copy stats. + */ + void operator=(const Wrap &); + public: Wrap() { @@ -726,16 +736,6 @@ class ScalarBase : public DataAccess return _bin->data(*_params); } - protected: - /** - * Copy constructor, copies are not allowed. - */ - ScalarBase(const ScalarBase &stat); - /** - * Can't copy stats. - */ - const ScalarBase &operator=(const ScalarBase &); - public: /** * Return the current value of this stat as its base type. @@ -822,6 +822,79 @@ class ScalarBase : public DataAccess }; +class ProxyData : public ScalarData +{ + public: + virtual void visit(Visit &visitor) { visitor.visit(*this); } + virtual bool binned() const { return false; } + virtual std::string str() const { return to_string(value()); } + virtual size_t size() const { return 1; } + virtual bool zero() const { return value() == 0; } + virtual bool check() const { return true; } + virtual void reset() { } +}; + +template +class ValueProxy : public ProxyData +{ + private: + T *scalar; + + public: + ValueProxy(T &val) : scalar(&val) {} + virtual Counter value() const { return *scalar; } + virtual Result result() const { return *scalar; } + virtual Result total() const { return *scalar; } +}; + +template +class FunctorProxy : public ProxyData +{ + private: + T *functor; + + public: + FunctorProxy(T &func) : functor(&func) {} + virtual Counter value() const { return (*functor)(); } + virtual Result result() const { return (*functor)(); } + virtual Result total() const { return (*functor)(); } +}; + +class ValueBase : public DataAccess +{ + private: + ProxyData *proxy; + + public: + ValueBase() : proxy(NULL) { } + ~ValueBase() { if (proxy) delete proxy; } + + template + void scalar(T &value) + { + proxy = new ValueProxy(value); + setInit(); + } + + template + void functor(T &func) + { + proxy = new FunctorProxy(func); + setInit(); + } + + Counter value() { return proxy->value(); } + Result result() const { return proxy->result(); } + Result total() const { return proxy->total(); }; + size_t size() const { return proxy->size(); } + + bool binned() const { return proxy->binned(); } + std::string str() const { return proxy->str(); } + bool zero() const { return proxy->zero(); } + bool check() const { return proxy != NULL; } + void reset() { } +}; + ////////////////////////////////////////////////////////////////////// // // Vector Statistics @@ -869,13 +942,6 @@ class VectorBase : public DataAccess return _bin->data(index, *_params); } - protected: - // Copying stats is not allowed - /** Copying stats isn't allowed. */ - VectorBase(const VectorBase &stat); - /** Copying stats isn't allowed. */ - const VectorBase &operator=(const VectorBase &); - public: void value(VCounter &vec) const { @@ -1127,11 +1193,6 @@ class Vector2dBase : public DataAccess return _bin->data(index, *_params); } - protected: - // Copying stats is not allowed - Vector2dBase(const Vector2dBase &stat); - const Vector2dBase &operator=(const Vector2dBase &); - public: Vector2dBase() {} @@ -1586,13 +1647,6 @@ class DistBase : public DataAccess return _bin->data(*_params); } - protected: - // Copying stats is not allowed - /** Copies are not allowed. */ - DistBase(const DistBase &stat); - /** Copies are not allowed. */ - const DistBase &operator=(const DistBase &); - public: DistBase() { } @@ -1659,11 +1713,6 @@ class VectorDistBase : public DataAccess return _bin->data(index, *_params); } - protected: - // Copying stats is not allowed - VectorDistBase(const VectorDistBase &stat); - const VectorDistBase &operator=(const VectorDistBase &); - public: VectorDistBase() {} @@ -1910,56 +1959,6 @@ class ConstNode : public Node virtual std::string str() const { return to_string(vresult[0]); } }; -template -class FunctorNode : public Node -{ - private: - T &functor; - mutable VResult vresult; - - public: - FunctorNode(T &f) : functor(f) { vresult.resize(1); } - const VResult &result() const - { - vresult[0] = (Result)functor(); - return vresult; - } - virtual Result total() const { return (Result)functor(); }; - - virtual size_t size() const { return 1; } - /** - * Return true if stat is binned. - *@return False since Functors aren't binned - */ - virtual bool binned() const { return false; } - virtual std::string str() const { return to_string(functor()); } -}; - -template -class ScalarNode : public Node -{ - private: - T &scalar; - mutable VResult vresult; - - public: - ScalarNode(T &s) : scalar(s) { vresult.resize(1); } - const VResult &result() const - { - vresult[0] = (Result)scalar; - return vresult; - } - virtual Result total() const { return (Result)scalar; }; - - virtual size_t size() const { return 1; } - /** - * Return true if stat is binned. - *@return False since Scalar's aren't binned - */ - virtual bool binned() const { return false; } - virtual std::string str() const { return to_string(scalar); } -}; - template struct OpString; @@ -2219,6 +2218,30 @@ class Scalar void operator=(const U &v) { Base::operator=(v); } }; +class Value + : public Wrap +{ + public: + /** The base implementation. */ + typedef ValueBase Base; + + template + Value &scalar(T &value) + { + Base::scalar(value); + return *this; + } + + template + Value &functor(T &func) + { + Base::functor(func); + return *this; + } +}; + /** * A stat that calculates the per cycle average of a value. * @sa Stat, ScalarBase, AvgStor @@ -2694,6 +2717,13 @@ class Temp Temp(const Scalar &s) : node(new ScalarStatNode(s.statData())) { } + /** + * Create a new ScalarStatNode. + * @param s The ScalarStat to place in a node. + */ + Temp(const Value &s) + : node(new ScalarStatNode(s.statData())) { } + /** * Create a new ScalarStatNode. * @param s The ScalarStat to place in a node. @@ -2861,20 +2891,6 @@ constant(T val) return NodePtr(new ConstNode(val)); } -template -inline Temp -functor(T &val) -{ - return NodePtr(new FunctorNode(val)); -} - -template -inline Temp -scalar(T &val) -{ - return NodePtr(new ScalarNode(val)); -} - inline Temp sum(Temp val) { diff --git a/cpu/base_cpu.cc b/cpu/base_cpu.cc index e00de8389..624023f0a 100644 --- a/cpu/base_cpu.cc +++ b/cpu/base_cpu.cc @@ -130,6 +130,13 @@ BaseCPU::BaseCPU(const string &_name, int _number_of_threads, void BaseCPU::regStats() { + using namespace Statistics; + + numCycles + .name(name() + ".numCycles") + .desc("number of cpu cycles simulated") + ; + int size = execContexts.size(); if (size > 1) { for (int i = 0; i < size; ++i) { diff --git a/cpu/base_cpu.hh b/cpu/base_cpu.hh index 648035732..c4826cf15 100644 --- a/cpu/base_cpu.hh +++ b/cpu/base_cpu.hh @@ -31,10 +31,10 @@ #include +#include "base/statistics.hh" #include "sim/eventq.hh" #include "sim/sim_object.hh" - -#include "targetarch/isa_traits.hh" // for Addr +#include "targetarch/isa_traits.hh" #ifdef FULL_SYSTEM class System; @@ -147,11 +147,27 @@ class BaseCPU : public SimObject */ virtual BranchPred *getBranchPred() { return NULL; }; + virtual Counter totalInstructions() const { return 0; } + private: static std::vector cpuList; //!< Static global cpu list public: static int numSimulatedCPUs() { return cpuList.size(); } + static Counter numSimulatedInstructions() + { + Counter total = 0; + + int size = cpuList.size(); + for (int i = 0; i < size; ++i) + total += cpuList[i]->totalInstructions(); + + return total; + } + + public: + // Number of CPU cycles simulated + Statistics::Scalar<> numCycles; }; #endif // __BASE_CPU_HH__ diff --git a/cpu/simple_cpu/simple_cpu.cc b/cpu/simple_cpu/simple_cpu.cc index 065140883..56ea0ae11 100644 --- a/cpu/simple_cpu/simple_cpu.cc +++ b/cpu/simple_cpu/simple_cpu.cc @@ -287,8 +287,6 @@ SimpleCPU::regStats() ; idleFraction = constant(1.0) - notIdleFraction; - numInsts = Statistics::scalar(numInst) - Statistics::scalar(startNumInst); - simInsts += numInsts; } void @@ -590,6 +588,8 @@ SimpleCPU::post_interrupt(int int_num, int index) void SimpleCPU::tick() { + numCycles++; + traceData = NULL; Fault fault = No_Fault; @@ -697,6 +697,7 @@ SimpleCPU::tick() // keep an instruction count numInst++; + numInsts++; // check for instruction-count-based events comInstEventQueue[0]->serviceEvents(numInst); diff --git a/cpu/simple_cpu/simple_cpu.hh b/cpu/simple_cpu/simple_cpu.hh index 4977e6992..07d6cb0c9 100644 --- a/cpu/simple_cpu/simple_cpu.hh +++ b/cpu/simple_cpu/simple_cpu.hh @@ -204,7 +204,12 @@ class SimpleCPU : public BaseCPU // number of simulated instructions Counter numInst; Counter startNumInst; - Statistics::Formula numInsts; + Statistics::Scalar<> numInsts; + + virtual Counter totalInstructions() const + { + return numInst - startNumInst; + } // number of simulated memory references Statistics::Scalar<> numMemRefs; diff --git a/sim/stat_control.cc b/sim/stat_control.cc index d6d7e2c91..c7d2fdd5b 100644 --- a/sim/stat_control.cc +++ b/sim/stat_control.cc @@ -39,6 +39,7 @@ #include "base/str.hh" #include "base/time.hh" #include "base/stats/output.hh" +#include "cpu/base_cpu.hh" #include "sim/eventq.hh" #include "sim/sim_object.hh" #include "sim/stat_control.hh" @@ -47,13 +48,14 @@ using namespace std; Statistics::Formula hostInstRate; -Statistics::Formula hostMemory; -Statistics::Formula hostSeconds; Statistics::Formula hostTickRate; +Statistics::Value hostMemory; +Statistics::Value hostSeconds; -Statistics::Formula simInsts; +Statistics::Value simTicks; +Statistics::Value simInsts; +Statistics::Value simFreq; Statistics::Formula simSeconds; -Statistics::Formula simTicks; namespace Statistics { @@ -84,6 +86,7 @@ void InitSimStats() { simInsts + .functor(BaseCPU::numSimulatedInstructions) .name("sim_insts") .desc("Number of instructions simulated") .precision(0) @@ -95,7 +98,14 @@ InitSimStats() .desc("Number of seconds simulated") ; + simFreq + .scalar(ticksPerSecond) + .name("sim_freq") + .desc("Frequency of simulated ticks") + ; + simTicks + .scalar(curTick) .name("sim_ticks") .desc("Number of ticks simulated") ; @@ -108,12 +118,14 @@ InitSimStats() ; hostMemory + .functor(memUsage) .name("host_mem_usage") .desc("Number of bytes of host memory used") .prereq(hostMemory) ; hostSeconds + .functor(statElapsedTime) .name("host_seconds") .desc("Real time elapsed on the host") .precision(2) @@ -125,11 +137,7 @@ InitSimStats() .precision(0) ; - simInsts = constant(0); - simTicks = scalar(curTick) - scalar(startTick); - simSeconds = simTicks / scalar(ticksPerSecond); - hostMemory = functor(memUsage); - hostSeconds = functor(statElapsedTime); + simSeconds = simTicks / simFreq; hostInstRate = simInsts / hostSeconds; hostTickRate = simTicks / hostSeconds; diff --git a/sim/stats.hh b/sim/stats.hh index b736850e7..c5e791cfb 100644 --- a/sim/stats.hh +++ b/sim/stats.hh @@ -31,11 +31,7 @@ #include "base/statistics.hh" -extern Statistics::Formula simTicks; extern Statistics::Formula simSeconds; -extern Statistics::Formula simInsts; -extern Statistics::Formula hostSeconds; -extern Statistics::Formula hostTickRate; -extern Statistics::Formula hostInstRate; +extern Statistics::Value simTicks; #endif // __SIM_SIM_STATS_HH__ diff --git a/test/Makefile b/test/Makefile index bf4200ba3..15019a1f5 100644 --- a/test/Makefile +++ b/test/Makefile @@ -2,18 +2,24 @@ CC?= gcc CXX?= g++ +PYTHON?=/usr/bin/env python CURDIR?= $(shell /bin/pwd) -SRCDIR?= .. +SRCDIR?= $(CURDIR)/.. CCFLAGS= -g -O0 -MMD -I. -I$(SRCDIR) -I- -DTRACING_ON=0 MYSQL= -I/usr/include/mysql -L/usr/lib/mysql -lmysqlclient -VPATH=$(SRCDIR) +VPATH=$(SRCDIR):$(CURDIR) default: @echo "You must specify a target" +base/traceflags.cc base/traceflags.hh: $(SRCDIR)/base/traceflags.py + mkdir -p base; \ + cd base; \ + $(PYTHON) $< + bitvectest: test/bitvectest.cc $(CXX) $(CCFLAGS) -o $@ $^ @@ -61,5 +67,5 @@ tracetest: $(TRACE) $(CXX) $(CCFLAGS) -o $@ $^ clean: - @rm -f *test *~ .#* *.core core + @rm -rf *test *~ .#* *.core core base .PHONY: clean diff --git a/test/stattest.cc b/test/stattest.cc index 7bf355c0e..9b7ba9857 100644 --- a/test/stattest.cc +++ b/test/stattest.cc @@ -66,8 +66,8 @@ Vector2d<> s16; Formula f1; Formula f2; Formula f3; -Formula f4; -Formula f5; +Value f4; +Value f5; Formula f6; Formula f7; @@ -279,11 +279,14 @@ main(int argc, char *argv[]) ; f4 + .functor(testfunc) .name("Formula4") .desc("this is formula 4") ; + TestClass testclass; f5 + .functor(testclass) .name("Formula5") .desc("this is formula 5") ; @@ -296,9 +299,6 @@ main(int argc, char *argv[]) f1 = s1 + s2; f2 = (-s1) / (-s2) * (-s3 + ULL(100) + s4); f3 = sum(s5) * s7; - f4 = functor(testfunc); - TestClass testclass; - f5 = functor(testclass); f6 += constant(10.0); f6 += s5[3]; f7 = constant(1); -- cgit v1.2.3 From ce697a592e9e999f49d39e8ffe75995f0fb7eeb9 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Thu, 13 May 2004 06:59:05 -0400 Subject: Avoid sending a signal to ourselves if we're not debugging --HG-- extra : convert_revision : d6ba1ce30bad4a44d716238a8107c3bff0ce89c4 --- sim/debug.cc | 2 ++ sim/debug.hh | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/sim/debug.cc b/sim/debug.cc index 09c604a95..b73ab4245 100644 --- a/sim/debug.cc +++ b/sim/debug.cc @@ -40,11 +40,13 @@ using namespace std; +#ifdef DEBUG void debug_break() { kill(getpid(), SIGTRAP); } +#endif // // Debug event: place a breakpoint on the process function and diff --git a/sim/debug.hh b/sim/debug.hh index eb0be772e..a4f8b8702 100644 --- a/sim/debug.hh +++ b/sim/debug.hh @@ -29,6 +29,10 @@ #ifndef __DEBUG_HH__ #define __DEBUG_HH__ +#ifdef DEBUG void debug_break(); +#else +inline void debug_break() { } +#endif #endif // __DEBUG_HH__ -- cgit v1.2.3 From 6a26c92d6f18035177b9653ad6a87da5a7d93e0d Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Thu, 13 May 2004 07:00:31 -0400 Subject: wrap mbuf stuff in the tru64 namespace since other OSes may be different --HG-- extra : convert_revision : 75ea218b5219c7a2b5bf7dca7c52dfff22740478 --- kern/tru64/mbuf.hh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kern/tru64/mbuf.hh b/kern/tru64/mbuf.hh index bfee0b3fa..a386fa611 100644 --- a/kern/tru64/mbuf.hh +++ b/kern/tru64/mbuf.hh @@ -32,6 +32,8 @@ #include "sim/host.hh" #include "targetarch/isa_traits.hh" +namespace tru64 { + struct m_hdr { Addr mh_next; // 0x00 Addr mh_nextpkt; // 0x08 @@ -91,4 +93,6 @@ struct mbuf { #define m_pktdat M_dat.MH.MH_dat.MH_databuf #define m_dat M_dat.M_databuf +} + #endif // __MBUF_HH__ -- cgit v1.2.3 From 8bc3ce93cb46c00e82432449a90bc4ed1225afd5 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Thu, 13 May 2004 07:28:54 -0400 Subject: pass the address of both the old an new pcbb on context switches. (Makes other uncommitted code easier to merge.) arch/alpha/ev5.cc: pass the address of both the old an new pcbb on context switches --HG-- extra : convert_revision : bff8c8d1b532ad5f9af6270169bbfb1b5c05256a --- arch/alpha/ev5.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/alpha/ev5.cc b/arch/alpha/ev5.cc index 9b3ac5fff..468acdc55 100644 --- a/arch/alpha/ev5.cc +++ b/arch/alpha/ev5.cc @@ -303,6 +303,7 @@ Fault ExecContext::setIpr(int idx, uint64_t val) { uint64_t *ipr = regs.ipr; + uint64_t old; if (misspeculating()) return No_Fault; @@ -355,8 +356,9 @@ ExecContext::setIpr(int idx, uint64_t val) case AlphaISA::IPR_PALtemp23: // write entire quad w/ no side-effect + old = ipr[idx]; ipr[idx] = val; - kernelStats.context(ipr[idx]); + kernelStats.context(old, val); Annotate::Context(this); break; -- cgit v1.2.3 From 2d8777a79bf3e3e93157ad30514996c3124324ca Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Thu, 13 May 2004 08:03:36 -0400 Subject: remove the annotation junk arch/alpha/isa_desc: remove the annotation junk Move some code to AlphaPseudo where it belongs arch/alpha/pseudo_inst.cc: arch/alpha/pseudo_inst.hh: remove the annotation junk add pseudo instruction code that was previously misplaced --HG-- extra : convert_revision : 97db8402aa34e0bdf044b138c52331fc9e714986 --- arch/alpha/ev5.cc | 6 ------ arch/alpha/isa_desc | 17 +++++------------ arch/alpha/pseudo_inst.cc | 19 +++++++++++++++++-- arch/alpha/pseudo_inst.hh | 3 +++ cpu/simple_cpu/simple_cpu.cc | 2 -- 5 files changed, 25 insertions(+), 22 deletions(-) diff --git a/arch/alpha/ev5.cc b/arch/alpha/ev5.cc index 468acdc55..f037a34ac 100644 --- a/arch/alpha/ev5.cc +++ b/arch/alpha/ev5.cc @@ -1,7 +1,6 @@ /* $Id$ */ #include "targetarch/alpha_memory.hh" -#include "sim/annotation.hh" #ifdef DEBUG #include "sim/debug.hh" #endif @@ -126,8 +125,6 @@ ExecContext::ev5_trap(Fault fault) regs.pc = ipr[AlphaISA::IPR_PAL_BASE] + AlphaISA::fault_addr[fault]; regs.npc = regs.pc + sizeof(MachInst); - - Annotate::Ev5Trap(this, fault); } @@ -359,7 +356,6 @@ ExecContext::setIpr(int idx, uint64_t val) old = ipr[idx]; ipr[idx] = val; kernelStats.context(old, val); - Annotate::Context(this); break; case AlphaISA::IPR_DTB_PTE: @@ -387,11 +383,9 @@ ExecContext::setIpr(int idx, uint64_t val) // only write least significant five bits - interrupt level ipr[idx] = val & 0x1f; kernelStats.swpipl(ipr[idx]); - Annotate::IPL(this, val & 0x1f); break; case AlphaISA::IPR_DTB_CM: - Annotate::ChangeMode(this, (val & 0x18) != 0); kernelStats.mode((val & 0x18) != 0); case AlphaISA::IPR_ICM: diff --git a/arch/alpha/isa_desc b/arch/alpha/isa_desc index 0d1e7138f..9bbdac9b4 100644 --- a/arch/alpha/isa_desc +++ b/arch/alpha/isa_desc @@ -25,7 +25,6 @@ let {{ #include "cpu/full_cpu/dyn_inst.hh" #include "cpu/simple_cpu/simple_cpu.hh" #include "cpu/static_inst.hh" -#include "sim/annotation.hh" #include "sim/sim_exit.hh" #ifdef FULL_SYSTEM @@ -2297,8 +2296,6 @@ decode OPCODE default Unknown::unknown() { // on this PAL call (including maybe suppress it) dopal = xc->simPalCheck(palFunc); - Annotate::Callpal(xc->xcBase(), palFunc); - if (dopal) { AlphaISA::swap_palshadow(&xc->xcBase()->regs, true); xc->setIpr(AlphaISA::IPR_EXC_ADDR, NPC); @@ -2357,24 +2354,20 @@ decode OPCODE default Unknown::unknown() { // M5 special opcodes use the reserved 0x01 opcode space 0x01: decode M5FUNC { 0x00: arm({{ - if (!xc->misspeculating()) { - Annotate::ARM(xc->xcBase()); - xc->xcBase()->kernelStats.arm(); - } + if (!xc->misspeculating()) + AlphaPseudo::arm(xc->xcBase()); }}); 0x01: quiesce({{ if (!xc->misspeculating()) AlphaPseudo::quiesce(xc->xcBase()); }}); 0x10: ivlb({{ - if (!xc->misspeculating()) { - Annotate::BeginInterval(xc->xcBase()); - xc->xcBase()->kernelStats.ivlb(); - } + if (!xc->misspeculating()) + AlphaPseudo::ivlb(xc->xcBase()); }}, No_OpClass); 0x11: ivle({{ if (!xc->misspeculating()) - Annotate::EndInterval(xc->xcBase()); + AlphaPseudo::ivle(xc->xcBase()); }}, No_OpClass); 0x20: m5exit_old({{ if (!xc->misspeculating()) diff --git a/arch/alpha/pseudo_inst.cc b/arch/alpha/pseudo_inst.cc index 194dc6400..0a5c5b006 100644 --- a/arch/alpha/pseudo_inst.cc +++ b/arch/alpha/pseudo_inst.cc @@ -30,7 +30,6 @@ #include "arch/alpha/pseudo_inst.hh" #include "cpu/exec_context.hh" -#include "sim/annotation.hh" #include "sim/param.hh" #include "sim/serialize.hh" #include "sim/sim_exit.hh" @@ -46,17 +45,33 @@ namespace AlphaPseudo bool doCheckpointInsts; bool doQuiesce; + void + arm(ExecContext *xc) + { + xc->kernelStats.arm(); + } + void quiesce(ExecContext *xc) { if (!doQuiesce) return; - Annotate::QUIESCE(xc); xc->suspend(); xc->kernelStats.quiesce(); } + void + ivlb(ExecContext *xc) + { + xc->kernelStats.ivlb(); + } + + void + ivle(ExecContext *xc) + { + } + void m5exit_old(ExecContext *xc) { diff --git a/arch/alpha/pseudo_inst.hh b/arch/alpha/pseudo_inst.hh index 85f432504..e5551a44b 100644 --- a/arch/alpha/pseudo_inst.hh +++ b/arch/alpha/pseudo_inst.hh @@ -37,7 +37,10 @@ namespace AlphaPseudo extern bool doCheckpointInsts; extern bool doQuiesce; + void arm(ExecContext *xc); void quiesce(ExecContext *xc); + void ivlb(ExecContext *xc); + void ivle(ExecContext *xc); void m5exit(ExecContext *xc); void m5exit_old(ExecContext *xc); void resetstats(ExecContext *xc); diff --git a/cpu/simple_cpu/simple_cpu.cc b/cpu/simple_cpu/simple_cpu.cc index 56ea0ae11..617c91e68 100644 --- a/cpu/simple_cpu/simple_cpu.cc +++ b/cpu/simple_cpu/simple_cpu.cc @@ -50,7 +50,6 @@ #include "cpu/static_inst.hh" #include "mem/base_mem.hh" #include "mem/mem_interface.hh" -#include "sim/annotation.hh" #include "sim/builder.hh" #include "sim/debug.hh" #include "sim/host.hh" @@ -579,7 +578,6 @@ SimpleCPU::post_interrupt(int int_num, int index) if (xc->status() == ExecContext::Suspended) { DPRINTF(IPI,"Suspended Processor awoke\n"); xc->activate(); - Annotate::Resume(xc); } } #endif // FULL_SYSTEM -- cgit v1.2.3 From f13926c0994698f7abce9230349bb80395f4b706 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Thu, 13 May 2004 08:08:42 -0400 Subject: Add VPtr class that makes it possible to esentially create a pointer to an object that lives inside simulated memory. Useful for doing a bit of analysis of what's going on in the running kernel. --HG-- extra : convert_revision : d78089cce5ec4334483a710ba512eaf18d9b0319 --- arch/alpha/vptr.hh | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 arch/alpha/vptr.hh diff --git a/arch/alpha/vptr.hh b/arch/alpha/vptr.hh new file mode 100644 index 000000000..7f0b036a3 --- /dev/null +++ b/arch/alpha/vptr.hh @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __VPTR_HH__ +#define __VPTR_HH__ + +#include "arch/alpha/vtophys.hh" + +class ExecContext; + +template +class VPtr +{ + public: + typedef T Type; + + private: + ExecContext *xc; + Addr ptr; + + public: + ExecContext *GetXC() const { return xc; } + Addr GetPointer() const { return ptr; } + + public: + explicit VPtr(ExecContext *_xc, Addr p = 0) : xc(_xc), ptr(p) { } + template + VPtr(const VPtr &vp) : xc(vp.GetXC()), ptr(vp.GetPointer()) {} + ~VPtr() {} + + bool operator!() const + { + return ptr == 0; + } + + VPtr operator+(int offset) + { + VPtr ptr(*this); + ptr += offset; + + return ptr; + } + + const VPtr &operator+=(int offset) + { + ptr += offset; + assert((ptr & (ALPHA_PGBYTES - 1)) + sizeof(T) < ALPHA_PGBYTES); + + return *this; + } + + const VPtr &operator=(Addr p) + { + assert((p & (ALPHA_PGBYTES - 1)) + sizeof(T) < ALPHA_PGBYTES); + ptr = p; + + return *this; + } + + template + const VPtr &operator=(const VPtr &vp) + { + xc = vp.GetXC(); + ptr = vp.GetPointer(); + + return *this; + } + + operator T *() + { + void *addr = vtomem(xc, ptr, sizeof(T)); + return (T *)addr; + } + + T *operator->() + { + void *addr = vtomem(xc, ptr, sizeof(T)); + return (T *)addr; + } + + T &operator*() + { + void *addr = vtomem(xc, ptr, sizeof(T)); + return *(T *)addr; + } +}; + +#endif // __VPTR_HH__ -- cgit v1.2.3 From 7f28ae6b01b08f166c81adc10139671e6e098780 Mon Sep 17 00:00:00 2001 From: Lisa Hsu Date: Thu, 13 May 2004 11:40:07 -0400 Subject: lift some things out of the tru64 directory into common directory so linux can use it without replication later. kern/tru64/tru64_events.cc: kern/tru64/tru64_events.hh: lift out SkipFuncEvent and FnEvents since these can be used by any OS. kern/tru64/tru64_system.cc: add system_events (the common OS events file) --HG-- extra : convert_revision : 4d7a843d67459af4d77e433ae3c1b0fbc5f0b56b --- kern/tru64/tru64_events.cc | 82 +++------------------------------------------- kern/tru64/tru64_events.hh | 22 +------------ kern/tru64/tru64_system.cc | 1 + 3 files changed, 6 insertions(+), 99 deletions(-) diff --git a/kern/tru64/tru64_events.cc b/kern/tru64/tru64_events.cc index 17a5e406a..89b808653 100644 --- a/kern/tru64/tru64_events.cc +++ b/kern/tru64/tru64_events.cc @@ -28,32 +28,14 @@ #include "cpu/exec_context.hh" #include "cpu/base_cpu.hh" -#include "cpu/full_cpu/bpred.hh" -#include "cpu/full_cpu/full_cpu.hh" +#include "kern/system_events.hh" +#include "kern/tru64/tru64_events.hh" #include "kern/tru64/dump_mbuf.hh" #include "kern/tru64/printf.hh" -#include "kern/tru64/tru64_events.hh" -#include "mem/functional_mem/memory_control.hh" #include "targetarch/arguments.hh" -#include "sim/system.hh" -#include "sim/sw_context.hh" - -void -SkipFuncEvent::process(ExecContext *xc) -{ - Addr newpc = xc->regs.intRegFile[ReturnAddressReg]; - - DPRINTF(PCEvent, "skipping %s: pc=%x, newpc=%x\n", description, - xc->regs.pc, newpc); - - xc->regs.pc = newpc; - xc->regs.npc = xc->regs.pc + sizeof(MachInst); +#include "mem/functional_mem/memory_control.hh" - BranchPred *bp = xc->cpu->getBranchPred(); - if (bp != NULL) { - bp->popRAS(xc->thread_num); - } -} +//void SkipFuncEvent::process(ExecContext *xc); void BadAddrEvent::process(ExecContext *xc) @@ -106,59 +88,3 @@ DumpMbufEvent::process(ExecContext *xc) tru64::DumpMbuf(args); } } - -FnEvent::FnEvent(PCEventQueue *q, const std::string & desc, System *system) - : PCEvent(q, desc), _name(desc) -{ - myBin = system->getBin(desc); - assert(myBin); -} - -void -FnEvent::process(ExecContext *xc) -{ - if (xc->misspeculating()) - return; - assert(xc->system->bin && "FnEvent must be in a binned system"); - SWContext *ctx = xc->swCtx; - DPRINTF(TCPIP, "%s: %s Event!!!\n", xc->system->name(), description); - - if (ctx && !ctx->callStack.empty()) { - DPRINTF(TCPIP, "already a callstack!\n"); - fnCall *last = ctx->callStack.top(); - - if (last->name == "idle_thread") - ctx->calls++; - - if (!xc->system->findCaller(myname(), "" ) && - !xc->system->findCaller(myname(), last->name)) { - - DPRINTF(TCPIP, "but can't find parent %s\n", last->name); - return; - } - ctx->calls--; - - //assert(!ctx->calls && "on a binned fn, calls should == 0 (but can happen in boot)"); - } else { - DPRINTF(TCPIP, "no callstack yet\n"); - if (!xc->system->findCaller(myname(), "")) { - DPRINTF(TCPIP, "not the right function, returning\n"); - return; - } - if (!ctx) { - DPRINTF(TCPIP, "creating new context for %s\n", myname()); - ctx = new SWContext; - xc->swCtx = ctx; - } - } - DPRINTF(TCPIP, "adding fn %s to context\n", myname()); - fnCall *call = new fnCall; - call->myBin = myBin; - call->name = myname(); - ctx->callStack.push(call); - myBin->activate(); - xc->system->fnCalls++; - DPRINTF(TCPIP, "fnCalls for %s is %d\n", description, - xc->system->fnCalls.value()); - xc->system->dumpState(xc); -} diff --git a/kern/tru64/tru64_events.hh b/kern/tru64/tru64_events.hh index 96e6a8b26..bcf33d686 100644 --- a/kern/tru64/tru64_events.hh +++ b/kern/tru64/tru64_events.hh @@ -32,19 +32,10 @@ #include #include "cpu/pc_event.hh" +#include "kern/system_events.hh" class ExecContext; -class System; - -class SkipFuncEvent : public PCEvent -{ - public: - SkipFuncEvent(PCEventQueue *q, const std::string &desc) - : PCEvent(q, desc) {} - virtual void process(ExecContext *xc); -}; - class BadAddrEvent : public SkipFuncEvent { public: @@ -80,15 +71,4 @@ class DumpMbufEvent : public PCEvent virtual void process(ExecContext *xc); }; -class FnEvent : public PCEvent -{ - public: - FnEvent(PCEventQueue *q, const std::string &desc, System *system); - virtual void process(ExecContext *xc); - std::string myname() const { return _name; } - - private: - std::string _name; - Statistics::MainBin *myBin; -}; #endif // __TRU64_EVENTS_HH__ diff --git a/kern/tru64/tru64_system.cc b/kern/tru64/tru64_system.cc index 3eed78cdf..7e68dc5a1 100644 --- a/kern/tru64/tru64_system.cc +++ b/kern/tru64/tru64_system.cc @@ -35,6 +35,7 @@ #include "cpu/exec_context.hh" #include "kern/tru64/tru64_events.hh" #include "kern/tru64/tru64_system.hh" +#include "kern/system_events.hh" #include "mem/functional_mem/memory_control.hh" #include "mem/functional_mem/physical_memory.hh" #include "sim/builder.hh" -- cgit v1.2.3 -- cgit v1.2.3 -- cgit v1.2.3 From 73501ea38f3c3e53fc02561444e25989c29224af Mon Sep 17 00:00:00 2001 From: Lisa Hsu Date: Mon, 17 May 2004 13:22:19 -0400 Subject: push the new system_events file that i was prevented from pushing way back when cable died. :(. also, fix the printing of binned stats, it was printing hex values instead of bin names. base/stats/text.cc: fix the printing of binned stats. --HG-- extra : convert_revision : 3a04d004f5ea1d90536f7102fce946fd6dd34613 --- base/stats/text.cc | 2 +- kern/system_events.cc | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++ kern/system_events.hh | 56 ++++++++++++++++++++++++++ 3 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 kern/system_events.cc create mode 100644 kern/system_events.hh diff --git a/base/stats/text.cc b/base/stats/text.cc index 0f43a1772..79a91e661 100644 --- a/base/stats/text.cc +++ b/base/stats/text.cc @@ -132,7 +132,7 @@ Text::output() for (i = bins().begin(); i != end; ++i) { MainBin *bin = *i; bin->activate(); - ccprintf(*stream,"---%s Bin------------\n", bin); + ccprintf(*stream,"---%s Bin------------\n", bin->name()); stat_list_t::const_iterator i, end = stats().end(); for (i = stats().begin(); i != end; ++i) (*i)->visit(*this); diff --git a/kern/system_events.cc b/kern/system_events.cc new file mode 100644 index 000000000..011dbce5f --- /dev/null +++ b/kern/system_events.cc @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cpu/exec_context.hh" +#include "cpu/base_cpu.hh" +#include "cpu/full_cpu/bpred.hh" +#include "cpu/full_cpu/full_cpu.hh" +#include "kern/system_events.hh" +#include "sim/system.hh" +#include "sim/sw_context.hh" + +void +SkipFuncEvent::process(ExecContext *xc) +{ + Addr newpc = xc->regs.intRegFile[ReturnAddressReg]; + + DPRINTF(PCEvent, "skipping %s: pc=%x, newpc=%x\n", description, + xc->regs.pc, newpc); + + xc->regs.pc = newpc; + xc->regs.npc = xc->regs.pc + sizeof(MachInst); + + BranchPred *bp = xc->cpu->getBranchPred(); + if (bp != NULL) { + bp->popRAS(xc->thread_num); + } +} + + +FnEvent::FnEvent(PCEventQueue *q, const std::string & desc, System *system) + : PCEvent(q, desc), _name(desc) +{ + myBin = system->getBin(desc); + assert(myBin); +} + +void +FnEvent::process(ExecContext *xc) +{ + if (xc->misspeculating()) + return; + assert(xc->system->bin && "FnEvent must be in a binned system"); + SWContext *ctx = xc->swCtx; + DPRINTF(TCPIP, "%s: %s Event!!!\n", xc->system->name(), description); + + if (ctx && !ctx->callStack.empty()) { + DPRINTF(TCPIP, "already a callstack!\n"); + fnCall *last = ctx->callStack.top(); + + if (last->name == "idle_thread") + ctx->calls++; + + if (!xc->system->findCaller(myname(), "" ) && + !xc->system->findCaller(myname(), last->name)) { + + DPRINTF(TCPIP, "but can't find parent %s\n", last->name); + return; + } + ctx->calls--; + + //assert(!ctx->calls && "on a binned fn, calls should == 0 (but can happen in boot)"); + } else { + DPRINTF(TCPIP, "no callstack yet\n"); + if (!xc->system->findCaller(myname(), "")) { + DPRINTF(TCPIP, "not the right function, returning\n"); + return; + } + if (!ctx) { + DPRINTF(TCPIP, "creating new context for %s\n", myname()); + ctx = new SWContext; + xc->swCtx = ctx; + } + } + DPRINTF(TCPIP, "adding fn %s to context\n", myname()); + fnCall *call = new fnCall; + call->myBin = myBin; + call->name = myname(); + ctx->callStack.push(call); + myBin->activate(); + xc->system->fnCalls++; + DPRINTF(TCPIP, "fnCalls for %s is %d\n", description, + xc->system->fnCalls.value()); + xc->system->dumpState(xc); +} diff --git a/kern/system_events.hh b/kern/system_events.hh new file mode 100644 index 000000000..fdf2a06c9 --- /dev/null +++ b/kern/system_events.hh @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SYSTEM_EVENTS_HH__ +#define __SYSTEM_EVENTS_HH__ + +#include "cpu/pc_event.hh" + +class System; + +class SkipFuncEvent : public PCEvent +{ + public: + SkipFuncEvent(PCEventQueue *q, const std::string &desc) + : PCEvent(q, desc) {} + virtual void process(ExecContext *xc); +}; + +class FnEvent : public PCEvent +{ + public: + FnEvent(PCEventQueue *q, const std::string &desc, System *system); + virtual void process(ExecContext *xc); + std::string myname() const { return _name; } + + private: + std::string _name; + Statistics::MainBin *myBin; +}; + +#endif // __SYSTEM_EVENTS_HH__ -- cgit v1.2.3 From 1d545281b96a6df358201c7b0e610bfaf9e8f213 Mon Sep 17 00:00:00 2001 From: Steve Reinhardt Date: Mon, 17 May 2004 11:49:46 -0700 Subject: Significant changes to ISA description to completely factor out CPU model. ISA description now generates multiple output source files to (in theory) reduce compilation time. arch/alpha/isa_desc: Update for parser changes. Move most constructors out of class declarations (which are now in decoder.hh) and into decoder.cc. Move all execute() methods into exec output. arch/isa_parser.py: Significant changes to make ISA description completely independent of CPU model, and isolate model-dependent parts of parser into one little class (CpuModel). Also split up code output into multiple files (a header, a main source file, and per-cpu execute() method files). Noticeable changes to language as a result. See updated Doxygen documentation. cpu/simple_cpu/simple_cpu.hh: SimpleCPUExecContext typedef no longer needed. Add forward declaration of Process. cpu/static_inst.hh: SimpleCPUExecContext and FullCPUExecContext typedefs no longer needed. Make eaCompInst() and memAccInst() return const refs. --HG-- extra : convert_revision : 71471f267804fafd0a881bac7445677e76334daf --- arch/alpha/isa_desc | 1394 +++++++++++++++++++++++------------------- arch/isa_parser.py | 678 ++++++++++++-------- cpu/simple_cpu/simple_cpu.hh | 9 +- cpu/static_inst.hh | 14 +- 4 files changed, 1227 insertions(+), 868 deletions(-) diff --git a/arch/alpha/isa_desc b/arch/alpha/isa_desc index 9bbdac9b4..f964101df 100644 --- a/arch/alpha/isa_desc +++ b/arch/alpha/isa_desc @@ -1,39 +1,67 @@ // -*- mode:c++ -*- + +//////////////////////////////////////////////////////////////////// // // Alpha ISA description file. // +//////////////////////////////////////////////////////////////////// -let {{ - global rcs_id - rcs_id = "$Id$" -}}; +//////////////////////////////////////////////////////////////////// +// +// Output include file directives. +// +output header {{ #include #include #include +#include "cpu/static_inst.hh" +#include "mem/mem_req.hh" // some constructors use MemReq flags +}}; + +output decoder {{ +#include "base/cprintf.hh" +#include "base/loader/symtab.hh" +#include "cpu/exec_context.hh" // for Jump::branchTarget() + #include #if defined(linux) #include #endif +}}; -#include "base/cprintf.hh" -#include "base/misc.hh" -#include "cpu/exec_context.hh" +output exec {{ +#include +#if defined(linux) +#include +#endif + +#include "cpu/base_cpu.hh" #include "cpu/exetrace.hh" -#include "cpu/full_cpu/dyn_inst.hh" -#include "cpu/simple_cpu/simple_cpu.hh" -#include "cpu/static_inst.hh" #include "sim/sim_exit.hh" #ifdef FULL_SYSTEM #include "arch/alpha/ev5.hh" #include "arch/alpha/pseudo_inst.hh" #endif +}}; + +//////////////////////////////////////////////////////////////////// +// +// Namespace statement. Everything below this line will be in the +// AlphaISAInst namespace. +// + namespace AlphaISA; +//////////////////////////////////////////////////////////////////// +// +// Bitfield definitions. +// + // Universal (format-independent) fields def bitfield OPCODE <31:26>; def bitfield RA <25:21>; @@ -92,70 +120,48 @@ def bitfield HW_IPR_IDX <15:0>; // IPR index // M5 instructions def bitfield M5FUNC <7:0>; -let {{ - global operandTypeMap - operandTypeMap = { - 'sb' : ('signed int', 8), - 'ub' : ('unsigned int', 8), - 'sw' : ('signed int', 16), - 'uw' : ('unsigned int', 16), - 'sl' : ('signed int', 32), - 'ul' : ('unsigned int', 32), - 'sq' : ('signed int', 64), - 'uq' : ('unsigned int', 64), - 'sf' : ('float', 32), - 'df' : ('float', 64) - } - - global operandTraitsMap - operandTraitsMap = { - # Int regs default to unsigned, but code should not count on this. - # For clarity, descriptions that depend on unsigned behavior should - # explicitly specify '.uq'. - 'Ra': IntRegOperandTraits('uq', 'RA', 'IsInteger', 1), - 'Rb': IntRegOperandTraits('uq', 'RB', 'IsInteger', 2), - 'Rc': IntRegOperandTraits('uq', 'RC', 'IsInteger', 3), - 'Fa': FloatRegOperandTraits('df', 'FA', 'IsFloating', 1), - 'Fb': FloatRegOperandTraits('df', 'FB', 'IsFloating', 2), - 'Fc': FloatRegOperandTraits('df', 'FC', 'IsFloating', 3), - 'Mem': MemOperandTraits('uq', None, - ('IsMemRef', 'IsLoad', 'IsStore'), 4), - 'NPC': NPCOperandTraits('uq', None, ( None, None, 'IsControl' ), 4), - 'Runiq': ControlRegOperandTraits('uq', 'Uniq', None, 1), - 'FPCR': ControlRegOperandTraits('uq', 'Fpcr', None, 1), - # The next two are hacks for non-full-system call-pal emulation - 'R0': IntRegOperandTraits('uq', '0', None, 1), - 'R16': IntRegOperandTraits('uq', '16', None, 1), - } +def operand_types {{ + 'sb' : ('signed int', 8), + 'ub' : ('unsigned int', 8), + 'sw' : ('signed int', 16), + 'uw' : ('unsigned int', 16), + 'sl' : ('signed int', 32), + 'ul' : ('unsigned int', 32), + 'sq' : ('signed int', 64), + 'uq' : ('unsigned int', 64), + 'sf' : ('float', 32), + 'df' : ('float', 64) +}}; - defineDerivedOperandVars() +def operands {{ + # Int regs default to unsigned, but code should not count on this. + # For clarity, descriptions that depend on unsigned behavior should + # explicitly specify '.uq'. + 'Ra': IntRegOperandTraits('uq', 'RA', 'IsInteger', 1), + 'Rb': IntRegOperandTraits('uq', 'RB', 'IsInteger', 2), + 'Rc': IntRegOperandTraits('uq', 'RC', 'IsInteger', 3), + 'Fa': FloatRegOperandTraits('df', 'FA', 'IsFloating', 1), + 'Fb': FloatRegOperandTraits('df', 'FB', 'IsFloating', 2), + 'Fc': FloatRegOperandTraits('df', 'FC', 'IsFloating', 3), + 'Mem': MemOperandTraits('uq', None, + ('IsMemRef', 'IsLoad', 'IsStore'), 4), + 'NPC': NPCOperandTraits('uq', None, ( None, None, 'IsControl' ), 4), + 'Runiq': ControlRegOperandTraits('uq', 'Uniq', None, 1), + 'FPCR': ControlRegOperandTraits('uq', 'Fpcr', None, 1), + # The next two are hacks for non-full-system call-pal emulation + 'R0': IntRegOperandTraits('uq', '0', None, 1), + 'R16': IntRegOperandTraits('uq', '16', None, 1) }}; -declare {{ -// just temporary, while comparing with old code for debugging -// #define SS_COMPATIBLE_DISASSEMBLY +//////////////////////////////////////////////////////////////////// +// +// Basic instruction classes/templates/formats etc. +// - /// Check "FP enabled" machine status bit. Called when executing any FP - /// instruction in full-system mode. - /// @retval Full-system mode: No_Fault if FP is enabled, Fen_Fault - /// if not. Non-full-system mode: always returns No_Fault. -#ifdef FULL_SYSTEM - template - inline Fault checkFpEnableFault(XC *xc) - { - Fault fault = No_Fault; // dummy... this ipr access should not fault - if (!ICSR_FPE(xc->readIpr(AlphaISA::IPR_ICSR, fault))) { - fault = Fen_Fault; - } - return fault; - } -#else - template - inline Fault checkFpEnableFault(XC *xc) - { - return No_Fault; - } -#endif +output header {{ +// uncomment the following to get SimpleScalar-compatible disassembly +// (useful for diffing output traces). +// #define SS_COMPATIBLE_DISASSEMBLY /** * Base class for all Alpha static instructions. @@ -183,47 +189,60 @@ declare {{ /// Print a register name for disassembly given the unique /// dependence tag number (FP or int). - void printReg(std::ostream &os, int reg) - { - if (reg < FP_Base_DepTag) { - ccprintf(os, "r%d", reg); - } - else { - ccprintf(os, "f%d", reg - FP_Base_DepTag); - } - } + void printReg(std::ostream &os, int reg); - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) - { - std::stringstream ss; + std::string generateDisassembly(Addr pc, const SymbolTable *symtab); + }; +}}; - ccprintf(ss, "%-10s ", mnemonic); +output decoder {{ + void + AlphaStaticInst::printReg(std::ostream &os, int reg) + { + if (reg < FP_Base_DepTag) { + ccprintf(os, "r%d", reg); + } + else { + ccprintf(os, "f%d", reg - FP_Base_DepTag); + } + } - // just print the first two source regs... if there's - // a third one, it's a read-modify-write dest (Rc), - // e.g. for CMOVxx - if (_numSrcRegs > 0) { - printReg(ss, _srcRegIdx[0]); - } - if (_numSrcRegs > 1) { - ss << ","; - printReg(ss, _srcRegIdx[1]); - } + std::string + AlphaStaticInst::generateDisassembly(Addr pc, const SymbolTable *symtab) + { + std::stringstream ss; - // just print the first dest... if there's a second one, - // it's generally implicit - if (_numDestRegs > 0) { - if (_numSrcRegs > 0) - ss << ","; - printReg(ss, _destRegIdx[0]); - } + ccprintf(ss, "%-10s ", mnemonic); - return ss.str(); + // just print the first two source regs... if there's + // a third one, it's a read-modify-write dest (Rc), + // e.g. for CMOVxx + if (_numSrcRegs > 0) { + printReg(ss, _srcRegIdx[0]); } - }; + if (_numSrcRegs > 1) { + ss << ","; + printReg(ss, _srcRegIdx[1]); + } + + // just print the first dest... if there's a second one, + // it's generally implicit + if (_numDestRegs > 0) { + if (_numSrcRegs > 0) + ss << ","; + printReg(ss, _destRegIdx[0]); + } + + return ss.str(); + } }}; +// Declarations for execute() methods. +def template BasicExecDeclare {{ + Fault execute(%(CPU_exec_context)s *, Trace::InstRecord *); +}}; +// Basic instruction class declaration template. def template BasicDeclare {{ /** * Static instruction class for "%(mnemonic)s". @@ -232,18 +251,24 @@ def template BasicDeclare {{ { public: /// Constructor. - %(class_name)s(MachInst machInst) - : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s) - { - %(constructor)s; - } + %(class_name)s(MachInst machInst); - %(exec_func_declarations)s + %(BasicExecDeclare)s }; }}; +// Basic instruction class constructor template. +def template BasicConstructor {{ + inline %(class_name)s::%(class_name)s(MachInst machInst) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s) + { + %(constructor)s; + } +}}; + +// Basic instruction class execute method template. def template BasicExecute {{ - Fault %(class_name)s::execute(%(cpu_model)s *xc, + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) { Fault fault = No_Fault; @@ -261,10 +286,12 @@ def template BasicExecute {{ } }}; +// Basic decode template. def template BasicDecode {{ return new %(class_name)s(machInst); }}; +// Basic decode template, passing mnemonic in as string arg to constructor. def template BasicDecodeWithMnemonic {{ return new %(class_name)s("%(mnemonic)s", machInst); }}; @@ -272,14 +299,20 @@ def template BasicDecodeWithMnemonic {{ // The most basic instruction format... used only for a few misc. insts def format BasicOperate(code, *flags) {{ iop = InstObjParams(name, Name, 'AlphaStaticInst', CodeBlock(code), flags) - return iop.subst('BasicDeclare', 'BasicDecode', 'BasicExecute') + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) }}; //////////////////////////////////////////////////////////////////// +// +// Nop +// -declare {{ +output header {{ /** * Static instruction class for no-ops. This is a leaf class. */ @@ -299,21 +332,21 @@ declare {{ ~Nop() { } - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) - { + std::string generateDisassembly(Addr pc, const SymbolTable *symtab); + + %(BasicExecDeclare)s + }; +}}; + +output decoder {{ + std::string Nop::generateDisassembly(Addr pc, const SymbolTable *symtab) + { #ifdef SS_COMPATIBLE_DISASSEMBLY - return originalDisassembly; + return originalDisassembly; #else - return csprintf("%-10s (%s)", "nop", originalDisassembly); + return csprintf("%-10s (%s)", "nop", originalDisassembly); #endif - } - - Fault execute(SimpleCPUExecContext *, Trace::InstRecord *) - { return No_Fault; } - - Fault execute(FullCPUExecContext *, Trace::InstRecord *) - { return No_Fault; } - }; + } /// Helper function for decoding nops. Substitute Nop object /// for original inst passed in as arg (and delete latter). @@ -327,18 +360,21 @@ declare {{ } }}; -def format Nop() {{ - return ('', 'return new Nop("%s", machInst);\n' % name, 'return No_Fault;') +output exec {{ + Fault + Nop::execute(%(CPU_exec_context)s *, Trace::InstRecord *) + { + return No_Fault; + } }}; - // integer & FP operate instructions use Rc as dest, so check for // Rc == 31 to detect nops def template OperateNopCheckDecode {{ { AlphaStaticInst *i = new %(class_name)s(machInst); if (RC == 31) { - i = makeNop(i); + i = makeNop(i); } return i; } @@ -348,7 +384,10 @@ def template OperateNopCheckDecode {{ def format BasicOperateWithNopCheck(code, *opt_args) {{ iop = InstObjParams(name, Name, 'AlphaStaticInst', CodeBlock(code), opt_args) - return iop.subst('BasicDeclare', 'OperateNopCheckDecode', 'BasicExecute') + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = OperateNopCheckDecode.subst(iop) + exec_output = BasicExecute.subst(iop) }}; @@ -357,7 +396,7 @@ def format BasicOperateWithNopCheck(code, *opt_args) {{ // Integer operate instructions // -declare {{ +output header {{ /** * Base class for integer immediate instructions. */ @@ -373,39 +412,45 @@ declare {{ { } - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) - { - std::stringstream ss; + std::string generateDisassembly(Addr pc, const SymbolTable *symtab); + }; +}}; - ccprintf(ss, "%-10s ", mnemonic); +output decoder {{ + std::string + IntegerImm::generateDisassembly(Addr pc, const SymbolTable *symtab) + { + std::stringstream ss; - // just print the first source reg... if there's - // a second one, it's a read-modify-write dest (Rc), - // e.g. for CMOVxx - if (_numSrcRegs > 0) { - printReg(ss, _srcRegIdx[0]); - ss << ","; - } + ccprintf(ss, "%-10s ", mnemonic); - ss << (int)imm; - - if (_numDestRegs > 0) { - ss << ","; - printReg(ss, _destRegIdx[0]); - } + // just print the first source reg... if there's + // a second one, it's a read-modify-write dest (Rc), + // e.g. for CMOVxx + if (_numSrcRegs > 0) { + printReg(ss, _srcRegIdx[0]); + ss << ","; + } - return ss.str(); + ss << (int)imm; + + if (_numDestRegs > 0) { + ss << ","; + printReg(ss, _destRegIdx[0]); } - }; + + return ss.str(); + } }}; + def template RegOrImmDecode {{ { AlphaStaticInst *i = - (IMM) ? (AlphaStaticInst *)new %(class_name)sImm(machInst) - : (AlphaStaticInst *)new %(class_name)s(machInst); + (IMM) ? (AlphaStaticInst *)new %(class_name)sImm(machInst) + : (AlphaStaticInst *)new %(class_name)s(machInst); if (RC == 31) { - i = makeNop(i); + i = makeNop(i); } return i; } @@ -432,24 +477,23 @@ def format IntegerOperate(code, *opt_flags) {{ # generate declaration for register version cblk = CodeBlock(code) iop = InstObjParams(name, Name, 'AlphaStaticInst', cblk, opt_flags) - (decls, exec_code) = iop.subst('BasicDeclare', 'BasicExecute') + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + exec_output = BasicExecute.subst(iop) if uses_imm: # append declaration for imm version imm_cblk = CodeBlock(imm_code) imm_iop = InstObjParams(name, Name + 'Imm', 'IntegerImm', imm_cblk, opt_flags) - (imm_decls, imm_exec_code) = \ - imm_iop.subst('BasicDeclare', 'BasicExecute') - decls += imm_decls - exec_code += imm_exec_code + header_output += BasicDeclare.subst(imm_iop) + decoder_output += BasicConstructor.subst(imm_iop) + exec_output += BasicExecute.subst(imm_iop) # decode checks IMM bit to pick correct version - decode = iop.subst('RegOrImmDecode') + decode_block = RegOrImmDecode.subst(iop) else: # no imm version: just check for nop - decode = iop.subst('OperateNopCheckDecode') - - return (decls, decode, exec_code) + decode_block = OperateNopCheckDecode.subst(iop) }}; @@ -462,7 +506,29 @@ def format IntegerOperate(code, *opt_flags) {{ // BasicOperateWithNopCheck. // -declare {{ +output exec {{ + /// Check "FP enabled" machine status bit. Called when executing any FP + /// instruction in full-system mode. + /// @retval Full-system mode: No_Fault if FP is enabled, Fen_Fault + /// if not. Non-full-system mode: always returns No_Fault. +#ifdef FULL_SYSTEM + inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc) + { + Fault fault = No_Fault; // dummy... this ipr access should not fault + if (!ICSR_FPE(xc->readIpr(AlphaISA::IPR_ICSR, fault))) { + fault = Fen_Fault; + } + return fault; + } +#else + inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc) + { + return No_Fault; + } +#endif +}}; + +output header {{ /** * Base class for general floating-point instructions. Includes * support for various Alpha rounding and trapping modes. Only FP @@ -524,61 +590,88 @@ declare {{ } #if defined(linux) - int - getC99RoundingMode(uint64_t fpcr_val) - { - if (roundingMode == Dynamic) { - return alphaToC99RoundingMode[bits(fpcr_val, 59, 58)]; - } - else { - return alphaToC99RoundingMode[roundingMode]; - } - } + int getC99RoundingMode(uint64_t fpcr_val); #endif // This differs from the AlphaStaticInst version only in // printing suffixes for non-default rounding & trapping modes. - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) - { - std::string mnem_str(mnemonic); + std::string generateDisassembly(Addr pc, const SymbolTable *symtab); + }; -#ifndef SS_COMPATIBLE_DISASSEMBLY - std::string suffix(""); - suffix += ((_destRegIdx[0] >= FP_Base_DepTag) - ? fpTrappingModeSuffix[trappingMode] - : intTrappingModeSuffix[trappingMode]); - suffix += roundingModeSuffix[roundingMode]; - - if (suffix != "") { - mnem_str = csprintf("%s/%s", mnemonic, suffix); - } +}}; + + +def template FloatingPointDecode {{ + { + bool fast = (FP_TRAPMODE == AlphaFP::Imprecise + && FP_ROUNDMODE == AlphaFP::Normal); + AlphaStaticInst *i = + fast ? (AlphaStaticInst *)new %(class_name)sFast(machInst) : + (AlphaStaticInst *)new %(class_name)sGeneral(machInst); + + if (FC == 31) { + i = makeNop(i); + } + + return i; + } +}}; + +output decoder {{ +#if defined(linux) + int + AlphaFP::getC99RoundingMode(uint64_t fpcr_val) + { + if (roundingMode == Dynamic) { + return alphaToC99RoundingMode[bits(fpcr_val, 59, 58)]; + } + else { + return alphaToC99RoundingMode[roundingMode]; + } + } #endif - std::stringstream ss; - ccprintf(ss, "%-10s ", mnem_str.c_str()); + std::string + AlphaFP::generateDisassembly(Addr pc, const SymbolTable *symtab) + { + std::string mnem_str(mnemonic); - // just print the first two source regs... if there's - // a third one, it's a read-modify-write dest (Rc), - // e.g. for CMOVxx - if (_numSrcRegs > 0) { - printReg(ss, _srcRegIdx[0]); - } - if (_numSrcRegs > 1) { - ss << ","; - printReg(ss, _srcRegIdx[1]); - } +#ifndef SS_COMPATIBLE_DISASSEMBLY + std::string suffix(""); + suffix += ((_destRegIdx[0] >= FP_Base_DepTag) + ? fpTrappingModeSuffix[trappingMode] + : intTrappingModeSuffix[trappingMode]); + suffix += roundingModeSuffix[roundingMode]; - // just print the first dest... if there's a second one, - // it's generally implicit - if (_numDestRegs > 0) { - if (_numSrcRegs > 0) - ss << ","; - printReg(ss, _destRegIdx[0]); - } + if (suffix != "") { + mnem_str = csprintf("%s/%s", mnemonic, suffix); + } +#endif - return ss.str(); + std::stringstream ss; + ccprintf(ss, "%-10s ", mnem_str.c_str()); + + // just print the first two source regs... if there's + // a third one, it's a read-modify-write dest (Rc), + // e.g. for CMOVxx + if (_numSrcRegs > 0) { + printReg(ss, _srcRegIdx[0]); } - }; + if (_numSrcRegs > 1) { + ss << ","; + printReg(ss, _srcRegIdx[1]); + } + + // just print the first dest... if there's a second one, + // it's generally implicit + if (_numDestRegs > 0) { + if (_numSrcRegs > 0) + ss << ","; + printReg(ss, _destRegIdx[0]); + } + + return ss.str(); + } #if defined(linux) const int AlphaFP::alphaToC99RoundingMode[] = { @@ -598,34 +691,19 @@ declare {{ { "", "v", "INVTM2", "INVTM3", "INVTM4", "sv", "INVTM6", "svi" }; }}; - -def template FloatingPointDecode {{ - { - bool fast = (FP_TRAPMODE == AlphaFP::Imprecise - && FP_ROUNDMODE == AlphaFP::Normal); - AlphaStaticInst *i = - fast ? (AlphaStaticInst *)new %(class_name)sFast(machInst) : - (AlphaStaticInst *)new %(class_name)sGeneral(machInst); - - if (FC == 31) { - i = makeNop(i); - } - - return i; - } -}}; - // General format for floating-point operate instructions: // - Checks trapping and rounding mode flags. Trapping modes // currently unimplemented (will fail). // - Generates NOP if FC == 31. def format FloatingPointOperate(code, *opt_args) {{ iop = InstObjParams(name, Name, 'AlphaFP', CodeBlock(code), opt_args) - decode = iop.subst('FloatingPointDecode') + decode_block = FloatingPointDecode.subst(iop) fast_iop = InstObjParams(name, Name + 'Fast', 'AlphaFP', - CodeBlock(code), opt_args) - (fast_declare, fast_exec) = fast_iop.subst('BasicDeclare', 'BasicExecute') + CodeBlock(code), opt_args) + header_output = BasicDeclare.subst(fast_iop) + decoder_output = BasicConstructor.subst(fast_iop) + exec_output = BasicExecute.subst(fast_iop) gen_code_prefix = r''' #if defined(linux) @@ -640,9 +718,9 @@ def format FloatingPointOperate(code, *opt_args) {{ gen_iop = InstObjParams(name, Name + 'General', 'AlphaFP', CodeBlock(gen_code_prefix + code + gen_code_suffix), opt_args) - (gen_declare, gen_exec) = gen_iop.subst('BasicDeclare', 'BasicExecute') - - return (fast_declare + gen_declare, decode, fast_exec + gen_exec) + header_output += BasicDeclare.subst(gen_iop) + decoder_output += BasicConstructor.subst(gen_iop) + exec_output += BasicExecute.subst(gen_iop) }}; @@ -651,7 +729,7 @@ def format FloatingPointOperate(code, *opt_args) {{ // Memory-format instructions: LoadAddress, Load, Store // -declare {{ +output header {{ /** * Base class for general Alpha memory-format instructions. */ @@ -659,49 +737,71 @@ declare {{ { protected: - /// Displacement for EA calculation (signed). - int32_t disp; /// Memory request flags. See mem_req_base.hh. unsigned memAccessFlags; + /// Pointer to EAComp object. + const StaticInstPtr eaCompPtr; + /// Pointer to MemAcc object. + const StaticInstPtr memAccPtr; /// Constructor - Memory(const char *mnem, MachInst _machInst, OpClass __opClass) + Memory(const char *mnem, MachInst _machInst, OpClass __opClass, + StaticInstPtr _eaCompPtr = nullStaticInstPtr, + StaticInstPtr _memAccPtr = nullStaticInstPtr) : AlphaStaticInst(mnem, _machInst, __opClass), - disp(MEMDISP), memAccessFlags(0) + memAccessFlags(0), eaCompPtr(_eaCompPtr), memAccPtr(_memAccPtr) { } - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) + std::string generateDisassembly(Addr pc, const SymbolTable *symtab); + + public: + + const StaticInstPtr &eaCompInst() const { return eaCompPtr; } + const StaticInstPtr &memAccInst() const { return memAccPtr; } + }; + + /** + * Base class for memory-format instructions using a 32-bit + * displacement (i.e. most of them). + */ + class MemoryDisp32 : public Memory + { + protected: + /// Displacement for EA calculation (signed). + int32_t disp; + + /// Constructor. + MemoryDisp32(const char *mnem, MachInst _machInst, OpClass __opClass, + StaticInstPtr _eaCompPtr = nullStaticInstPtr, + StaticInstPtr _memAccPtr = nullStaticInstPtr) + : Memory(mnem, _machInst, __opClass, _eaCompPtr, _memAccPtr), + disp(MEMDISP) { - return csprintf("%-10s %c%d,%d(r%d)", mnemonic, - flags[IsFloating] ? 'f' : 'r', RA, MEMDISP, RB); } }; + /** * Base class for a few miscellaneous memory-format insts * that don't interpret the disp field: wh64, fetch, fetch_m, ecb. * None of these instructions has a destination register either. */ - class MemoryNoDisp : public AlphaStaticInst + class MemoryNoDisp : public Memory { protected: - /// Memory request flags. See mem_req_base.hh. - unsigned memAccessFlags; - /// Constructor - MemoryNoDisp(const char *mnem, MachInst _machInst, OpClass __opClass) - : AlphaStaticInst(mnem, _machInst, __opClass), - memAccessFlags(0) + MemoryNoDisp(const char *mnem, MachInst _machInst, OpClass __opClass, + StaticInstPtr _eaCompPtr, + StaticInstPtr _memAccPtr) + : Memory(mnem, _machInst, __opClass, _eaCompPtr, _memAccPtr) { } - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) - { - return csprintf("%-10s (r%d)", mnemonic, RB); - } + std::string generateDisassembly(Addr pc, const SymbolTable *symtab); }; + /** * Base class for "fake" effective-address computation * instructions returnded by eaCompInst(). @@ -715,11 +815,7 @@ declare {{ { } - Fault execute(SimpleCPUExecContext *, Trace::InstRecord *) - { panic("attempt to execute eacomp"); } - - Fault execute(FullCPUExecContext *, Trace::InstRecord *) - { panic("attempt to execute eacomp"); } + %(BasicExecDeclare)s }; /** @@ -735,19 +831,48 @@ declare {{ { } - Fault execute(SimpleCPUExecContext *, Trace::InstRecord *) - { panic("attempt to execute memacc"); } - - Fault execute(FullCPUExecContext *, Trace::InstRecord *) - { panic("attempt to execute memacc"); } + %(BasicExecDeclare)s }; }}; +output decoder {{ + std::string + Memory::generateDisassembly(Addr pc, const SymbolTable *symtab) + { + return csprintf("%-10s %c%d,%d(r%d)", mnemonic, + flags[IsFloating] ? 'f' : 'r', RA, MEMDISP, RB); + } + + std::string + MemoryNoDisp::generateDisassembly(Addr pc, const SymbolTable *symtab) + { + return csprintf("%-10s (r%d)", mnemonic, RB); + } +}}; + +output exec {{ + Fault + EACompBase::execute(%(CPU_exec_context)s *, Trace::InstRecord *) + { + panic("attempt to execute eacomp"); + } + + Fault + MemAccBase::execute(%(CPU_exec_context)s *, Trace::InstRecord *) + { + panic("attempt to execute memacc"); + } +}}; + + def format LoadAddress(code) {{ - iop = InstObjParams(name, Name, 'Memory', CodeBlock(code)) - return iop.subst('BasicDeclare', 'BasicDecode', 'BasicExecute') + iop = InstObjParams(name, Name, 'MemoryDisp32', CodeBlock(code)) + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) }}; @@ -766,11 +891,7 @@ def template LoadStoreDeclare {{ { public: /// Constructor - EAComp(MachInst machInst) - : EACompBase(machInst) - { - %(ea_constructor)s; - } + EAComp(MachInst machInst); }; /** @@ -780,37 +901,41 @@ def template LoadStoreDeclare {{ { public: /// Constructor - MemAcc(MachInst machInst) - : MemAccBase(machInst, %(op_class)s) - { - %(memacc_constructor)s; - } - }; - - /// Pointer to EAComp object. - StaticInstPtr eaCompPtr; - /// Pointer to MemAcc object. - StaticInstPtr memAccPtr; + MemAcc(MachInst machInst); + }; public: - StaticInstPtr eaCompInst() { return eaCompPtr; } - StaticInstPtr memAccInst() { return memAccPtr; } - /// Constructor. - %(class_name)s(MachInst machInst) - : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s), - eaCompPtr(new EAComp(machInst)), memAccPtr(new MemAcc(machInst)) - { - %(constructor)s; - } + %(class_name)s(MachInst machInst); - %(exec_func_declarations)s + %(BasicExecDeclare)s }; }}; +def template LoadStoreConstructor {{ + inline %(class_name)s::EAComp::EAComp(MachInst machInst) + : EACompBase(machInst) + { + %(ea_constructor)s; + } + + inline %(class_name)s::MemAcc::MemAcc(MachInst machInst) + : MemAccBase(machInst, %(op_class)s) + { + %(memacc_constructor)s; + } + + inline %(class_name)s::%(class_name)s(MachInst machInst) + : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s, + new EAComp(machInst), new MemAcc(machInst)) + { + %(constructor)s; + } +}}; + def template LoadStoreExecute {{ - Fault %(class_name)s::execute(%(cpu_model)s *xc, + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) { Addr EA; @@ -842,66 +967,9 @@ def template LoadStoreExecute {{ } }}; -def template PrefetchDeclare {{ - /** - * Static instruction class for "%(mnemonic)s". - */ - class %(class_name)s : public %(base_class)s - { - protected: - - /** - * "Fake" effective address computation class for "%(mnemonic)s". - */ - class EAComp : public EACompBase - { - public: - /// Constructor - EAComp(MachInst machInst) - : EACompBase(machInst) - { - %(ea_constructor)s; - } - }; - - /** - * "Fake" memory access instruction class for "%(mnemonic)s". - */ - class MemAcc : public MemAccBase - { - public: - /// Constructor - MemAcc(MachInst machInst) - : MemAccBase(machInst, %(op_class)s) - { - %(memacc_constructor)s; - } - }; - - /// Pointer to EAComp object. - StaticInstPtr eaCompPtr; - /// Pointer to MemAcc object. - StaticInstPtr memAccPtr; - - public: - - StaticInstPtr eaCompInst() { return eaCompPtr; } - StaticInstPtr memAccInst() { return memAccPtr; } - - /// Constructor - %(class_name)s(MachInst machInst) - : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s), - eaCompPtr(new EAComp(machInst)), memAccPtr(new MemAcc(machInst)) - { - %(constructor)s; - } - - %(exec_func_declarations)s - }; -}}; def template PrefetchExecute {{ - Fault %(class_name)s::execute(%(cpu_model)s *xc, + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) { Addr EA; @@ -947,12 +1015,10 @@ def template LoadPrefetchCheckDecode {{ let {{ -global LoadStoreBase def LoadStoreBase(name, Name, ea_code, memacc_code, postacc_code = '', - base_class = 'Memory', flags = [], - declare_template = 'LoadStoreDeclare', - decode_template = 'BasicDecode', - exec_template = 'LoadStoreExecute'): + base_class = 'MemoryDisp32', flags = [], + decode_template = BasicDecode, + exec_template = LoadStoreExecute): # Segregate flags into instruction flags (handled by InstObjParams) # and memory access flags (handled here). @@ -983,62 +1049,68 @@ def LoadStoreBase(name, Name, ea_code, memacc_code, postacc_code = '', if mem_flags != '': iop.constructor += '\n\tmemAccessFlags = ' + mem_flags + ';' - return iop.subst(declare_template, decode_template, exec_template) + # (header_output, decoder_output, decode_block, exec_output) + return (LoadStoreDeclare.subst(iop), LoadStoreConstructor.subst(iop), + decode_template.subst(iop), exec_template.subst(iop)) }}; def format LoadOrNop(ea_code, memacc_code, *flags) {{ - return LoadStoreBase(name, Name, ea_code, memacc_code, - flags = flags, - decode_template = 'LoadNopCheckDecode') + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, memacc_code, flags = flags, + decode_template = LoadNopCheckDecode) }}; // Note that the flags passed in apply only to the prefetch version def format LoadOrPrefetch(ea_code, memacc_code, *pf_flags) {{ # declare the load instruction object and generate the decode block - (decls, decode, exec_code) = \ + (header_output, decoder_output, decode_block, exec_output) = \ LoadStoreBase(name, Name, ea_code, memacc_code, - decode_template = 'LoadPrefetchCheckDecode') + decode_template = LoadPrefetchCheckDecode) # Declare the prefetch instruction object. # convert flags from tuple to list to make them mutable pf_flags = list(pf_flags) + ['IsMemRef', 'IsLoad', 'IsDataPrefetch', 'RdPort'] - (pfdecls, pfdecode, pfexec) = \ + (pf_header_output, pf_decoder_output, _, pf_exec_output) = \ LoadStoreBase(name, Name + 'Prefetch', ea_code, '', - flags = pf_flags, - declare_template = 'PrefetchDeclare', - exec_template = 'PrefetchExecute') + flags = pf_flags, exec_template = PrefetchExecute) - return (decls + pfdecls, decode, exec_code + pfexec) + header_output += pf_header_output + decoder_output += pf_decoder_output + exec_output += pf_exec_output }}; def format Store(ea_code, memacc_code, *flags) {{ - return LoadStoreBase(name, Name, ea_code, memacc_code, - flags = flags) + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, memacc_code, flags = flags) }}; def format StoreCond(ea_code, memacc_code, postacc_code, *flags) {{ - return LoadStoreBase(name, Name, ea_code, memacc_code, postacc_code, - flags = flags) + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, memacc_code, postacc_code, + flags = flags) }}; // Use 'MemoryNoDisp' as base: for wh64, fetch, ecb def format MiscPrefetch(ea_code, memacc_code, *flags) {{ - return LoadStoreBase(name, Name, ea_code, memacc_code, - flags = flags, base_class = 'MemoryNoDisp') + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name, ea_code, memacc_code, flags = flags, + base_class = 'MemoryNoDisp') }}; //////////////////////////////////////////////////////////////////// +// +// Control transfer instructions +// - -declare {{ +output header {{ /** * Base class for instructions whose disassembly is not purely a @@ -1065,22 +1137,7 @@ declare {{ { } - const std::string &disassemble(Addr pc, const SymbolTable *symtab) - { - if (!cachedDisassembly || - pc != cachedPC || symtab != cachedSymtab) - { - if (cachedDisassembly) - delete cachedDisassembly; - - cachedDisassembly = - new std::string(generateDisassembly(pc, symtab)); - cachedPC = pc; - cachedSymtab = symtab; - } - - return *cachedDisassembly; - } + const std::string &disassemble(Addr pc, const SymbolTable *symtab); }; /** @@ -1100,47 +1157,9 @@ declare {{ { } - Addr branchTarget(Addr branchPC) const - { - return branchPC + 4 + disp; - } - - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) - { - std::stringstream ss; - - ccprintf(ss, "%-10s ", mnemonic); - - // There's only one register arg (RA), but it could be - // either a source (the condition for conditional - // branches) or a destination (the link reg for - // unconditional branches) - if (_numSrcRegs > 0) { - printReg(ss, _srcRegIdx[0]); - ss << ","; - } - else if (_numDestRegs > 0) { - printReg(ss, _destRegIdx[0]); - ss << ","; - } - -#ifdef SS_COMPATIBLE_DISASSEMBLY - if (_numSrcRegs == 0 && _numDestRegs == 0) { - printReg(ss, 31); - ss << ","; - } -#endif - - Addr target = pc + 4 + disp; + Addr branchTarget(Addr branchPC) const; - std::string str; - if (symtab && symtab->findSymbol(target, str)) - ss << str; - else - ccprintf(ss, "0x%x", target); - - return ss.str(); - } + std::string generateDisassembly(Addr pc, const SymbolTable *symtab); }; /** @@ -1162,36 +1181,106 @@ declare {{ { } - Addr branchTarget(ExecContext *xc) const + Addr branchTarget(ExecContext *xc) const; + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab); + }; +}}; + +output decoder {{ + Addr + Branch::branchTarget(Addr branchPC) const + { + return branchPC + 4 + disp; + } + + Addr + Jump::branchTarget(ExecContext *xc) const + { + Addr NPC = xc->readPC() + 4; + uint64_t Rb = xc->readIntReg(_srcRegIdx[0]); + return (Rb & ~3) | (NPC & 1); + } + + const std::string & + PCDependentDisassembly::disassemble(Addr pc, const SymbolTable *symtab) + { + if (!cachedDisassembly || + pc != cachedPC || symtab != cachedSymtab) { - Addr NPC = xc->readPC() + 4; - uint64_t Rb = xc->readIntReg(_srcRegIdx[0]); - return (Rb & ~3) | (NPC & 1); + if (cachedDisassembly) + delete cachedDisassembly; + + cachedDisassembly = + new std::string(generateDisassembly(pc, symtab)); + cachedPC = pc; + cachedSymtab = symtab; } - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) - { - std::stringstream ss; + return *cachedDisassembly; + } + + std::string + Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) + { + std::stringstream ss; - ccprintf(ss, "%-10s ", mnemonic); + ccprintf(ss, "%-10s ", mnemonic); + + // There's only one register arg (RA), but it could be + // either a source (the condition for conditional + // branches) or a destination (the link reg for + // unconditional branches) + if (_numSrcRegs > 0) { + printReg(ss, _srcRegIdx[0]); + ss << ","; + } + else if (_numDestRegs > 0) { + printReg(ss, _destRegIdx[0]); + ss << ","; + } #ifdef SS_COMPATIBLE_DISASSEMBLY - if (_numDestRegs == 0) { - printReg(ss, 31); - ss << ","; - } + if (_numSrcRegs == 0 && _numDestRegs == 0) { + printReg(ss, 31); + ss << ","; + } #endif - if (_numDestRegs > 0) { - printReg(ss, _destRegIdx[0]); - ss << ","; - } + Addr target = pc + 4 + disp; - ccprintf(ss, "(r%d)", RB); + std::string str; + if (symtab && symtab->findSymbol(target, str)) + ss << str; + else + ccprintf(ss, "0x%x", target); - return ss.str(); + return ss.str(); + } + + std::string + Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) + { + std::stringstream ss; + + ccprintf(ss, "%-10s ", mnemonic); + +#ifdef SS_COMPATIBLE_DISASSEMBLY + if (_numDestRegs == 0) { + printReg(ss, 31); + ss << ","; } - }; +#endif + + if (_numDestRegs > 0) { + printReg(ss, _destRegIdx[0]); + ss << ","; + } + + ccprintf(ss, "(r%d)", RB); + + return ss.str(); + } }}; def template JumpOrBranchDecode {{ @@ -1204,44 +1293,56 @@ def format CondBranch(code) {{ code = 'bool cond;\n' + code + '\nif (cond) NPC = NPC + disp;\n'; iop = InstObjParams(name, Name, 'Branch', CodeBlock(code), ('IsDirectControl', 'IsCondControl')) - return iop.subst('BasicDeclare', 'BasicDecode', 'BasicExecute') + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) }}; let {{ -global UncondCtrlBase def UncondCtrlBase(name, Name, base_class, npc_expr, flags): # Declare basic control transfer w/o link (i.e. link reg is R31) nolink_code = 'NPC = %s;\n' % npc_expr nolink_iop = InstObjParams(name, Name, base_class, CodeBlock(nolink_code), flags) - (decls, exec_code) = nolink_iop.subst('BasicDeclare', 'BasicExecute') + header_output = BasicDeclare.subst(nolink_iop) + decoder_output = BasicConstructor.subst(nolink_iop) + exec_output = BasicExecute.subst(nolink_iop) # Generate declaration of '*AndLink' version, append to decls link_code = 'Ra = NPC & ~3;\n' + nolink_code link_iop = InstObjParams(name, Name + 'AndLink', base_class, CodeBlock(link_code), flags) - (link_decls, link_exec_code) = \ - link_iop.subst('BasicDeclare', 'BasicExecute') - decls += link_decls - exec_code += link_exec_code + header_output += BasicDeclare.subst(link_iop) + decoder_output += BasicConstructor.subst(link_iop) + exec_output += BasicExecute.subst(link_iop) # need to use link_iop for the decode template since it is expecting # the shorter version of class_name (w/o "AndLink") - return (decls, nolink_iop.subst('JumpOrBranchDecode'), exec_code) + + return (header_output, decoder_output, + JumpOrBranchDecode.subst(nolink_iop), exec_output) }}; def format UncondBranch(*flags) {{ flags += ('IsUncondControl', 'IsDirectControl') - return UncondCtrlBase(name, Name, 'Branch', 'NPC + disp', flags) + (header_output, decoder_output, decode_block, exec_output) = \ + UncondCtrlBase(name, Name, 'Branch', 'NPC + disp', flags) }}; def format Jump(*flags) {{ flags += ('IsUncondControl', 'IsIndirectControl') - return UncondCtrlBase(name, Name, 'Jump', '(Rb & ~3) | (NPC & 1)', flags) + (header_output, decoder_output, decode_block, exec_output) = \ + UncondCtrlBase(name, Name, 'Jump', '(Rb & ~3) | (NPC & 1)', flags) }}; -declare {{ +//////////////////////////////////////////////////////////////////// +// +// PAL calls +// + +output header {{ /** * Base class for emulated call_pal calls (used only in * non-full-system mode). @@ -1257,23 +1358,31 @@ declare {{ { } - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) - { + std::string generateDisassembly(Addr pc, const SymbolTable *symtab); + }; +}}; + +output decoder {{ + std::string + EmulatedCallPal::generateDisassembly(Addr pc, const SymbolTable *symtab) + { #ifdef SS_COMPATIBLE_DISASSEMBLY - return csprintf("%s %s", "call_pal", mnemonic); + return csprintf("%s %s", "call_pal", mnemonic); #else - return csprintf("%-10s %s", "call_pal", mnemonic); + return csprintf("%-10s %s", "call_pal", mnemonic); #endif - } - }; + } }}; def format EmulatedCallPal(code) {{ iop = InstObjParams(name, Name, 'EmulatedCallPal', CodeBlock(code)) - return iop.subst('BasicDeclare', 'BasicDecode', 'BasicExecute') + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) }}; -declare {{ +output header {{ /** * Base class for full-system-mode call_pal instructions. * Probably could turn this into a leaf class and get rid of the @@ -1289,106 +1398,130 @@ declare {{ /// Constructor. CallPalBase(const char *mnem, MachInst _machInst, - OpClass __opClass) - : AlphaStaticInst(mnem, _machInst, __opClass), - palFunc(PALFUNC) - { - // From the 21164 HRM (paraphrased): - // Bit 7 of the function code (mask 0x80) indicates - // whether the call is privileged (bit 7 == 0) or - // unprivileged (bit 7 == 1). The privileged call table - // starts at 0x2000, the unprivielged call table starts at - // 0x3000. Bits 5-0 (mask 0x3f) are used to calculate the - // offset. - const int palPrivMask = 0x80; - const int palOffsetMask = 0x3f; - - // Pal call is invalid unless all other bits are 0 - palValid = ((machInst & ~(palPrivMask | palOffsetMask)) == 0); - palPriv = ((machInst & palPrivMask) == 0); - int shortPalFunc = (machInst & palOffsetMask); - // Add 1 to base to set pal-mode bit - palOffset = (palPriv ? 0x2001 : 0x3001) + (shortPalFunc << 6); - } - - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) - { - return csprintf("%-10s %#x", "call_pal", palFunc); - } + OpClass __opClass); + + std::string generateDisassembly(Addr pc, const SymbolTable *symtab); }; }}; +output decoder {{ + inline + CallPalBase::CallPalBase(const char *mnem, MachInst _machInst, + OpClass __opClass) + : AlphaStaticInst(mnem, _machInst, __opClass), + palFunc(PALFUNC) + { + // From the 21164 HRM (paraphrased): + // Bit 7 of the function code (mask 0x80) indicates + // whether the call is privileged (bit 7 == 0) or + // unprivileged (bit 7 == 1). The privileged call table + // starts at 0x2000, the unprivielged call table starts at + // 0x3000. Bits 5-0 (mask 0x3f) are used to calculate the + // offset. + const int palPrivMask = 0x80; + const int palOffsetMask = 0x3f; + + // Pal call is invalid unless all other bits are 0 + palValid = ((machInst & ~(palPrivMask | palOffsetMask)) == 0); + palPriv = ((machInst & palPrivMask) == 0); + int shortPalFunc = (machInst & palOffsetMask); + // Add 1 to base to set pal-mode bit + palOffset = (palPriv ? 0x2001 : 0x3001) + (shortPalFunc << 6); + } + + std::string + CallPalBase::generateDisassembly(Addr pc, const SymbolTable *symtab) + { + return csprintf("%-10s %#x", "call_pal", palFunc); + } +}}; def format CallPal(code) {{ iop = InstObjParams(name, Name, 'CallPalBase', CodeBlock(code)) - return iop.subst('BasicDeclare', 'BasicDecode', 'BasicExecute') + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) }}; +//////////////////////////////////////////////////////////////////// // // hw_ld, hw_st // -declare {{ + +output header {{ /** * Base class for hw_ld and hw_st. */ - class HwLoadStore : public AlphaStaticInst + class HwLoadStore : public Memory { protected: /// Displacement for EA calculation (signed). int16_t disp; - /// Memory request flags. See mem_req_base.hh. - unsigned memAccessFlags; /// Constructor - HwLoadStore(const char *mnem, MachInst _machInst, OpClass __opClass) - : AlphaStaticInst(mnem, _machInst, __opClass), disp(HW_LDST_DISP) - { - memAccessFlags = 0; - if (HW_LDST_PHYS) memAccessFlags |= PHYSICAL; - if (HW_LDST_ALT) memAccessFlags |= ALTMODE; - if (HW_LDST_VPTE) memAccessFlags |= VPTE; - if (HW_LDST_LOCK) memAccessFlags |= LOCKED; - } + HwLoadStore(const char *mnem, MachInst _machInst, OpClass __opClass, + StaticInstPtr _eaCompPtr, + StaticInstPtr _memAccPtr); - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) - { + std::string generateDisassembly(Addr pc, const SymbolTable *symtab); + }; +}}; + + +output decoder {{ + inline + HwLoadStore::HwLoadStore(const char *mnem, MachInst _machInst, + OpClass __opClass, + StaticInstPtr _eaCompPtr, + StaticInstPtr _memAccPtr) + : Memory(mnem, _machInst, __opClass, _eaCompPtr, _memAccPtr), + disp(HW_LDST_DISP) + { + memAccessFlags = 0; + if (HW_LDST_PHYS) memAccessFlags |= PHYSICAL; + if (HW_LDST_ALT) memAccessFlags |= ALTMODE; + if (HW_LDST_VPTE) memAccessFlags |= VPTE; + if (HW_LDST_LOCK) memAccessFlags |= LOCKED; + } + + std::string + HwLoadStore::generateDisassembly(Addr pc, const SymbolTable *symtab) + { #ifdef SS_COMPATIBLE_DISASSEMBLY - return csprintf("%-10s r%d,%d(r%d)", mnemonic, RA, disp, RB); + return csprintf("%-10s r%d,%d(r%d)", mnemonic, RA, disp, RB); #else - // HW_LDST_LOCK and HW_LDST_COND are the same bit. - const char *lock_str = - (HW_LDST_LOCK) ? (flags[IsLoad] ? ",LOCK" : ",COND") : ""; - - return csprintf("%-10s r%d,%d(r%d)%s%s%s%s%s", - mnemonic, RA, disp, RB, - HW_LDST_PHYS ? ",PHYS" : "", - HW_LDST_ALT ? ",ALT" : "", - HW_LDST_QUAD ? ",QUAD" : "", - HW_LDST_VPTE ? ",VPTE" : "", - lock_str); + // HW_LDST_LOCK and HW_LDST_COND are the same bit. + const char *lock_str = + (HW_LDST_LOCK) ? (flags[IsLoad] ? ",LOCK" : ",COND") : ""; + + return csprintf("%-10s r%d,%d(r%d)%s%s%s%s%s", + mnemonic, RA, disp, RB, + HW_LDST_PHYS ? ",PHYS" : "", + HW_LDST_ALT ? ",ALT" : "", + HW_LDST_QUAD ? ",QUAD" : "", + HW_LDST_VPTE ? ",VPTE" : "", + lock_str); #endif - } - }; + } }}; - def format HwLoadStore(ea_code, memacc_code, class_ext, *flags) {{ - return LoadStoreBase(name, Name + class_ext, ea_code, memacc_code, - flags = flags, - base_class = 'HwLoadStore') + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name + class_ext, ea_code, memacc_code, + flags = flags, base_class = 'HwLoadStore') }}; def format HwStoreCond(ea_code, memacc_code, postacc_code, class_ext, *flags) {{ - return LoadStoreBase(name, Name + class_ext, - ea_code, memacc_code, postacc_code, - flags = flags, - base_class = 'HwLoadStore') + (header_output, decoder_output, decode_block, exec_output) = \ + LoadStoreBase(name, Name + class_ext, ea_code, memacc_code, + postacc_code, flags = flags, base_class = 'HwLoadStore') }}; -declare {{ +output header {{ /** * Base class for hw_mfpr and hw_mtpr. */ @@ -1405,28 +1538,42 @@ declare {{ { } - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) - { - if (_numSrcRegs > 0) { - // must be mtpr - return csprintf("%-10s r%d,IPR(%#x)", - mnemonic, RA, ipr_index); - } - else { - // must be mfpr - return csprintf("%-10s IPR(%#x),r%d", - mnemonic, ipr_index, RA); - } - } + std::string generateDisassembly(Addr pc, const SymbolTable *symtab); }; }}; +output decoder {{ + std::string + HwMoveIPR::generateDisassembly(Addr pc, const SymbolTable *symtab) + { + if (_numSrcRegs > 0) { + // must be mtpr + return csprintf("%-10s r%d,IPR(%#x)", + mnemonic, RA, ipr_index); + } + else { + // must be mfpr + return csprintf("%-10s IPR(%#x),r%d", + mnemonic, ipr_index, RA); + } + } +}}; + def format HwMoveIPR(code) {{ iop = InstObjParams(name, Name, 'HwMoveIPR', CodeBlock(code)) - return iop.subst('BasicDeclare', 'BasicDecode', 'BasicExecute') + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = BasicDecode.subst(iop) + exec_output = BasicExecute.subst(iop) }}; -declare {{ + +//////////////////////////////////////////////////////////////////// +// +// Unimplemented instructions +// + +output header {{ /** * Static instruction class for unimplemented instructions that * cause simulator termination. Note that these are recognized @@ -1443,29 +1590,9 @@ declare {{ { } - Fault execute(SimpleCPUExecContext *xc, - Trace::InstRecord *traceData) - { - panic("attempt to execute unimplemented instruction '%s' " - "(inst 0x%08x, opcode 0x%x)", mnemonic, machInst, OPCODE); - return Unimplemented_Opcode_Fault; - } - - Fault execute(FullCPUExecContext *xc, - Trace::InstRecord *traceData) - { - // don't panic if this is a misspeculated instruction - if (!xc->misspeculating()) - panic("attempt to execute unimplemented instruction '%s' " - "(inst 0x%08x, opcode 0x%x)", - mnemonic, machInst, OPCODE); - return Unimplemented_Opcode_Fault; - } + %(BasicExecDeclare)s - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) - { - return csprintf("%-10s (unimplemented)", mnemonic); - } + std::string generateDisassembly(Addr pc, const SymbolTable *symtab); }; /** @@ -1490,39 +1617,56 @@ declare {{ { } - Fault execute(SimpleCPUExecContext *xc, - Trace::InstRecord *traceData) - { - if (!warned) { - warn("instruction '%s' unimplemented\n", mnemonic); - warned = true; - } - - return No_Fault; - } + %(BasicExecDeclare)s - Fault execute(FullCPUExecContext *xc, - Trace::InstRecord *traceData) - { - if (!xc->misspeculating() && !warned) { - warn("instruction '%s' unimplemented\n", mnemonic); - warned = true; - } + std::string generateDisassembly(Addr pc, const SymbolTable *symtab); + }; +}}; - return No_Fault; - } +output decoder {{ + std::string + FailUnimplemented::generateDisassembly(Addr pc, const SymbolTable *symtab) + { + return csprintf("%-10s (unimplemented)", mnemonic); + } - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) - { + std::string + WarnUnimplemented::generateDisassembly(Addr pc, const SymbolTable *symtab) + { #ifdef SS_COMPATIBLE_DISASSEMBLY - return csprintf("%-10s", mnemonic); + return csprintf("%-10s", mnemonic); #else - return csprintf("%-10s (unimplemented)", mnemonic); + return csprintf("%-10s (unimplemented)", mnemonic); #endif - } - }; + } }}; +output exec {{ + Fault + FailUnimplemented::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) + { + if (!xc->misspeculating()) + panic("attempt to execute unimplemented instruction '%s' " + "(inst 0x%08x, opcode 0x%x)", mnemonic, machInst, OPCODE); + return Unimplemented_Opcode_Fault; + } + + Fault + WarnUnimplemented::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) + { + if (!xc->misspeculating()) + if (!warned) { + warn("instruction '%s' unimplemented\n", mnemonic); + warned = true; + } + + return No_Fault; + } +}}; + + def template WarnUnimplDeclare {{ /** * Static instruction class for "%(mnemonic)s". @@ -1541,15 +1685,16 @@ def template WarnUnimplDeclare {{ def format FailUnimpl() {{ iop = InstObjParams(name, 'FailUnimplemented') - return ('', iop.subst('BasicDecodeWithMnemonic'), '') + decode_block = BasicDecodeWithMnemonic.subst(iop) }}; def format WarnUnimpl() {{ iop = InstObjParams(name, Name, 'WarnUnimplemented') - return iop.subst('WarnUnimplDeclare', 'BasicDecode') + [''] + header_output = WarnUnimplDeclare.subst(iop) + decode_block = BasicDecode.subst(iop) }}; -declare {{ +output header {{ /** * Static instruction class for unknown (illegal) instructions. * These cause simulator termination if they are executed in a @@ -1564,37 +1709,47 @@ declare {{ { } - Fault execute(SimpleCPUExecContext *xc, - Trace::InstRecord *traceData) - { - panic("attempt to execute unknown instruction " - "(inst 0x%08x, opcode 0x%x)", machInst, OPCODE); - return Unimplemented_Opcode_Fault; - } + %(BasicExecDeclare)s - Fault execute(FullCPUExecContext *xc, - Trace::InstRecord *traceData) - { - // don't panic if this is a misspeculated instruction - if (!xc->misspeculating()) - panic("attempt to execute unknown instruction " - "(inst 0x%08x, opcode 0x%x)", machInst, OPCODE); - return Unimplemented_Opcode_Fault; - } - - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) - { - return csprintf("%-10s (inst 0x%x, opcode 0x%x)", - "unknown", machInst, OPCODE); - } + std::string generateDisassembly(Addr pc, const SymbolTable *symtab); }; }}; +//////////////////////////////////////////////////////////////////// +// +// Unknown instructions +// + +output decoder {{ + std::string + Unknown::generateDisassembly(Addr pc, const SymbolTable *symtab) + { + return csprintf("%-10s (inst 0x%x, opcode 0x%x)", + "unknown", machInst, OPCODE); + } +}}; + +output exec {{ + Fault + Unknown::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) + { + if (!xc->misspeculating()) + panic("attempt to execute unknown instruction " + "(inst 0x%08x, opcode 0x%x)", machInst, OPCODE); + return Unimplemented_Opcode_Fault; + } +}}; + def format Unknown() {{ - return ('', 'return new Unknown(machInst);\n', '') + decode_block = 'return new Unknown(machInst);\n' }}; -declare {{ +//////////////////////////////////////////////////////////////////// +// +// Utility functions for execute methods +// + +output exec {{ /// Return opa + opb, summing carry into third arg. inline uint64_t @@ -1608,7 +1763,7 @@ declare {{ /// Multiply two 64-bit values (opa * opb), returning the 128-bit /// product in res_hi and res_lo. - void + inline void mul128(uint64_t opa, uint64_t opb, uint64_t &res_hi, uint64_t &res_lo) { // do a 64x64 --> 128 multiply using four 32x32 --> 64 multiplies @@ -1678,6 +1833,11 @@ declare {{ } }}; +//////////////////////////////////////////////////////////////////// +// +// The actual decoder specification +// + decode OPCODE default Unknown::unknown() { format LoadAddress { diff --git a/arch/isa_parser.py b/arch/isa_parser.py index 0ee9e2e2d..621720709 100755 --- a/arch/isa_parser.py +++ b/arch/isa_parser.py @@ -63,8 +63,9 @@ import yacc # using the same regexp as generic IDs, but distinguished in the # t_ID() function. The PLY documentation suggests this approach. reserved = ( - 'BITFIELD', 'DECLARE', 'DECODE', 'DEFAULT', 'DEF', 'FORMAT', - 'LET', 'NAMESPACE', 'SIGNED', 'TEMPLATE' + 'BITFIELD', 'DECODE', 'DECODER', 'DEFAULT', 'DEF', 'EXEC', 'FORMAT', + 'HEADER', 'LET', 'NAMESPACE', 'OPERAND_TYPES', 'OPERANDS', + 'OUTPUT', 'SIGNED', 'TEMPLATE' ) # List of tokens. The lex module requires this. @@ -195,14 +196,6 @@ lex.lex() # (by assigning to t[0]). ##################################################################### -# Not sure why, but we get a handful of shift/reduce conflicts on DECLARE. -# By default these get resolved as shifts, which is correct, but -# warnings are printed. Explicitly marking DECLARE as right-associative -# suppresses the warnings. -precedence = ( - ('right', 'DECLARE'), - ) - # The LHS of the first grammar rule is used as the start symbol # (in this case, 'specification'). Note that this rule enforces # that there will be exactly one namespace declaration, with 0 or more @@ -210,163 +203,123 @@ precedence = ( # the namespace decl will be outside the namespace; those after # will be inside. The decoder function is always inside the namespace. def p_specification(t): - 'specification : opt_defs_and_declares name_decl opt_defs_and_declares decode_block' - global_decls1 = t[1] + 'specification : opt_defs_and_outputs name_decl opt_defs_and_outputs decode_block' + global_code = t[1] isa_name = t[2] namespace = isa_name + "Inst" - global_decls2 = t[3] - (inst_decls, decode_code, exec_code) = t[4] - decode_code = indent(decode_code) - # grab the last three path components of isa_desc_filename - filename = '/'.join(isa_desc_filename.split('/')[-3:]) - # if the isa_desc file defines a 'rcs_id' string, - # echo that into the output too - try: - local_rcs_id = rcs_id - # strip $s out of ID so it doesn't get re-substituted - local_rcs_id = re.sub(r'\$', '', local_rcs_id) - except NameError: - local_rcs_id = 'Id: no RCS id found' - output = open(decoder_filename, 'w') - # split string to keep rcs from substituting this file's RCS id in - print >> output, '/* $Id' + '''$ */ - -/* - * Copyright (c) 2003 - * The Regents of The University of Michigan - * All Rights Reserved - * - * This code is part of the M5 simulator, developed by Nathan Binkert, - * Erik Hallnor, Steve Raasch, and Steve Reinhardt, with contributions - * from Ron Dreslinski, Dave Greene, and Lisa Hsu. - * - * Permission is granted to use, copy, create derivative works and - * redistribute this software and such derivative works for any - * purpose, so long as the copyright notice above, this grant of - * permission, and the disclaimer below appear in all copies made; and - * so long as the name of The University of Michigan is not used in - * any advertising or publicity pertaining to the use or distribution - * of this software without specific, written prior authorization. - * - * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE - * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND - * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE - * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT, - * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM - * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN - * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGES. - */ - -/* - * DO NOT EDIT THIS FILE!!! - * - * It was automatically generated from this ISA description: - * Filename: %(filename)s - * RCS %(local_rcs_id)s - */ - -#include "base/bitfield.hh" // required for bitfield support - - -///////////////////////////////////// -// Global defs (outside namespace) // -///////////////////////////////////// - -%(global_decls1)s - -/** - * Namespace for %(isa_name)s static instruction objects. - */ -namespace %(namespace)s -{ - -///////////////////////////////////// -// Global defs (within namespace) // -///////////////////////////////////// - -%(global_decls2)s - -//////////////////////////////////// -// Declares from inst definitions // -//////////////////////////////////// - -%(inst_decls)s - -%(exec_code)s - -} // namespace %(namespace)s - -////////////////////// -// Decoder function // -////////////////////// - + # wrap the decode block as a function definition + t[4].wrap_decode_block(''' StaticInstPtr<%(isa_name)s> %(isa_name)s::decodeInst(%(isa_name)s::MachInst machInst) { using namespace %(namespace)s; -%(decode_code)s -} // decodeInst -''' % vars() - output.close() +''' % vars(), '}') + # both the latter output blocks and the decode block are in the namespace + namespace_code = t[3] + t[4] + # pass it all back to the caller of yacc.parse() + t[0] = (isa_name, namespace, global_code, namespace_code) # ISA name declaration looks like "namespace ;" def p_name_decl(t): 'name_decl : NAMESPACE ID SEMI' t[0] = t[2] -# 'opt_defs_and_declares' is a possibly empty sequence of -# defs and/or declares. -def p_opt_defs_and_declares_0(t): - 'opt_defs_and_declares : empty' - t[0] = '' +# 'opt_defs_and_outputs' is a possibly empty sequence of +# def and/or output statements. +def p_opt_defs_and_outputs_0(t): + 'opt_defs_and_outputs : empty' + t[0] = GenCode() -def p_opt_defs_and_declares_1(t): - 'opt_defs_and_declares : defs_and_declares' +def p_opt_defs_and_outputs_1(t): + 'opt_defs_and_outputs : defs_and_outputs' t[0] = t[1] -def p_defs_and_declares_0(t): - 'defs_and_declares : def_or_declare' +def p_defs_and_outputs_0(t): + 'defs_and_outputs : def_or_output' t[0] = t[1] -def p_defs_and_declares_1(t): - 'defs_and_declares : defs_and_declares def_or_declare' +def p_defs_and_outputs_1(t): + 'defs_and_outputs : defs_and_outputs def_or_output' t[0] = t[1] + t[2] -# The list of possible definition/declaration statements. -def p_def_or_declare(t): - '''def_or_declare : def_format - | def_bitfield - | def_template - | global_declare - | global_let - | cpp_directive''' +# The list of possible definition/output statements. +def p_def_or_output(t): + '''def_or_output : def_format + | def_bitfield + | def_template + | def_operand_types + | def_operands + | output_header + | output_decoder + | output_exec + | global_let''' t[0] = t[1] -# preprocessor directives are copied directly to the output. -def p_cpp_directive(t): - '''cpp_directive : CPPDIRECTIVE''' - t[0] = t[1] - -# Global declares 'declare {{...}}' (C++ code blocks) are copied -# directly to the output. -def p_global_declare(t): - 'global_declare : DECLARE CODELIT SEMI' - t[0] = substBitOps(t[2]) +# Output blocks 'output {{...}}' (C++ code blocks) are copied +# directly to the appropriate output section. + +# Massage output block by substituting in template definitions and bit +# operators. We handle '%'s embedded in the string that don't +# indicate template substitutions (or CPU-specific symbols, which get +# handled in GenCode) by doubling them first so that the format +# operation will reduce them back to single '%'s. +def process_output(s): + # protect any non-substitution '%'s (not followed by '(') + s = re.sub(r'%(?!\()', '%%', s) + # protects cpu-specific symbols too + s = protect_cpu_symbols(s) + return substBitOps(s % templateMap) + +def p_output_header(t): + 'output_header : OUTPUT HEADER CODELIT SEMI' + t[0] = GenCode(header_output = process_output(t[3])) + +def p_output_decoder(t): + 'output_decoder : OUTPUT DECODER CODELIT SEMI' + t[0] = GenCode(decoder_output = process_output(t[3])) + +def p_output_exec(t): + 'output_exec : OUTPUT EXEC CODELIT SEMI' + t[0] = GenCode(exec_output = process_output(t[3])) # global let blocks 'let {{...}}' (Python code blocks) are executed -# directly when seen. These are typically used to initialize global -# Python variables used in later format definitions. +# directly when seen. Note that these execute in a special variable +# context 'exportContext' to prevent the code from polluting this +# script's namespace. def p_global_let(t): 'global_let : LET CODELIT SEMI' + updateExportContext() + try: + exec fixPythonIndentation(t[2]) in exportContext + except Exception, exc: + error(t.lineno(1), + 'error: %s in global let block "%s".' % (exc, t[2])) + t[0] = GenCode() # contributes nothing to the output C++ file + +# Define the mapping from operand type extensions to C++ types and bit +# widths (stored in operandTypeMap). +def p_def_operand_types(t): + 'def_operand_types : DEF OPERAND_TYPES CODELIT SEMI' + s = 'global operandTypeMap; operandTypeMap = {' + t[3] + '}' try: - exec(fixPythonIndentation(t[2])) - except: - error_bt(t.lineno(1), 'error in global let block "%s".' % t[2]) - t[0] = '' # contributes nothing to the output C++ file + exec s + except Exception, exc: + error(t.lineno(1), + 'error: %s in def operand_types block "%s".' % (exc, t[3])) + t[0] = GenCode() # contributes nothing to the output C++ file + +# Define the mapping from operand names to operand classes and other +# traits. Stored in operandTraitsMap. +def p_def_operands(t): + 'def_operands : DEF OPERANDS CODELIT SEMI' + s = 'global operandTraitsMap; operandTraitsMap = {' + t[3] + '}' + try: + exec s + except Exception, exc: + error(t.lineno(1), + 'error: %s in def operands block "%s".' % (exc, t[3])) + defineDerivedOperandVars() + t[0] = GenCode() # contributes nothing to the output C++ file # A bitfield definition looks like: # 'def [signed] bitfield [:]' @@ -376,7 +329,8 @@ def p_def_bitfield_0(t): expr = 'bits(machInst, %2d, %2d)' % (t[6], t[8]) if (t[2] == 'signed'): expr = 'sext<%d>(%s)' % (t[6] - t[8] + 1, expr) - t[0] = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr) + hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr) + t[0] = GenCode(header_output = hash_define) # alternate form for single bit: 'def [signed] bitfield []' def p_def_bitfield_1(t): @@ -384,7 +338,8 @@ def p_def_bitfield_1(t): expr = 'bits(machInst, %2d, %2d)' % (t[6], t[6]) if (t[2] == 'signed'): expr = 'sext<%d>(%s)' % (1, expr) - t[0] = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr) + hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr) + t[0] = GenCode(header_output = hash_define) def p_opt_signed_0(t): 'opt_signed : SIGNED' @@ -399,8 +354,8 @@ templateMap = {} def p_def_template(t): 'def_template : DEF TEMPLATE ID CODELIT SEMI' - templateMap[t[3]] = t[4] - t[0] = '' + templateMap[t[3]] = Template(t[4]) + t[0] = GenCode() # An instruction format definition looks like # "def format () {{...}};" @@ -408,12 +363,7 @@ def p_def_format(t): 'def_format : DEF FORMAT ID LPAREN param_list RPAREN CODELIT SEMI' (id, params, code) = (t[3], t[5], t[7]) defFormat(id, params, code, t.lineno(1)) - # insert a comment into the output to note that the def was processed - t[0] = ''' -// -// parser: format %s defined -// -''' % id + t[0] = GenCode() # The formal parameter list for an instruction format is a possibly # empty list of comma-separated parameters. @@ -453,19 +403,13 @@ def p_param_1(t): def p_decode_block(t): 'decode_block : DECODE ID opt_default LBRACE decode_stmt_list RBRACE' default_defaults = defaultStack.pop() - (decls, decode_code, exec_code, has_default) = t[5] + codeObj = t[5] # use the "default defaults" only if there was no explicit # default statement in decode_stmt_list - if not has_default: - (default_decls, default_decode, default_exec) = default_defaults - decls += default_decls - decode_code += default_decode - exec_code += default_exec - t[0] = (decls, ''' -switch (%s) { -%s -} -''' % (t[2], indent(decode_code)), exec_code) + if not codeObj.has_decode_default: + codeObj += default_defaults + codeObj.wrap_decode_block('switch (%s) {\n' % t[2], '}\n') + t[0] = codeObj # The opt_default statement serves only to push the "default defaults" # onto defaultStack. This value will be used by nested decode blocks, @@ -481,8 +425,9 @@ def p_opt_default_0(t): def p_opt_default_1(t): 'opt_default : DEFAULT inst' # push the new default - (decls, decode_code, exec_code) = t[2] - defaultStack.push((decls, '\ndefault:\n%sbreak;' % decode_code, exec_code)) + codeObj = t[2] + codeObj.wrap_decode_block('\ndefault:\n', 'break;\n') + defaultStack.push(codeObj) # no meaningful value returned t[0] = None @@ -492,12 +437,9 @@ def p_decode_stmt_list_0(t): def p_decode_stmt_list_1(t): 'decode_stmt_list : decode_stmt decode_stmt_list' - (decls1, decode_code1, exec_code1, has_default1) = t[1] - (decls2, decode_code2, exec_code2, has_default2) = t[2] - if (has_default1 and has_default2): + if (t[1].has_decode_default and t[2].has_decode_default): error(t.lineno(1), 'Two default cases in decode block') - t[0] = (decls1 + '\n' + decls2, decode_code1 + '\n' + decode_code2, - exec_code1 + '\n' + exec_code2, has_default1 or has_default2) + t[0] = t[1] + t[2] # # Decode statement rules @@ -510,7 +452,7 @@ def p_decode_stmt_list_1(t): # Preprocessor directives found in a decode statement list are passed -# through to the output, replicated to both the declaration and decode +# through to the output, replicated to all of the output code # streams. This works well for ifdefs, so we can ifdef out both the # declarations and the decode cases generated by an instruction # definition. Handling them as part of the grammar makes it easy to @@ -518,7 +460,7 @@ def p_decode_stmt_list_1(t): # the other statements. def p_decode_stmt_cpp(t): 'decode_stmt : CPPDIRECTIVE' - t[0] = (t[1], t[1], t[1], 0) + t[0] = GenCode(t[1], t[1], t[1], t[1]) # A format block 'format { ... }' sets the default instruction # format used to handle instruction definitions inside the block. @@ -547,29 +489,31 @@ def p_push_format_id(t): # specified constant, do a nested decode on some other field. def p_decode_stmt_decode(t): 'decode_stmt : case_label COLON decode_block' - (label, is_default) = t[1] - (decls, decode_code, exec_code) = t[3] + label = t[1] + codeObj = t[3] # just wrap the decoding code from the block as a case in the # outer switch statement. - t[0] = (decls, '\n%s:\n%s' % (label, indent(decode_code)), - exec_code, is_default) + codeObj.wrap_decode_block('\n%s:\n' % label) + codeObj.has_decode_default = (label == 'default') + t[0] = codeObj # Instruction definition (finally!). def p_decode_stmt_inst(t): 'decode_stmt : case_label COLON inst SEMI' - (label, is_default) = t[1] - (decls, decode_code, exec_code) = t[3] - t[0] = (decls, '\n%s:%sbreak;' % (label, indent(decode_code)), - exec_code, is_default) + label = t[1] + codeObj = t[3] + codeObj.wrap_decode_block('\n%s:' % label, 'break;\n') + codeObj.has_decode_default = (label == 'default') + t[0] = codeObj # The case label is either a list of one or more constants or 'default' def p_case_label_0(t): 'case_label : intlit_list' - t[0] = (': '.join(map(lambda a: 'case %#x' % a, t[1])), 0) + t[0] = ': '.join(map(lambda a: 'case %#x' % a, t[1])) def p_case_label_1(t): 'case_label : DEFAULT' - t[0] = ('default', 1) + t[0] = 'default' # # The constant list for a decode case label must be non-empty, but may have @@ -591,13 +535,13 @@ def p_inst_0(t): 'inst : ID LPAREN arg_list RPAREN' # Pass the ID and arg list to the current format class to deal with. currentFormat = formatStack.top() - (decls, decode_code, exec_code) = \ - currentFormat.defineInst(t[1], t[3], t.lineno(1)) + codeObj = currentFormat.defineInst(t[1], t[3], t.lineno(1)) args = ','.join(map(str, t[3])) args = re.sub('(?m)^', '//', args) args = re.sub('^//', '', args) - comment = '// %s::%s(%s)\n' % (currentFormat.id, t[1], args) - t[0] = (comment + decls, comment + decode_code, comment + exec_code) + comment = '\n// %s::%s(%s)\n' % (currentFormat.id, t[1], args) + codeObj.prepend_all(comment) + t[0] = codeObj # Define an instruction using an explicitly specified format: # "::()" @@ -607,10 +551,10 @@ def p_inst_1(t): format = formatMap[t[1]] except KeyError: error(t.lineno(1), 'instruction format "%s" not defined.' % t[1]) - (decls, decode_code, exec_code) = \ - format.defineInst(t[3], t[5], t.lineno(1)) - comment = '// %s::%s(%s)\n' % (t[1], t[3], t[5]) - t[0] = (comment + decls, comment + decode_code, comment + exec_code) + codeObj = format.defineInst(t[3], t[5], t.lineno(1)) + comment = '\n// %s::%s(%s)\n' % (t[1], t[3], t[5]) + codeObj.prepend_all(comment) + t[0] = codeObj def p_arg_list_0(t): 'arg_list : empty' @@ -652,6 +596,133 @@ def p_error(t): # Now build the parser. yacc.yacc() + +##################################################################### +# +# Support Classes +# +##################################################################### + +################ +# CpuModel class +# +# The CpuModel class encapsulates everything we need to know about a +# particular CPU model. + +class CpuModel: + # List of all CPU models. Accessible as CpuModel.list. + list = [] + + # Constructor. Automatically adds models to CpuModel.list. + def __init__(self, name, filename, includes, strings): + self.name = name + self.filename = filename # filename for output exec code + self.includes = includes # include files needed in exec file + # The 'strings' dict holds all the per-CPU symbols we can + # substitute into templates etc. + self.strings = strings + # Add self to list. + CpuModel.list.append(self) + +# Define CPU models. The following lines should contain the only +# CPU-model-specific information in this file. Note that the ISA +# description itself should have *no* CPU-model-specific content. +CpuModel('SimpleCPU', 'simple_cpu_exec.cc', + '#include "cpu/simple_cpu/simple_cpu.hh"', + { 'CPU_exec_context': 'SimpleCPU' }) +CpuModel('FullCPU', 'full_cpu_exec.cc', + '#include "cpu/full_cpu/dyn_inst.hh"', + { 'CPU_exec_context': 'DynInst' }) + +# Expand template with CPU-specific references into a dictionary with +# an entry for each CPU model name. The entry key is the model name +# and the corresponding value is the template with the CPU-specific +# refs substituted for that model. +def expand_cpu_symbols_to_dict(template): + # Protect '%'s that don't go with CPU-specific terms + t = re.sub(r'%(?!\(CPU_)', '%%', template) + result = {} + for cpu in CpuModel.list: + result[cpu.name] = t % cpu.strings + return result + +# *If* the template has CPU-specific references, return a single +# string containing a copy of the template for each CPU model with the +# corresponding values substituted in. If the template has no +# CPU-specific references, it is returned unmodified. +def expand_cpu_symbols_to_string(template): + if template.find('%(CPU_') != -1: + return reduce(lambda x,y: x+y, + expand_cpu_symbols_to_dict(template).values()) + else: + return template + +# Protect CPU-specific references by doubling the corresponding '%'s +# (in preparation for substituting a different set of references into +# the template). +def protect_cpu_symbols(template): + return re.sub(r'%(?=\(CPU_)', '%%', template) + +############### +# GenCode class +# +# The GenCode class encapsulates generated code destined for various +# output files. The header_output and decoder_output attributes are +# strings containing code destined for decoder.hh and decoder.cc +# respectively. The decode_block attribute contains code to be +# incorporated in the decode function itself (that will also end up in +# decoder.cc). The exec_output attribute is a dictionary with a key +# for each CPU model name; the value associated with a particular key +# is the string of code for that CPU model's exec.cc file. The +# has_decode_default attribute is used in the decode block to allow +# explicit default clauses to override default default clauses. + +class GenCode: + # Constructor. At this point we substitute out all CPU-specific + # symbols. For the exec output, these go into the per-model + # dictionary. For all other output types they get collapsed into + # a single string. + def __init__(self, + header_output = '', decoder_output = '', exec_output = '', + decode_block = '', has_decode_default = False): + self.header_output = expand_cpu_symbols_to_string(header_output) + self.decoder_output = expand_cpu_symbols_to_string(decoder_output) + if isinstance(exec_output, dict): + self.exec_output = exec_output + elif isinstance(exec_output, str): + # If the exec_output arg is a single string, we replicate + # it for each of the CPU models, substituting and + # %(CPU_foo)s params appropriately. + self.exec_output = expand_cpu_symbols_to_dict(exec_output) + self.decode_block = expand_cpu_symbols_to_string(decode_block) + self.has_decode_default = has_decode_default + + # Override '+' operator: generate a new GenCode object that + # concatenates all the individual strings in the operands. + def __add__(self, other): + exec_output = {} + for cpu in CpuModel.list: + n = cpu.name + exec_output[n] = self.exec_output[n] + other.exec_output[n] + return GenCode(self.header_output + other.header_output, + self.decoder_output + other.decoder_output, + exec_output, + self.decode_block + other.decode_block, + self.has_decode_default or other.has_decode_default) + + # Prepend a string (typically a comment) to all the strings. + def prepend_all(self, pre): + self.header_output = pre + self.header_output + self.decoder_output = pre + self.decoder_output + self.decode_block = pre + self.decode_block + for cpu in CpuModel.list: + self.exec_output[cpu.name] = pre + self.exec_output[cpu.name] + + # Wrap the decode block in a pair of strings (e.g., 'case foo:' + # and 'break;'). Used to build the big nested switch statement. + def wrap_decode_block(self, pre, post = ''): + self.decode_block = pre + indent(self.decode_block) + post + ################ # Format object. # @@ -664,24 +735,31 @@ class Format: # constructor: just save away arguments self.id = id self.params = params - # strip blank lines from code (ones at the end are troublesome) - code = re.sub(r'(?m)^\s*$', '', code); - if code == '': - code = ' pass\n' + label = 'def format ' + id + self.user_code = compile(fixPythonIndentation(code), label, 'exec') param_list = string.join(params, ", ") - f = 'def defInst(name, Name, ' + param_list + '):\n' + code - c = compile(f, 'def format ' + id, 'exec') - exec(c) + f = '''def defInst(_code, _context, %s): + my_locals = vars().copy() + exec _code in _context, my_locals + return my_locals\n''' % param_list + c = compile(f, label + ' wrapper', 'exec') + exec c self.func = defInst def defineInst(self, name, args, lineno): - # automatically provide a capitalized version of mnemonic - Name = string.capitalize(name) + context = {} + updateExportContext() + context.update(exportContext) + context.update({ 'name': name, 'Name': string.capitalize(name) }) try: - retval = self.func(name, Name, *args) - except: - error_bt(lineno, 'error defining "%s".' % name) - return retval + vars = self.func(self.user_code, context, *args) + except Exception, exc: + error(lineno, 'error defining "%s": %s.' % (name, exc)) + for k in vars.keys(): + if k not in ('header_output', 'decoder_output', + 'exec_output', 'decode_block'): + del vars[k] + return GenCode(**vars) # Special null format to catch an implicit-format instruction # definition outside of any format block. @@ -766,13 +844,13 @@ def fixPythonIndentation(s): # Error handler. Just call exit. Output formatted to work under # Emacs compile-mode. def error(lineno, string): - sys.exit("%s:%d: %s" % (isa_desc_filename, lineno, string)) + sys.exit("%s:%d: %s" % (input_filename, lineno, string)) # Like error(), but include a Python stack backtrace (for processing # Python exceptions). def error_bt(lineno, string): traceback.print_exc() - print >> sys.stderr, "%s:%d: %s" % (isa_desc_filename, lineno, string) + print >> sys.stderr, "%s:%d: %s" % (input_filename, lineno, string) sys.exit(1) @@ -817,6 +895,37 @@ def substBitOps(code): return code +#################### +# Template objects. +# +# Template objects are format strings that allow substitution from +# the attribute spaces of other objects (e.g. InstObjParams instances). + +class Template: + def __init__(self, t): + self.template = t + + def subst(self, d): + # Start with the template namespace. Make a copy since we're + # going to modify it. + myDict = templateMap.copy() + # if the argument is a dictionary, we just use it. + if isinstance(d, dict): + myDict.update(d) + # if the argument is an object, we use its attribute map. + elif hasattr(d, '__dict__'): + myDict.update(d.__dict__) + else: + raise TypeError, "Template.subst() arg must be or have dictionary" + # CPU-model-specific substitutions are handled later (in GenCode). + return protect_cpu_symbols(self.template) % myDict + + # Convert to string. This handles the case when a template with a + # CPU-specific term gets interpolated into another template or into + # an output block. + def __str__(self): + return expand_cpu_symbols_to_string(self.template) + ##################################################################### # # Code Parser @@ -1111,6 +1220,22 @@ class NPCOperandTraits(OperandTraits): return 'xc->setNextPC(%s);\n' % op_desc.munged_name +exportContextSymbols = ('IntRegOperandTraits', 'FloatRegOperandTraits', + 'ControlRegOperandTraits', 'MemOperandTraits', + 'NPCOperandTraits', 'InstObjParams', 'CodeBlock', + 're', 'string') + +exportContext = {} + +def updateExportContext(): + exportContext.update(exportDict(*exportContextSymbols)) + exportContext.update(templateMap) + + +def exportDict(*symNames): + return dict([(s, eval(s)) for s in symNames]) + + # # Define operand variables that get derived from the basic declaration # of ISA-specific operands in operandTraitsMap. This function must be @@ -1385,10 +1510,6 @@ class InstObjParams: self.mnemonic = mnem self.class_name = class_name self.base_class = base_class - self.exec_func_declarations = ''' - Fault execute(SimpleCPUExecContext *, Trace::InstRecord *); - Fault execute(FullCPUExecContext *, Trace::InstRecord *); -''' if code_block: for code_attr in code_block.__dict__.keys(): setattr(self, code_attr, getattr(code_block, code_attr)) @@ -1419,48 +1540,125 @@ class InstObjParams: else: self.fp_enable_check = '' - def _subst(self, template): - try: - return template % self.__dict__ - except KeyError, key: - raise KeyError, 'InstObjParams.subst: no definition for %s' % key - - def subst(self, *args): - result = [] - for t in args: - try: template = templateMap[t] - except KeyError: - error(0, 'InstObjParams::subst: undefined template "%s"' % t) - if template.find('%(cpu_model)') != -1: - tmp = '' - for cpu_model in ('SimpleCPUExecContext', 'FullCPUExecContext'): - self.cpu_model = cpu_model - tmp += self._subst(template) - result.append(tmp) - else: - result.append(self._subst(template)) - if len(args) == 1: - result = result[0] - return result +####################### +# +# Output file template +# + +file_template = ''' +/* + * Copyright (c) 2003 + * The Regents of The University of Michigan + * All Rights Reserved + * + * This code is part of the M5 simulator, developed by Nathan Binkert, + * Erik Hallnor, Steve Raasch, and Steve Reinhardt, with contributions + * from Ron Dreslinski, Dave Greene, and Lisa Hsu. + * + * Permission is granted to use, copy, create derivative works and + * redistribute this software and such derivative works for any + * purpose, so long as the copyright notice above, this grant of + * permission, and the disclaimer below appear in all copies made; and + * so long as the name of The University of Michigan is not used in + * any advertising or publicity pertaining to the use or distribution + * of this software without specific, written prior authorization. + * + * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE + * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND + * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE + * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT, + * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM + * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN + * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGES. + */ + +/* + * DO NOT EDIT THIS FILE!!! + * + * It was automatically generated from the ISA description in %(filename)s + */ + +%(includes)s + +%(global_output)s + +namespace %(namespace)s { + +%(namespace_output)s + +} // namespace %(namespace)s +''' + + +# Update the output file only if the new contents are different from +# the current contents. Minimizes the files that need to be rebuilt +# after minor changes. +def update_if_needed(file, contents): + update = False + if os.access(file, os.R_OK): + f = open(file, 'r') + old_contents = f.read() + f.close() + if contents != old_contents: + print 'Updating', file + os.remove(file) # in case it's write-protected + update = True + else: + print 'File', file, 'is unchanged' + else: + print 'Generating', file + update = True + if update: + f = open(file, 'w') + f.write(contents) + f.close() # # Read in and parse the ISA description. # -def parse_isa_desc(isa_desc_file, decoder_file): - # Arguments are the name of the ISA description (input) file and - # the name of the C++ decoder (output) file. - global isa_desc_filename, decoder_filename - isa_desc_filename = isa_desc_file - decoder_filename = decoder_file +def parse_isa_desc(isa_desc_file, output_dir, include_path): + # set a global var for the input filename... used in error messages + global input_filename + input_filename = isa_desc_file # Suck the ISA description file in. - input = open(isa_desc_filename) + input = open(isa_desc_file) isa_desc = input.read() input.close() # Parse it. - yacc.parse(isa_desc) + (isa_name, namespace, global_code, namespace_code) = yacc.parse(isa_desc) + + # grab the last three path components of isa_desc_file to put in + # the output + filename = '/'.join(isa_desc_file.split('/')[-3:]) + + # generate decoder.hh + includes = '#include "base/bitfield.hh" // for bitfield support' + global_output = global_code.header_output + namespace_output = namespace_code.header_output + update_if_needed(output_dir + '/decoder.hh', file_template % vars()) + + # generate decoder.cc + includes = '#include "%s/decoder.hh"' % include_path + global_output = global_code.decoder_output + namespace_output = namespace_code.decoder_output + namespace_output += namespace_code.decode_block + update_if_needed(output_dir + '/decoder.cc', file_template % vars()) + + # generate per-cpu exec files + for cpu in CpuModel.list: + includes = '#include "%s/decoder.hh"\n' % include_path + includes += cpu.includes + global_output = global_code.exec_output[cpu.name] + namespace_output = namespace_code.exec_output[cpu.name] + update_if_needed(output_dir + '/' + cpu.filename, + file_template % vars()) # Called as script: get args from command line. if __name__ == '__main__': - parse_isa_desc(sys.argv[1], sys.argv[2]) + parse_isa_desc(sys.argv[1], sys.argv[2], sys.argv[3]) diff --git a/cpu/simple_cpu/simple_cpu.hh b/cpu/simple_cpu/simple_cpu.hh index 07d6cb0c9..a04dcd057 100644 --- a/cpu/simple_cpu/simple_cpu.hh +++ b/cpu/simple_cpu/simple_cpu.hh @@ -34,7 +34,7 @@ #include "base/loader/symtab.hh" #include "cpu/pc_event.hh" #include "base/statistics.hh" - +#include "cpu/exec_context.hh" // forward declarations #ifdef FULL_SYSTEM @@ -46,6 +46,11 @@ class PhysicalMemory; class RemoteGDB; class GDBListener; + +#else + +class Process; + #endif // FULL_SYSTEM class MemInterface; @@ -305,6 +310,4 @@ class SimpleCPU : public BaseCPU ExecContext *xcBase() { return xc; } }; -typedef SimpleCPU SimpleCPUExecContext; - #endif // __SIMPLE_CPU_HH__ diff --git a/cpu/static_inst.hh b/cpu/static_inst.hh index 57208f8e6..1065fa3d4 100644 --- a/cpu/static_inst.hh +++ b/cpu/static_inst.hh @@ -42,9 +42,7 @@ // forward declarations class ExecContext; class DynInst; -typedef DynInst FullCPUExecContext; class SimpleCPU; -typedef SimpleCPU SimpleCPUExecContext; class SymbolTable; namespace Trace { @@ -249,7 +247,8 @@ class StaticInst : public StaticInstBase * obtain the dependence info (numSrcRegs and srcRegIdx[]) for * just the EA computation. */ - virtual StaticInstPtr eaCompInst() { return nullStaticInstPtr; } + virtual const + StaticInstPtr &eaCompInst() const { return nullStaticInstPtr; } /** * Memory references only: returns "fake" instruction representing @@ -257,7 +256,8 @@ class StaticInst : public StaticInstBase * obtain the dependence info (numSrcRegs and srcRegIdx[]) for * just the memory access (not the EA computation). */ - virtual StaticInstPtr memAccInst() { return nullStaticInstPtr; } + virtual const + StaticInstPtr &memAccInst() const { return nullStaticInstPtr; } /// The binary machine instruction. const MachInst machInst; @@ -307,14 +307,12 @@ class StaticInst : public StaticInstBase /** * Execute this instruction under SimpleCPU model. */ - virtual Fault execute(SimpleCPUExecContext *xc, - Trace::InstRecord *traceData) = 0; + virtual Fault execute(SimpleCPU *xc, Trace::InstRecord *traceData) = 0; /** * Execute this instruction under detailed FullCPU model. */ - virtual Fault execute(FullCPUExecContext *xc, - Trace::InstRecord *traceData) = 0; + virtual Fault execute(DynInst *xc, Trace::InstRecord *traceData) = 0; /** * Return the target address for a PC-relative branch. -- cgit v1.2.3 From b8082eb508f15f09eb7416a67b6d3a1886b4fa34 Mon Sep 17 00:00:00 2001 From: Lisa Hsu Date: Mon, 17 May 2004 15:08:24 -0400 Subject: lift system-independent binning stuff out of Tru64System into System. kern/tru64/tru64_system.cc: make binned_fns a parameter for System in addition to Tru64System. Do all the fnEvents setting at the System level, since that is system-independent. kern/tru64/tru64_system.hh: deal with FnEvents in the System, and move some fns over to System. sim/system.cc: sim/system.hh: lift binning stuff into System out of Tru64System --HG-- extra : convert_revision : 591dee6f2013f5c43037726c529a00682b5cf82e --- kern/tru64/tru64_system.cc | 68 +-------------------------------------- kern/tru64/tru64_system.hh | 13 -------- sim/system.cc | 79 ++++++++++++++++++++++++++++++++++++++++++++-- sim/system.hh | 22 +++++++++---- 4 files changed, 94 insertions(+), 88 deletions(-) diff --git a/kern/tru64/tru64_system.cc b/kern/tru64/tru64_system.cc index 7e68dc5a1..0717bcbbe 100644 --- a/kern/tru64/tru64_system.cc +++ b/kern/tru64/tru64_system.cc @@ -49,7 +49,7 @@ Tru64System::Tru64System(const string _name, const uint64_t _init_param, const string &kernel_path, const string &console_path, const string &palcode, const string &boot_osflags, const bool _bin, const vector &binned_fns) - : System(_name, _init_param, _memCtrl, _physmem, _bin), + : System(_name, _init_param, _memCtrl, _physmem, _bin, binned_fns), bin(_bin), binned_fns(binned_fns) { kernelSymtab = new SymbolTable; @@ -163,33 +163,14 @@ Tru64System::Tru64System(const string _name, const uint64_t _init_param, // BINNING STUFF if (bin == true) { int end = binned_fns.size(); - assert(!(end & 1)); - - Statistics::MainBin *Bin; Addr address = 0; - fnEvents.resize(end>>1); - for (int i = 0; i < end; i +=2) { - Bin = new Statistics::MainBin(binned_fns[i]); - fnBins.insert(make_pair(binned_fns[i], Bin)); - - fnEvents[(i>>1)] = new FnEvent(&pcEventQueue, binned_fns[i], this); if (kernelSymtab->findAddress(binned_fns[i], address)) fnEvents[(i>>1)]->schedule(address); else panic("could not find kernel symbol %s\n", binned_fns[i]); - - if (binned_fns[i+1] == "null") - populateMap(binned_fns[i], ""); - else - populateMap(binned_fns[i], binned_fns[i+1]); } - - fnCalls - .name(name() + ":fnCalls") - .desc("all fn calls being tracked") - ; } // } @@ -213,14 +194,6 @@ Tru64System::~Tru64System() delete debugPrintfEvent; delete debugPrintfrEvent; delete dumpMbufEvent; - - if (bin == true) { - int end = fnEvents.size(); - for (int i = 0; i < end; ++i) { - delete fnEvents[i]; - } - fnEvents.clear(); - } } int @@ -261,45 +234,6 @@ Tru64System::breakpoint() return remoteGDB[0]->trap(ALPHA_KENTRY_INT); } -void -Tru64System::populateMap(std::string callee, std::string caller) -{ - multimap::const_iterator i; - i = callerMap.insert(make_pair(callee, caller)); - assert(i != callerMap.end() && "should not fail populating callerMap"); -} - -bool -Tru64System::findCaller(std::string callee, std::string caller) const -{ - typedef multimap::const_iterator iter; - pair range; - - range = callerMap.equal_range(callee); - for (iter i = range.first; i != range.second; ++i) { - if ((*i).second == caller) - return true; - } - return false; -} - -void -Tru64System::dumpState(ExecContext *xc) const -{ - if (xc->swCtx) { - stack copy(xc->swCtx->callStack); - if (copy.empty()) - return; - DPRINTF(TCPIP, "xc->swCtx, size: %d:\n", copy.size()); - fnCall *top; - DPRINTF(TCPIP, "|| call : %d\n",xc->swCtx->calls); - for (top = copy.top(); !copy.empty(); copy.pop() ) { - top = copy.top(); - DPRINTF(TCPIP, "|| %13s : %s \n", top->name, top->myBin->name()); - } - } -} - BEGIN_DECLARE_SIM_OBJECT_PARAMS(Tru64System) Param bin; diff --git a/kern/tru64/tru64_system.hh b/kern/tru64/tru64_system.hh index 34569664d..144febbf9 100644 --- a/kern/tru64/tru64_system.hh +++ b/kern/tru64/tru64_system.hh @@ -67,8 +67,6 @@ class Tru64System : public System DebugPrintfEvent *debugPrintfrEvent; DumpMbufEvent *dumpMbufEvent; - std::vector fnEvents; - private: Addr kernelStart; @@ -104,17 +102,6 @@ class Tru64System : public System static void Printf(AlphaArguments args); static void DumpMbuf(AlphaArguments args); - - - // Lisa's binning stuff - private: - std::multimap callerMap; - void populateMap(std::string caller, std::string callee); - - public: - bool findCaller(std::string callee, std::string caller) const; - void dumpState(ExecContext *xc) const; - // }; #endif // __TRU64_SYSTEM_HH__ diff --git a/sim/system.cc b/sim/system.cc index 43f43baec..791a092ac 100644 --- a/sim/system.cc +++ b/sim/system.cc @@ -30,6 +30,7 @@ #include "targetarch/vtophys.hh" #include "sim/param.hh" #include "sim/system.hh" +#include "base/trace.hh" using namespace std; @@ -41,12 +42,15 @@ System::System(const std::string _name, const uint64_t _init_param, MemoryController *_memCtrl, PhysicalMemory *_physmem, - const bool _bin) + const bool _bin, + const std::vector &binned_fns) + : SimObject(_name), init_param(_init_param), memCtrl(_memCtrl), physmem(_physmem), - bin(_bin) + bin(_bin), + binned_fns(binned_fns) { // add self to global system list systemList.push_back(this); @@ -54,6 +58,31 @@ System::System(const std::string _name, Kernel = new Statistics::MainBin("non TCPIP Kernel stats"); Kernel->activate(); User = new Statistics::MainBin("User stats"); + + int end = binned_fns.size(); + assert(!(end & 1)); + + Statistics::MainBin *Bin; + + fnEvents.resize(end>>1); + + for (int i = 0; i < end; i +=2) { + Bin = new Statistics::MainBin(binned_fns[i]); + fnBins.insert(make_pair(binned_fns[i], Bin)); + + fnEvents[(i>>1)] = new FnEvent(&pcEventQueue, binned_fns[i], this); + + if (binned_fns[i+1] == "null") + populateMap(binned_fns[i], ""); + else + populateMap(binned_fns[i], binned_fns[i+1]); + } + + fnCalls + .name(name() + ":fnCalls") + .desc("all fn calls being tracked") + ; + } else Kernel = NULL; } @@ -61,6 +90,13 @@ System::System(const std::string _name, System::~System() { + if (bin == true) { + int end = fnEvents.size(); + for (int i = 0; i < end; ++i) { + delete fnEvents[i]; + } + fnEvents.clear(); + } } @@ -103,6 +139,45 @@ printSystems() System::printSystems(); } +void +System::populateMap(std::string callee, std::string caller) +{ + multimap::const_iterator i; + i = callerMap.insert(make_pair(callee, caller)); + assert(i != callerMap.end() && "should not fail populating callerMap"); +} + +bool +System::findCaller(std::string callee, std::string caller) const +{ + typedef multimap::const_iterator iter; + pair range; + + range = callerMap.equal_range(callee); + for (iter i = range.first; i != range.second; ++i) { + if ((*i).second == caller) + return true; + } + return false; +} + +void +System::dumpState(ExecContext *xc) const +{ + if (xc->swCtx) { + stack copy(xc->swCtx->callStack); + if (copy.empty()) + return; + DPRINTF(TCPIP, "xc->swCtx, size: %d:\n", copy.size()); + fnCall *top; + DPRINTF(TCPIP, "|| call : %d\n",xc->swCtx->calls); + for (top = copy.top(); !copy.empty(); copy.pop() ) { + top = copy.top(); + DPRINTF(TCPIP, "|| %13s : %s \n", top->name, top->myBin->name()); + } + } +} + Statistics::MainBin * System::getBin(const std::string &name) { diff --git a/sim/system.hh b/sim/system.hh index 050d1dd11..564579fe4 100644 --- a/sim/system.hh +++ b/sim/system.hh @@ -35,6 +35,7 @@ #include "base/loader/symtab.hh" #include "base/statistics.hh" #include "cpu/pc_event.hh" +#include "kern/system_events.hh" #include "sim/sim_object.hh" #include "sim/sw_context.hh" @@ -48,17 +49,20 @@ class ExecContext; class System : public SimObject { // lisa's binning stuff - protected: + private: std::map fnBins; std::map swCtxMap; + protected: + std::vector fnEvents; + public: Statistics::Scalar<> fnCalls; Statistics::MainBin *Kernel; Statistics::MainBin *User; Statistics::MainBin * getBin(const std::string &name); - virtual bool findCaller(std::string, std::string) const = 0; + bool findCaller(std::string, std::string) const; SWContext *findContext(Addr pcb); bool addContext(Addr pcb, SWContext *ctx) { @@ -68,18 +72,23 @@ class System : public SimObject swCtxMap.erase(pcb); return; } - - virtual void dumpState(ExecContext *xc) const = 0; + void dumpState(ExecContext *xc) const; virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); - // + + + private: + std::multimap callerMap; + void populateMap(std::string caller, std::string callee); +// public: const uint64_t init_param; MemoryController *memCtrl; PhysicalMemory *physmem; bool bin; + std::vector binned_fns; PCEventQueue pcEventQueue; @@ -90,7 +99,8 @@ class System : public SimObject public: System(const std::string _name, const uint64_t _init_param, - MemoryController *, PhysicalMemory *, const bool); + MemoryController *, PhysicalMemory *, const bool, + const std::vector &binned_fns); ~System(); virtual Addr getKernelStart() const = 0; -- cgit v1.2.3