Get rid of the immediate and displacement components of the EmulEnv struct and use them directly out of the instruction. The extra copies are conceptually realistic but are just innefficient as implemented. Also don't use the zeroeth microcode register for general storage since it's now the zero register, and implement a load and a store microops.

--HG--
extra : convert_revision : 0686296ca8b72940d961ecc6051063bfda1e932d
This commit is contained in:
Gabe Black 2007-06-19 14:18:25 +00:00
parent 8caef7d25a
commit 6e286cddfa
9 changed files with 349 additions and 46 deletions

View file

@ -67,11 +67,11 @@ def macroop MOV_R_M {
};
def macroop MOV_R_I {
limm "env.reg", "env.immediate"
limm "env.reg", "IMMEDIATE"
};
def macroop MOV_M_I {
limm "env.reg", "env.immediate"
limm "env.reg", "IMMEDIATE"
#Do a store to put the register operand into memory
};
'''

View file

@ -55,15 +55,21 @@
microcode = '''
def macroop POP_R {
# Make the default data size of pops 64 bits in 64 bit mode
.adjust_env "if(machInst.mode.submode == SixtyFourBitMode && env.dataSize == 4) env.dataSize = 8\;"
# There needs to be a load here to actually "pop" the data
ld "env.reg", 2, [0, "NUM_INTREGS", "INTREG_RSP"]
addi "INTREG_RSP", "INTREG_RSP", "env.dataSize"
};
def macroop PUSH_R {
# Make the default data size of pops 64 bits in 64 bit mode
.adjust_env "if(machInst.mode.submode == SixtyFourBitMode && env.dataSize == 4) env.dataSize = 8\;"
subi "INTREG_RSP", "INTREG_RSP", "env.dataSize"
# There needs to be a store here to actually "push" the data
st "env.reg", 2, [0, "NUM_INTREGS", "INTREG_RSP"]
};
'''
#let {{

View file

@ -61,34 +61,34 @@ def macroop XOR_R_R
def macroop XOR_R_I
{
limm "NUM_INTREGS", "env.immediate"
xor "env.reg", "env.reg", "NUM_INTREGS"
limm "NUM_INTREGS+1", "IMMEDIATE"
xor "env.reg", "env.reg", "NUM_INTREGS+1"
};
def macroop XOR_M_R
{
#Do a load to get one of the sources
xor "NUM_INTREGS", "NUM_INTREGS", "env.reg"
xor "NUM_INTREGS+1", "NUM_INTREGS+1", "env.reg"
#Do a store to write the destination
};
def macroop XOR_R_M
{
#Do a load to get one of the sources
xor "env.reg", "env.reg", "NUM_INTREGS"
xor "env.reg", "env.reg", "NUM_INTREGS+1"
};
def macroop AND_R_I
{
limm "NUM_INTREGS", "env.immediate"
and "env.reg", "env.reg", "NUM_INTREGS"
limm "NUM_INTREGS+1", "IMMEDIATE"
and "env.reg", "env.reg", "NUM_INTREGS+1"
};
def macroop AND_M_I
{
#Do a load to get one of the sources
limm "NUM_INTREGS", "env.immediate"
and "NUM_INTREGS", "NUM_INTREGS", "NUM_INTREGS+1"
limm "NUM_INTREGS+1", "IMMEDIATE"
and "NUM_INTREGS+1", "NUM_INTREGS+1", "NUM_INTREGS+2"
#Do a store to write the destination
};
'''

View file

