// 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 SparcDelayedMicroInst { protected: // Constructor BlockMemMicro(const char *mnem, ExtMachInst _machInst, OpClass __opClass, int8_t _offset) : SparcDelayedMicroInst(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 }; class %(class_name)s_1 : public %(base_class)sMicro { public: //Constructor %(class_name)s_1(ExtMachInst machInst); %(BasicExecDeclare)s }; class %(class_name)s_2 : public %(base_class)sMicro { public: //Constructor %(class_name)s_2(ExtMachInst machInst); %(BasicExecDeclare)s }; class %(class_name)s_3 : public %(base_class)sMicro { public: //Constructor %(class_name)s_3(ExtMachInst machInst); %(BasicExecDeclare)s }; class %(class_name)s_4 : public %(base_class)sMicro { public: //Constructor %(class_name)s_4(ExtMachInst machInst); %(BasicExecDeclare)s }; class %(class_name)s_5 : public %(base_class)sMicro { public: //Constructor %(class_name)s_5(ExtMachInst machInst); %(BasicExecDeclare)s }; class %(class_name)s_6 : public %(base_class)sMicro { public: //Constructor %(class_name)s_6(ExtMachInst machInst); %(BasicExecDeclare)s }; class %(class_name)s_7 : public %(base_class)sMicro { public: //Constructor %(class_name)s_7(ExtMachInst machInst); %(BasicExecDeclare)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; } }}; def template MicroLoadExecute {{ Fault %(class_name)s::%(class_name)s_%(micro_pc)s::execute( %(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const { Fault fault = NoFault; Addr EA; %(op_decl)s; %(op_rd)s; %(ea_code)s; %(fault_check)s; DPRINTF(Sparc, "The address is 0x%x\n", EA); xc->read(EA, (uint%(mem_acc_size)s_t&)Mem, 0); %(code)s; if(fault == NoFault) { //Write the resulting state to the execution context %(op_wb)s; } return fault; } }}; def template MicroStoreExecute {{ Fault %(class_name)s::%(class_name)s_%(micro_pc)s::execute( %(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const { Fault fault = NoFault; uint64_t write_result = 0; Addr EA; %(op_decl)s; %(op_rd)s; %(ea_code)s; %(fault_check)s; DPRINTF(Sparc, "The address is 0x%x\n", EA); %(code)s; if(fault == NoFault) { xc->write((uint%(mem_acc_size)s_t)Mem, EA, 0, &write_result); //Write the resulting state to the execution context %(op_wb)s; } return fault; } }}; let {{ def doBlockMemFormat(code, 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 faultCheck = '''if(bits(Pstate,2,2) == 0 && (EXT_ASI & 0x80) == 0) return new PrivilegedAction; if(AsiIsAsIfUser((ASI)EXT_ASI) && !bits(Pstate,2,2)) return new PrivilegedAction; //The LSB can be zero, since it's really the MSB in doubles //and quads if(RD & 0xe) return new IllegalInstruction; if(EA & 0x3f) return new MemAddressNotAligned; ''' 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;" pcedCode = matcher.sub("Frd_%d" % microPC, code) iop = InstObjParams(name, Name, 'BlockMem', pcedCode, opt_flags, {"ea_code": addrCalcReg, "fault_check": faultCheck, "micro_pc": microPC, "set_flags": flag_code}) iop_imm = InstObjParams(name, Name + 'Imm', 'BlockMemImm', pcedCode, opt_flags, {"ea_code": addrCalcImm, "fault_check": faultCheck, "micro_pc": microPC, "set_flags": flag_code}) exec_output += execute.subst(iop) exec_output += execute.subst(iop_imm) decoder_output += BlockMemMicroConstructor.subst(iop) decoder_output += BlockMemMicroConstructor.subst(iop_imm) faultCheck = '' return (header_output, decoder_output, exec_output, decode_block) }}; def format BlockLoad(code, *opt_flags) {{ (header_output, decoder_output, exec_output, decode_block) = doBlockMemFormat(code, MicroLoadExecute, name, Name, opt_flags) }}; def format BlockStore(code, *opt_flags) {{ (header_output, decoder_output, exec_output, decode_block) = doBlockMemFormat(code, MicroStoreExecute, name, Name, opt_flags) }};