| // Copyright (c) 2007-2008 The Hewlett-Packard Development Company | |
| // All rights reserved. | |
| // | |
| // The license below extends only to copyright in the software and shall | |
| // not be construed as granting a license to any other intellectual | |
| // property including but not limited to intellectual property relating | |
| // to a hardware implementation of the functionality of the software | |
| // licensed hereunder. You may use the software subject to the license | |
| // terms below provided that you ensure that this notice is replicated | |
| // unmodified and in its entirety in all distributions of the software, | |
| // modified or unmodified, in source code or in binary form. | |
| // | |
| // Copyright (c) 2008 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. | |
| // | |
| // Authors: Gabe Black | |
| ////////////////////////////////////////////////////////////////////////// | |
| // | |
| // LdStOp Microop templates | |
| // | |
| ////////////////////////////////////////////////////////////////////////// | |
| // LEA template | |
| def template MicroLeaExecute {{ | |
| Fault %(class_name)s::execute(CPU_EXEC_CONTEXT *xc, | |
| Trace::InstRecord *traceData) const | |
| { | |
| Fault fault = NoFault; | |
| Addr EA; | |
| %(op_decl)s; | |
| %(op_rd)s; | |
| %(ea_code)s; | |
| DPRINTF(X86, "%s : %s: The address is %#x\n", instMnem, mnemonic, EA); | |
| %(code)s; | |
| if(fault == NoFault) | |
| { | |
| %(op_wb)s; | |
| } | |
| return fault; | |
| } | |
| }}; | |
| def template MicroLeaDeclare {{ | |
| class %(class_name)s : public %(base_class)s | |
| { | |
| public: | |
| %(class_name)s(ExtMachInst _machInst, | |
| const char * instMnem, uint64_t setFlags, | |
| uint8_t _scale, InstRegIndex _index, InstRegIndex _base, | |
| uint64_t _disp, InstRegIndex _segment, | |
| InstRegIndex _data, | |
| uint8_t _dataSize, uint8_t _addressSize, | |
| Request::FlagsType _memFlags); | |
| %(BasicExecDeclare)s | |
| }; | |
| }}; | |
| // Load templates | |
| def template MicroLoadExecute {{ | |
| Fault %(class_name)s::execute(CPU_EXEC_CONTEXT *xc, | |
| Trace::InstRecord *traceData) const | |
| { | |
| Fault fault = NoFault; | |
| Addr EA; | |
| %(op_decl)s; | |
| %(op_rd)s; | |
| %(ea_code)s; | |
| DPRINTF(X86, "%s : %s: The address is %#x\n", instMnem, mnemonic, EA); | |
| fault = readMemAtomic(xc, traceData, EA, Mem, dataSize, memFlags); | |
| if (fault == NoFault) { | |
| %(code)s; | |
| } else if (memFlags & Request::PREFETCH) { | |
| // For prefetches, ignore any faults/exceptions. | |
| return NoFault; | |
| } | |
| if(fault == NoFault) | |
| { | |
| %(op_wb)s; | |
| } | |
| return fault; | |
| } | |
| }}; | |
| def template MicroLoadInitiateAcc {{ | |
| Fault %(class_name)s::initiateAcc(CPU_EXEC_CONTEXT * xc, | |
| Trace::InstRecord * traceData) const | |
| { | |
| Fault fault = NoFault; | |
| Addr EA; | |
| %(op_decl)s; | |
| %(op_rd)s; | |
| %(ea_code)s; | |
| DPRINTF(X86, "%s : %s: The address is %#x\n", instMnem, mnemonic, EA); | |
| fault = readMemTiming(xc, traceData, EA, Mem, dataSize, memFlags); | |
| return fault; | |
| } | |
| }}; | |
| def template MicroLoadCompleteAcc {{ | |
| Fault %(class_name)s::completeAcc(PacketPtr pkt, | |
| CPU_EXEC_CONTEXT * xc, | |
| Trace::InstRecord * traceData) const | |
| { | |
| Fault fault = NoFault; | |
| %(op_decl)s; | |
| %(op_rd)s; | |
| Mem = getMem(pkt, dataSize, traceData); | |
| %(code)s; | |
| if(fault == NoFault) | |
| { | |
| %(op_wb)s; | |
| } | |
| return fault; | |
| } | |
| }}; | |
| // Store templates | |
| def template MicroStoreExecute {{ | |
| Fault %(class_name)s::execute(CPU_EXEC_CONTEXT * xc, | |
| Trace::InstRecord *traceData) const | |
| { | |
| Fault fault = NoFault; | |
| Addr EA; | |
| %(op_decl)s; | |
| %(op_rd)s; | |
| %(ea_code)s; | |
| DPRINTF(X86, "%s : %s: The address is %#x\n", instMnem, mnemonic, EA); | |
| %(code)s; | |
| if(fault == NoFault) | |
| { | |
| fault = writeMemAtomic(xc, traceData, Mem, dataSize, EA, | |
| memFlags, NULL); | |
| if(fault == NoFault) | |
| { | |
| %(op_wb)s; | |
| } | |
| } | |
| return fault; | |
| } | |
| }}; | |
| def template MicroStoreInitiateAcc {{ | |
| Fault %(class_name)s::initiateAcc(CPU_EXEC_CONTEXT * xc, | |
| Trace::InstRecord * traceData) const | |
| { | |
| Fault fault = NoFault; | |
| Addr EA; | |
| %(op_decl)s; | |
| %(op_rd)s; | |
| %(ea_code)s; | |
| DPRINTF(X86, "%s : %s: The address is %#x\n", instMnem, mnemonic, EA); | |
| %(code)s; | |
| if(fault == NoFault) | |
| { | |
| fault = writeMemTiming(xc, traceData, Mem, dataSize, EA, | |
| memFlags, NULL); | |
| } | |
| return fault; | |
| } | |
| }}; | |
| def template MicroStoreCompleteAcc {{ | |
| Fault %(class_name)s::completeAcc(PacketPtr pkt, | |
| CPU_EXEC_CONTEXT * xc, Trace::InstRecord * traceData) const | |
| { | |
| %(op_decl)s; | |
| %(op_rd)s; | |
| %(complete_code)s; | |
| %(op_wb)s; | |
| return NoFault; | |
| } | |
| }}; | |
| // Common templates | |
| //This delcares the initiateAcc function in memory operations | |
| def template InitiateAccDeclare {{ | |
| Fault initiateAcc(%(CPU_exec_context)s *, Trace::InstRecord *) const; | |
| }}; | |
| //This declares the completeAcc function in memory operations | |
| def template CompleteAccDeclare {{ | |
| Fault completeAcc(PacketPtr, %(CPU_exec_context)s *, Trace::InstRecord *) const; | |
| }}; | |
| def template MicroLdStOpDeclare {{ | |
| class %(class_name)s : public %(base_class)s | |
| { | |
| public: | |
| %(class_name)s(ExtMachInst _machInst, | |
| const char * instMnem, uint64_t setFlags, | |
| uint8_t _scale, InstRegIndex _index, InstRegIndex _base, | |
| uint64_t _disp, InstRegIndex _segment, | |
| InstRegIndex _data, | |
| uint8_t _dataSize, uint8_t _addressSize, | |
| Request::FlagsType _memFlags); | |
| %(BasicExecDeclare)s | |
| %(InitiateAccDeclare)s | |
| %(CompleteAccDeclare)s | |
| }; | |
| }}; | |
| def template MicroLdStOpConstructor {{ | |
| %(class_name)s::%(class_name)s( | |
| ExtMachInst machInst, const char * instMnem, uint64_t setFlags, | |
| uint8_t _scale, InstRegIndex _index, InstRegIndex _base, | |
| uint64_t _disp, InstRegIndex _segment, | |
| InstRegIndex _data, | |
| uint8_t _dataSize, uint8_t _addressSize, | |
| Request::FlagsType _memFlags) : | |
| %(base_class)s(machInst, "%(mnemonic)s", instMnem, setFlags, | |
| _scale, _index, _base, | |
| _disp, _segment, _data, | |
| _dataSize, _addressSize, _memFlags, %(op_class)s) | |
| { | |
| %(constructor)s; | |
| } | |
| }}; | |
| let {{ | |
| class LdStOp(X86Microop): | |
| def __init__(self, data, segment, addr, disp, | |
| dataSize, addressSize, baseFlags, atCPL0, prefetch, nonSpec): | |
| self.data = data | |
| [self.scale, self.index, self.base] = addr | |
| self.disp = disp | |
| self.segment = segment | |
| self.dataSize = dataSize | |
| self.addressSize = addressSize | |
| self.memFlags = baseFlags | |
| if atCPL0: | |
| self.memFlags += " | (CPL0FlagBit << FlagShift)" | |
| self.instFlags = "" | |
| if prefetch: | |
| self.memFlags += " | Request::PREFETCH" | |
| self.instFlags += " | (1ULL << StaticInst::IsDataPrefetch)" | |
| if nonSpec: | |
| self.instFlags += " | (1ULL << StaticInst::IsNonSpeculative)" | |
| self.memFlags += " | (machInst.legacy.addr ? " + \ | |
| "(AddrSizeFlagBit << FlagShift) : 0)" | |
| def getAllocator(self, microFlags): | |
| allocator = '''new %(class_name)s(machInst, macrocodeBlock, | |
| %(flags)s, %(scale)s, %(index)s, %(base)s, | |
| %(disp)s, %(segment)s, %(data)s, | |
| %(dataSize)s, %(addressSize)s, %(memFlags)s)''' % { | |
| "class_name" : self.className, | |
| "flags" : self.microFlagsText(microFlags) + self.instFlags, | |
| "scale" : self.scale, "index" : self.index, | |
| "base" : self.base, | |
| "disp" : self.disp, | |
| "segment" : self.segment, "data" : self.data, | |
| "dataSize" : self.dataSize, "addressSize" : self.addressSize, | |
| "memFlags" : self.memFlags} | |
| return allocator | |
| class BigLdStOp(X86Microop): | |
| def __init__(self, data, segment, addr, disp, | |
| dataSize, addressSize, baseFlags, atCPL0, prefetch, nonSpec): | |
| self.data = data | |
| [self.scale, self.index, self.base] = addr | |
| self.disp = disp | |
| self.segment = segment | |
| self.dataSize = dataSize | |
| self.addressSize = addressSize | |
| self.memFlags = baseFlags | |
| if atCPL0: | |
| self.memFlags += " | (CPL0FlagBit << FlagShift)" | |
| self.instFlags = "" | |
| if prefetch: | |
| self.memFlags += " | Request::PREFETCH" | |
| self.instFlags += " | (1ULL << StaticInst::IsDataPrefetch)" | |
| if nonSpec: | |
| self.instFlags += " | (1ULL << StaticInst::IsNonSpeculative)" | |
| self.memFlags += " | (machInst.legacy.addr ? " + \ | |
| "(AddrSizeFlagBit << FlagShift) : 0)" | |
| def getAllocator(self, microFlags): | |
| allocString = ''' | |
| (%(dataSize)s >= 4) ? | |
| (StaticInstPtr)(new %(class_name)sBig(machInst, | |
| macrocodeBlock, %(flags)s, %(scale)s, %(index)s, | |
| %(base)s, %(disp)s, %(segment)s, %(data)s, | |
| %(dataSize)s, %(addressSize)s, %(memFlags)s)) : | |
| (StaticInstPtr)(new %(class_name)s(machInst, | |
| macrocodeBlock, %(flags)s, %(scale)s, %(index)s, | |
| %(base)s, %(disp)s, %(segment)s, %(data)s, | |
| %(dataSize)s, %(addressSize)s, %(memFlags)s)) | |
| ''' | |
| allocator = allocString % { | |
| "class_name" : self.className, | |
| "flags" : self.microFlagsText(microFlags) + self.instFlags, | |
| "scale" : self.scale, "index" : self.index, | |
| "base" : self.base, | |
| "disp" : self.disp, | |
| "segment" : self.segment, "data" : self.data, | |
| "dataSize" : self.dataSize, "addressSize" : self.addressSize, | |
| "memFlags" : self.memFlags} | |
| return allocator | |
| }}; | |
| let {{ | |
| # Make these empty strings so that concatenating onto | |
| # them will always work. | |
| header_output = "" | |
| decoder_output = "" | |
| exec_output = "" | |
| calculateEA = ''' | |
| EA = SegBase + bits(scale * Index + Base + disp, addressSize * 8 - 1, 0); | |
| ''' | |
| def defineMicroLoadOp(mnemonic, code, bigCode='', | |
| mem_flags="0", big=True): | |
| global header_output | |
| global decoder_output | |
| global exec_output | |
| global microopClasses | |
| Name = mnemonic | |
| name = mnemonic.lower() | |
| # Build up the all register version of this micro op | |
| iops = [InstObjParams(name, Name, 'X86ISA::LdStOp', | |
| {"code": code, "ea_code": calculateEA})] | |
| if big: | |
| iops += [InstObjParams(name, Name + "Big", 'X86ISA::LdStOp', | |
| {"code": bigCode, "ea_code": calculateEA})] | |
| for iop in iops: | |
| header_output += MicroLdStOpDeclare.subst(iop) | |
| decoder_output += MicroLdStOpConstructor.subst(iop) | |
| exec_output += MicroLoadExecute.subst(iop) | |
| exec_output += MicroLoadInitiateAcc.subst(iop) | |
| exec_output += MicroLoadCompleteAcc.subst(iop) | |
| base = LdStOp | |
| if big: | |
| base = BigLdStOp | |
| class LoadOp(base): | |
| def __init__(self, data, segment, addr, disp = 0, | |
| dataSize="env.dataSize", | |
| addressSize="env.addressSize", | |
| atCPL0=False, prefetch=False, nonSpec=False): | |
| super(LoadOp, self).__init__(data, segment, addr, | |
| disp, dataSize, addressSize, mem_flags, | |
| atCPL0, prefetch, nonSpec) | |
| self.className = Name | |
| self.mnemonic = name | |
| microopClasses[name] = LoadOp | |
| defineMicroLoadOp('Ld', 'Data = merge(Data, Mem, dataSize);', | |
| 'Data = Mem & mask(dataSize * 8);') | |
| defineMicroLoadOp('Ldst', 'Data = merge(Data, Mem, dataSize);', | |
| 'Data = Mem & mask(dataSize * 8);', | |
| '(StoreCheck << FlagShift)') | |
| defineMicroLoadOp('Ldstl', 'Data = merge(Data, Mem, dataSize);', | |
| 'Data = Mem & mask(dataSize * 8);', | |
| '(StoreCheck << FlagShift) | Request::LOCKED') | |
| defineMicroLoadOp('Ldfp', code='FpData_uqw = Mem', big = False) | |
| defineMicroLoadOp('Ldfp87', code=''' | |
| switch (dataSize) | |
| { | |
| case 4: | |
| FpData_df = *(float *)&Mem; | |
| break; | |
| case 8: | |
| FpData_df = *(double *)&Mem; | |
| break; | |
| default: | |
| panic("Unhandled data size in LdFp87.\\n"); | |
| } | |
| ''', big = False) | |
| def defineMicroStoreOp(mnemonic, code, completeCode="", mem_flags="0"): | |
| global header_output | |
| global decoder_output | |
| global exec_output | |
| global microopClasses | |
| Name = mnemonic | |
| name = mnemonic.lower() | |
| # Build up the all register version of this micro op | |
| iop = InstObjParams(name, Name, 'X86ISA::LdStOp', | |
| {"code": code, | |
| "complete_code": completeCode, | |
| "ea_code": calculateEA}) | |
| header_output += MicroLdStOpDeclare.subst(iop) | |
| decoder_output += MicroLdStOpConstructor.subst(iop) | |
| exec_output += MicroStoreExecute.subst(iop) | |
| exec_output += MicroStoreInitiateAcc.subst(iop) | |
| exec_output += MicroStoreCompleteAcc.subst(iop) | |
| class StoreOp(LdStOp): | |
| def __init__(self, data, segment, addr, disp = 0, | |
| dataSize="env.dataSize", | |
| addressSize="env.addressSize", | |
| atCPL0=False, nonSpec=False): | |
| super(StoreOp, self).__init__(data, segment, addr, disp, | |
| dataSize, addressSize, mem_flags, atCPL0, False, | |
| nonSpec) | |
| self.className = Name | |
| self.mnemonic = name | |
| microopClasses[name] = StoreOp | |
| defineMicroStoreOp('St', 'Mem = pick(Data, 2, dataSize);') | |
| defineMicroStoreOp('Stul', 'Mem = pick(Data, 2, dataSize);', | |
| mem_flags="Request::LOCKED") | |
| defineMicroStoreOp('Stfp', code='Mem = FpData_uqw;') | |
| defineMicroStoreOp('Stfp87', code=''' | |
| switch (dataSize) | |
| { | |
| case 4: { | |
| float single(FpData_df); | |
| Mem = *(uint32_t *)&single; | |
| } break; | |
| case 8: | |
| Mem = *(uint64_t *)&FpData_df; | |
| break; | |
| default: | |
| panic("Unhandled data size in StFp87.\\n"); | |
| } | |
| ''') | |
| defineMicroStoreOp('Cda', 'Mem = 0;', mem_flags="Request::NO_ACCESS") | |
| iop = InstObjParams("lea", "Lea", 'X86ISA::LdStOp', | |
| {"code": "Data = merge(Data, EA, dataSize);", | |
| "ea_code": ''' | |
| EA = bits(scale * Index + Base + disp, addressSize * 8 - 1, 0); | |
| '''}) | |
| header_output += MicroLeaDeclare.subst(iop) | |
| decoder_output += MicroLdStOpConstructor.subst(iop) | |
| exec_output += MicroLeaExecute.subst(iop) | |
| class LeaOp(LdStOp): | |
| def __init__(self, data, segment, addr, disp = 0, | |
| dataSize="env.dataSize", addressSize="env.addressSize"): | |
| super(LeaOp, self).__init__(data, segment, addr, disp, | |
| dataSize, addressSize, "0", False, False, False) | |
| self.className = "Lea" | |
| self.mnemonic = "lea" | |
| microopClasses["lea"] = LeaOp | |
| iop = InstObjParams("tia", "Tia", 'X86ISA::LdStOp', | |
| {"code": "xc->demapPage(EA, 0);", | |
| "ea_code": calculateEA}) | |
| header_output += MicroLeaDeclare.subst(iop) | |
| decoder_output += MicroLdStOpConstructor.subst(iop) | |
| exec_output += MicroLeaExecute.subst(iop) | |
| class TiaOp(LdStOp): | |
| def __init__(self, segment, addr, disp = 0, | |
| dataSize="env.dataSize", | |
| addressSize="env.addressSize"): | |
| super(TiaOp, self).__init__("InstRegIndex(NUM_INTREGS)", segment, | |
| addr, disp, dataSize, addressSize, "0", False, False, | |
| False) | |
| self.className = "Tia" | |
| self.mnemonic = "tia" | |
| microopClasses["tia"] = TiaOp | |
| class CdaOp(LdStOp): | |
| def __init__(self, segment, addr, disp = 0, | |
| dataSize="env.dataSize", | |
| addressSize="env.addressSize", atCPL0=False): | |
| super(CdaOp, self).__init__("InstRegIndex(NUM_INTREGS)", segment, | |
| addr, disp, dataSize, addressSize, "Request::NO_ACCESS", | |
| atCPL0, False, False) | |
| self.className = "Cda" | |
| self.mnemonic = "cda" | |
| microopClasses["cda"] = CdaOp | |
| }}; | |