diff options
Diffstat (limited to 'cpu/o3/regfile.hh')
-rw-r--r-- | cpu/o3/regfile.hh | 634 |
1 files changed, 634 insertions, 0 deletions
diff --git a/cpu/o3/regfile.hh b/cpu/o3/regfile.hh new file mode 100644 index 000000000..e07944e67 --- /dev/null +++ b/cpu/o3/regfile.hh @@ -0,0 +1,634 @@ +/* + * Copyright (c) 2004-2005 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 __CPU_BETA_CPU_REGFILE_HH__ +#define __CPU_BETA_CPU_REGFILE_HH__ + +// @todo: Destructor + +#include "arch/alpha/isa_traits.hh" +#include "base/trace.hh" +#include "cpu/o3/comm.hh" + +#ifdef FULL_SYSTEM +#include "arch/alpha/ev5.hh" +#include "kern/kernel_stats.hh" + +using namespace EV5; +#endif + +// This really only depends on the ISA, and not the Impl. It might be nicer +// to see if I can make it depend on nothing... +// Things that are in the ifdef FULL_SYSTEM are pretty dependent on the ISA, +// and should go in the AlphaFullCPU. + +template <class Impl> +class PhysRegFile +{ + //Note that most of the definitions of the IntReg, FloatReg, etc. exist + //within the Impl/ISA class and not within this PhysRegFile class. + + //Will need some way to allow stuff like swap_palshadow to access the + //correct registers. Might require code changes to swap_palshadow and + //other execution contexts. + + //Will make these registers public for now, but they probably should + //be private eventually with some accessor functions. + public: + typedef typename Impl::ISA ISA; + typedef typename Impl::FullCPU FullCPU; + + PhysRegFile(unsigned _numPhysicalIntRegs, + unsigned _numPhysicalFloatRegs); + + //Everything below should be pretty well identical to the normal + //register file that exists within AlphaISA class. + //The duplication is unfortunate but it's better than having + //different ways to access certain registers. + + //Add these in later when everything else is in place +// void serialize(std::ostream &os); +// void unserialize(Checkpoint *cp, const std::string §ion); + + uint64_t readIntReg(PhysRegIndex reg_idx) + { + assert(reg_idx < numPhysicalIntRegs); + + DPRINTF(IEW, "RegFile: Access to int register %i, has data " + "%i\n", int(reg_idx), intRegFile[reg_idx]); + return intRegFile[reg_idx]; + } + + float readFloatRegSingle(PhysRegIndex reg_idx) + { + // Remove the base Float reg dependency. + reg_idx = reg_idx - numPhysicalIntRegs; + + assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); + + DPRINTF(IEW, "RegFile: Access to float register %i as single, has " + "data %8.8f\n", int(reg_idx), (float)floatRegFile[reg_idx].d); + + return (float)floatRegFile[reg_idx].d; + } + + double readFloatRegDouble(PhysRegIndex reg_idx) + { + // Remove the base Float reg dependency. + reg_idx = reg_idx - numPhysicalIntRegs; + + assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); + + DPRINTF(IEW, "RegFile: Access to float register %i as double, has " + " data %8.8f\n", int(reg_idx), floatRegFile[reg_idx].d); + + return floatRegFile[reg_idx].d; + } + + uint64_t readFloatRegInt(PhysRegIndex reg_idx) + { + // Remove the base Float reg dependency. + reg_idx = reg_idx - numPhysicalIntRegs; + + assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); + + DPRINTF(IEW, "RegFile: Access to float register %i as int, has data " + "%lli\n", int(reg_idx), floatRegFile[reg_idx].q); + + return floatRegFile[reg_idx].q; + } + + void setIntReg(PhysRegIndex reg_idx, uint64_t val) + { + assert(reg_idx < numPhysicalIntRegs); + + DPRINTF(IEW, "RegFile: Setting int register %i to %lli\n", + int(reg_idx), val); + + intRegFile[reg_idx] = val; + } + + void setFloatRegSingle(PhysRegIndex reg_idx, float val) + { + // Remove the base Float reg dependency. + reg_idx = reg_idx - numPhysicalIntRegs; + + assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); + + DPRINTF(IEW, "RegFile: Setting float register %i to %8.8f\n", + int(reg_idx), val); + + floatRegFile[reg_idx].d = (double)val; + } + + void setFloatRegDouble(PhysRegIndex reg_idx, double val) + { + // Remove the base Float reg dependency. + reg_idx = reg_idx - numPhysicalIntRegs; + + assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); + + DPRINTF(IEW, "RegFile: Setting float register %i to %8.8f\n", + int(reg_idx), val); + + floatRegFile[reg_idx].d = val; + } + + void setFloatRegInt(PhysRegIndex reg_idx, uint64_t val) + { + // Remove the base Float reg dependency. + reg_idx = reg_idx - numPhysicalIntRegs; + + assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs); + + DPRINTF(IEW, "RegFile: Setting float register %i to %lli\n", + int(reg_idx), val); + + floatRegFile[reg_idx].q = val; + } + + uint64_t readPC() + { + return pc; + } + + void setPC(uint64_t val) + { + pc = val; + } + + void setNextPC(uint64_t val) + { + npc = val; + } + + //Consider leaving this stuff and below in some implementation specific + //file as opposed to the general register file. Or have a derived class. + uint64_t readUniq() + { + return miscRegs.uniq; + } + + void setUniq(uint64_t val) + { + miscRegs.uniq = val; + } + + uint64_t readFpcr() + { + return miscRegs.fpcr; + } + + void setFpcr(uint64_t val) + { + miscRegs.fpcr = val; + } + +#ifdef FULL_SYSTEM + uint64_t readIpr(int idx, Fault &fault); + Fault setIpr(int idx, uint64_t val); + InternalProcReg *getIpr() { return ipr; } + int readIntrFlag() { return intrflag; } + void setIntrFlag(int val) { intrflag = val; } +#endif + + // These should be private eventually, but will be public for now + // so that I can hack around the initregs issue. + public: + /** (signed) integer register file. */ + IntReg *intRegFile; + + /** Floating point register file. */ + FloatReg *floatRegFile; + + /** Miscellaneous register file. */ + MiscRegFile miscRegs; + + /** Program counter. */ + Addr pc; + + /** Next-cycle program counter. */ + Addr npc; + +#ifdef FULL_SYSTEM + private: + // This is ISA specifc stuff; remove it eventually once ISAImpl is used + IntReg palregs[NumIntRegs]; // PAL shadow registers + InternalProcReg ipr[NumInternalProcRegs]; // internal processor regs + int intrflag; // interrupt flag + bool pal_shadow; // using pal_shadow registers +#endif + + private: + FullCPU *cpu; + + public: + void setCPU(FullCPU *cpu_ptr) { cpu = cpu_ptr; } + + unsigned numPhysicalIntRegs; + unsigned numPhysicalFloatRegs; +}; + +template <class Impl> +PhysRegFile<Impl>::PhysRegFile(unsigned _numPhysicalIntRegs, + unsigned _numPhysicalFloatRegs) + : numPhysicalIntRegs(_numPhysicalIntRegs), + numPhysicalFloatRegs(_numPhysicalFloatRegs) +{ + intRegFile = new IntReg[numPhysicalIntRegs]; + floatRegFile = new FloatReg[numPhysicalFloatRegs]; + + memset(intRegFile, 0, sizeof(*intRegFile)); + memset(floatRegFile, 0, sizeof(*floatRegFile)); +} + +#ifdef FULL_SYSTEM + +//Problem: This code doesn't make sense at the RegFile level because it +//needs things such as the itb and dtb. Either put it at the CPU level or +//the DynInst level. +template <class Impl> +uint64_t +PhysRegFile<Impl>::readIpr(int idx, Fault &fault) +{ + uint64_t retval = 0; // return value, default 0 + + switch (idx) { + case ISA::IPR_PALtemp0: + case ISA::IPR_PALtemp1: + case ISA::IPR_PALtemp2: + case ISA::IPR_PALtemp3: + case ISA::IPR_PALtemp4: + case ISA::IPR_PALtemp5: + case ISA::IPR_PALtemp6: + case ISA::IPR_PALtemp7: + case ISA::IPR_PALtemp8: + case ISA::IPR_PALtemp9: + case ISA::IPR_PALtemp10: + case ISA::IPR_PALtemp11: + case ISA::IPR_PALtemp12: + case ISA::IPR_PALtemp13: + case ISA::IPR_PALtemp14: + case ISA::IPR_PALtemp15: + case ISA::IPR_PALtemp16: + case ISA::IPR_PALtemp17: + case ISA::IPR_PALtemp18: + case ISA::IPR_PALtemp19: + case ISA::IPR_PALtemp20: + case ISA::IPR_PALtemp21: + case ISA::IPR_PALtemp22: + case ISA::IPR_PALtemp23: + case ISA::IPR_PAL_BASE: + + case ISA::IPR_IVPTBR: + case ISA::IPR_DC_MODE: + case ISA::IPR_MAF_MODE: + case ISA::IPR_ISR: + case ISA::IPR_EXC_ADDR: + case ISA::IPR_IC_PERR_STAT: + case ISA::IPR_DC_PERR_STAT: + case ISA::IPR_MCSR: + case ISA::IPR_ASTRR: + case ISA::IPR_ASTER: + case ISA::IPR_SIRR: + case ISA::IPR_ICSR: + case ISA::IPR_ICM: + case ISA::IPR_DTB_CM: + case ISA::IPR_IPLR: + case ISA::IPR_INTID: + case ISA::IPR_PMCTR: + // no side-effect + retval = ipr[idx]; + break; + + case ISA::IPR_CC: + retval |= ipr[idx] & ULL(0xffffffff00000000); + retval |= curTick & ULL(0x00000000ffffffff); + break; + + case ISA::IPR_VA: + retval = ipr[idx]; + break; + + case ISA::IPR_VA_FORM: + case ISA::IPR_MM_STAT: + case ISA::IPR_IFAULT_VA_FORM: + case ISA::IPR_EXC_MASK: + case ISA::IPR_EXC_SUM: + retval = ipr[idx]; + break; + + case ISA::IPR_DTB_PTE: + { + typename ISA::PTE &pte = cpu->dtb->index(1); + + retval |= ((u_int64_t)pte.ppn & ULL(0x7ffffff)) << 32; + retval |= ((u_int64_t)pte.xre & ULL(0xf)) << 8; + retval |= ((u_int64_t)pte.xwe & ULL(0xf)) << 12; + retval |= ((u_int64_t)pte.fonr & ULL(0x1)) << 1; + retval |= ((u_int64_t)pte.fonw & ULL(0x1))<< 2; + retval |= ((u_int64_t)pte.asma & ULL(0x1)) << 4; + retval |= ((u_int64_t)pte.asn & ULL(0x7f)) << 57; + } + break; + + // write only registers + case ISA::IPR_HWINT_CLR: + case ISA::IPR_SL_XMIT: + case ISA::IPR_DC_FLUSH: + case ISA::IPR_IC_FLUSH: + case ISA::IPR_ALT_MODE: + case ISA::IPR_DTB_IA: + case ISA::IPR_DTB_IAP: + case ISA::IPR_ITB_IA: + case ISA::IPR_ITB_IAP: + fault = Unimplemented_Opcode_Fault; + break; + + default: + // invalid IPR + fault = Unimplemented_Opcode_Fault; + break; + } + + return retval; +} + +extern int break_ipl; + +template <class Impl> +Fault +PhysRegFile<Impl>::setIpr(int idx, uint64_t val) +{ + uint64_t old; + + switch (idx) { + case ISA::IPR_PALtemp0: + case ISA::IPR_PALtemp1: + case ISA::IPR_PALtemp2: + case ISA::IPR_PALtemp3: + case ISA::IPR_PALtemp4: + case ISA::IPR_PALtemp5: + case ISA::IPR_PALtemp6: + case ISA::IPR_PALtemp7: + case ISA::IPR_PALtemp8: + case ISA::IPR_PALtemp9: + case ISA::IPR_PALtemp10: + case ISA::IPR_PALtemp11: + case ISA::IPR_PALtemp12: + case ISA::IPR_PALtemp13: + case ISA::IPR_PALtemp14: + case ISA::IPR_PALtemp15: + case ISA::IPR_PALtemp16: + case ISA::IPR_PALtemp17: + case ISA::IPR_PALtemp18: + case ISA::IPR_PALtemp19: + case ISA::IPR_PALtemp20: + case ISA::IPR_PALtemp21: + case ISA::IPR_PALtemp22: + case ISA::IPR_PAL_BASE: + case ISA::IPR_IC_PERR_STAT: + case ISA::IPR_DC_PERR_STAT: + case ISA::IPR_PMCTR: + // write entire quad w/ no side-effect + ipr[idx] = val; + break; + + case ISA::IPR_CC_CTL: + // This IPR resets the cycle counter. We assume this only + // happens once... let's verify that. + assert(ipr[idx] == 0); + ipr[idx] = 1; + break; + + case ISA::IPR_CC: + // This IPR only writes the upper 64 bits. It's ok to write + // all 64 here since we mask out the lower 32 in rpcc (see + // isa_desc). + ipr[idx] = val; + break; + + case ISA::IPR_PALtemp23: + // write entire quad w/ no side-effect + old = ipr[idx]; + ipr[idx] = val; + break; + + case ISA::IPR_DTB_PTE: + // write entire quad w/ no side-effect, tag is forthcoming + ipr[idx] = val; + break; + + case ISA::IPR_EXC_ADDR: + // second least significant bit in PC is always zero + ipr[idx] = val & ~2; + break; + + case ISA::IPR_ASTRR: + case ISA::IPR_ASTER: + // only write least significant four bits - privilege mask + ipr[idx] = val & 0xf; + break; + + case ISA::IPR_IPLR: + // only write least significant five bits - interrupt level + ipr[idx] = val & 0x1f; + break; + + case ISA::IPR_DTB_CM: + + case ISA::IPR_ICM: + // only write two mode bits - processor mode + ipr[idx] = val & 0x18; + break; + + case ISA::IPR_ALT_MODE: + // only write two mode bits - processor mode + ipr[idx] = val & 0x18; + break; + + case ISA::IPR_MCSR: + // more here after optimization... + ipr[idx] = val; + break; + + case ISA::IPR_SIRR: + // only write software interrupt mask + ipr[idx] = val & 0x7fff0; + break; + + case ISA::IPR_ICSR: + ipr[idx] = val & ULL(0xffffff0300); + break; + + case ISA::IPR_IVPTBR: + case ISA::IPR_MVPTBR: + ipr[idx] = val & ULL(0xffffffffc0000000); + break; + + case ISA::IPR_DC_TEST_CTL: + ipr[idx] = val & 0x1ffb; + break; + + case ISA::IPR_DC_MODE: + case ISA::IPR_MAF_MODE: + ipr[idx] = val & 0x3f; + break; + + case ISA::IPR_ITB_ASN: + ipr[idx] = val & 0x7f0; + break; + + case ISA::IPR_DTB_ASN: + ipr[idx] = val & ULL(0xfe00000000000000); + break; + + case ISA::IPR_EXC_SUM: + case ISA::IPR_EXC_MASK: + // any write to this register clears it + ipr[idx] = 0; + break; + + case ISA::IPR_INTID: + case ISA::IPR_SL_RCV: + case ISA::IPR_MM_STAT: + case ISA::IPR_ITB_PTE_TEMP: + case ISA::IPR_DTB_PTE_TEMP: + // read-only registers + return Unimplemented_Opcode_Fault; + + case ISA::IPR_HWINT_CLR: + case ISA::IPR_SL_XMIT: + case ISA::IPR_DC_FLUSH: + case ISA::IPR_IC_FLUSH: + // the following are write only + ipr[idx] = val; + break; + + case ISA::IPR_DTB_IA: + // really a control write + ipr[idx] = 0; + + cpu->dtb->flushAll(); + break; + + case ISA::IPR_DTB_IAP: + // really a control write + ipr[idx] = 0; + + cpu->dtb->flushProcesses(); + break; + + case ISA::IPR_DTB_IS: + // really a control write + ipr[idx] = val; + + cpu->dtb->flushAddr(val, DTB_ASN_ASN(ipr[ISA::IPR_DTB_ASN])); + break; + + case ISA::IPR_DTB_TAG: { + struct ISA::PTE pte; + + // FIXME: granularity hints NYI... + if (DTB_PTE_GH(ipr[ISA::IPR_DTB_PTE]) != 0) + panic("PTE GH field != 0"); + + // write entire quad + ipr[idx] = val; + + // construct PTE for new entry + pte.ppn = DTB_PTE_PPN(ipr[ISA::IPR_DTB_PTE]); + pte.xre = DTB_PTE_XRE(ipr[ISA::IPR_DTB_PTE]); + pte.xwe = DTB_PTE_XWE(ipr[ISA::IPR_DTB_PTE]); + pte.fonr = DTB_PTE_FONR(ipr[ISA::IPR_DTB_PTE]); + pte.fonw = DTB_PTE_FONW(ipr[ISA::IPR_DTB_PTE]); + pte.asma = DTB_PTE_ASMA(ipr[ISA::IPR_DTB_PTE]); + pte.asn = DTB_ASN_ASN(ipr[ISA::IPR_DTB_ASN]); + + // insert new TAG/PTE value into data TLB + cpu->dtb->insert(val, pte); + } + break; + + case ISA::IPR_ITB_PTE: { + struct ISA::PTE pte; + + // FIXME: granularity hints NYI... + if (ITB_PTE_GH(val) != 0) + panic("PTE GH field != 0"); + + // write entire quad + ipr[idx] = val; + + // construct PTE for new entry + pte.ppn = ITB_PTE_PPN(val); + pte.xre = ITB_PTE_XRE(val); + pte.xwe = 0; + pte.fonr = ITB_PTE_FONR(val); + pte.fonw = ITB_PTE_FONW(val); + pte.asma = ITB_PTE_ASMA(val); + pte.asn = ITB_ASN_ASN(ipr[ISA::IPR_ITB_ASN]); + + // insert new TAG/PTE value into data TLB + cpu->itb->insert(ipr[ISA::IPR_ITB_TAG], pte); + } + break; + + case ISA::IPR_ITB_IA: + // really a control write + ipr[idx] = 0; + + cpu->itb->flushAll(); + break; + + case ISA::IPR_ITB_IAP: + // really a control write + ipr[idx] = 0; + + cpu->itb->flushProcesses(); + break; + + case ISA::IPR_ITB_IS: + // really a control write + ipr[idx] = val; + + cpu->itb->flushAddr(val, ITB_ASN_ASN(ipr[ISA::IPR_ITB_ASN])); + break; + + default: + // invalid IPR + return Unimplemented_Opcode_Fault; + } + + // no error... + return No_Fault; +} + +#endif // #ifdef FULL_SYSTEM + +#endif // __CPU_BETA_CPU_REGFILE_HH__ |