@ -189,17 +189,18 @@ output header {{
{
X86ISA::RegIndex reg;
X86ISA::RegIndex regm;
uint64_t immediate;
uint64_t displacement;
int addressSize;
uint8_t scale;
X86ISA::RegIndex index;
X86ISA::RegIndex base;
int dataSize;
int addressSize;
int stackSize;
EmulEnv(X86ISA::RegIndex _reg, X86ISA::RegIndex _regm,
uint64_t _immediate, uint64_t _displacement,
int _addressSize, int _dataSize) :
int _dataSize, int _addressSize, int _stackSize) :
reg(_reg), regm(_regm),
immediate(_immediate), displacement(_displacement),
addressSize(_addressSize), dataSize(_dataSize)
dataSize(_dataSize), addressSize(_addressSize),
stackSize(_stackSize)
{;}
};
}};
@ -211,17 +212,15 @@ let {{
self.regUsed = False
self.regm = "0"
self.regmUsed = False
self.immediate = "IMMEDIATE"
self.displacement = "DISPLACEMENT"
self.addressSize = "ADDRSIZE"
self.dataSize = "OPSIZE"
self.stackSize = "STACKSIZE"
def getAllocator(self):
return '''EmulEnv(%(reg)s,
%(regm)s,
%(immediate)s,
%(displacement)s,
%(dataSize)s,
%(addressSize)s,
%(dataSize)s)''' % \
%(stackSize)s)''' % \
self.__dict__
def addReg(self, reg):
if not self.regUsed:

View file

@ -59,8 +59,14 @@
//
//////////////////////////////////////////////////////////////////////////
def template MicroLdStOpDeclare {{
class %(class_name)s : public X86MicroopBase
// Load templates
output header {{
/**
* Base class for load and store ops
*/
class LdStOp : public X86MicroopBase
{
protected:
const uint8_t scale;
@ -71,6 +77,195 @@ def template MicroLdStOpDeclare {{
const RegIndex data;
const uint8_t dataSize;
const uint8_t addressSize;
//Constructor
LdStOp(ExtMachInst _machInst,
const char * mnem, 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,
OpClass __opClass) :
X86MicroopBase(machInst, mnem, _instMnem,
isMicro, isDelayed, isFirst, isLast, __opClass),
scale(_scale), index(_index), base(_base),
disp(_disp), segment(_segment),
data(_data),
dataSize(_dataSize), addressSize(_addressSize)
{}
std::string generateDisassembly(Addr pc,
const SymbolTable *symtab) const;
};
}};
output decoder {{
std::string LdStOp::generateDisassembly(Addr pc,
const SymbolTable *symtab) const
{
std::stringstream response;
printMnemonic(response, instMnem, mnemonic);
printReg(response, data);
response << ", ";
printSegment(response, segment);
ccprintf(response, ":[%d*", scale);
printReg(response, index);
response << " + ";
printReg(response, base);
ccprintf(response, " + %#x]", disp);
return response.str();
}
}};
def template MicroLoadExecute {{
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);
fault = xc->read(EA, (%(mem_acc_type)s%(mem_acc_size)s_t&)Mem, 0);
if(fault == NoFault)
{
%(code)s;
}
if(fault == NoFault)
{
%(op_wb)s;
}
return fault;
}
}};
def template MicroLoadInitiateAcc {{
Fault %(class_name)s::initiateAcc(%(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);
fault = xc->read(EA, (%(mem_acc_type)s%(mem_acc_size)s_t&)Mem, 0);
return fault;
}
}};
def template MicroLoadCompleteAcc {{
Fault %(class_name)s::completeAcc(PacketPtr pkt,
%(CPU_exec_context)s * xc,
Trace::InstRecord * traceData) const
{
Fault fault = NoFault;
%(op_decl)s;
%(op_rd)s;
Mem = pkt->get<typeof(Mem)>();
%(code)s;
if(fault == NoFault)
{
%(op_wb)s;
}
return fault;
}
}};
// Store templates
def template MicroStoreExecute {{
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)
{
fault = xc->write((%(mem_acc_type)s%(mem_acc_size)s_t)Mem,
EA, 0, 0);
}
if(fault == NoFault)
{
%(op_wb)s;
}
return fault;
}
}};
def template MicroStoreInitiateAcc {{
Fault %(class_name)s::initiateAcc(%(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)
{
fault = xc->write((%(mem_acc_type)s%(mem_acc_size)s_t)Mem,
EA, 0, 0);
}
if(fault == NoFault)
{
%(op_wb)s;
}
return fault;
}
}};
def template MicroStoreCompleteAcc {{
Fault %(class_name)s::completeAcc(PacketPtr, %(CPU_exec_context)s * xc,
Trace::InstRecord * traceData) const
{
return NoFault;
}
}};
// Common templates
//This delcares the initiateAcc function in memory operations
def template InitiateAccDeclare {{
Fault initiateAcc(%(CPU_exec_context)s *, Trace::InstRecord *) const;
}};
//This declares the completeAcc function in memory operations
def template CompleteAccDeclare {{
Fault completeAcc(PacketPtr, %(CPU_exec_context)s *, Trace::InstRecord *) const;
}};
def template MicroLdStOpDeclare {{
class %(class_name)s : public %(base_class)s
{
protected:
void buildMe();
public:
@ -90,6 +285,10 @@ def template MicroLdStOpDeclare {{
uint8_t _dataSize, uint8_t _addressSize);
%(BasicExecDeclare)s
%(InitiateAccDeclare)s
%(CompleteAccDeclare)s
};
}};
@ -107,11 +306,10 @@ def template MicroLdStOpConstructor {{
RegIndex _data,
uint8_t _dataSize, uint8_t _addressSize) :
%(base_class)s(machInst, "%(mnemonic)s", instMnem,
false, false, false, false, %(op_class)s),
scale(_scale), index(_index), base(_base),
disp(_disp), segment(_segment),
data(_data),
dataSize(_dataSize), addressSize(_addressSize)
false, false, false, false,
_scale, _index, _base,
_disp, _segment, _data,
_dataSize, _addressSize, %(op_class)s)
{
buildMe();
}
@ -120,17 +318,106 @@ def template MicroLdStOpConstructor {{
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) :
uint64_t _disp, uint8_t _segment,
RegIndex _data,
uint8_t _dataSize, uint8_t _addressSize) :
%(base_class)s(machInst, "%(mnemonic)s", instMnem,
isMicro, isDelayed, isFirst, isLast, %(op_class)s),
scale(_scale), index(_index), base(_base),
disp(_disp), segment(_segment),
data(_data),
dataSize(_dataSize), addressSize(_addressSize)
isMicro, isDelayed, isFirst, isLast,
_scale, _index, _base,
_disp, _segment, _data,
_dataSize, _addressSize, %(op_class)s)
{
buildMe();
}
}};
let {{
class LdStOp(X86Microop):
def __init__(self, data, segment, addr, disp):
self.data = data
[self.scale, self.index, self.base] = addr
self.disp = disp
self.segment = segment
self.dataSize = "env.dataSize"
self.addressSize = "env.addressSize"
def getAllocator(self, *microFlags):
allocator = '''new %(class_name)s(machInst, mnemonic
%(flags)s, %(scale)s, %(index)s, %(base)s,
%(disp)s, %(segment)s, %(data)s,
%(dataSize)s, %(addressSize)s)''' % {
"class_name" : self.className,
"flags" : self.microFlagsText(microFlags),
"scale" : self.scale, "index" : self.index,
"base" : self.base,
"disp" : self.disp,
"segment" : self.segment, "data" : self.data,
"dataSize" : self.dataSize, "addressSize" : self.addressSize}
return allocator
}};
let {{
# Make these empty strings so that concatenating onto
# them will always work.
header_output = ""
decoder_output = ""
exec_output = ""
calculateEA = "EA = scale * Index + Base + disp;"
def defineMicroLoadOp(mnemonic, code):
global header_output
global decoder_output
global exec_output
global microopClasses
Name = mnemonic
name = mnemonic.lower()
# Build up the all register version of this micro op
iop = InstObjParams(name, Name, 'LdStOp',
{"code": code, "ea_code": calculateEA})
header_output += MicroLdStOpDeclare.subst(iop)
decoder_output += MicroLdStOpConstructor.subst(iop)
exec_output += MicroLoadExecute.subst(iop)
exec_output += MicroLoadInitiateAcc.subst(iop)
exec_output += MicroLoadCompleteAcc.subst(iop)
class LoadOp(LdStOp):
def __init__(self, data, segment, addr, disp = 0):
super(LoadOp, self).__init__(data, segment, addr, disp)
self.className = Name
self.mnemonic = name
microopClasses[name] = LoadOp
defineMicroLoadOp('Ld', 'Data = merge(Data, Mem, dataSize);')
def defineMicroStoreOp(mnemonic, code):
global header_output
global decoder_output
global exec_output
global microopClasses
Name = mnemonic
name = mnemonic.lower()
# Build up the all register version of this micro op
iop = InstObjParams(name, Name, 'LdStOp',
{"code": code, "ea_code": calculateEA})
header_output += MicroLdStOpDeclare.subst(iop)
decoder_output += MicroLdStOpConstructor.subst(iop)
exec_output += MicroStoreExecute.subst(iop)
exec_output += MicroStoreInitiateAcc.subst(iop)
exec_output += MicroStoreCompleteAcc.subst(iop)
class StoreOp(LdStOp):
def __init__(self, data, addr, segment):
super(LoadOp, self).__init__(data, addr, segment)
self.className = Name
self.mnemonic = name
microopClasses[name] = StoreOp
defineMicroLoadOp('St', 'Mem = Data;')
}};

View file

@ -99,7 +99,9 @@ def operands {{
'DestReg': ('IntReg', 'uqw', 'dest', 'IsInteger', 1),
'SrcReg1': ('IntReg', 'uqw', 'src1', 'IsInteger', 2),
'SrcReg2': ('IntReg', 'uqw', 'src2', 'IsInteger', 3),
'IntRegOp0': ('IntReg', 'udw', 'param0', 'IsInteger', 1),
'IntRegOp1': ('IntReg', 'udw', 'param1', 'IsInteger', 2),
'IntRegOp2': ('IntReg', 'udw', 'param2', 'IsInteger', 2),
'Base': ('IntReg', 'uqw', 'base', 'IsInteger', 4),
'Index': ('IntReg', 'uqw', 'index', 'IsInteger', 5),
'Data': ('IntReg', 'uqw', 'data', 'IsInteger', 6),
'RIP': ('NPC', 'uqw', None, (None, None, 'IsControl'), 10),
'Mem': ('Mem', 'uqw', None, ('IsMemRef', 'IsLoad', 'IsStore'), 100)
}};

View file

@ -93,7 +93,7 @@ namespace X86ISA
// semantically meaningful register indices
//There is no such register in X86
const int ZeroReg = 0;
const int ZeroReg = NUM_INTREGS;
const int StackPointerReg = INTREG_RSP;
//X86 doesn't seem to have a link register
const int ReturnAddressReg = 0;

View file

@ -169,6 +169,8 @@ namespace X86ISA
uint8_t opSize;
//The effective address size.
uint8_t addrSize;
//The effective stack size.
uint8_t stackSize;
//Mode information
OperatingMode mode;
@ -193,8 +195,6 @@ namespace X86ISA
inline static bool
operator == (const ExtMachInst &emi1, const ExtMachInst &emi2)
{
if(emi1.mode != emi2.mode)
return false;
if(emi1.legacy != emi2.legacy)
return false;
if(emi1.rex != emi2.rex)
@ -215,6 +215,14 @@ namespace X86ISA
return false;
if(emi1.displacement != emi2.displacement)
return false;
if(emi1.mode != emi2.mode)
return false;
if(emi1.opSize != emi2.opSize)
return false;
if(emi1.addrSize != emi2.addrSize)
return false;
if(emi1.stackSize != emi2.stackSize)
return false;
return true;
}

View file

@ -79,7 +79,8 @@ namespace __hash_namespace {
((uint64_t)emi.opcode.prefixB << 8) |
((uint64_t)emi.opcode.op)) ^
emi.immediate ^ emi.displacement ^
emi.mode ^ emi.opSize;
emi.mode ^
emi.opSize ^ emi.addrSize ^ emi.stackSize;
};
};
}