Make memory instructions work better, add more macroop implementations, add an lea...
authorGabe Black <gblack@eecs.umich.edu>
Wed, 20 Jun 2007 15:02:50 +0000 (15:02 +0000)
committerGabe Black <gblack@eecs.umich.edu>
Wed, 20 Jun 2007 15:02:50 +0000 (15:02 +0000)
--HG--
extra : convert_revision : 1212b8463eab1c1dcba7182c487d1e9184cf9bea

12 files changed:
src/arch/x86/SConscript
src/arch/x86/isa/decoder/one_byte_opcodes.isa
src/arch/x86/isa/includes.isa
src/arch/x86/isa/insts/arithmetic/add_and_subtract.py
src/arch/x86/isa/insts/compare_and_test/test.py
src/arch/x86/isa/insts/data_transfer/move.py
src/arch/x86/isa/insts/load_effective_address.py
src/arch/x86/isa/macroop.isa
src/arch/x86/isa/microops/ldstop.isa
src/arch/x86/isa/specialize.isa
src/arch/x86/predecoder.cc
src/arch/x86/types.hh

index 2e2c5b0069b185c03032e5e789482fb9cb67b9a9..6de243c9c24cc15681e8ef7eb0f35f6c286d7058 100644 (file)
@@ -85,6 +85,7 @@
 
 Import('*')
 if env['TARGET_ISA'] == 'x86':
+    Source('emulenv.cc')
     Source('floatregfile.cc')
     Source('intregfile.cc')
     Source('miscregfile.cc')
index c3f95137a4cc079143b8663e8b215088bf5a5209..3b4e72347aa5c49740e9694d5c26742a09ca07ee 100644 (file)
         }
         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();
                 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();
         }
             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
         }
             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();
             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();
index 8bb282150997e7d3c2ad601a538d6a3cb92bc055..14406931bf3327f278c197adea14cc9f692be8a8 100644 (file)
@@ -96,6 +96,7 @@ output header {{
 #include <sstream>
 #include <iostream>
 
+#include "arch/x86/emulenv.hh"
 #include "arch/x86/faults.hh"
 #include "arch/x86/isa_traits.hh"
 #include "arch/x86/regfile.hh"
index 283152f307397dab8e00f408d105d242dcfe1faa..349c2bb46d2f6c1395a2cf1095d0672f8fd51020 100644 (file)
 #
 # 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"
index b4d1cf9b8fceee434be0c5a460b27d1328d88a61..36abab5d1f2026717734faa1644f84d9e0e78d54 100644 (file)
 #
 # 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"
+};
+'''
index 1464e63791b1b02ab80671182945ef61057f4e99..c674329ea98695d7fdc04aabe276bf2f068ec726 100644 (file)
@@ -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 {
index dab6960b1c7330d310f7c908ad5c9f9401dc570f..ac32638a0fb60b4e10d5fa6029d53b3a7b4dacf1 100644 (file)
@@ -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"
+};
+'''
index 0cc818409e6915b2a35a879eb5c4f96ace1e6ab3..8453a4fe9322212cc31eee4a4fe8ba5f63753c60 100644 (file)
@@ -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
index 38b690e6a4eb456517e0466e287eb56284856b62..fbff899a0815711f4bfcd90fca91178de7046ae8 100644 (file)
@@ -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
 }};
 
index bb2be47d9fa4fd01b562ffb7d2c9aa98141ec7a5..10e57ba182c5c6e45432121b19cc9e78dcf19d3c 100644 (file)
@@ -85,7 +85,7 @@ let {{
 
 let {{
     class OpType(object):
-        parser = re.compile(r"(?P<tag>[A-Z][A-Z]*)(?P<size>[a-z][a-z]*)|(r(?P<reg>[A-Z0-9]*)(?P<rsize>[a-z]*))")
+        parser = re.compile(r"(?P<tag>[A-Z]+)(?P<size>[a-z]*)|(r(?P<reg>[A-Z0-9]+)(?P<rsize>[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
index 3ed18aeb24c24587a82555e07ffff47f99687476..bbbad7dd0cec3f46356d9b5daa43e40016e9b1ea 100644 (file)
@@ -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;
     }
 
index 298dff80b239383b27d1e5aae0cb6fe9c0f3a02a..61ab2bac9e2932a0d03d654df6faa11d95cd90ef 100644 (file)
@@ -160,7 +160,7 @@ namespace X86ISA
         } opcode;
         //Modifier bytes
         ModRM modRM;
-        uint8_t sib;
+        Sib sib;
         //Immediate fields
         uint64_t immediate;
         uint64_t displacement;