Make the predecoder an object with it's own switched header file. Start adding predecoding functionality to x86.

src/arch/SConscript:
src/arch/alpha/utility.hh:
src/arch/mips/utility.hh:
src/arch/sparc/utility.hh:
src/cpu/base.hh:
src/cpu/o3/fetch.hh:
src/cpu/o3/fetch_impl.hh:
src/cpu/simple/atomic.cc:
src/cpu/simple/base.cc:
src/cpu/simple/base.hh:
src/cpu/static_inst.hh:
src/arch/alpha/predecoder.hh:
src/arch/mips/predecoder.hh:
src/arch/sparc/predecoder.hh:
    Make the predecoder an object with it's own switched header file.

--HG--
extra : convert_revision : 77206e29089130e86b97164c30022a062699ba86
This commit is contained in:
Gabe Black 2007-03-15 02:47:42 +00:00
parent ce18d900a1
commit a2b56088fb
20 changed files with 1004 additions and 91 deletions

View file

@ -55,6 +55,7 @@ isa_switch_hdrs = Split('''
locked_mem.hh
mmaped_ipr.hh
process.hh
predecoder.hh
regfile.hh
remote_gdb.hh
stacktrace.hh

View file

@ -0,0 +1,107 @@
/*
* Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 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 holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* 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_ALPHA_PREDECODER_HH__
#define __ARCH_ALPHA_PREDECODER_HH__
#include "arch/alpha/types.hh"
#include "base/misc.hh"
#include "sim/host.hh"
class ThreadContext;
namespace AlphaISA
{
class Predecoder
{
protected:
ThreadContext * tc;
//The pc of the current instruction
Addr fetchPC;
//The extended machine instruction being generated
ExtMachInst ext_inst;
public:
Predecoder(ThreadContext * _tc) : tc(_tc)
{}
ThreadContext * getTC()
{
return tc;
}
void setTC(ThreadContext * _tc)
{
tc = _tc;
}
void process()
{
}
//Use this to give data to the predecoder. This should be used
//when there is control flow.
void moreBytes(Addr pc, Addr off, MachInst inst)
{
fetchPC = pc;
assert(off == 0);
ext_inst = inst;
#if FULL_SYSTEM
if (pc && 0x1)
ext_inst|=(static_cast<ExtMachInst>(pc & 0x1) << 32);
#endif
}
//Use this to give data to the predecoder. This should be used
//when instructions are executed in order.
void moreBytes(MachInst machInst)
{
moreBytes(fetchPC + sizeof(machInst), 0, machInst);
}
bool needMoreBytes()
{
return true;
}
bool extMachInstReady()
{
return true;
}
//This returns a constant reference to the ExtMachInst to avoid a copy
const ExtMachInst & getExtMachInst()
{
return ext_inst;
}
};
};
#endif // __ARCH_ALPHA_PREDECODER_HH__

View file

@ -48,21 +48,6 @@ namespace AlphaISA
return (tc->readMiscRegNoEffect(AlphaISA::IPR_DTB_CM) & 0x18) != 0;
}
enum PredecodeResult {
MoreBytes = 1,
ExtMIReady = 2
};
static inline unsigned int
predecode(ExtMachInst & ext_inst, Addr pc, MachInst inst, ThreadContext *) {
ext_inst = inst;
#if FULL_SYSTEM
if (pc && 0x1)
ext_inst|=(static_cast<ExtMachInst>(pc & 0x1) << 32);
#endif
return MoreBytes | ExtMIReady;
}
inline bool isCallerSaveIntegerRegister(unsigned int reg) {
panic("register classification not implemented");
return (reg >= 1 && reg <= 8 || reg >= 22 && reg <= 25 || reg == 27);

100
src/arch/mips/predecoder.hh Normal file
View file

@ -0,0 +1,100 @@
/*
* Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 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 holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* 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_MIPS_PREDECODER_HH__
#define __ARCH_MIPS_PREDECODER_HH__
#include "arch/mips/types.hh"
#include "base/misc.hh"
#include "sim/host.hh"
class ThreadContext;
namespace MipsISA
{
class Predecoder
{
protected:
ThreadContext * tc;
//The extended machine instruction being generated
ExtMachInst emi;
public:
Predecoder(ThreadContext * _tc) : tc(_tc)
{}
ThreadContext * getTC()
{
return tc;
}
void setTC(ThreadContext * _tc)
{
tc = _tc;
}
void process()
{
}
//Use this to give data to the predecoder. This should be used
//when there is control flow.
void moreBytes(Addr currPC, Addr off, MachInst inst)
{
assert(off == 0);
emi = inst;
}
//Use this to give data to the predecoder. This should be used
//when instructions are executed in order.
void moreBytes(MachInst machInst)
{
moreBytes(0, 0, machInst);
}
bool needMoreBytes()
{
return true;
}
bool extMachInstReady()
{
return true;
}
//This returns a constant reference to the ExtMachInst to avoid a copy
const ExtMachInst & getExtMachInst()
{
return emi;
}
};
};
#endif // __ARCH_MIPS_PREDECODER_HH__

View file

@ -87,17 +87,6 @@ namespace MipsISA {
panic("makeRegisterCopy not implemented");
return 0;
}
enum PredecodeResult {
MoreBytes = 1,
ExtMIReady = 2
};
static inline unsigned int
predecode(ExtMachInst &emi, Addr, MachInst inst, ThreadContext *) {
emi = inst;
return MoreBytes | ExtMIReady;
}
};

View file

@ -0,0 +1,112 @@
/*
* Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 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 holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* 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_SPARC_PREDECODER_HH__
#define __ARCH_SPARC_PREDECODER_HH__
#include "arch/sparc/types.hh"
#include "base/misc.hh"
#include "sim/host.hh"
class ThreadContext;
namespace SparcISA
{
class Predecoder
{
protected:
ThreadContext * tc;
//The extended machine instruction being generated
ExtMachInst emi;
public:
Predecoder(ThreadContext * _tc) : tc(_tc)
{}
ThreadContext * getTC()
{
return tc;
}
void setTC(ThreadContext * _tc)
{
tc = _tc;
}
void process()
{
}
//Use this to give data to the predecoder. This should be used
//when there is control flow.
void moreBytes(Addr currPC, Addr off, 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
//slightly redundant, but it removes the need to put a condition
//into all the execute functions
if(inst & (1 << 13))
emi |= (static_cast<ExtMachInst>(
tc->readMiscRegNoEffect(MISCREG_ASI))
<< (sizeof(MachInst) * 8));
else
emi |= (static_cast<ExtMachInst>(bits(inst, 12, 5))
<< (sizeof(MachInst) * 8));
}
//Use this to give data to the predecoder. This should be used
//when instructions are executed in order.
void moreBytes(MachInst machInst)
{
moreBytes(0, 0, machInst);
}
bool needMoreBytes()
{
return true;
}
bool extMachInstReady()
{
return true;
}
//This returns a constant reference to the ExtMachInst to avoid a copy
const ExtMachInst & getExtMachInst()
{
return emi;
}
};
};
#endif // __ARCH_SPARC_PREDECODER_HH__

View file

@ -48,28 +48,6 @@ namespace SparcISA
tc->readMiscRegNoEffect(MISCREG_HPSTATE & (1 << 2)));
}
enum PredecodeResult {
MoreBytes = 1,
ExtMIReady = 2
};
inline unsigned int
predecode(ExtMachInst &emi, Addr currPC, MachInst inst,
ThreadContext * xc) {
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
//slightly redundant, but it removes the need to put a condition
//into all the execute functions
if(inst & (1 << 13))
emi |= (static_cast<ExtMachInst>(xc->readMiscRegNoEffect(MISCREG_ASI))
<< (sizeof(MachInst) * 8));
else
emi |= (static_cast<ExtMachInst>(bits(inst, 12, 5))
<< (sizeof(MachInst) * 8));
return MoreBytes | ExtMIReady;
}
inline bool isCallerSaveIntegerRegister(unsigned int reg) {
panic("register classification not implemented");
return false;

View file

@ -103,6 +103,7 @@ base_sources = Split('''
miscregfile.cc
regfile.cc
remote_gdb.cc
predecoder_tables.cc
''')
# Full-system sources

View file

@ -120,7 +120,8 @@ output exec {{
Fault Unknown::execute(%(CPU_exec_context)s *xc,
Trace::InstRecord *traceData) const
{
panic("No instructions are implemented for X86!\n");
warn("No instructions are implemented for X86!\n");
return NoFault;
}
}};

412
src/arch/x86/predecoder.hh Normal file
View file

@ -0,0 +1,412 @@
/*
* 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_PREDECODER_HH__
#define __ARCH_X86_PREDECODER_HH__
#include "arch/x86/types.hh"
#include "base/bitfield.hh"
#include "base/misc.hh"
#include "sim/host.hh"
class ThreadContext;
namespace X86ISA
{
class Predecoder
{
private:
static const uint8_t Prefixes[256];
static const uint8_t UsesModRM[2][256];
protected:
ThreadContext * tc;
//The bytes to be predecoded
MachInst fetchChunk;
//The pc of the start of fetchChunk
Addr basePC;
//The offset into fetchChunk of current processing
int offset;
//The extended machine instruction being generated
ExtMachInst emi;
//State machine state
protected:
//Whether or not we're out of bytes
bool outOfBytes;
//Whether we've completed generating an ExtMachInst
bool emiIsReady;
//The size of the displacement value
int displacementSize;
int displacementCollected;
//The size of the immediate value
int immediateSize;
int immediateCollected;
//These are local to some of the states. I need to turn the states
//into inline functions to clean things up a bit.
int toGet;
int remaining;
MachInst partialDisp;
enum State {
Prefix,
Opcode,
ModRM,
SIB,
Displacement,
Immediate
};
State state;
public:
Predecoder(ThreadContext * _tc) :
tc(_tc), basePC(0), offset(0),
outOfBytes(true), emiIsReady(false),
state(Prefix)
{}
ThreadContext * getTC()
{
return tc;
}
void setTC(ThreadContext * _tc)
{
tc = _tc;
}
void process()
{
warn("About to process some bytes\n");
assert(!outOfBytes);
assert(!emiIsReady);
while(!emiIsReady && !outOfBytes)
{
uint8_t nextByte = (fetchChunk >> (offset * 8)) & 0xff;
switch(state)
{
case Prefix:
uint8_t prefix = Prefixes[nextByte];
switch(prefix)
{
//Operand size override prefixes
case OperandSizeOverride:
warn("Found operand size override prefix!\n");
offset++;
break;
case AddressSizeOverride:
warn("Found address size override prefix!\n");
offset++;
break;
//Segment override prefixes
case CSOverride:
warn("Found cs segment override!\n");
offset++;
break;
case DSOverride:
warn("Found ds segment override!\n");
offset++;
break;
case ESOverride:
warn("Found es segment override!\n");
offset++;
break;
case FSOverride:
warn("Found fs segment override!\n");
offset++;
break;
case GSOverride:
warn("Found gs segment override!\n");
offset++;
break;
case SSOverride:
warn("Found ss segment override!\n");
offset++;
break;
case Lock:
warn("Found lock prefix!\n");
offset++;
break;
case Rep:
warn("Found rep prefix!\n");
offset++;
break;
case Repne:
warn("Found repne prefix!\n");
offset++;
break;
case Rex:
warn("Found Rex prefix %#x!\n", nextByte);
offset++;
break;
case 0:
emi.twoByteOpcode = false;
state = Opcode;
break;
default:
panic("Unrecognized prefix %#x\n", nextByte);
}
break;
case Opcode:
if(nextByte == 0xf0)
{
warn("Found two byte opcode!\n");
emi.twoByteOpcode = true;
}
else
{
warn("Found opcode %#x!\n", nextByte);
if (UsesModRM[emi.twoByteOpcode ? 1 : 0][nextByte]) {
state = ModRM;
} else if(0 /* uses immediate */) {
//Figure out how big the immediate should be
immediateCollected = 0;
emi.immediate = 0;
state = Immediate;
} else {
emiIsReady = true;
state = Prefix;
}
}
offset++;
break;
case ModRM:
warn("Found modrm byte %#x!\n", nextByte);
if (0) {//in 16 bit mode
//figure out 16 bit displacement size
if(nextByte & 0xC7 == 0x06 ||
nextByte & 0xC0 == 0x40)
displacementSize = 1;
else if(nextByte & 0xC7 == 0x80)
displacementSize = 2;
else
displacementSize = 0;
} else {
//figure out 32/64 bit displacement size
if(nextByte & 0xC7 == 0x06 ||
nextByte & 0xC0 == 0x40)
displacementSize = 4;
else if(nextByte & 0xC7 == 0x80)
displacementSize = 2;
else
displacementSize = 4;
}
//If there's an SIB, get that next.
//There is no SIB in 16 bit mode.
if(nextByte & 0x7 == 4 &&
nextByte & 0xC0 != 0xC0) {
// && in 32/64 bit mode)
state = SIB;
} else if(displacementSize) {
displacementCollected = 0;
emi.displacement = 0;
state = Displacement;
} else if(immediateSize) {
immediateCollected = 0;
emi.immediate = 0;
state = Immediate;
} else {
emiIsReady = true;
state = Prefix;
}
//The ModRM byte is consumed no matter what
offset++;
break;
case SIB:
warn("Found SIB byte %#x!\n", nextByte);
offset++;
if(displacementSize) {
displacementCollected = 0;
emi.displacement = 0;
state = Displacement;
} else if(immediateSize) {
immediateCollected = 0;
emi.immediate = 0;
state = Immediate;
} else {
emiIsReady = true;
state = Prefix;
}
break;
case Displacement:
//Gather up the displacement, or at least as much of it
//as we can get.
//Figure out how many bytes we still need to get for the
//displacement.
toGet = displacementSize - displacementCollected;
//Figure out how many bytes are left in our "buffer"
remaining = sizeof(MachInst) - offset;
//Get as much as we need, up to the amount available.
toGet = toGet > remaining ? remaining : toGet;
//Shift the bytes we want to be all the way to the right
partialDisp = fetchChunk >> offset;
//Mask off what we don't want
partialDisp &= mask(toGet * 8);
//Shift it over to overlay with our displacement.
partialDisp <<= displacementCollected;
//Put it into our displacement
emi.displacement |= partialDisp;
//Update how many bytes we've collected.
displacementCollected += toGet;
if(displacementSize == displacementCollected) {
//Sign extend the displacement
switch(displacementSize)
{
case 1:
emi.displacement = sext<8>(emi.displacement);
break;
case 2:
emi.displacement = sext<16>(emi.displacement);
break;
case 4:
emi.displacement = sext<32>(emi.displacement);
break;
default:
panic("Undefined displacement size!\n");
}
if(immediateSize) {
immediateCollected = 0;
emi.immediate = 0;
state = Immediate;
} else {
emiIsReady = true;
state = Prefix;
}
}
break;
case Immediate:
//Gather up the displacement, or at least as much of it
//as we can get
//Figure out how many bytes we still need to get for the
//immediate.
toGet = immediateSize - immediateCollected;
//Figure out how many bytes are left in our "buffer"
remaining = sizeof(MachInst) - offset;
//Get as much as we need, up to the amount available.
toGet = toGet > remaining ? remaining : toGet;
//Shift the bytes we want to be all the way to the right
partialDisp = fetchChunk >> offset;
//Mask off what we don't want
partialDisp &= mask(toGet * 8);
//Shift it over to overlay with our immediate.
partialDisp <<= displacementCollected;
//Put it into our immediate
emi.displacement |= partialDisp;
//Update how many bytes we've collected.
displacementCollected += toGet;
if(immediateSize == immediateCollected)
{
emiIsReady = true;
state = Prefix;
}
break;
default:
panic("Unrecognized state! %d\n", state);
}
if(offset == sizeof(MachInst))
outOfBytes = true;
}
}
//Use this to give data to the predecoder. This should be used
//when there is control flow.
void moreBytes(Addr currPC, Addr off, MachInst data)
{
basePC = currPC;
offset = off;
fetchChunk = data;
assert(off < sizeof(MachInst));
outOfBytes = false;
warn("About to call process.\n");
process();
}
//Use this to give data to the predecoder. This should be used
//when instructions are executed in order.
void moreBytes(MachInst machInst)
{
moreBytes(basePC + sizeof(machInst), 0, machInst);
}
bool needMoreBytes()
{
return outOfBytes;
}
bool extMachInstReady()
{
return emiIsReady;
}
//This returns a constant reference to the ExtMachInst to avoid a copy
const ExtMachInst & getExtMachInst()
{
assert(emiIsReady);
emiIsReady = false;
return emi;
}
};
};
#endif // __ARCH_X86_PREDECODER_HH__

View file

@ -0,0 +1,143 @@
/*
* 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/predecoder.hh"
#include "arch/x86/types.hh"
namespace X86ISA
{
const uint8_t CS = CSOverride;
const uint8_t DS = DSOverride;
const uint8_t ES = ESOverride;
const uint8_t FS = FSOverride;
const uint8_t GS = GSOverride;
const uint8_t SS = SSOverride;
const uint8_t OO = OperandSizeOverride;
const uint8_t AO = AddressSizeOverride;
const uint8_t LO = Lock;
const uint8_t RE = Rep;
const uint8_t RN = Repne;
const uint8_t RX = Rex;
//This table identifies whether a byte is a prefix, and if it is,
//which prefix it is.
const uint8_t Predecoder::Prefixes[256] =
{ //LSB
// MSB 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F
/* 0*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
/* 1*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
/* 2*/ 0 , 0 , 0 , 0 , 0 , 0 , ES, 0 , 0 , 0 , 0 , 0 , 0 , 0 , CS, 0,
/* 3*/ 0 , 0 , 0 , 0 , 0 , 0 , SS, 0 , 0 , 0 , 0 , 0 , 0 , 0 , DS, 0,
/* 4*/ RX, RX, RX, RX, RX, RX, RX, RX, RX, RX, RX, RX, RX, RX, RX, RX,
/* 5*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
/* 6*/ 0 , 0 , 0 , 0 , FS, GS, OO, AO, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
/* 7*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
/* 8*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
/* 9*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
/* A*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
/* B*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
/* C*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
/* D*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
/* E*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
/* F*/ LO, 0 , RN, RE, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
};
//This table identifies whether a particular opcode uses the ModRM byte
const uint8_t Predecoder::UsesModRM[2][256] =
{//For one byte instructions
{ //LSB
// MSB 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F
/* 0 */ 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0,
/* 1 */ 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0,
/* 2 */ 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0,
/* 3 */ 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0,
/* 4 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
/* 5 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
/* 6 */ 0 , 0 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 1 , 0 , 0 , 0 , 0,
/* 7 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
/* 8 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1,
/* 9 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
/* A */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
/* B */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
/* C */ 1 , 1 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
/* D */ 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1,
/* E */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
/* F */ 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1
},
//For two byte instructions
{ //LSB
// MSB 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F
/* 0 */ 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 1,
/* 1 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
/* 2 */ 1 , 1 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1,
/* 3 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
/* 4 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1,
/* 5 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1,
/* 6 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1,
/* 7 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1,
/* 8 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
/* 9 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1,
/* A */ 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1,
/* B */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1,
/* C */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
/* D */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1,
/* E */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1,
/* F */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0
}
};
}

View file

@ -59,18 +59,72 @@
#define __ARCH_X86_TYPES_HH__
#include <inttypes.h>
#include <iostream>
namespace X86ISA
{
//This really determines how many bytes are passed to the predecoder.
typedef uint64_t MachInst;
enum Prefixes {
NoOverride = 0,
CSOverride = 1,
DSOverride = 2,
ESOverride = 3,
FSOverride = 4,
GSOverride = 5,
SSOverride = 6,
//The Rex prefix obviously doesn't fit in with the above, but putting
//it here lets us save double the space the enums take up.
Rex = 7,
//There can be only one segment override, so they share the
//first 3 bits in the legacyPrefixes bitfield.
SegmentOverride = 0x7,
OperandSizeOverride = 8,
AddressSizeOverride = 16,
Lock = 32,
Rep = 64,
Repne = 128
};
//The intermediate structure the x86 predecoder returns.
struct ExtMachInst
{
//Empty for now...
public: //XXX These should be hidden in the future
uint8_t legacyPrefixes;
uint8_t rexPrefix;
bool twoByteOpcode;
uint8_t opcode;
uint64_t immediate;
uint64_t displacement;
public:
//These are to pacify the decoder for now. This will go away once
//it can handle non integer inputs, and in the mean time allow me to
//excercise the predecoder a little.
operator unsigned int()
{
return 0;
}
ExtMachInst(unsigned int)
{;}
ExtMachInst()
{;}
};
bool operator == (const ExtMachInst &emi1, const ExtMachInst &emi2)
inline static std::ostream &
operator << (std::ostream & os, const ExtMachInst & emi)
{
os << "{X86 ExtMachInst}";
return os;
}
inline static bool
operator == (const ExtMachInst &emi1, const ExtMachInst &emi2)
{
//Since this is empty, it's always equal
return true;

View file

@ -59,11 +59,22 @@
#define __ARCH_X86_UTILITY_HH__
#include "arch/x86/types.hh"
#include "base/hashmap.hh"
#include "base/misc.hh"
#include "sim/host.hh"
class ThreadContext;
namespace __hash_namespace {
template<>
struct hash<X86ISA::ExtMachInst> {
size_t operator()(const X86ISA::ExtMachInst &emi) const {
//Because these are all the same, return 0
return 0;
};
};
}
namespace X86ISA
{
static inline bool
@ -72,18 +83,6 @@ namespace X86ISA
return false;
}
PredecodeResult {
MoreBytes = 1,
ExtMIReady = 2
};
unsigned int
predecode(ExtMachInst &extMachInst, Addr currPC, MachInst machInst,
ThreadContext * xc) {
//Do something to fill up extMachInst...
return MoreBytes | ExtMIReady;
}
inline bool isCallerSaveIntegerRegister(unsigned int reg) {
panic("register classification not implemented");
return false;

View file

@ -34,11 +34,11 @@
#include <vector>
#include "arch/isa_traits.hh"
#include "base/statistics.hh"
#include "config/full_system.hh"
#include "sim/eventq.hh"
#include "mem/mem_object.hh"
#include "arch/isa_traits.hh"
#if FULL_SYSTEM
#include "arch/interrupts.hh"
@ -50,6 +50,11 @@ class ThreadContext;
class System;
class Port;
namespace TheISA
{
class Predecoder;
}
class CPUProgressEvent : public Event
{
protected:
@ -125,6 +130,7 @@ class BaseCPU : public MemObject
protected:
std::vector<ThreadContext *> threadContexts;
std::vector<TheISA::Predecoder *> predecoders;
public:

View file

@ -33,6 +33,7 @@
#define __CPU_O3_FETCH_HH__
#include "arch/utility.hh"
#include "arch/predecoder.hh"
#include "base/statistics.hh"
#include "base/timebuf.hh"
#include "cpu/pc_event.hh"
@ -338,6 +339,9 @@ class DefaultFetch
/** BPredUnit. */
BPredUnit branchPred;
/** Predecoder. */
TheISA::Predecoder predecoder;
/** Per-thread fetch PC. */
Addr PC[Impl::MaxThreads];

View file

@ -103,6 +103,7 @@ DefaultFetch<Impl>::IcachePort::recvRetry()
template<class Impl>
DefaultFetch<Impl>::DefaultFetch(Params *params)
: branchPred(params),
predecoder(NULL),
decodeToFetchDelay(params->decodeToFetchDelay),
renameToFetchDelay(params->renameToFetchDelay),
iewToFetchDelay(params->iewToFetchDelay),
@ -1117,9 +1118,10 @@ DefaultFetch<Impl>::fetch(bool &status_change)
inst = TheISA::gtoh(*reinterpret_cast<TheISA::MachInst *>
(&cacheData[tid][offset]));
//unsigned int result =
TheISA::predecode(ext_inst, fetch_PC, inst,
cpu->thread[tid]->getTC());
predecoder.setTC(cpu->thread[tid]->getTC());
predecoder.moreBytes(fetch_PC, 0, inst);
ext_inst = predecoder.getExtMachInst();
// Create a new DynInst from the instruction fetched.
DynInstPtr instruction = new DynInst(ext_inst,

View file

@ -500,17 +500,28 @@ AtomicSimpleCPU::tick()
Fault fault = setupFetchRequest(ifetch_req);
if (fault == NoFault) {
ifetch_pkt->reinitFromRequest();
Tick icache_latency = icachePort.sendAtomic(ifetch_pkt);
// ifetch_req is initialized to read the instruction directly
// into the CPU object's inst field.
Tick icache_latency = 0;
bool icache_access = false;
dcache_access = false; // assume no dcache access
//Fetch more instruction memory if necessary
if(predecoder.needMoreBytes())
{
icache_access = true;
ifetch_pkt->reinitFromRequest();
icache_latency = icachePort.sendAtomic(ifetch_pkt);
// ifetch_req is initialized to read the instruction directly
// into the CPU object's inst field.
}
preExecute();
fault = curStaticInst->execute(this, traceData);
postExecute();
if(curStaticInst)
{
fault = curStaticInst->execute(this, traceData);
postExecute();
}
// @todo remove me after debugging with legion done
if (curStaticInst && (!curStaticInst->isMicroOp() ||
@ -518,7 +529,8 @@ AtomicSimpleCPU::tick()
instCnt++;
if (simulate_stalls) {
Tick icache_stall = icache_latency - cycles(1);
Tick icache_stall =
icache_access ? icache_latency - cycles(1) : 0;
Tick dcache_stall =
dcache_access ? dcache_latency - cycles(1) : 0;
Tick stall_cycles = (icache_stall + dcache_stall) / cycles(1);
@ -529,8 +541,8 @@ AtomicSimpleCPU::tick()
}
}
advancePC(fault);
if(predecoder.needMoreBytes())
advancePC(fault);
}
if (_status != Idle)

View file

@ -70,7 +70,7 @@ using namespace std;
using namespace TheISA;
BaseSimpleCPU::BaseSimpleCPU(Params *p)
: BaseCPU(p), thread(NULL)
: BaseCPU(p), thread(NULL), predecoder(NULL)
{
#if FULL_SYSTEM
thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb);
@ -370,11 +370,16 @@ BaseSimpleCPU::preExecute()
StaticInstPtr instPtr = NULL;
//Predecode, ie bundle up an ExtMachInst
unsigned int result =
predecode(extMachInst, thread->readPC(), inst, thread->getTC());
//This should go away once the constructor can be set up properly
predecoder.setTC(thread->getTC());
//If more fetch data is needed, pass it in.
if(predecoder.needMoreBytes())
predecoder.moreBytes(thread->readPC(), 0, inst);
else
predecoder.process();
//If an instruction is ready, decode it
if (result & ExtMIReady)
instPtr = StaticInst::decode(extMachInst);
if (predecoder.extMachInstReady())
instPtr = StaticInst::decode(predecoder.getExtMachInst());
//If we decoded an instruction and it's microcoded, start pulling
//out micro ops
@ -446,9 +451,9 @@ BaseSimpleCPU::advancePC(Fault fault)
fault->invoke(tc);
thread->setMicroPC(0);
thread->setNextMicroPC(1);
} else {
} else if (predecoder.needMoreBytes()) {
//If we're at the last micro op for this instruction
if (curStaticInst->isLastMicroOp()) {
if (curStaticInst && curStaticInst->isLastMicroOp()) {
//We should be working with a macro op
assert(curMacroStaticInst);
//Close out this macro op, and clean up the
@ -467,13 +472,9 @@ BaseSimpleCPU::advancePC(Fault fault)
} else {
// go to the next instruction
thread->setPC(thread->readNextPC());
#if ISA_HAS_DELAY_SLOT
thread->setNextPC(thread->readNextNPC());
thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst));
assert(thread->readNextPC() != thread->readNextNPC());
#else
thread->setNextPC(thread->readNextPC() + sizeof(MachInst));
#endif
}
}

View file

@ -33,6 +33,7 @@
#ifndef __CPU_SIMPLE_BASE_HH__
#define __CPU_SIMPLE_BASE_HH__
#include "arch/predecoder.hh"
#include "base/statistics.hh"
#include "config/full_system.hh"
#include "cpu/base.hh"
@ -63,6 +64,10 @@ class Process;
class RemoteGDB;
class GDBListener;
namespace TheISA
{
class Predecoder;
}
class ThreadContext;
class Checkpoint;
@ -123,8 +128,8 @@ class BaseSimpleCPU : public BaseCPU
// current instruction
TheISA::MachInst inst;
// current extended machine instruction
TheISA::ExtMachInst extMachInst;
// The predecoder
TheISA::Predecoder predecoder;
// Static data storage
TheISA::LargestRead dataReg;

View file

@ -35,6 +35,7 @@
#include <string>
#include "arch/isa_traits.hh"
#include "arch/utility.hh"
#include "sim/faults.hh"
#include "base/bitfield.hh"
#include "base/hashmap.hh"