diff options
Diffstat (limited to 'src/arch')
33 files changed, 1348 insertions, 334 deletions
diff --git a/src/arch/alpha/predecoder.hh b/src/arch/alpha/predecoder.hh index 0407ce99b..4887de856 100644 --- a/src/arch/alpha/predecoder.hh +++ b/src/arch/alpha/predecoder.hh @@ -44,8 +44,6 @@ namespace AlphaISA { protected: ThreadContext * tc; - //The pc of the current instruction - Addr fetchPC; //The extended machine instruction being generated ExtMachInst ext_inst; @@ -69,10 +67,8 @@ namespace AlphaISA //Use this to give data to the predecoder. This should be used //when there is control flow. - void moreBytes(Addr pc, Addr _fetchPC, Addr off, MachInst inst) + void moreBytes(Addr pc, Addr fetchPC, MachInst inst) { - fetchPC = _fetchPC; - assert(off == 0); ext_inst = inst; #if FULL_SYSTEM if (pc && 0x1) diff --git a/src/arch/micro_asm.py b/src/arch/micro_asm.py index a8a63e1f8..5aa910cc3 100644 --- a/src/arch/micro_asm.py +++ b/src/arch/micro_asm.py @@ -131,7 +131,8 @@ def handle_statement(parser, container, statement): microop = eval('parser.microops[statement.mnemonic](%s)' % statement.params) except: - print_error("Error creating microop object.") + print_error("Error creating microop object with mnemonic %s." % \ + statement.mnemonic) raise try: for label in statement.labels: @@ -237,9 +238,7 @@ def t_params_PARAMS(t): unescapeParamsRE = re.compile(r'(\\[\n;\\])') def unescapeParams(mo): val = mo.group(0) - print "About to sub %s for %s" % (val[1], val) return val[1] - print "Looking for matches in %s" % t.value t.value = unescapeParamsRE.sub(unescapeParams, t.value) t.lexer.begin('asm') return t @@ -482,9 +481,9 @@ class MicroAssembler(object): def assemble(self, asm): self.parser.parse(asm, lexer=self.lexer) # Begin debug printing - for macroop in self.parser.macroops.values(): - print macroop - print self.parser.rom + #for macroop in self.parser.macroops.values(): + # print macroop + #print self.parser.rom # End debug printing macroops = self.parser.macroops self.parser.macroops = {} diff --git a/src/arch/mips/predecoder.hh b/src/arch/mips/predecoder.hh index 90f768d73..e310dded4 100644 --- a/src/arch/mips/predecoder.hh +++ b/src/arch/mips/predecoder.hh @@ -66,9 +66,8 @@ namespace MipsISA //Use this to give data to the predecoder. This should be used //when there is control flow. - void moreBytes(Addr pc, Addr fetchPC, Addr off, MachInst inst) + void moreBytes(Addr pc, Addr fetchPC, MachInst inst) { - assert(off == 0); emi = inst; } diff --git a/src/arch/sparc/predecoder.hh b/src/arch/sparc/predecoder.hh index 38d8fd1a2..d990c3256 100644 --- a/src/arch/sparc/predecoder.hh +++ b/src/arch/sparc/predecoder.hh @@ -67,10 +67,8 @@ namespace SparcISA //Use this to give data to the predecoder. This should be used //when there is control flow. - void moreBytes(Addr pc, Addr fetchPC, Addr off, MachInst inst) + void moreBytes(Addr pc, Addr fetchPC, MachInst inst) { - assert(off == 0); - emi = inst; //The I bit, bit 13, is used to figure out where the ASI //should come from. Use that in the ExtMachInst. This is 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/emulenv.cc b/src/arch/x86/emulenv.cc new file mode 100644 index 000000000..e3f703cff --- /dev/null +++ b/src/arch/x86/emulenv.cc @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2007 The Hewlett-Packard Development Company + * All rights reserved. + * + * Redistribution and use of this software in source and binary forms, + * with or without modification, are permitted provided that the + * following conditions are met: + * + * The software must be used only for Non-Commercial Use which means any + * use which is NOT directed to receiving any direct monetary + * compensation for, or commercial advantage from such use. Illustrative + * examples of non-commercial use are academic research, personal study, + * teaching, education and corporate research & development. + * Illustrative examples of commercial use are distributing products for + * commercial advantage and providing services using the software for + * commercial advantage. + * + * If you wish to use this software or functionality therein that may be + * covered by patents for commercial use, please contact: + * Director of Intellectual Property Licensing + * Office of Strategy and Technology + * Hewlett-Packard Company + * 1501 Page Mill Road + * Palo Alto, California 94304 + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. Redistributions + * in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. Neither the name of + * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. No right of + * sublicense is granted herewith. Derivatives of the software and + * output created using the software may be prepared, but only for + * Non-Commercial Uses. Derivatives of the software may be shared with + * others provided: (i) the others agree to abide by the list of + * conditions herein which includes the Non-Commercial Use restrictions; + * and (ii) such Derivatives of the software include the above copyright + * notice to acknowledge the contribution from this software where + * applicable, this list of conditions and the disclaimer below. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "arch/x86/emulenv.hh" +#include "base/misc.hh" + +using namespace X86ISA; + +void EmulEnv::doModRM(const ExtMachInst & machInst) +{ + assert(machInst.modRM.mod != 3); + //Use the SIB byte for addressing if the modrm byte calls for it. + if (machInst.modRM.rm == 4 && machInst.addrSize != 2) { + scale = 1 << machInst.sib.scale; + index = machInst.sib.index; + base = machInst.sib.base; + //In this special case, we don't use a base. The displacement also + //changes, but that's managed by the predecoder. + if (machInst.sib.base == INTREG_RBP && machInst.modRM.mod == 0) + base = NUM_INTREGS; + //In -this- special case, we don't use an index. + if (machInst.sib.index == INTREG_RSP) + index = NUM_INTREGS; + } else { + if (machInst.addrSize == 2) { + warn("I'm not really using 16 bit MODRM like I'm supposed to!\n"); + } else { + scale = 0; + base = machInst.modRM.rm; + if (machInst.modRM.mod == 0 && machInst.modRM.rm == 5) { + base = NUM_INTREGS; + if (machInst.mode.submode == SixtyFourBitMode) + base = NUM_INTREGS+7; + } + } + } +} + diff --git a/src/arch/x86/emulenv.hh b/src/arch/x86/emulenv.hh new file mode 100644 index 000000000..66c56fb79 --- /dev/null +++ b/src/arch/x86/emulenv.hh @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2007 The Hewlett-Packard Development Company + * All rights reserved. + * + * Redistribution and use of this software in source and binary forms, + * with or without modification, are permitted provided that the + * following conditions are met: + * + * The software must be used only for Non-Commercial Use which means any + * use which is NOT directed to receiving any direct monetary + * compensation for, or commercial advantage from such use. Illustrative + * examples of non-commercial use are academic research, personal study, + * teaching, education and corporate research & development. + * Illustrative examples of commercial use are distributing products for + * commercial advantage and providing services using the software for + * commercial advantage. + * + * If you wish to use this software or functionality therein that may be + * covered by patents for commercial use, please contact: + * Director of Intellectual Property Licensing + * Office of Strategy and Technology + * Hewlett-Packard Company + * 1501 Page Mill Road + * Palo Alto, California 94304 + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. Redistributions + * in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. Neither the name of + * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. No right of + * sublicense is granted herewith. Derivatives of the software and + * output created using the software may be prepared, but only for + * Non-Commercial Uses. Derivatives of the software may be shared with + * others provided: (i) the others agree to abide by the list of + * conditions herein which includes the Non-Commercial Use restrictions; + * and (ii) such Derivatives of the software include the above copyright + * notice to acknowledge the contribution from this software where + * applicable, this list of conditions and the disclaimer below. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_X86_EMULENV_HH__ +#define __ARCH_X86_EMULENV_HH__ + +#include "arch/x86/types.hh" +#include "arch/x86/intregs.hh" + +namespace X86ISA +{ + struct EmulEnv + { + RegIndex reg; + RegIndex regm; + uint8_t scale; + RegIndex index; + RegIndex base; + int dataSize; + int addressSize; + int stackSize; + + EmulEnv(RegIndex _reg, RegIndex _regm, + int _dataSize, int _addressSize, int _stackSize) : + reg(_reg), regm(_regm), + scale(0), index(NUM_INTREGS), + base(NUM_INTREGS), + dataSize(_dataSize), addressSize(_addressSize), + stackSize(_stackSize) + {;} + + void doModRM(const ExtMachInst & machInst); + }; +}; + +#endif // __ARCH_X86_TYPES_HH__ diff --git a/src/arch/x86/isa/base.isa b/src/arch/x86/isa/base.isa index eba24f709..eed969b47 100644 --- a/src/arch/x86/isa/base.isa +++ b/src/arch/x86/isa/base.isa @@ -95,6 +95,14 @@ output header {{ /** * Base class for all X86 static instructions. */ + BitUnion64(X86IntReg) + Bitfield<63,0> R; + Bitfield<31,0> E; + Bitfield<15,0> X; + Bitfield<15,8> H; + Bitfield<7, 0> L; + EndBitUnion(X86IntReg) + class X86StaticInst : public StaticInst { protected: @@ -114,10 +122,50 @@ output header {{ inline uint64_t merge(uint64_t into, uint64_t val, int size) const { - //FIXME This needs to be significantly more sophisticated + X86IntReg reg; + reg = into; + //FIXME This needs to be handle high bytes as well + switch(size) + { + case 1: + reg.L = val; + break; + case 2: + reg.X = val; + break; + case 4: + //XXX Check if this should be zeroed or sign extended + reg = 0; + reg.E = val; + break; + case 8: + reg.R = val; + break; + default: + panic("Tried to merge with unrecognized size %d.\n", size); + } return val; } + inline uint64_t pick(uint64_t from, int size) + { + X86IntReg reg; + reg = from; + switch(size) + { + case 1: + return reg.L; + case 2: + return reg.E; + case 4: + return reg.X; + case 8: + return reg.R; + default: + panic("Tried to pick with unrecognized size %d.\n", size); + } + } + }; }}; @@ -128,6 +176,39 @@ output decoder {{ ccprintf(os, "\t%s ", mnemonic); } + inline void printMnemonic(std::ostream &os, + const char * instMnemonic, const char * mnemonic) + { + ccprintf(os, "\t%s : %s ", instMnemonic, mnemonic); + } + + void printSegment(std::ostream &os, int segment) + { + switch (segment) + { + case 0: + ccprintf(os, "ES"); + break; + case 1: + ccprintf(os, "CS"); + break; + case 2: + ccprintf(os, "SS"); + break; + case 3: + ccprintf(os, "DS"); + break; + case 4: + ccprintf(os, "FS"); + break; + case 5: + ccprintf(os, "GS"); + break; + default: + panic("Unrecognized segment %d\n", segment); + } + } + void X86StaticInst::printSrcReg(std::ostream &os, int reg) const { @@ -197,6 +278,8 @@ output decoder {{ case INTREG_R15W: ccprintf(os, "r15"); break; + default: + ccprintf(os, "t%d", reg - NUM_INTREGS); } } else if (reg < Ctrl_Base_DepTag) { ccprintf(os, "%%f%d", reg - FP_Base_DepTag); diff --git a/src/arch/x86/isa/bitfields.isa b/src/arch/x86/isa/bitfields.isa index 82fa4f25b..8707bbb4c 100644 --- a/src/arch/x86/isa/bitfields.isa +++ b/src/arch/x86/isa/bitfields.isa @@ -100,3 +100,8 @@ def bitfield SIB_BASE sib.base; def bitfield OPSIZE opSize; def bitfield ADDRSIZE addrSize; +def bitfield STACKSIZE stackSize; + +def bitfield MODE mode; +def bitfield MODE_MODE mode.mode; +def bitfield MODE_SUBMODE mode.submode; diff --git a/src/arch/x86/isa/decoder/one_byte_opcodes.isa b/src/arch/x86/isa/decoder/one_byte_opcodes.isa index b72b2b16a..484f8160d 100644 --- a/src/arch/x86/isa/decoder/one_byte_opcodes.isa +++ b/src/arch/x86/isa/decoder/one_byte_opcodes.isa @@ -63,8 +63,14 @@ 0x00: decode OPCODE_OP_BOTTOM3 { 0x4: ADD(); 0x5: ADD(); - 0x6: push_ES(); - 0x7: pop_ES(); + 0x6: decode MODE_SUBMODE { + 0x0: This_should_be_an_illegal_instruction(); + default: push_ES(); + } + 0x7: decode MODE_SUBMODE { + 0x0: This_should_be_an_illegal_instruction(); + default: pop_ES(); + } default: ADD(); } 0x01: decode OPCODE_OP_BOTTOM3 { @@ -74,7 +80,10 @@ 0x3: or_Gv_Ev(); 0x4: or_Al_Ib(); 0x5: or_rAX_Iz(); - 0x6: push_CS(); + 0x6: decode MODE_SUBMODE { + 0x0: This_should_be_an_illegal_instruction(); + default: push_CS(); + } //Any time this is seen, it should generate a two byte opcode 0x7: M5InternalError::error( {{"Saw a one byte opcode whose value was 0x0F!"}}); @@ -86,8 +95,14 @@ 0x3: adc_Gv_Ev(); 0x4: adc_Al_Ib(); 0x5: adc_rAX_Iz(); - 0x6: push_SS(); - 0x7: pop_SS(); + 0x6: decode MODE_SUBMODE { + 0x0: This_should_be_an_illegal_instruction(); + default: push_SS(); + } + 0x7: decode MODE_SUBMODE { + 0x0: This_should_be_an_illegal_instruction(); + default: pop_SS(); + } } 0x03: decode OPCODE_OP_BOTTOM3 { 0x0: sbb_Eb_Gb(); @@ -96,8 +111,14 @@ 0x3: sbb_Gv_Ev(); 0x4: sbb_Al_Ib(); 0x5: sbb_rAX_Iz(); - 0x6: push_DS(); - 0x7: pop_DS(); + 0x6: decode MODE_SUBMODE { + 0x0: This_should_be_an_illegal_instruction(); + default: push_DS(); + } + 0x7: decode MODE_SUBMODE { + 0x0: This_should_be_an_illegal_instruction(); + default: pop_DS(); + } } 0x04: decode OPCODE_OP_BOTTOM3 { 0x0: and_Eb_Gb(); @@ -108,7 +129,10 @@ 0x5: and_rAX_Iz(); 0x6: M5InternalError::error( {{"Tried to execute the ES segment override prefix!"}}); - 0x7: daa(); + 0x7: decode MODE_SUBMODE { + 0x0: This_should_be_an_illegal_instruction(); + default: daa(); + } } 0x05: decode OPCODE_OP_BOTTOM3 { 0x0: sub_Eb_Gb(); @@ -126,7 +150,10 @@ 0x5: Inst::XOR(rAx,Iz); 0x6: M5InternalError::error( {{"Tried to execute the SS segment override prefix!"}}); - 0x7: aaa(); + 0x7: decode MODE_SUBMODE { + 0x0: This_should_be_an_illegal_instruction(); + default: aaa(); + } default: MultiInst::XOR(OPCODE_OP_BOTTOM3, [Eb,Gb], [Ev,Gv], [Gb,Eb], [Gv,Ev]); @@ -140,53 +167,78 @@ 0x5: cmp_rAX_Iz(); 0x6: M5InternalError::error( {{"Tried to execute the DS segment override prefix!"}}); - 0x7: aas(); - } - 0x08: decode OPCODE_OP_BOTTOM3 { - 0x0: inc_eAX(); - 0x1: inc_eCX(); - 0x2: inc_eDX(); - 0x3: inc_eBX(); - 0x4: inc_eSP(); - 0x5: inc_eBP(); - 0x6: inc_eSI(); - 0x7: inc_eDI(); + 0x7: decode MODE_SUBMODE { + 0x0: This_should_be_an_illegal_instruction(); + default: aas(); + } } - 0x09: decode OPCODE_OP_BOTTOM3 { - 0x0: dec_eAX(); - 0x1: dec_eCX(); - 0x2: dec_eDX(); - 0x3: dec_eBX(); - 0x4: dec_eSP(); - 0x5: dec_eBP(); - 0x6: dec_eSI(); - 0x7: dec_eDI(); + 0x08: decode MODE_SUBMODE { + 0x0: M5InternalError::error ( + {{"Tried to execute an REX prefix!"}}); + default: decode OPCODE_OP_BOTTOM3 { + 0x0: inc_eAX(); + 0x1: inc_eCX(); + 0x2: inc_eDX(); + 0x3: inc_eBX(); + 0x4: inc_eSP(); + 0x5: inc_eBP(); + 0x6: inc_eSI(); + 0x7: inc_eDI(); + } } - 0x0A: decode OPCODE_OP_BOTTOM3 { - 0x0: Inst::PUSH(rAx); - 0x1: push_rCX(); - 0x2: push_rDX(); - 0x3: push_rBX(); - 0x4: Inst::PUSH(rSP); - 0x5: push_rBP(); - 0x6: push_rSI(); - 0x7: push_rDI(); + 0x09: decode MODE_SUBMODE { + 0x0: M5InternalError::error ( + {{"Tried to execute an REX prefix!"}}); + default: decode OPCODE_OP_BOTTOM3 { + 0x0: dec_eAX(); + 0x1: dec_eCX(); + 0x2: dec_eDX(); + 0x3: dec_eBX(); + 0x4: dec_eSP(); + 0x5: dec_eBP(); + 0x6: dec_eSI(); + 0x7: dec_eDI(); + } } - 0x0B: decode OPCODE_OP_BOTTOM3 { - 0x0: pop_rAX(); - 0x1: pop_rCX(); - 0x2: pop_rDX(); - 0x3: pop_rBX(); - 0x4: pop_rSP(); - 0x5: pop_rBP(); - 0x6: Inst::POP(rSI); - 0x7: pop_rDI(); + format Inst { + 0x0A: decode OPCODE_OP_BOTTOM3 { + 0x0: PUSH(rAx); + 0x1: PUSH(rCx); + 0x2: PUSH(rDx); + 0x3: PUSH(rBx); + 0x4: PUSH(rSP); + 0x5: PUSH(rBP); + 0x6: PUSH(rSI); + 0x7: PUSH(rDI); + } + 0x0B: decode OPCODE_OP_BOTTOM3 { + 0x0: POP(rAx); + 0x1: POP(rCx); + 0x2: POP(rDx); + 0x3: POP(rBx); + 0x4: POP(rSP); + 0x5: POP(rBP); + 0x6: POP(rSI); + 0x7: POP(rDI); + } } 0x0C: decode OPCODE_OP_BOTTOM3 { - 0x0: pusha(); - 0x1: popa(); - 0x2: bound_Gv_Ma(); - 0x3: arpl_Ew_Gw(); + 0x0: decode MODE_SUBMODE { + 0x0: This_should_be_an_illegal_instruction(); + default: pusha(); + } + 0x1: decode MODE_SUBMODE { + 0x0: This_should_be_an_illegal_instruction(); + default: popa(); + } + 0x2: decode MODE_SUBMODE { + 0x0: This_should_be_an_illegal_instruction(); + default: bound_Gv_Ma(); + } + 0x3: decode MODE_SUBMODE { + 0x0: Inst::MOVSXD(Gv,Ed); + default: arpl_Ew_Gw(); + } 0x4: M5InternalError::error( {{"Tried to execute the FS segment override prefix!"}}); 0x5: M5InternalError::error( @@ -228,8 +280,21 @@ } 0x10: decode OPCODE_OP_BOTTOM3 { 0x0: group1_Eb_Ib(); - 0x1: group1_Ev_Iz(); - 0x2: group1_Eb_Ib(); + //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(); + } //0x3: group1_Ev_Ib(); 0x3: decode MODRM_REG { 0x0: add_Eb_Ib(); @@ -241,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(); } @@ -250,14 +315,14 @@ 0x0: Inst::MOV(Eb,Gb); 0x1: Inst::MOV(Ev,Gv); 0x2: Inst::MOV(Gb,Eb); - 0x3: Inst::MOV(Gv,Eb); + 0x3: Inst::MOV(Gv,Ev); 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 } 0x12: decode OPCODE_OP_BOTTOM3 { - 0x0: nop_or_pause(); //Check for repe prefix + default: nop_or_pause(); //Check for repe prefix 0x1: xchg_rCX_rAX(); 0x2: xchg_rDX_rAX(); 0x3: xchg_rVX_rAX(); @@ -269,12 +334,23 @@ 0x13: decode OPCODE_OP_BOTTOM3 { 0x0: cbw_or_cwde_or_cdqe_rAX(); 0x1: cwd_or_cdq_or_cqo_rAX_rDX(); - 0x2: call_Ap(); + 0x2: decode MODE_SUBMODE { + 0x0: This_should_be_an_illegal_instruction(); + default: call_Ap(); + } 0x3: fwait(); //aka wait 0x4: pushf_Fv(); 0x5: popf_Fv(); - 0x6: sahf(); - 0x7: lahf(); + //Both of these should be illegal only if CPUID.AHF64=0, + //according to sandpile.org + 0x6: decode MODE_SUBMODE { + 0x0: This_should_be_an_illegal_instruction(); + default: sahf(); + } + 0x7: decode MODE_SUBMODE { + 0x0: This_should_be_an_illegal_instruction(); + default: lahf(); + } } 0x14: decode OPCODE_OP_BOTTOM3 { 0x0: mov_Al_Ob(); @@ -287,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(); @@ -306,23 +382,31 @@ 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(); 0x1: group2_Ev_Ib(); 0x2: ret_near_Iw(); 0x3: ret_near(); - 0x4: les_Gz_Mp(); - 0x5: lds_Gz_Mp(); + 0x4: decode MODE_SUBMODE { + 0x0: This_should_be_an_illegal_instruction(); + default: les_Gz_Mp(); + } + 0x5: decode MODE_SUBMODE { + 0x0: This_should_be_an_illegal_instruction(); + default: lds_Gz_Mp(); + } //0x6: group12_Eb_Ib(); 0x6: decode MODRM_REG { 0x0: Inst::MOV(Eb,Ib); @@ -339,7 +423,10 @@ 0x3: ret_far(); 0x4: int3(); 0x5: int_Ib(); - 0x6: into(); + 0x6: decode MODE_SUBMODE { + 0x0: This_should_be_an_illegal_instruction(); + default: into(); + } 0x7: iret(); } 0x1A: decode OPCODE_OP_BOTTOM3 { @@ -347,9 +434,18 @@ 0x1: group2_Ev_1(); 0x2: group2_Eb_Cl(); 0x3: group2_Ev_Cl(); - 0x4: aam_Ib(); - 0x5: aad_Ib(); - 0x6: salc(); + 0x4: decode MODE_SUBMODE { + 0x0: This_should_be_an_illegal_instruction(); + default: aam_Ib(); + } + 0x5: decode MODE_SUBMODE { + 0x0: This_should_be_an_illegal_instruction(); + default: aad_Ib(); + } + 0x6: decode MODE_SUBMODE { + 0x0: This_should_be_an_illegal_instruction(); + default: salc(); + } 0x7: xlat(); } 0x1B: decode OPCODE_OP_BOTTOM3 { @@ -373,9 +469,12 @@ 0x7: out_Ib_eAX(); } 0x1D: decode OPCODE_OP_BOTTOM3 { - 0x0: call_Jz(); + 0x0: Inst::CALL(Jz); 0x1: jmp_Jz(); - 0x2: jmp_Ap(); + 0x2: decode MODE_SUBMODE { + 0x0: This_should_be_an_illegal_instruction(); + default: jmp_Ap(); + } 0x3: jmp_Jb(); 0x4: in_Al_Dx(); 0x5: in_eAX_Dx(); diff --git a/src/arch/x86/isa/formats/multi.isa b/src/arch/x86/isa/formats/multi.isa index 37b28fe64..97777f727 100644 --- a/src/arch/x86/isa/formats/multi.isa +++ b/src/arch/x86/isa/formats/multi.isa @@ -70,8 +70,8 @@ def format Inst(*opTypeSet) {{ def format MultiInst(switchVal, *opTypeSets) {{ switcher = {} for (count, opTypeSet) in zip(xrange(len(opTypeSets)), opTypeSets): - switcher[count] = (Name, opTypeSet, EmulEnv()) - blocks = doSplitDecode(specializeInst, switchVal, switcher) + switcher[count] = (specializeInst, Name, opTypeSet, EmulEnv()) + blocks = doSplitDecode(switchVal, switcher) (header_output, decoder_output, decode_block, exec_output) = blocks.makeList() }}; 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 <sstream> #include <iostream> +#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..de66f70f3 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,31 @@ # # Authors: Gabe Black -microcode = "" +microcode = ''' +def macroop SUB_R_I +{ + subi "env.reg", "env.reg", "IMMEDIATE" +}; + +def macroop SUB_M_I +{ + ld "NUM_INTREGS+1", 3, ["env.scale", "env.index", "env.base"], \ + "DISPLACEMENT" + subi "NUM_INTREGS+1", "NUM_INTREGS+1", "IMMEDIATE" + st "NUM_INTREGS+1", 3, ["env.scale", "env.index", "env.base"], \ + "DISPLACEMENT" +}; + +def macroop SUB_P_I +{ + rdip "NUM_INTREGS+7" + ld "NUM_INTREGS+1", 3, ["env.scale", "env.index", "env.base"], \ + "DISPLACEMENT" + subi "NUM_INTREGS+1", "NUM_INTREGS+1", "IMMEDIATE" + st "NUM_INTREGS+1", 3, ["env.scale", "env.index", "env.base"], \ + "DISPLACEMENT" +}; +''' #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..7b4ab0781 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,47 @@ # # 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_P_R +{ + rdip "NUM_INTREGS+7" + 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_P_I +{ + rdip "NUM_INTREGS+7" + 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/control_transfer/call.py b/src/arch/x86/isa/insts/control_transfer/call.py index 231db6e40..5cd8a6359 100644 --- a/src/arch/x86/isa/insts/control_transfer/call.py +++ b/src/arch/x86/isa/insts/control_transfer/call.py @@ -53,7 +53,18 @@ # # Authors: Gabe Black -microcode = "" +microcode = ''' +def macroop CALL_I +{ + .adjust_env "if(machInst.mode.submode == SixtyFourBitMode && env.dataSize == 4) env.dataSize = 8\;" + + limm "NUM_INTREGS+2", "IMMEDIATE" + rdip "NUM_INTREGS+1" + subi "INTREG_RSP", "INTREG_RSP", "env.dataSize" + st "NUM_INTREGS+1", 2, [0, "NUM_INTREGS", "INTREG_RSP"] + wrip "NUM_INTREGS+1", "NUM_INTREGS+2" +}; +''' #let {{ # class CALL(Inst): # "GenFault ${new UnimpInstFault}" diff --git a/src/arch/x86/isa/insts/data_transfer/move.py b/src/arch/x86/isa/insts/data_transfer/move.py index 9d23b24e8..662b2c373 100644 --- a/src/arch/x86/isa/insts/data_transfer/move.py +++ b/src/arch/x86/isa/insts/data_transfer/move.py @@ -59,20 +59,55 @@ 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_P_R { + rdip "NUM_INTREGS+7" + 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_P { + rdip "NUM_INTREGS+7" + ld "env.reg", 3, ["env.scale", "env.index", "env.base"], "DISPLACEMENT" }; def macroop MOV_R_I { - limm "env.reg", "env.immediate" + limm "env.reg", "IMMEDIATE" }; def macroop MOV_M_I { - limm "env.reg", "env.immediate" - #Do a store to put the register operand into memory + limm "NUM_INTREGS+1", "IMMEDIATE" + st "NUM_INTREGS+1", 3, ["env.scale", "env.index", "env.base"], \ + "DISPLACEMENT" +}; + +def macroop MOV_P_I { + rdip "NUM_INTREGS+7" + limm "NUM_INTREGS+1", "IMMEDIATE" + st "NUM_INTREGS+1", 3, ["env.scale", "env.index", "env.base"], \ + "DISPLACEMENT" +}; + +def macroop MOVSXD_R_R { + sext "env.reg", "env.regm", "env.dataSize" +}; + +def macroop MOVSXD_R_M { + ld "NUM_INTREGS+1", 3, ["env.scale", "env.index", "env.base"], \ + "DISPLACEMENT" + sext "env.reg", "NUM_INTREGS+1", "env.dataSize" +}; + +def macroop MOVSXD_R_P { + rdip "NUM_INTREGS+7" + ld "NUM_INTREGS+1", 3, ["env.scale", "env.index", "env.base"], \ + "DISPLACEMENT" + sext "env.reg", "NUM_INTREGS+1", "env.dataSize" }; ''' #let {{ diff --git a/src/arch/x86/isa/insts/data_transfer/stack_operations.py b/src/arch/x86/isa/insts/data_transfer/stack_operations.py index b7ec0ec66..ad95fd468 100644 --- a/src/arch/x86/isa/insts/data_transfer/stack_operations.py +++ b/src/arch/x86/isa/insts/data_transfer/stack_operations.py @@ -55,28 +55,28 @@ 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 {{ -# class POP(Inst): -# "GenFault ${new UnimpInstFault}" -# class POPA(Inst): -# "GenFault ${new UnimpInstFault}" # class POPA(Inst): # "GenFault ${new UnimpInstFault}" # class POPAD(Inst): # "GenFault ${new UnimpInstFault}" -# class PUSH(Inst): -# "GenFault ${new UnimpInstFault}" # class PUSHA(Inst): # "GenFault ${new UnimpInstFault}" # class PUSHAD(Inst): diff --git a/src/arch/x86/isa/insts/load_effective_address.py b/src/arch/x86/isa/insts/load_effective_address.py index dab6960b1..f5f92ddbf 100644 --- a/src/arch/x86/isa/insts/load_effective_address.py +++ b/src/arch/x86/isa/insts/load_effective_address.py @@ -53,8 +53,13 @@ # # 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" +}; + +def macroop LEA_R_P { + rdip "NUM_INTREGS+7" + lea "env.reg", 3, ["env.scale", "env.index", "env.base"], "DISPLACEMENT" +}; +''' diff --git a/src/arch/x86/isa/insts/logical.py b/src/arch/x86/isa/insts/logical.py index ec0ed97b2..d02bfd586 100644 --- a/src/arch/x86/isa/insts/logical.py +++ b/src/arch/x86/isa/insts/logical.py @@ -61,51 +61,77 @@ 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" - #Do a store to write the destination + ld "NUM_INTREGS+1", 3, ["env.scale", "env.index", "env.base"], \ + "DISPLACEMENT" + xor "NUM_INTREGS+1", "NUM_INTREGS+1", "env.reg" + st "NUM_INTREGS+1", 3, ["env.scale", "env.index", "env.base"], \ + "DISPLACEMENT" +}; + +def macroop XOR_P_R +{ + rdip "NUM_INTREGS+7" + ld "NUM_INTREGS+1", 3, ["env.scale", "env.index", "env.base"], \ + "DISPLACEMENT" + xor "NUM_INTREGS+1", "NUM_INTREGS+1", "env.reg" + st "NUM_INTREGS+1", 3, ["env.scale", "env.index", "env.base"], \ + "DISPLACEMENT" }; def macroop XOR_R_M { - #Do a load to get one of the sources - xor "env.reg", "env.reg", "NUM_INTREGS" + ld "NUM_INTREGS+1", 3, ["env.scale", "env.index", "env.base"], \ + "DISPLACEMENT" + xor "env.reg", "env.reg", "NUM_INTREGS+1" +}; + +def macroop XOR_R_P +{ + rdip "NUM_INTREGS+7" + ld "NUM_INTREGS+1", 3, ["env.scale", "env.index", "env.base"], \ + "DISPLACEMENT" + 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" - #Do a store to write the destination + ld "NUM_INTREGS+2", 3, ["env.scale", "env.index", "env.base"], \ + "DISPLACEMENT" + limm "NUM_INTREGS+1", "IMMEDIATE" + and "NUM_INTREGS+2", "NUM_INTREGS+2", "NUM_INTREGS+1" + st "NUM_INTREGS+2", 3, ["env.scale", "env.index", "env.base"], \ + "DISPLACEMENT" +}; + +def macroop AND_P_I +{ + rdip "NUM_INTREGS+7" + ld "NUM_INTREGS+2", 3, ["env.scale", "env.index", "env.base"], \ + "DISPLACEMENT" + limm "NUM_INTREGS+1", "IMMEDIATE" + and "NUM_INTREGS+2", "NUM_INTREGS+2", "NUM_INTREGS+1" + st "NUM_INTREGS+2", 3, ["env.scale", "env.index", "env.base"], \ + "DISPLACEMENT" }; ''' #let {{ #microcodeString = ''' -# def macroop AND -# { -# And reg reg regm -# }; # def macroop OR # { # Or reg reg regm # }; -# def macroop XOR -# { -# Xor reg reg regm -# }; # def macroop NOT # { # Xor reg reg "0xFFFFFFFFFFFFFFFFULL" diff --git a/src/arch/x86/isa/macroop.isa b/src/arch/x86/isa/macroop.isa index 2d928d7c9..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,30 +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; - uint64_t immediate; - uint64_t displacement; - int addressSize; - int dataSize; - - EmulEnv(X86ISA::RegIndex _reg, X86ISA::RegIndex _regm, - uint64_t _immediate, uint64_t _displacement, - int _addressSize, int _dataSize) : - reg(_reg), regm(_regm), - immediate(_immediate), displacement(_displacement), - addressSize(_addressSize), dataSize(_dataSize) - {;} - }; -}}; - let {{ class EmulEnv(object): def __init__(self): @@ -211,17 +196,17 @@ 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" + self.doModRM = False + 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: @@ -235,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/microasm.isa b/src/arch/x86/isa/microasm.isa index fde430691..50addb33f 100644 --- a/src/arch/x86/isa/microasm.isa +++ b/src/arch/x86/isa/microasm.isa @@ -68,7 +68,7 @@ let {{ import sys sys.path[0:0] = ["src/arch/x86/isa/"] from insts import microcode - print microcode + # print microcode from micro_asm import MicroAssembler, Rom_Macroop, Rom mainRom = Rom('main ROM') assembler = MicroAssembler(X86Macroop, microopClasses, mainRom, Rom_Macroop) diff --git a/src/arch/x86/isa/microops/ldstop.isa b/src/arch/x86/isa/microops/ldstop.isa index 7e164fa82..fbff899a0 100644 --- a/src/arch/x86/isa/microops/ldstop.isa +++ b/src/arch/x86/isa/microops/ldstop.isa @@ -59,8 +59,11 @@ // ////////////////////////////////////////////////////////////////////////// -def template MicroLdStOpDeclare {{ - class %(class_name)s : public X86MicroopBase +output header {{ + /** + * Base class for load and store ops + */ + class LdStOp : public X86MicroopBase { protected: const uint8_t scale; @@ -71,6 +74,76 @@ 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(); + } +}}; + +// 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: @@ -93,6 +166,181 @@ def template MicroLdStOpDeclare {{ }; }}; +// Load templates + +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: + %(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 + + %(InitiateAccDeclare)s + + %(CompleteAccDeclare)s + }; +}}; + def template MicroLdStOpConstructor {{ inline void %(class_name)s::buildMe() @@ -107,11 +355,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 +367,120 @@ 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, 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/microops/limmop.isa b/src/arch/x86/isa/microops/limmop.isa index c76c074b1..141d7523f 100644 --- a/src/arch/x86/isa/microops/limmop.isa +++ b/src/arch/x86/isa/microops/limmop.isa @@ -79,6 +79,9 @@ def template MicroLimmOpDeclare {{ const uint64_t imm; void buildMe(); + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + public: %(class_name)s(ExtMachInst _machInst, const char * instMnem, @@ -93,6 +96,20 @@ def template MicroLimmOpDeclare {{ }; }}; +def template MicroLimmOpDisassembly {{ + std::string %(class_name)s::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + + printMnemonic(response, instMnem, mnemonic); + printReg(response, dest); + response << ", "; + ccprintf(response, "%#x", imm); + return response.str(); + } +}}; + def template MicroLimmOpConstructor {{ inline void %(class_name)s::buildMe() @@ -148,5 +165,6 @@ let {{ {"code" : "DestReg = imm;"}) header_output += MicroLimmOpDeclare.subst(iop) decoder_output += MicroLimmOpConstructor.subst(iop) + decoder_output += MicroLimmOpDisassembly.subst(iop) exec_output += MicroLimmOpExecute.subst(iop) }}; diff --git a/src/arch/x86/isa/microops/regop.isa b/src/arch/x86/isa/microops/regop.isa index a99194c5e..7c5b6df01 100644 --- a/src/arch/x86/isa/microops/regop.isa +++ b/src/arch/x86/isa/microops/regop.isa @@ -59,6 +59,100 @@ // ////////////////////////////////////////////////////////////////////////// +output header {{ + /** + * Base classes for RegOps which provides a generateDisassembly method. + */ + class RegOp : public X86MicroopBase + { + protected: + const RegIndex src1; + const RegIndex src2; + const RegIndex dest; + const bool setStatus; + const uint8_t dataSize; + const uint8_t ext; + + // Constructor + RegOp(ExtMachInst _machInst, + const char *mnem, const char *_instMnem, + bool isMicro, bool isDelayed, + bool isFirst, bool isLast, + RegIndex _src1, RegIndex _src2, RegIndex _dest, + bool _setStatus, uint8_t _dataSize, uint8_t _ext, + OpClass __opClass) : + X86MicroopBase(_machInst, mnem, _instMnem, + isMicro, isDelayed, isFirst, isLast, + __opClass), + src1(_src1), src2(_src2), dest(_dest), + setStatus(_setStatus), dataSize(_dataSize), ext(_ext) + { + } + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + }; + + class RegOpImm : public X86MicroopBase + { + protected: + const RegIndex src1; + const uint8_t imm8; + const RegIndex dest; + const bool setStatus; + const uint8_t dataSize; + const uint8_t ext; + + // Constructor + RegOpImm(ExtMachInst _machInst, + const char * mnem, const char *_instMnem, + bool isMicro, bool isDelayed, + bool isFirst, bool isLast, + RegIndex _src1, uint8_t _imm8, RegIndex _dest, + bool _setStatus, uint8_t _dataSize, uint8_t _ext, + OpClass __opClass) : + X86MicroopBase(_machInst, mnem, _instMnem, + isMicro, isDelayed, isFirst, isLast, + __opClass), + src1(_src1), imm8(_imm8), dest(_dest), + setStatus(_setStatus), dataSize(_dataSize), ext(_ext) + { + } + + std::string generateDisassembly(Addr pc, + const SymbolTable *symtab) const; + }; +}}; + +output decoder {{ + std::string RegOp::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + + printMnemonic(response, instMnem, mnemonic); + printReg(response, dest); + response << ", "; + printReg(response, src1); + response << ", "; + printReg(response, src2); + return response.str(); + } + + std::string RegOpImm::generateDisassembly(Addr pc, + const SymbolTable *symtab) const + { + std::stringstream response; + + printMnemonic(response, instMnem, mnemonic); + printReg(response, dest); + response << ", "; + printReg(response, src1); + ccprintf(response, ", %#x", imm8); + return response.str(); + } +}}; + def template MicroRegOpExecute {{ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const @@ -101,12 +195,6 @@ def template MicroRegOpDeclare {{ class %(class_name)s : public %(base_class)s { protected: - const RegIndex src1; - const RegIndex src2; - const RegIndex dest; - const bool setStatus; - const uint8_t dataSize; - const uint8_t ext; void buildMe(); public: @@ -130,12 +218,6 @@ def template MicroRegOpImmDeclare {{ class %(class_name)sImm : public %(base_class)s { protected: - const RegIndex src1; - const uint8_t imm8; - const RegIndex dest; - const bool setStatus; - const uint8_t dataSize; - const uint8_t ext; void buildMe(); public: @@ -166,9 +248,9 @@ def template MicroRegOpConstructor {{ RegIndex _src1, RegIndex _src2, RegIndex _dest, bool _setStatus, uint8_t _dataSize, uint8_t _ext) : %(base_class)s(machInst, "%(mnemonic)s", instMnem, - false, false, false, false, %(op_class)s), - src1(_src1), src2(_src2), dest(_dest), - setStatus(_setStatus), dataSize(_dataSize), ext(_ext) + false, false, false, false, + _src1, _src2, _dest, _setStatus, _dataSize, _ext, + %(op_class)s) { buildMe(); } @@ -179,9 +261,9 @@ def template MicroRegOpConstructor {{ RegIndex _src1, RegIndex _src2, RegIndex _dest, bool _setStatus, uint8_t _dataSize, uint8_t _ext) : %(base_class)s(machInst, "%(mnemonic)s", instMnem, - isMicro, isDelayed, isFirst, isLast, %(op_class)s), - src1(_src1), src2(_src2), dest(_dest), - setStatus(_setStatus), dataSize(_dataSize), ext(_ext) + isMicro, isDelayed, isFirst, isLast, + _src1, _src2, _dest, _setStatus, _dataSize, _ext, + %(op_class)s) { buildMe(); } @@ -199,9 +281,9 @@ def template MicroRegOpImmConstructor {{ RegIndex _src1, uint8_t _imm8, RegIndex _dest, bool _setStatus, uint8_t _dataSize, uint8_t _ext) : %(base_class)s(machInst, "%(mnemonic)s", instMnem, - false, false, false, false, %(op_class)s), - src1(_src1), imm8(_imm8), dest(_dest), - setStatus(_setStatus), dataSize(_dataSize), ext(_ext) + false, false, false, false, + _src1, _imm8, _dest, _setStatus, _dataSize, _ext, + %(op_class)s) { buildMe(); } @@ -212,9 +294,9 @@ def template MicroRegOpImmConstructor {{ RegIndex _src1, uint8_t _imm8, RegIndex _dest, bool _setStatus, uint8_t _dataSize, uint8_t _ext) : %(base_class)s(machInst, "%(mnemonic)s", instMnem, - isMicro, isDelayed, isFirst, isLast, %(op_class)s), - src1(_src1), imm8(_imm8), dest(_dest), - setStatus(_setStatus), dataSize(_dataSize), ext(_ext) + isMicro, isDelayed, isFirst, isLast, + _src1, _imm8, _dest, _setStatus, _dataSize, _ext, + %(op_class)s) { buildMe(); } @@ -227,7 +309,7 @@ let {{ self.src1 = src1 self.src2 = src2 self.setStatus = False - self.dataSize = 1 + self.dataSize = "env.dataSize" self.ext = 0 def getAllocator(self, *microFlags): @@ -249,7 +331,7 @@ let {{ self.src1 = src1 self.imm8 = imm8 self.setStatus = False - self.dataSize = 1 + self.dataSize = "env.dataSize" self.ext = 0 def getAllocator(self, *microFlags): @@ -274,11 +356,20 @@ let {{ decoder_output = "" exec_output = "" - def defineMicroRegOp(mnemonic, code): + def setUpMicroRegOp(name, Name, base, code, child): global header_output global decoder_output global exec_output global microopClasses + + iop = InstObjParams(name, Name, base, {"code" : code}) + header_output += MicroRegOpDeclare.subst(iop) + decoder_output += MicroRegOpConstructor.subst(iop) + exec_output += MicroRegOpExecute.subst(iop) + + microopClasses[name] = child + + def defineMicroRegOp(mnemonic, code): Name = mnemonic name = mnemonic.lower() @@ -289,34 +380,23 @@ let {{ regCode = matcher.sub("SrcReg2", code) immCode = matcher.sub("imm8", code) - # Build up the all register version of this micro op - iop = InstObjParams(name, Name, 'X86MicroopBase', {"code" : regCode}) - header_output += MicroRegOpDeclare.subst(iop) - decoder_output += MicroRegOpConstructor.subst(iop) - exec_output += MicroRegOpExecute.subst(iop) - + # Build the all register version of this micro op class RegOpChild(RegOp): def __init__(self, dest, src1, src2): super(RegOpChild, self).__init__(dest, src1, src2) self.className = Name self.mnemonic = name - microopClasses[name] = RegOpChild - - # Build up the immediate version of this micro op - iop = InstObjParams(name + "i", Name, - 'X86MicroopBase', {"code" : immCode}) - header_output += MicroRegOpImmDeclare.subst(iop) - decoder_output += MicroRegOpImmConstructor.subst(iop) - exec_output += MicroRegOpImmExecute.subst(iop) + setUpMicroRegOp(name, Name, "RegOp", regCode, RegOpChild); - class RegOpImmChild(RegOpImm): - def __init__(self, dest, src1, imm): - super(RegOpImmChild, self).__init__(dest, src1, imm) + # Build the immediate version of this micro op + class RegOpChildImm(RegOpImm): + def __init__(self, dest, src1, src2): + super(RegOpChildImm, self).__init__(dest, src1, src2) self.className = Name + "Imm" self.mnemonic = name + "i" - microopClasses[name + "i"] = RegOpImmChild + setUpMicroRegOp(name + "i", Name + "Imm", "RegOpImm", immCode, RegOpChildImm); defineMicroRegOp('Add', 'DestReg = merge(DestReg, SrcReg1 + op2, dataSize)') #Needs to set OF,CF,SF defineMicroRegOp('Or', 'DestReg = merge(DestReg, SrcReg1 | op2, dataSize)') @@ -328,4 +408,68 @@ let {{ defineMicroRegOp('Cmp', 'DestReg = merge(DestReg, DestReg - op2, dataSize)') #Needs to set OF,CF,SF and not DestReg defineMicroRegOp('Mov', 'DestReg = merge(SrcReg1, op2, dataSize)') + # This has it's own function because Wr ops have implicit destinations + def defineMicroRegOpWr(mnemonic, code): + Name = mnemonic + name = mnemonic.lower() + + # Find op2 in each of the instruction definitions. Create two versions + # of the code, one with an integer operand, and one with an immediate + # operand. + matcher = re.compile("op2(?P<typeQual>\\.\\w+)?") + regCode = matcher.sub("SrcReg2", code) + immCode = matcher.sub("imm8", code) + + # Build the all register version of this micro op + class RegOpChild(RegOp): + def __init__(self, src1, src2): + super(RegOpChild, self).__init__("NUM_INTREGS", src1, src2) + self.className = Name + self.mnemonic = name + + setUpMicroRegOp(name, Name, "RegOp", regCode, RegOpChild); + + # Build the immediate version of this micro op + class RegOpChildImm(RegOpImm): + def __init__(self, src1, src2): + super(RegOpChildImm, self).__init__("NUM_INTREGS", src1, src2) + self.className = Name + "Imm" + self.mnemonic = name + "i" + + setUpMicroRegOp(name + "i", Name + "Imm", "RegOpImm", immCode, RegOpChildImm); + + defineMicroRegOpWr('Wrip', 'RIP = SrcReg1 + op2') + + # This has it's own function because Rd ops don't always have two parameters + def defineMicroRegOpRd(mnemonic, code): + Name = mnemonic + name = mnemonic.lower() + + class RegOpChild(RegOp): + def __init__(self, dest, src1 = "NUM_INTREGS"): + super(RegOpChild, self).__init__(dest, src1, "NUM_INTREGS") + self.className = Name + self.mnemonic = name + + setUpMicroRegOp(name, Name, "RegOp", code, RegOpChild); + + defineMicroRegOpRd('Rdip', 'DestReg = RIP') + + def defineMicroRegOpImm(mnemonic, code): + Name = mnemonic + name = mnemonic.lower() + + class RegOpChild(RegOpImm): + def __init__(self, dest, src1, src2): + super(RegOpChild, self).__init__(dest, src1, src2) + self.className = Name + self.mnemonic = name + + setUpMicroRegOp(name, Name, "RegOpImm", code, RegOpChild); + + defineMicroRegOpImm('Sext', ''' + IntReg val = SrcReg1; + int sign_bit = bits(val, imm8-1, imm8-1); + val = sign_bit ? (val | ~mask(imm8)) : val; + DestReg = merge(DestReg, val, dataSize);''') }}; diff --git a/src/arch/x86/isa/microops/specop.isa b/src/arch/x86/isa/microops/specop.isa index 96fdf1c5e..b56223390 100644 --- a/src/arch/x86/isa/microops/specop.isa +++ b/src/arch/x86/isa/microops/specop.isa @@ -59,67 +59,63 @@ // ////////////////////////////////////////////////////////////////////////// -def template MicroFaultExecute {{ - Fault %(class_name)s ::execute(%(CPU_exec_context)s *xc, - Trace::InstRecord *traceData) const - { - //Return the fault we were constructed with - return fault; - } -}}; - -def template MicroFaultDeclare {{ - class %(class_name)s : public X86MicroopBase +output header {{ + class MicroFault : public X86MicroopBase { protected: Fault fault; void buildMe(); public: - %(class_name)s(ExtMachInst _machInst, - const char * instMnem, + MicroFault(ExtMachInst _machInst, const char * instMnem, bool isMicro, bool isDelayed, bool isFirst, bool isLast, Fault _fault); - %(class_name)s(ExtMachInst _machInst, - const char * instMnem, + MicroFault(ExtMachInst _machInst, const char * instMnem, Fault _fault); %(BasicExecDeclare)s }; }}; -def template MicroFaultConstructor {{ - - inline void %(class_name)s::buildMe() - { - %(constructor)s; - } +output decoder {{ + Fault MicroFault::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) const + { + //Return the fault we were constructed with + return fault; + } +}}; - inline %(class_name)s::%(class_name)s( +output decoder {{ + inline MicroFault::MicroFault( ExtMachInst machInst, const char * instMnem, Fault _fault) : - %(base_class)s(machInst, "%(mnemonic)s", instMnem, - false, false, false, false, %(op_class)s), fault(_fault) + X86MicroopBase(machInst, "fault", instMnem, + false, false, false, false, No_OpClass), fault(_fault) { - buildMe(); } - inline %(class_name)s::%(class_name)s( + inline MicroFault::MicroFault( ExtMachInst machInst, const char * instMnem, bool isMicro, bool isDelayed, bool isFirst, bool isLast, Fault _fault) : - %(base_class)s(machInst, "%(mnemonic)s", instMnem, - isMicro, isDelayed, isFirst, isLast, %(op_class)s), + X86MicroopBase(machInst, "fault", instMnem, + isMicro, isDelayed, isFirst, isLast, No_OpClass), fault(_fault) { - buildMe(); } }}; let {{ - # This microop takes in a single parameter, a fault to return. - iop = InstObjParams("fault", "GenFault", 'X86MicroopBase', {"code" : ""}) - header_output += MicroFaultDeclare.subst(iop) - decoder_output += MicroFaultConstructor.subst(iop) - exec_output += MicroFaultExecute.subst(iop) + class Fault(X86Microop): + def __init__(self, fault): + self.fault = fault + + def getAllocator(self, *microFlags): + allocator = '''new MicroFault(machInst, mnemonic + %(flags)s, %(fault)s)''' % { + "flags" : self.microFlagsText(microFlags), + "fault" : self.fault} + return allocator + microopClasses["fault"] = Fault }}; diff --git a/src/arch/x86/isa/operands.isa b/src/arch/x86/isa/operands.isa index 1564c23e9..b2ac17d66 100644 --- a/src/arch/x86/isa/operands.isa +++ b/src/arch/x86/isa/operands.isa @@ -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) }}; diff --git a/src/arch/x86/isa/specialize.isa b/src/arch/x86/isa/specialize.isa index faf863351..3183f32ba 100644 --- a/src/arch/x86/isa/specialize.isa +++ b/src/arch/x86/isa/specialize.isa @@ -64,18 +64,18 @@ let {{ # This code builds up a decode block which decodes based on switchval. # vals is a dict which matches case values with what should be decoded to. - # builder is called on the exploded contents of "vals" values to generate - # whatever code should be used. - def doSplitDecode(builder, switchVal, vals, default = None): + # Each element of the dict is a list containing a function and then the + # arguments to pass to it. + def doSplitDecode(switchVal, vals, default = None): blocks = OutputBlocks() blocks.decode_block = 'switch(%s) {\n' % switchVal for (val, todo) in vals.items(): - new_blocks = builder(*todo) + new_blocks = todo[0](*todo[1:]) new_blocks.decode_block = \ '\tcase %s: %s\n' % (val, new_blocks.decode_block) blocks.append(new_blocks) if default: - new_blocks = builder(*default) + new_blocks = default[0](*default[1:]) new_blocks.decode_block = \ '\tdefault: %s\n' % new_blocks.decode_block blocks.append(new_blocks) @@ -84,8 +84,29 @@ let {{ }}; let {{ + def doRipRelativeDecode(Name, opTypes, env): + # print "RIPing %s with opTypes %s" % (Name, opTypes) + normBlocks = specializeInst(Name + "_M", copy.copy(opTypes), copy.copy(env)) + ripBlocks = specializeInst(Name + "_P", copy.copy(opTypes), copy.copy(env)) + + blocks = OutputBlocks() + blocks.append(normBlocks) + blocks.append(ripBlocks) + + blocks.decode_block = ''' + if(machInst.modRM.mod == 0 && + machInst.modRM.rm == 5 && + machInst.mode.submode == SixtyFourBitMode) + { %s } + else + { %s }''' % \ + (ripBlocks.decode_block, normBlocks.decode_block) + return blocks +}}; + +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 +126,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 +143,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,40 +157,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" - return doSplitDecode(specializeInst, "MODRM_MOD", - {"3" : (regName, regTypes, regEnv)}, - (memName, memTypes, memEnv)) + memEnv.doModRM = True + return doSplitDecode("MODRM_MOD", + {"3" : (specializeInst, Name + "_R", copy.copy(opTypes), regEnv)}, + (doRipRelativeDecode, Name, copy.copy(opTypes), memEnv)) elif opType.tag in ("I", "J"): # Immediates - print "IMMEDIATE" 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/isa_traits.hh b/src/arch/x86/isa_traits.hh index 5a625f741..4c02ee35e 100644 --- a/src/arch/x86/isa_traits.hh +++ b/src/arch/x86/isa_traits.hh @@ -81,8 +81,8 @@ namespace X86ISA // These enumerate all the registers for dependence tracking. enum DependenceTags { - //The number of microcode registers needs to be added to this - FP_Base_DepTag = 16, + //There are 16 microcode registers at the moment + FP_Base_DepTag = 32, Ctrl_Base_DepTag = FP_Base_DepTag + //mmx/x87 registers @@ -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; diff --git a/src/arch/x86/predecoder.cc b/src/arch/x86/predecoder.cc index 3ed18aeb2..49f76699b 100644 --- a/src/arch/x86/predecoder.cc +++ b/src/arch/x86/predecoder.cc @@ -264,31 +264,30 @@ 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.rm == 5) + || 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 +300,7 @@ namespace X86ISA } //The ModRM byte is consumed no matter what consumeByte(); + emi.modRM = modRM; return nextState; } diff --git a/src/arch/x86/predecoder.hh b/src/arch/x86/predecoder.hh index 3c858f061..f34b66364 100644 --- a/src/arch/x86/predecoder.hh +++ b/src/arch/x86/predecoder.hh @@ -195,12 +195,12 @@ namespace X86ISA //Use this to give data to the predecoder. This should be used //when there is control flow. - void moreBytes(Addr pc, Addr fetchPC, Addr off, MachInst data) + void moreBytes(Addr pc, Addr fetchPC, MachInst data) { + DPRINTF(Predecoder, "Getting more bytes.\n"); basePC = fetchPC; - offset = off; + offset = (fetchPC >= pc) ? 0 : pc - fetchPC; fetchChunk = data; - assert(off < sizeof(MachInst)); outOfBytes = false; process(); } diff --git a/src/arch/x86/process.cc b/src/arch/x86/process.cc index af7494598..7deb54945 100644 --- a/src/arch/x86/process.cc +++ b/src/arch/x86/process.cc @@ -268,7 +268,6 @@ X86LiveProcess::argsInit(int intSize, int pageSize) int argv_array_size = intSize * (argv.size() + 1); int argc_size = intSize; - int window_save_size = intSize * 16; int space_needed = mysterious_size + @@ -276,8 +275,7 @@ X86LiveProcess::argsInit(int intSize, int pageSize) aux_array_size + envp_array_size + argv_array_size + - argc_size + - window_save_size; + argc_size; stack_min = stack_base - space_needed; stack_min &= alignmentMask; @@ -296,10 +294,6 @@ X86LiveProcess::argsInit(int intSize, int pageSize) Addr envp_array_base = auxv_array_base - envp_array_size; Addr argv_array_base = envp_array_base - argv_array_size; Addr argc_base = argv_array_base - argc_size; -#ifndef NDEBUG - // only used in DPRINTF - Addr window_save_base = argc_base - window_save_size; -#endif DPRINTF(X86, "The addresses of items on the initial stack:\n"); DPRINTF(X86, "0x%x - file name\n", file_name_base); @@ -309,7 +303,6 @@ X86LiveProcess::argsInit(int intSize, int pageSize) DPRINTF(X86, "0x%x - envp array\n", envp_array_base); DPRINTF(X86, "0x%x - argv array\n", argv_array_base); DPRINTF(X86, "0x%x - argc \n", argc_base); - DPRINTF(X86, "0x%x - window save\n", window_save_base); DPRINTF(X86, "0x%x - stack min\n", stack_min); // write contents to stack diff --git a/src/arch/x86/types.hh b/src/arch/x86/types.hh index fc9f1d82b..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; @@ -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; } diff --git a/src/arch/x86/utility.hh b/src/arch/x86/utility.hh index ed401a519..3f3f1cca3 100644 --- a/src/arch/x86/utility.hh +++ b/src/arch/x86/utility.hh @@ -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; }; }; } |