From a68ddf685c739220d09fdc44000dd217d0707f8e Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Wed, 20 Jun 2007 15:02:50 +0000 Subject: [PATCH] Make memory instructions work better, add more macroop implementations, add an lea microop, move EmulEnv into it's own .cc and .hh. --HG-- extra : convert_revision : 1212b8463eab1c1dcba7182c487d1e9184cf9bea --- src/arch/x86/SConscript | 1 + src/arch/x86/isa/decoder/one_byte_opcodes.isa | 42 +++++++---- src/arch/x86/isa/includes.isa | 1 + .../isa/insts/arithmetic/add_and_subtract.py | 14 +++- .../x86/isa/insts/compare_and_test/test.py | 32 ++++++-- src/arch/x86/isa/insts/data_transfer/move.py | 4 +- .../x86/isa/insts/load_effective_address.py | 10 +-- src/arch/x86/isa/macroop.isa | 47 +++++------- src/arch/x86/isa/microops/ldstop.isa | 73 +++++++++++++++++-- src/arch/x86/isa/specialize.isa | 39 ++++------ src/arch/x86/predecoder.cc | 17 ++--- src/arch/x86/types.hh | 2 +- 12 files changed, 186 insertions(+), 96 deletions(-) diff --git a/src/arch/x86/SConscript b/src/arch/x86/SConscript index 2e2c5b006..6de243c9c 100644 --- a/src/arch/x86/SConscript +++ b/src/arch/x86/SConscript @@ -85,6 +85,7 @@ Import('*') if env['TARGET_ISA'] == 'x86': + Source('emulenv.cc') Source('floatregfile.cc') Source('intregfile.cc') Source('miscregfile.cc') diff --git a/src/arch/x86/isa/decoder/one_byte_opcodes.isa b/src/arch/x86/isa/decoder/one_byte_opcodes.isa index c3f95137a..3b4e72347 100644 --- a/src/arch/x86/isa/decoder/one_byte_opcodes.isa +++ b/src/arch/x86/isa/decoder/one_byte_opcodes.isa @@ -280,7 +280,17 @@ } 0x10: decode OPCODE_OP_BOTTOM3 { 0x0: group1_Eb_Ib(); - 0x1: group1_Ev_Iz(); + //0x1: group1_Ev_Iz(); + 0x1: decode MODRM_REG { + 0x0: add_Ev_Iz(); + 0x1: or_Ev_Ibz(); + 0x2: adc_Ev_Iz(); + 0x3: sbb_Ev_Iz(); + 0x4: Inst::AND(Ev,Iz); + 0x5: Inst::SUB(Ev,Iz); + 0x6: xor_Ev_Iz(); + 0x7: cmp_Ev_Iz(); + } 0x2: decode MODE_SUBMODE { 0x0: This_should_be_an_illegal_instruction(); default: group1_Eb_Ib(); @@ -296,8 +306,8 @@ 0x6: xor_Eb_Ib(); 0x7: cmp_Eb_Ib(); } - 0x4: test_Eb_Gb(); - 0x5: test_Ev_Gv(); + 0x4: Inst::TEST(Eb,Gb); + 0x5: Inst::TEST(Ev,Gv); 0x6: xchg_Eb_Gb(); 0x7: xchg_Ev_Gv(); } @@ -307,7 +317,7 @@ 0x2: Inst::MOV(Gb,Eb); 0x3: Inst::MOV(Gv,Eb); 0x4: mov_MwRv_Sw(); //What to do with this one? - 0x5: lea_Gv_M(); + 0x5: Inst::LEA(Gv,M); 0x6: mov_Sw_MwRv(); 0x7: group10_Ev(); //Make sure this is Ev } @@ -353,8 +363,8 @@ 0x7: cmps_Yv_Xv(); } 0x15: decode OPCODE_OP_BOTTOM3 { - 0x0: test_Al_Ib(); - 0x1: test_rAX_Iz(); + 0x0: Inst::TEST(rAl,Ib); + 0x1: Inst::TEST(rAX,Iz); 0x2: stos_Yb_Al(); 0x3: stos_Yv_rAX(); 0x4: lods_Al_Xb(); @@ -372,15 +382,17 @@ 0x6: mov_Dh_Ib(); 0x7: mov_Bh_Ib(); } - 0x17: decode OPCODE_OP_BOTTOM3 { - 0x0: mov_rAX_Iv(); - 0x1: mov_rCX_Iv(); - 0x2: mov_rDX_Iv(); - 0x3: mov_rBX_Iv(); - 0x4: mov_rSP_Iv(); - 0x5: mov_rBP_Iv(); - 0x6: mov_rSI_Iv(); - 0x7: mov_rDI_Iv(); + format Inst { + 0x17: decode OPCODE_OP_BOTTOM3 { + 0x0: MOV(rAX,Iv); + 0x1: MOV(rCX,Iv); + 0x2: MOV(rDX,Iv); + 0x3: MOV(rBX,Iv); + 0x4: MOV(rSP,Iv); + 0x5: MOV(rBP,Iv); + 0x6: MOV(rSI,Iv); + 0x7: MOV(rDI,Iv); + } } 0x18: decode OPCODE_OP_BOTTOM3 { 0x0: group2_Eb_Ib(); diff --git a/src/arch/x86/isa/includes.isa b/src/arch/x86/isa/includes.isa index 8bb282150..14406931b 100644 --- a/src/arch/x86/isa/includes.isa +++ b/src/arch/x86/isa/includes.isa @@ -96,6 +96,7 @@ output header {{ #include #include +#include "arch/x86/emulenv.hh" #include "arch/x86/faults.hh" #include "arch/x86/isa_traits.hh" #include "arch/x86/regfile.hh" diff --git a/src/arch/x86/isa/insts/arithmetic/add_and_subtract.py b/src/arch/x86/isa/insts/arithmetic/add_and_subtract.py index 283152f30..349c2bb46 100644 --- a/src/arch/x86/isa/insts/arithmetic/add_and_subtract.py +++ b/src/arch/x86/isa/insts/arithmetic/add_and_subtract.py @@ -53,7 +53,19 @@ # # Authors: Gabe Black -microcode = "" +microcode = ''' +def macroop SUB_R_I +{ + subi "env.reg", "env.reg", "IMMEDIATE" +}; + +def macroop SUB_M_I +{ + #Load into t1 + subi "NUM_INTREGS+1", "NUM_INTREGS+1", "IMMEDIATE" + #save from t1 +}; +''' #let {{ # class ADC(Inst): # "Adc ^0 ^0 ^1" diff --git a/src/arch/x86/isa/insts/compare_and_test/test.py b/src/arch/x86/isa/insts/compare_and_test/test.py index b4d1cf9b8..36abab5d1 100644 --- a/src/arch/x86/isa/insts/compare_and_test/test.py +++ b/src/arch/x86/isa/insts/compare_and_test/test.py @@ -53,8 +53,30 @@ # # Authors: Gabe Black -microcode = "" -#let {{ -# class TEST(Inst): -# "GenFault ${new UnimpInstFault}" -#}}; +microcode = ''' +def macroop TEST_M_R +{ + ld "NUM_INTREGS+1", 3, ["env.scale", "env.index", "env.base"], \ + "DISPLACEMENT" + and "NUM_INTREGS", "NUM_INTREGS+1", "env.reg" +}; + +def macroop TEST_R_R +{ + and "NUM_INTREGS", "env.reg", "env.regm" +}; + +def macroop TEST_M_I +{ + ld "NUM_INTREGS+1", 3, ["env.scale", "env.index", "env.base"], \ + "DISPLACEMENT" + limm "NUM_INTREGS+2", "IMMEDIATE" + and "NUM_INTREGS", "NUM_INTREGS+1", "NUM_INTREGS+2" +}; + +def macroop TEST_R_I +{ + limm "NUM_INTREGS+1", "IMMEDIATE" + and "NUM_INTREGS", "env.reg", "NUM_INTREGS+1" +}; +''' diff --git a/src/arch/x86/isa/insts/data_transfer/move.py b/src/arch/x86/isa/insts/data_transfer/move.py index 1464e6379..c674329ea 100644 --- a/src/arch/x86/isa/insts/data_transfer/move.py +++ b/src/arch/x86/isa/insts/data_transfer/move.py @@ -59,11 +59,11 @@ def macroop MOV_R_R { }; def macroop MOV_M_R { - #Do a store to put the register operand into memory + st "env.reg", 3, ["env.scale", "env.index", "env.base"], "DISPLACEMENT" }; def macroop MOV_R_M { - #Do a load to fill the register operand from memory + ld "env.reg", 3, ["env.scale", "env.index", "env.base"], "DISPLACEMENT" }; def macroop MOV_R_I { diff --git a/src/arch/x86/isa/insts/load_effective_address.py b/src/arch/x86/isa/insts/load_effective_address.py index dab6960b1..ac32638a0 100644 --- a/src/arch/x86/isa/insts/load_effective_address.py +++ b/src/arch/x86/isa/insts/load_effective_address.py @@ -53,8 +53,8 @@ # # Authors: Gabe Black -microcode = "" -#let {{ -# class LEA(Inst): -# "GenFault ${new UnimpInstFault}" -#}}; +microcode = ''' +def macroop LEA_R_M { + lea "env.reg", 3, ["env.scale", "env.index", "env.base"], "DISPLACEMENT" +}; +''' diff --git a/src/arch/x86/isa/macroop.isa b/src/arch/x86/isa/macroop.isa index 0cc818409..8453a4fe9 100644 --- a/src/arch/x86/isa/macroop.isa +++ b/src/arch/x86/isa/macroop.isa @@ -111,6 +111,12 @@ output header {{ }; }}; +////////////////////////////////////////////////////////////////////////////// +// +// X86 specific +// +////////////////////////////////////////////////////////////////////////////// + // Basic instruction class declaration template. def template MacroDeclare {{ namespace X86Macroop @@ -122,17 +128,19 @@ def template MacroDeclare {{ { public: // Constructor. - %(class_name)s(ExtMachInst machInst, EmulEnv env); + %(class_name)s(ExtMachInst machInst, X86ISA::EmulEnv env); }; }; }}; // Basic instruction class constructor template. def template MacroConstructor {{ - inline X86Macroop::%(class_name)s::%(class_name)s(ExtMachInst machInst, EmulEnv env) + inline X86Macroop::%(class_name)s::%(class_name)s( + ExtMachInst machInst, EmulEnv env) : %(base_class)s("%(mnemonic)s", machInst, %(num_microops)s) { %(adjust_env)s; + %(do_modrm)s; %(constructor)s; //alloc_microops is the code that sets up the microops //array in the parent class. @@ -140,11 +148,6 @@ def template MacroConstructor {{ } }}; -////////////////////////////////////////////////////////////////////////////// -// -// X86 specific -// - let {{ from micro_asm import Combinational_Macroop, Rom_Macroop class X86Macroop(Combinational_Macroop): @@ -157,6 +160,7 @@ let {{ } self.declared = False self.adjust_env = "" + self.doModRM = "" def getAllocator(self, env): return "new X86Macroop::%s(machInst, %s)" % (self.name, env.getAllocator()) def getDeclaration(self): @@ -180,31 +184,11 @@ let {{ iop = InstObjParams(self.name, self.name, "Macroop", {"code" : "", "num_microops" : numMicroops, "alloc_microops" : allocMicroops, - "adjust_env" : self.adjust_env}) + "adjust_env" : self.adjust_env, + "do_modrm" : self.doModRM}) return MacroConstructor.subst(iop); }}; -output header {{ - struct EmulEnv - { - X86ISA::RegIndex reg; - X86ISA::RegIndex regm; - uint8_t scale; - X86ISA::RegIndex index; - X86ISA::RegIndex base; - int dataSize; - int addressSize; - int stackSize; - - EmulEnv(X86ISA::RegIndex _reg, X86ISA::RegIndex _regm, - int _dataSize, int _addressSize, int _stackSize) : - reg(_reg), regm(_regm), - dataSize(_dataSize), addressSize(_addressSize), - stackSize(_stackSize) - {;} - }; -}}; - let {{ class EmulEnv(object): def __init__(self): @@ -215,6 +199,8 @@ let {{ self.addressSize = "ADDRSIZE" self.dataSize = "OPSIZE" self.stackSize = "STACKSIZE" + self.doModRM = False + def getAllocator(self): return '''EmulEnv(%(reg)s, %(regm)s, @@ -234,12 +220,15 @@ let {{ }}; let {{ + doModRMString = "env.doModRM(machInst);\n" def genMacroop(Name, env): blocks = OutputBlocks() if not macroopDict.has_key(Name): raise Exception, "Unrecognized instruction: %s" % Name macroop = macroopDict[Name] if not macroop.declared: + if env.doModRM: + macroop.doModRM = doModRMString blocks.header_output = macroop.getDeclaration() blocks.decoder_output = macroop.getDefinition() macroop.declared = True diff --git a/src/arch/x86/isa/microops/ldstop.isa b/src/arch/x86/isa/microops/ldstop.isa index 38b690e6a..fbff899a0 100644 --- a/src/arch/x86/isa/microops/ldstop.isa +++ b/src/arch/x86/isa/microops/ldstop.isa @@ -59,9 +59,6 @@ // ////////////////////////////////////////////////////////////////////////// - -// Load templates - output header {{ /** * Base class for load and store ops @@ -119,6 +116,58 @@ output decoder {{ } }}; +// LEA template + +def template MicroLeaExecute {{ + Fault %(class_name)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; + 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 + { + protected: + void buildMe(); + + public: + %(class_name)s(ExtMachInst _machInst, + const char * instMnem, + bool isMicro, bool isDelayed, bool isFirst, bool isLast, + uint8_t _scale, RegIndex _index, RegIndex _base, + uint64_t _disp, uint8_t _segment, + RegIndex _data, + uint8_t _dataSize, uint8_t _addressSize); + + %(class_name)s(ExtMachInst _machInst, + const char * instMnem, + uint8_t _scale, RegIndex _index, RegIndex _base, + uint64_t _disp, uint8_t _segment, + RegIndex _data, + uint8_t _dataSize, uint8_t _addressSize); + + %(BasicExecDeclare)s + }; +}}; + +// Load templates + def template MicroLoadExecute {{ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const @@ -411,13 +460,27 @@ let {{ exec_output += MicroStoreCompleteAcc.subst(iop) class StoreOp(LdStOp): - def __init__(self, data, addr, segment): - super(LoadOp, self).__init__(data, addr, segment) + def __init__(self, data, segment, addr, disp = 0): + super(LoadOp, self).__init__(data, segment, addr, disp) self.className = Name self.mnemonic = name microopClasses[name] = StoreOp defineMicroLoadOp('St', 'Mem = Data;') + + iop = InstObjParams("lea", "Lea", 'LdStOp', + {"code": "Data = merge(Data, EA, dataSize);", "ea_code": calculateEA}) + 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): + super(LeaOp, self).__init__(data, segment, addr, disp) + self.className = "Lea" + self.mnemonic = "lea" + + microopClasses["lea"] = LeaOp }}; diff --git a/src/arch/x86/isa/specialize.isa b/src/arch/x86/isa/specialize.isa index bb2be47d9..10e57ba18 100644 --- a/src/arch/x86/isa/specialize.isa +++ b/src/arch/x86/isa/specialize.isa @@ -85,7 +85,7 @@ let {{ let {{ class OpType(object): - parser = re.compile(r"(?P[A-Z][A-Z]*)(?P[a-z][a-z]*)|(r(?P[A-Z0-9]*)(?P[a-z]*))") + parser = re.compile(r"(?P[A-Z]+)(?P[a-z]*)|(r(?P[A-Z0-9]+)(?P[a-z]*))") def __init__(self, opTypeString): match = OpType.parser.search(opTypeString) if match == None: @@ -105,14 +105,15 @@ let {{ while len(opTypes): # Parse the operand type string we're working with opType = OpType(opTypes[0]) + opTypes.pop(0) if opType.reg: #Figure out what to do with fixed register operands #This is the index to use, so we should stick it some place. if opType.reg in ("A", "B", "C", "D"): - env.addReg("INTREG_R%sX" % opType.reg) + env.addReg("INTREG_R%sX | (REX_B << 3)" % opType.reg) else: - env.addReg("INTREG_R%s" % opType.reg) + env.addReg("INTREG_R%s | (REX_B << 3)" % opType.reg) if opType.size: if opType.rsize in ("l", "h", "b"): print "byte" @@ -121,6 +122,11 @@ let {{ else: print "Didn't recognize fixed register size %s!" % opType.rsize Name += "_R" + elif opType.tag == "M": + # This refers to memory. The macroop constructor sets up modrm + # addressing. Non memory modrm settings should cause an error. + Name += "_M" + env.doModRM = True elif opType.tag == None or opType.size == None: raise Exception, "Problem parsing operand tag: %s" % opType.tag elif opType.tag in ("C", "D", "G", "P", "S", "T", "V"): @@ -130,39 +136,24 @@ let {{ elif opType.tag in ("E", "Q", "W"): # This might refer to memory or to a register. We need to # divide it up farther. - regTypes = copy.copy(opTypes) - regTypes.pop(0) regEnv = copy.copy(env) regEnv.addReg(ModRMRMIndex) - regName = Name + "_R" - # This needs to refer to memory, but we'll fill in the details - # later. It needs to take into account unaligned memory - # addresses. - memTypes = copy.copy(opTypes) - memTypes.pop(0) + # This refers to memory. The macroop constructor should set up + # modrm addressing. memEnv = copy.copy(env) - memName = Name + "_M" - print "%0" + memEnv.doModRM = True return doSplitDecode(specializeInst, "MODRM_MOD", - {"3" : (regName, regTypes, regEnv)}, - (memName, memTypes, memEnv)) + {"3" : (Name + "_R", copy.copy(opTypes), regEnv)}, + (Name + "_M", copy.copy(opTypes), memEnv)) elif opType.tag in ("I", "J"): # Immediates Name += "_I" - elif opType.tag == "M": - # This needs to refer to memory, but we'll fill in the details - # later. It needs to take into account unaligned memory - # addresses. - print "%0" - Name += "_M" elif opType.tag in ("PR", "R", "VR"): - # There should probably be a check here to verify that mod - # is equal to 11b + # Non register modrm settings should cause an error env.addReg(ModRMRMIndex) Name += "_R" else: raise Exception, "Unrecognized tag %s." % opType.tag - opTypes.pop(0) # Generate code to return a macroop of the given name which will # operate in the "emulation environment" env diff --git a/src/arch/x86/predecoder.cc b/src/arch/x86/predecoder.cc index 3ed18aeb2..bbbad7dd0 100644 --- a/src/arch/x86/predecoder.cc +++ b/src/arch/x86/predecoder.cc @@ -264,31 +264,29 @@ namespace X86ISA Predecoder::State Predecoder::doModRMState(uint8_t nextByte) { State nextState = ErrorState; - emi.modRM = nextByte; + ModRM modRM; + modRM = nextByte; DPRINTF(Predecoder, "Found modrm byte %#x.\n", nextByte); if (0) {//FIXME in 16 bit mode //figure out 16 bit displacement size - if(nextByte & 0xC7 == 0x06 || - nextByte & 0xC0 == 0x80) + if(modRM.mod == 0 && modRM.rm == 6 || modRM.mod == 2) displacementSize = 2; - else if(nextByte & 0xC0 == 0x40) + else if(modRM.mod == 1) displacementSize = 1; else displacementSize = 0; } else { //figure out 32/64 bit displacement size - if(nextByte & 0xC6 == 0x04 || - nextByte & 0xC0 == 0x80) + if(modRM.mod == 0 && modRM.rm == 4 || modRM.mod == 2) displacementSize = 4; - else if(nextByte & 0xC0 == 0x40) + else if(modRM.mod == 1) displacementSize = 1; else displacementSize = 0; } //If there's an SIB, get that next. //There is no SIB in 16 bit mode. - if(nextByte & 0x7 == 4 && - nextByte & 0xC0 != 0xC0) { + if(modRM.rm == 4 && modRM.mod != 3) { // && in 32/64 bit mode) nextState = SIBState; } else if(displacementSize) { @@ -301,6 +299,7 @@ namespace X86ISA } //The ModRM byte is consumed no matter what consumeByte(); + emi.modRM = modRM; return nextState; } diff --git a/src/arch/x86/types.hh b/src/arch/x86/types.hh index 298dff80b..61ab2bac9 100644 --- a/src/arch/x86/types.hh +++ b/src/arch/x86/types.hh @@ -160,7 +160,7 @@ namespace X86ISA } opcode; //Modifier bytes ModRM modRM; - uint8_t sib; + Sib sib; //Immediate fields uint64_t immediate; uint64_t displacement; -- 2.30.2