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:
parent
d2ccf5e509
commit
a68ddf685c
12 changed files with 186 additions and 96 deletions
|
@ -85,6 +85,7 @@
|
|||
|
||||
Import('*')
|
||||
if env['TARGET_ISA'] == 'x86':
|
||||
Source('emulenv.cc')
|
||||
Source('floatregfile.cc')
|
||||
Source('intregfile.cc')
|
||||
Source('miscregfile.cc')
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
};
|
||||
'''
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"
|
||||
};
|
||||
'''
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -160,7 +160,7 @@ namespace X86ISA
|
|||
} opcode;
|
||||
//Modifier bytes
|
||||
ModRM modRM;
|
||||
uint8_t sib;
|
||||
Sib sib;
|
||||
//Immediate fields
|
||||
uint64_t immediate;
|
||||
uint64_t displacement;
|
||||
|
|
Loading…
Reference in a new issue