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
This commit is contained in:
Gabe Black 2007-06-20 15:02:50 +00:00
parent d2ccf5e509
commit a68ddf685c
12 changed files with 186 additions and 96 deletions

View file

@ -85,6 +85,7 @@
Import('*')
if env['TARGET_ISA'] == 'x86':
Source('emulenv.cc')
Source('floatregfile.cc')
Source('intregfile.cc')
Source('miscregfile.cc')

View file

@ -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();

View 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"

View file

@ -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"

View file

@ -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"
};
'''

View 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 {

View 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"
};
'''

View 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

View 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
}};

View 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

View 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;
}

View 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;