// Copyright (c) 2006 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: Ali Saidi // Gabe Black //////////////////////////////////////////////////////////////////// // // Block Memory instructions // output header {{ class BlockMem : public SparcMacroInst { protected: // Constructor // We make the assumption that all block memory operations // Will take 8 instructions to execute BlockMem(const char *mnem, ExtMachInst _machInst) : SparcMacroInst(mnem, _machInst, No_OpClass, 8) {} }; class BlockMemImm : public BlockMem { protected: // Constructor BlockMemImm(const char *mnem, ExtMachInst _machInst) : BlockMem(mnem, _machInst) {} }; class BlockMemMicro : public SparcMicroInst { protected: // Constructor BlockMemMicro(const char *mnem, ExtMachInst _machInst, OpClass __opClass, int8_t _offset) : SparcMicroInst(mnem, _machInst, __opClass), offset(_offset) {} std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; const int8_t offset; }; class BlockMemImmMicro : public BlockMemMicro { protected: // Constructor BlockMemImmMicro(const char *mnem, ExtMachInst _machInst, OpClass __opClass, int8_t _offset) : BlockMemMicro(mnem, _machInst, __opClass, _offset), imm(sext<13>(SIMM13)) {} std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const; const int32_t imm; }; }}; output decoder {{ std::string BlockMemMicro::generateDisassembly(Addr pc, const SymbolTable *symtab) const { std::stringstream response; bool load = flags[IsLoad]; bool save = flags[IsStore]; printMnemonic(response, mnemonic); if(save) { printReg(response, _srcRegIdx[0]); ccprintf(response, ", "); } ccprintf(response, "[ "); printReg(response, _srcRegIdx[!save ? 0 : 1]); ccprintf(response, " + "); printReg(response, _srcRegIdx[!save ? 1 : 2]); ccprintf(response, " ]"); if(load) { ccprintf(response, ", "); printReg(response, _destRegIdx[0]); } return response.str(); } std::string BlockMemImmMicro::generateDisassembly(Addr pc, const SymbolTable *symtab) const { std::stringstream response; bool load = flags[IsLoad]; bool save = flags[IsStore]; printMnemonic(response, mnemonic); if(save) { printReg(response, _srcRegIdx[1]); ccprintf(response, ", "); } ccprintf(response, "[ "); printReg(response, _srcRegIdx[0]); if(imm >= 0) ccprintf(response, " + 0x%x ]", imm); else ccprintf(response, " + -0x%x ]", -imm); if(load) { ccprintf(response, ", "); printReg(response, _destRegIdx[0]); } return response.str(); } }}; def template BlockMemDeclare {{ /** * Static instruction class for a block memory operation */ class %(class_name)s : public %(base_class)s { public: //Constructor %(class_name)s(ExtMachInst machInst); protected: class %(class_name)s_0 : public %(base_class)sMicro { public: //Constructor %(class_name)s_0(ExtMachInst machInst); %(BasicExecDeclare)s %(InitiateAccDeclare)s %(CompleteAccDeclare)s }; class %(class_name)s_1 : public %(base_class)sMicro { public: //Constructor %(class_name)s_1(ExtMachInst machInst); %(BasicExecDeclare)s %(InitiateAccDeclare)s %(CompleteAccDeclare)s }; class %(class_name)s_2 : public %(base_class)sMicro { public: //Constructor %(class_name)s_2(ExtMachInst machInst); %(BasicExecDeclare)s %(InitiateAccDeclare)s %(CompleteAccDeclare)s }; class %(class_name)s_3 : public %(base_class)sMicro { public: //Constructor %(class_name)s_3(ExtMachInst machInst); %(BasicExecDeclare)s %(InitiateAccDeclare)s %(CompleteAccDeclare)s }; class %(class_name)s_4 : public %(base_class)sMicro { public: //Constructor %(class_name)s_4(ExtMachInst machInst); %(BasicExecDeclare)s %(InitiateAccDeclare)s %(CompleteAccDeclare)s }; class %(class_name)s_5 : public %(base_class)sMicro { public: //Constructor %(class_name)s_5(ExtMachInst machInst); %(BasicExecDeclare)s %(InitiateAccDeclare)s %(CompleteAccDeclare)s }; class %(class_name)s_6 : public %(base_class)sMicro { public: //Constructor %(class_name)s_6(ExtMachInst machInst); %(BasicExecDeclare)s %(InitiateAccDeclare)s %(CompleteAccDeclare)s }; class %(class_name)s_7 : public %(base_class)sMicro { public: //Constructor %(class_name)s_7(ExtMachInst machInst); %(BasicExecDeclare)s %(InitiateAccDeclare)s %(CompleteAccDeclare)s }; }; }}; // Basic instruction class constructor template. def template BlockMemConstructor {{ inline %(class_name)s::%(class_name)s(ExtMachInst machInst) : %(base_class)s("%(mnemonic)s", machInst) { %(constructor)s; microOps[0] = new %(class_name)s_0(machInst); microOps[1] = new %(class_name)s_1(machInst); microOps[2] = new %(class_name)s_2(machInst); microOps[3] = new %(class_name)s_3(machInst); microOps[4] = new %(class_name)s_4(machInst); microOps[5] = new %(class_name)s_5(machInst); microOps[6] = new %(class_name)s_6(machInst); microOps[7] = new %(class_name)s_7(machInst); } }}; def template BlockMemMicroConstructor {{ inline %(class_name)s:: %(class_name)s_%(micro_pc)s:: %(class_name)s_%(micro_pc)s(ExtMachInst machInst) : %(base_class)sMicro("%(mnemonic)s[%(micro_pc)s]", machInst, %(op_class)s, %(micro_pc)s * 8) { %(constructor)s; %(set_flags)s; } }}; let {{ def doBlockMemFormat(code, faultCode, execute, name, Name, opt_flags): # XXX Need to take care of pstate.hpriv as well. The lower ASIs # are split into ones that are available in priv and hpriv, and # those that are only available in hpriv addrCalcReg = 'EA = Rs1 + Rs2 + offset;' addrCalcImm = 'EA = Rs1 + imm + offset;' iop = InstObjParams(name, Name, 'BlockMem', code, opt_flags) iop_imm = InstObjParams(name, Name + 'Imm', 'BlockMemImm', code, opt_flags) header_output = BlockMemDeclare.subst(iop) + BlockMemDeclare.subst(iop_imm) decoder_output = BlockMemConstructor.subst(iop) + BlockMemConstructor.subst(iop_imm) decode_block = ROrImmDecode.subst(iop) matcher = re.compile(r'Frd_N') exec_output = '' for microPc in range(8): flag_code = '' if (microPc == 7): flag_code = "flags[IsLastMicroOp] = true;" else: flag_code = "flags[IsDelayedCommit] = true;" pcedCode = matcher.sub("Frd_%d" % microPc, code) iop = InstObjParams(name, Name, 'BlockMem', {"code": pcedCode, "ea_code": addrCalcReg, "fault_check": faultCode, "micro_pc": microPc, "set_flags": flag_code}, opt_flags) iop_imm = InstObjParams(name, Name + 'Imm', 'BlockMemImm', {"code": pcedCode, "ea_code": addrCalcImm, "fault_check": faultCode, "micro_pc": microPc, "set_flags": flag_code}, opt_flags) decoder_output += BlockMemMicroConstructor.subst(iop) decoder_output += BlockMemMicroConstructor.subst(iop_imm) exec_output += doDualSplitExecute( pcedCode, addrCalcReg, addrCalcImm, execute, faultCode, makeMicroName(name, microPc), makeMicroName(name + "Imm", microPc), makeMicroName(Name, microPc), makeMicroName(Name + "Imm", microPc), opt_flags); faultCode = '' return (header_output, decoder_output, exec_output, decode_block) }}; def format BlockLoad(code, *opt_flags) {{ # We need to make sure to check the highest priority fault last. # That way, if other faults have been detected, they'll be overwritten # rather than the other way around. faultCode = AlternateASIPrivFaultCheck + BlockAlignmentFaultCheck (header_output, decoder_output, exec_output, decode_block) = doBlockMemFormat(code, faultCode, LoadFuncs, name, Name, opt_flags) }}; def format BlockStore(code, *opt_flags) {{ # We need to make sure to check the highest priority fault last. # That way, if other faults have been detected, they'll be overwritten # rather than the other way around. faultCode = AlternateASIPrivFaultCheck + BlockAlignmentFaultCheck (header_output, decoder_output, exec_output, decode_block) = doBlockMemFormat(code, faultCode, StoreFuncs, name, Name, opt_flags) }};