CPU: Merge the predecoder and decoder.

These classes are always used together, and merging them will give the ISAs
more flexibility in how they cache things and manage the process.

--HG--
rename : src/arch/x86/predecoder_tables.cc => src/arch/x86/decoder_tables.cc
This commit is contained in:
Gabe Black 2012-05-26 13:44:46 -07:00
parent eae1e97fb0
commit 0cba96ba6a
43 changed files with 1121 additions and 1548 deletions

View file

@ -54,7 +54,6 @@ isa_switch_hdrs = Split('''
mmapped_ipr.hh
mt.hh
process.hh
predecoder.hh
registers.hh
remote_gdb.hh
stacktrace.hh

View file

@ -34,12 +34,69 @@
#include "arch/types.hh"
#include "cpu/decode_cache.hh"
#include "cpu/static_inst_fwd.hh"
#include "sim/full_system.hh"
namespace AlphaISA
{
class Decoder
{
protected:
ThreadContext *tc;
// The extended machine instruction being generated
ExtMachInst ext_inst;
bool instDone;
public:
Decoder(ThreadContext * _tc) : tc(_tc), instDone(false)
{}
ThreadContext *
getTC()
{
return tc;
}
void
setTC(ThreadContext * _tc)
{
tc = _tc;
}
void
process()
{ }
void
reset()
{
instDone = false;
}
// Use this to give data to the predecoder. This should be used
// when there is control flow.
void
moreBytes(const PCState &pc, Addr fetchPC, MachInst inst)
{
ext_inst = inst;
instDone = true;
if (FullSystem)
ext_inst |= (static_cast<ExtMachInst>(pc.pc() & 0x1) << 32);
}
bool
needMoreBytes()
{
return true;
}
bool
instReady()
{
return instDone;
}
protected:
/// A cache of decoded instruction objects.
static DecodeCache defaultCache;
@ -55,6 +112,15 @@ class Decoder
{
return defaultCache.decode(this, mach_inst, addr);
}
StaticInstPtr
decode(AlphaISA::PCState &nextPC)
{
if (!instDone)
return NULL;
instDone = false;
return decode(ext_inst, nextPC.instAddr());
}
};
} // namespace AlphaISA

View file

@ -73,6 +73,7 @@ using namespace AlphaISA;
output exec {{
#include <cmath>
#include "arch/alpha/decoder.hh"
#include "arch/alpha/registers.hh"
#include "arch/alpha/regredir.hh"
#include "arch/generic/memhelpers.hh"

View file

@ -1,113 +0,0 @@
/*
* 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 "base/types.hh"
#include "sim/full_system.hh"
class ThreadContext;
namespace AlphaISA {
class Predecoder
{
protected:
ThreadContext *tc;
// The extended machine instruction being generated
ExtMachInst ext_inst;
bool emiIsReady;
public:
Predecoder(ThreadContext * _tc)
: tc(_tc), emiIsReady(false)
{}
ThreadContext *
getTC()
{
return tc;
}
void
setTC(ThreadContext * _tc)
{
tc = _tc;
}
void
process()
{ }
void
reset()
{
emiIsReady = false;
}
// Use this to give data to the predecoder. This should be used
// when there is control flow.
void
moreBytes(const PCState &pc, Addr fetchPC, MachInst inst)
{
ext_inst = inst;
emiIsReady = true;
if (FullSystem)
ext_inst |= (static_cast<ExtMachInst>(pc.pc() & 0x1) << 32);
}
bool
needMoreBytes()
{
return true;
}
bool
extMachInstReady()
{
return emiIsReady;
}
// This returns a constant reference to the ExtMachInst to avoid a copy
const ExtMachInst &
getExtMachInst(PCState &pc)
{
emiIsReady = false;
return ext_inst;
}
};
} // namespace AlphaISA
#endif // __ARCH_ALPHA_PREDECODER_HH__

View file

@ -62,7 +62,6 @@ if env['TARGET_ISA'] == 'arm':
Source('linux/system.cc')
Source('miscregs.cc')
Source('nativetrace.cc')
Source('predecoder.cc')
Source('process.cc')
Source('remote_gdb.cc')
Source('stacktrace.cc')
@ -78,9 +77,9 @@ if env['TARGET_ISA'] == 'arm':
SimObject('ArmTLB.py')
DebugFlag('Arm')
DebugFlag('TLBVerbose')
DebugFlag('Decoder', "Instructions returned by the predecoder")
DebugFlag('Faults', "Trace Exceptions, interrupts, svc/swi")
DebugFlag('Predecoder', "Instructions returned by the predecoder")
DebugFlag('TLBVerbose')
# Add in files generated by the ISA description.
isa_desc_files = env.ISADesc('isa/main.isa')

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011 Google
* Copyright (c) 2012 Google
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -29,10 +29,96 @@
*/
#include "arch/arm/decoder.hh"
#include "arch/arm/isa_traits.hh"
#include "arch/arm/utility.hh"
#include "base/trace.hh"
#include "cpu/thread_context.hh"
#include "debug/Decoder.hh"
namespace ArmISA
{
DecodeCache Decoder::defaultCache;
void
Decoder::process()
{
// emi is typically ready, with some caveats below...
instDone = true;
if (!emi.thumb) {
emi.instBits = data;
emi.sevenAndFour = bits(data, 7) && bits(data, 4);
emi.isMisc = (bits(data, 24, 23) == 0x2 &&
bits(data, 20) == 0);
consumeBytes(4);
DPRINTF(Decoder, "Arm inst: %#x.\n", (uint64_t)emi);
} else {
uint16_t word = (data >> (offset * 8));
if (bigThumb) {
// A 32 bit thumb inst is half collected.
emi.instBits = emi.instBits | word;
bigThumb = false;
consumeBytes(2);
DPRINTF(Decoder, "Second half of 32 bit Thumb: %#x.\n",
emi.instBits);
} else {
uint16_t highBits = word & 0xF800;
if (highBits == 0xE800 || highBits == 0xF000 ||
highBits == 0xF800) {
// The start of a 32 bit thumb inst.
emi.bigThumb = 1;
if (offset == 0) {
// We've got the whole thing.
emi.instBits = (data >> 16) | (data << 16);
DPRINTF(Decoder, "All of 32 bit Thumb: %#x.\n",
emi.instBits);
consumeBytes(4);
} else {
// We only have the first half word.
DPRINTF(Decoder,
"First half of 32 bit Thumb.\n");
emi.instBits = (uint32_t)word << 16;
bigThumb = true;
consumeBytes(2);
// emi not ready yet.
instDone = false;
}
} else {
// A 16 bit thumb inst.
consumeBytes(2);
emi.instBits = word;
// Set the condition code field artificially.
emi.condCode = COND_UC;
DPRINTF(Decoder, "16 bit Thumb: %#x.\n",
emi.instBits);
if (bits(word, 15, 8) == 0xbf &&
bits(word, 3, 0) != 0x0) {
foundIt = true;
itBits = bits(word, 7, 0);
DPRINTF(Decoder,
"IT detected, cond = %#x, mask = %#x\n",
itBits.cond, itBits.mask);
}
}
}
}
}
//Use this to give data to the decoder. This should be used
//when there is control flow.
void
Decoder::moreBytes(const PCState &pc, Addr fetchPC, MachInst inst)
{
data = inst;
offset = (fetchPC >= pc.instAddr()) ? 0 : pc.instAddr() - fetchPC;
emi.thumb = pc.thumb();
FPSCR fpscr = tc->readMiscReg(MISCREG_FPSCR);
emi.fpscrLen = fpscr.len;
emi.fpscrStride = fpscr.stride;
outOfBytes = false;
process();
}
}

View file

@ -31,15 +31,95 @@
#ifndef __ARCH_ARM_DECODER_HH__
#define __ARCH_ARM_DECODER_HH__
#include "arch/types.hh"
#include <cassert>
#include "arch/arm/miscregs.hh"
#include "arch/arm/types.hh"
#include "base/types.hh"
#include "cpu/decode_cache.hh"
#include "cpu/static_inst_fwd.hh"
class ThreadContext;
namespace ArmISA
{
class Decoder
{
protected:
ThreadContext * tc;
//The extended machine instruction being generated
ExtMachInst emi;
MachInst data;
bool bigThumb;
bool instDone;
bool outOfBytes;
int offset;
bool foundIt;
ITSTATE itBits;
public:
void reset()
{
bigThumb = false;
offset = 0;
emi = 0;
instDone = false;
outOfBytes = true;
foundIt = false;
}
Decoder(ThreadContext * _tc) : tc(_tc), data(0)
{
reset();
}
ThreadContext * getTC()
{
return tc;
}
void
setTC(ThreadContext * _tc)
{
tc = _tc;
}
void process();
//Use this to give data to the decoder. This should be used
//when there is control flow.
void moreBytes(const PCState &pc, Addr fetchPC, MachInst inst);
//Use this to give data to the decoder. This should be used
//when instructions are executed in order.
void moreBytes(MachInst machInst)
{
moreBytes(0, 0, machInst);
}
inline void consumeBytes(int numBytes)
{
offset += numBytes;
assert(offset <= sizeof(MachInst));
if (offset == sizeof(MachInst))
outOfBytes = true;
}
bool needMoreBytes() const
{
return outOfBytes;
}
bool instReady() const
{
return instDone;
}
int getInstSize() const
{
return (!emi.thumb || emi.bigThumb) ? 4 : 2;
}
protected:
/// A cache of decoded instruction objects.
static DecodeCache defaultCache;
@ -55,6 +135,25 @@ class Decoder
{
return defaultCache.decode(this, mach_inst, addr);
}
StaticInstPtr
decode(ArmISA::PCState &nextPC)
{
if (!instDone)
return NULL;
assert(instDone);
ExtMachInst thisEmi = emi;
nextPC.npc(nextPC.pc() + getInstSize());
if (foundIt)
nextPC.nextItstate(itBits);
thisEmi.itstate = nextPC.itstate();
nextPC.size(getInstSize());
emi = 0;
instDone = false;
foundIt = false;
return decode(thisEmi, nextPC.instAddr());
}
};
} // namespace ArmISA

View file

@ -1,135 +0,0 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2006 The Regents of The University of Michigan
* Copyright (c) 2007-2008 The Florida State University
* 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
*/
#include "arch/arm/isa_traits.hh"
#include "arch/arm/predecoder.hh"
#include "arch/arm/utility.hh"
#include "base/trace.hh"
#include "cpu/thread_context.hh"
#include "debug/Predecoder.hh"
namespace ArmISA
{
void
Predecoder::process()
{
// emi is typically ready, with some caveats below...
emiReady = true;
if (!emi.thumb) {
emi.instBits = data;
emi.sevenAndFour = bits(data, 7) && bits(data, 4);
emi.isMisc = (bits(data, 24, 23) == 0x2 &&
bits(data, 20) == 0);
consumeBytes(4);
DPRINTF(Predecoder, "Arm inst: %#x.\n", (uint64_t)emi);
} else {
uint16_t word = (data >> (offset * 8));
if (bigThumb) {
// A 32 bit thumb inst is half collected.
emi.instBits = emi.instBits | word;
bigThumb = false;
consumeBytes(2);
DPRINTF(Predecoder, "Second half of 32 bit Thumb: %#x.\n",
emi.instBits);
} else {
uint16_t highBits = word & 0xF800;
if (highBits == 0xE800 || highBits == 0xF000 ||
highBits == 0xF800) {
// The start of a 32 bit thumb inst.
emi.bigThumb = 1;
if (offset == 0) {
// We've got the whole thing.
emi.instBits = (data >> 16) | (data << 16);
DPRINTF(Predecoder, "All of 32 bit Thumb: %#x.\n",
emi.instBits);
consumeBytes(4);
} else {
// We only have the first half word.
DPRINTF(Predecoder,
"First half of 32 bit Thumb.\n");
emi.instBits = (uint32_t)word << 16;
bigThumb = true;
consumeBytes(2);
// emi not ready yet.
emiReady = false;
}
} else {
// A 16 bit thumb inst.
consumeBytes(2);
emi.instBits = word;
// Set the condition code field artificially.
emi.condCode = COND_UC;
DPRINTF(Predecoder, "16 bit Thumb: %#x.\n",
emi.instBits);
if (bits(word, 15, 8) == 0xbf &&
bits(word, 3, 0) != 0x0) {
foundIt = true;
itBits = bits(word, 7, 0);
DPRINTF(Predecoder,
"IT detected, cond = %#x, mask = %#x\n",
itBits.cond, itBits.mask);
}
}
}
}
}
//Use this to give data to the predecoder. This should be used
//when there is control flow.
void
Predecoder::moreBytes(const PCState &pc, Addr fetchPC, MachInst inst)
{
data = inst;
offset = (fetchPC >= pc.instAddr()) ? 0 : pc.instAddr() - fetchPC;
emi.thumb = pc.thumb();
FPSCR fpscr = tc->readMiscReg(MISCREG_FPSCR);
emi.fpscrLen = fpscr.len;
emi.fpscrStride = fpscr.stride;
outOfBytes = false;
process();
}
}

View file

@ -1,154 +0,0 @@
/*
* Copyright (c) 2010 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2006 The Regents of The University of Michigan
* Copyright (c) 2007-2008 The Florida State University
* 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
* Stephen Hines
*/
#ifndef __ARCH_ARM_PREDECODER_HH__
#define __ARCH_ARM_PREDECODER_HH__
#include <cassert>
#include "arch/arm/miscregs.hh"
#include "arch/arm/types.hh"
#include "base/types.hh"
class ThreadContext;
namespace ArmISA
{
class Predecoder
{
protected:
ThreadContext * tc;
//The extended machine instruction being generated
ExtMachInst emi;
MachInst data;
bool bigThumb;
bool emiReady;
bool outOfBytes;
int offset;
bool foundIt;
ITSTATE itBits;
public:
void reset()
{
bigThumb = false;
offset = 0;
emi = 0;
emiReady = false;
outOfBytes = true;
foundIt = false;
}
Predecoder(ThreadContext * _tc) :
tc(_tc), data(0)
{
reset();
}
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(const PCState &pc, Addr fetchPC, MachInst 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);
}
inline void consumeBytes(int numBytes)
{
offset += numBytes;
assert(offset <= sizeof(MachInst));
if (offset == sizeof(MachInst))
outOfBytes = true;
}
bool needMoreBytes() const
{
return outOfBytes;
}
bool extMachInstReady() const
{
return emiReady;
}
int getInstSize() const
{
return (!emi.thumb || emi.bigThumb) ? 4 : 2;
}
//This returns a constant reference to the ExtMachInst to avoid a copy
ExtMachInst getExtMachInst(PCState &pc)
{
assert(emiReady);
ExtMachInst thisEmi = emi;
pc.npc(pc.pc() + getInstSize());
if (foundIt)
pc.nextItstate(itBits);
thisEmi.itstate = pc.itstate();
pc.size(getInstSize());
emi = 0;
emiReady = false;
foundIt = false;
return thisEmi;
}
};
}
#endif // __ARCH_ARM_PREDECODER_HH__

View file

@ -48,7 +48,7 @@
#include "base/hashmap.hh"
#include "base/misc.hh"
#include "base/types.hh"
#include "debug/Predecoder.hh"
#include "debug/Decoder.hh"
namespace ArmISA
{
@ -342,7 +342,7 @@ namespace ArmISA
ITSTATE it = _itstate;
uint8_t cond_mask = it.mask;
uint8_t thumb_cond = it.cond;
DPRINTF(Predecoder, "Advancing ITSTATE from %#x,%#x.\n",
DPRINTF(Decoder, "Advancing ITSTATE from %#x,%#x.\n",
thumb_cond, cond_mask);
cond_mask <<= 1;
uint8_t new_bit = bits(cond_mask, 4);
@ -351,7 +351,7 @@ namespace ArmISA
thumb_cond = 0;
else
replaceBits(thumb_cond, 0, new_bit);
DPRINTF(Predecoder, "Advancing ITSTATE to %#x,%#x.\n",
DPRINTF(Decoder, "Advancing ITSTATE to %#x,%#x.\n",
thumb_cond, cond_mask);
it.mask = cond_mask;
it.cond = thumb_cond;

View file

@ -31,15 +31,72 @@
#ifndef __ARCH_MIPS_DECODER_HH__
#define __ARCH_MIPS_DECODER_HH__
#include "arch/types.hh"
#include "arch/mips/types.hh"
#include "base/misc.hh"
#include "base/types.hh"
#include "cpu/decode_cache.hh"
#include "cpu/static_inst_fwd.hh"
class ThreadContext;
namespace MipsISA
{
class Decoder
{
protected:
ThreadContext * tc;
//The extended machine instruction being generated
ExtMachInst emi;
bool instDone;
public:
Decoder(ThreadContext * _tc) : tc(_tc), instDone(false)
{}
ThreadContext *getTC()
{
return tc;
}
void
setTC(ThreadContext *_tc)
{
tc = _tc;
}
void
process()
{
}
void
reset()
{
instDone = false;
}
//Use this to give data to the decoder. This should be used
//when there is control flow.
void
moreBytes(const PCState &pc, Addr fetchPC, MachInst inst)
{
emi = inst;
instDone = true;
}
bool
needMoreBytes()
{
return true;
}
bool
instReady()
{
return instDone;
}
protected:
/// A cache of decoded instruction objects.
static DecodeCache defaultCache;
@ -55,6 +112,15 @@ class Decoder
{
return defaultCache.decode(this, mach_inst, addr);
}
StaticInstPtr
decode(MipsISA::PCState &nextPC)
{
if (!instDone)
return NULL;
instDone = false;
return decode(emi, nextPC.instAddr());
}
};
} // namespace MipsISA

View file

@ -1,110 +0,0 @@
/*
* 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 "base/types.hh"
class ThreadContext;
namespace MipsISA
{
class Predecoder
{
protected:
ThreadContext * tc;
//The extended machine instruction being generated
ExtMachInst emi;
bool emiIsReady;
public:
Predecoder(ThreadContext * _tc) : tc(_tc), emiIsReady(false)
{}
ThreadContext *getTC()
{
return tc;
}
void
setTC(ThreadContext *_tc)
{
tc = _tc;
}
void
process()
{
}
void
reset()
{
emiIsReady = false;
}
//Use this to give data to the predecoder. This should be used
//when there is control flow.
void
moreBytes(const PCState &pc, Addr fetchPC, MachInst inst)
{
emi = inst;
emiIsReady = true;
}
bool
needMoreBytes()
{
return true;
}
bool
extMachInstReady()
{
return emiIsReady;
}
//This returns a constant reference to the ExtMachInst to avoid a copy
const ExtMachInst &
getExtMachInst(PCState &pc)
{
emiIsReady = false;
return emi;
}
};
};
#endif // __ARCH_MIPS_PREDECODER_HH__

View file

@ -40,6 +40,69 @@ namespace PowerISA
class Decoder
{
protected:
ThreadContext * tc;
// The extended machine instruction being generated
ExtMachInst emi;
bool instDone;
public:
Decoder(ThreadContext * _tc) : tc(_tc), instDone(false)
{
}
ThreadContext *
getTC()
{
return tc;
}
void
setTC(ThreadContext * _tc)
{
tc = _tc;
}
void
process()
{
}
void
reset()
{
instDone = false;
}
// Use this to give data to the predecoder. This should be used
// when there is control flow.
void
moreBytes(const PCState &pc, Addr fetchPC, MachInst inst)
{
emi = inst;
instDone = true;
}
// 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
instReady()
{
return instDone;
}
protected:
/// A cache of decoded instruction objects.
static DecodeCache defaultCache;
@ -55,6 +118,15 @@ class Decoder
{
return defaultCache.decode(this, mach_inst, addr);
}
StaticInstPtr
decode(PowerISA::PCState &nextPC)
{
if (!instDone)
return NULL;
instDone = false;
return decode(emi, nextPC.instAddr());
}
};
} // namespace PowerISA

View file

@ -1,125 +0,0 @@
/*
* Copyright (c) 2006 The Regents of The University of Michigan
* Copyright (c) 2007-2008 The Florida State University
* Copyright (c) 2009 The University of Edinburgh
* 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
* Stephen Hines
* Timothy M. Jones
*/
#ifndef __ARCH_ARM_PREDECODER_HH__
#define __ARCH_ARM_PREDECODER_HH__
#include "arch/power/types.hh"
#include "base/misc.hh"
#include "base/types.hh"
class ThreadContext;
namespace PowerISA
{
class Predecoder
{
protected:
ThreadContext * tc;
// The extended machine instruction being generated
ExtMachInst emi;
bool emiIsReady;
public:
Predecoder(ThreadContext * _tc)
: tc(_tc), emiIsReady(false)
{
}
ThreadContext *
getTC()
{
return tc;
}
void
setTC(ThreadContext * _tc)
{
tc = _tc;
}
void
process()
{
}
void
reset()
{
emiIsReady = false;
}
// Use this to give data to the predecoder. This should be used
// when there is control flow.
void
moreBytes(const PCState &pc, Addr fetchPC, MachInst inst)
{
emi = inst;
emiIsReady = true;
}
// 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 emiIsReady;
}
// This returns a constant reference to the ExtMachInst to avoid a copy
const ExtMachInst &
getExtMachInst(PCState &pcState)
{
emiIsReady = false;
return emi;
}
};
} // namespace PowerISA
#endif // __ARCH_POWER_PREDECODER_HH__

View file

@ -31,15 +31,82 @@
#ifndef __ARCH_SPARC_DECODER_HH__
#define __ARCH_SPARC_DECODER_HH__
#include "arch/sparc/registers.hh"
#include "arch/types.hh"
#include "cpu/decode_cache.hh"
#include "cpu/static_inst_fwd.hh"
#include "cpu/thread_context.hh"
class ThreadContext;
namespace SparcISA
{
class Decoder
{
protected:
ThreadContext * tc;
// The extended machine instruction being generated
ExtMachInst emi;
bool instDone;
public:
Decoder(ThreadContext * _tc) : tc(_tc), instDone(false)
{}
ThreadContext *
getTC()
{
return tc;
}
void
setTC(ThreadContext * _tc)
{
tc = _tc;
}
void process() {}
void
reset()
{
instDone = false;
}
// Use this to give data to the predecoder. This should be used
// when there is control flow.
void
moreBytes(const PCState &pc, Addr fetchPC, MachInst inst)
{
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));
}
instDone = true;
}
bool
needMoreBytes()
{
return true;
}
bool
instReady()
{
return instDone;
}
protected:
/// A cache of decoded instruction objects.
static DecodeCache defaultCache;
@ -55,6 +122,15 @@ class Decoder
{
return defaultCache.decode(this, mach_inst, addr);
}
StaticInstPtr
decode(SparcISA::PCState &nextPC)
{
if (!instDone)
return NULL;
instDone = false;
return decode(emi, nextPC.instAddr());
}
};
} // namespace SparcISA

View file

@ -1,121 +0,0 @@
/*
* 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/registers.hh"
#include "arch/sparc/types.hh"
#include "base/bitfield.hh"
#include "base/misc.hh"
#include "base/types.hh"
#include "cpu/thread_context.hh"
class ThreadContext;
namespace SparcISA
{
class Predecoder
{
protected:
ThreadContext * tc;
// The extended machine instruction being generated
ExtMachInst emi;
bool emiIsReady;
public:
Predecoder(ThreadContext * _tc) : tc(_tc), emiIsReady(false)
{}
ThreadContext *
getTC()
{
return tc;
}
void
setTC(ThreadContext * _tc)
{
tc = _tc;
}
void process() {}
void
reset()
{
emiIsReady = false;
}
// Use this to give data to the predecoder. This should be used
// when there is control flow.
void
moreBytes(const PCState &pc, Addr fetchPC, MachInst inst)
{
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));
}
emiIsReady = true;
}
bool
needMoreBytes()
{
return true;
}
bool
extMachInstReady()
{
return emiIsReady;
}
// This returns a constant reference to the ExtMachInst to avoid a copy
const ExtMachInst &
getExtMachInst(PCState &pcState)
{
emiIsReady = false;
return emi;
}
};
};
#endif // __ARCH_SPARC_PREDECODER_HH__

View file

@ -45,6 +45,7 @@ Import('*')
if env['TARGET_ISA'] == 'x86':
Source('cpuid.cc')
Source('decoder.cc')
Source('decoder_tables.cc')
Source('emulenv.cc')
Source('faults.cc')
Source('insts/badmicroop.cc')
@ -63,8 +64,6 @@ if env['TARGET_ISA'] == 'x86':
Source('nativetrace.cc')
Source('pagetable.cc')
Source('pagetable_walker.cc')
Source('predecoder.cc')
Source('predecoder_tables.cc')
Source('process.cc')
Source('remote_gdb.cc')
Source('stacktrace.cc')
@ -83,7 +82,7 @@ if env['TARGET_ISA'] == 'x86':
DebugFlag('LocalApic', "Local APIC debugging")
DebugFlag('PageTableWalker', \
"Page table walker state machine debugging")
DebugFlag('Predecoder', "Predecoder debug output")
DebugFlag('Decoder', "Decoder debug output")
DebugFlag('X86', "Generic X86 ISA debugging")
python_files = (

View file

@ -29,9 +29,384 @@
*/
#include "arch/x86/decoder.hh"
#include "arch/x86/regs/misc.hh"
#include "base/misc.hh"
#include "base/trace.hh"
#include "base/types.hh"
#include "cpu/thread_context.hh"
#include "debug/Decoder.hh"
namespace X86ISA
{
void Decoder::doReset()
{
origPC = basePC + offset;
DPRINTF(Decoder, "Setting origPC to %#x\n", origPC);
emi.rex = 0;
emi.legacy = 0;
emi.opcode.num = 0;
emi.opcode.op = 0;
emi.opcode.prefixA = emi.opcode.prefixB = 0;
immediateCollected = 0;
emi.immediate = 0;
emi.displacement = 0;
emi.dispSize = 0;
emi.modRM = 0;
emi.sib = 0;
m5Reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
emi.mode.mode = m5Reg.mode;
emi.mode.submode = m5Reg.submode;
}
void Decoder::process()
{
//This function drives the decoder state machine.
//Some sanity checks. You shouldn't try to process more bytes if
//there aren't any, and you shouldn't overwrite an already
//decoder ExtMachInst.
assert(!outOfBytes);
assert(!instDone);
//While there's still something to do...
while(!instDone && !outOfBytes)
{
uint8_t nextByte = getNextByte();
switch(state)
{
case ResetState:
doReset();
state = PrefixState;
case PrefixState:
state = doPrefixState(nextByte);
break;
case OpcodeState:
state = doOpcodeState(nextByte);
break;
case ModRMState:
state = doModRMState(nextByte);
break;
case SIBState:
state = doSIBState(nextByte);
break;
case DisplacementState:
state = doDisplacementState();
break;
case ImmediateState:
state = doImmediateState();
break;
case ErrorState:
panic("Went to the error state in the decoder.\n");
default:
panic("Unrecognized state! %d\n", state);
}
}
}
//Either get a prefix and record it in the ExtMachInst, or send the
//state machine on to get the opcode(s).
Decoder::State Decoder::doPrefixState(uint8_t nextByte)
{
uint8_t prefix = Prefixes[nextByte];
State nextState = PrefixState;
// REX prefixes are only recognized in 64 bit mode.
if (prefix == RexPrefix && emi.mode.submode != SixtyFourBitMode)
prefix = 0;
if (prefix)
consumeByte();
switch(prefix)
{
//Operand size override prefixes
case OperandSizeOverride:
DPRINTF(Decoder, "Found operand size override prefix.\n");
emi.legacy.op = true;
break;
case AddressSizeOverride:
DPRINTF(Decoder, "Found address size override prefix.\n");
emi.legacy.addr = true;
break;
//Segment override prefixes
case CSOverride:
case DSOverride:
case ESOverride:
case FSOverride:
case GSOverride:
case SSOverride:
DPRINTF(Decoder, "Found segment override.\n");
emi.legacy.seg = prefix;
break;
case Lock:
DPRINTF(Decoder, "Found lock prefix.\n");
emi.legacy.lock = true;
break;
case Rep:
DPRINTF(Decoder, "Found rep prefix.\n");
emi.legacy.rep = true;
break;
case Repne:
DPRINTF(Decoder, "Found repne prefix.\n");
emi.legacy.repne = true;
break;
case RexPrefix:
DPRINTF(Decoder, "Found Rex prefix %#x.\n", nextByte);
emi.rex = nextByte;
break;
case 0:
nextState = OpcodeState;
break;
default:
panic("Unrecognized prefix %#x\n", nextByte);
}
return nextState;
}
//Load all the opcodes (currently up to 2) and then figure out
//what immediate and/or ModRM is needed.
Decoder::State Decoder::doOpcodeState(uint8_t nextByte)
{
State nextState = ErrorState;
emi.opcode.num++;
//We can't handle 3+ byte opcodes right now
assert(emi.opcode.num < 4);
consumeByte();
if(emi.opcode.num == 1 && nextByte == 0x0f)
{
nextState = OpcodeState;
DPRINTF(Decoder, "Found two byte opcode.\n");
emi.opcode.prefixA = nextByte;
}
else if(emi.opcode.num == 2 && (nextByte == 0x38 || nextByte == 0x3A))
{
nextState = OpcodeState;
DPRINTF(Decoder, "Found three byte opcode.\n");
emi.opcode.prefixB = nextByte;
}
else
{
DPRINTF(Decoder, "Found opcode %#x.\n", nextByte);
emi.opcode.op = nextByte;
//Figure out the effective operand size. This can be overriden to
//a fixed value at the decoder level.
int logOpSize;
if (emi.rex.w)
logOpSize = 3; // 64 bit operand size
else if (emi.legacy.op)
logOpSize = m5Reg.altOp;
else
logOpSize = m5Reg.defOp;
//Set the actual op size
emi.opSize = 1 << logOpSize;
//Figure out the effective address size. This can be overriden to
//a fixed value at the decoder level.
int logAddrSize;
if(emi.legacy.addr)
logAddrSize = m5Reg.altAddr;
else
logAddrSize = m5Reg.defAddr;
//Set the actual address size
emi.addrSize = 1 << logAddrSize;
//Figure out the effective stack width. This can be overriden to
//a fixed value at the decoder level.
emi.stackSize = 1 << m5Reg.stack;
//Figure out how big of an immediate we'll retreive based
//on the opcode.
int immType = ImmediateType[emi.opcode.num - 1][nextByte];
if (emi.opcode.num == 1 && nextByte >= 0xA0 && nextByte <= 0xA3)
immediateSize = SizeTypeToSize[logAddrSize - 1][immType];
else
immediateSize = SizeTypeToSize[logOpSize - 1][immType];
//Determine what to expect next
if (UsesModRM[emi.opcode.num - 1][nextByte]) {
nextState = ModRMState;
} else {
if(immediateSize) {
nextState = ImmediateState;
} else {
instDone = true;
nextState = ResetState;
}
}
}
return nextState;
}
//Get the ModRM byte and determine what displacement, if any, there is.
//Also determine whether or not to get the SIB byte, displacement, or
//immediate next.
Decoder::State Decoder::doModRMState(uint8_t nextByte)
{
State nextState = ErrorState;
ModRM modRM;
modRM = nextByte;
DPRINTF(Decoder, "Found modrm byte %#x.\n", nextByte);
if (m5Reg.defOp == 1) {
//figure out 16 bit displacement size
if ((modRM.mod == 0 && modRM.rm == 6) || modRM.mod == 2)
displacementSize = 2;
else if (modRM.mod == 1)
displacementSize = 1;
else
displacementSize = 0;
} else {
//figure out 32/64 bit displacement size
if ((modRM.mod == 0 && modRM.rm == 5) || modRM.mod == 2)
displacementSize = 4;
else if (modRM.mod == 1)
displacementSize = 1;
else
displacementSize = 0;
}
// The "test" instruction in group 3 needs an immediate, even though
// the other instructions with the same actual opcode don't.
if (emi.opcode.num == 1 && (modRM.reg & 0x6) == 0) {
if (emi.opcode.op == 0xF6)
immediateSize = 1;
else if (emi.opcode.op == 0xF7)
immediateSize = (emi.opSize == 8) ? 4 : emi.opSize;
}
//If there's an SIB, get that next.
//There is no SIB in 16 bit mode.
if (modRM.rm == 4 && modRM.mod != 3) {
// && in 32/64 bit mode)
nextState = SIBState;
} else if(displacementSize) {
nextState = DisplacementState;
} else if(immediateSize) {
nextState = ImmediateState;
} else {
instDone = true;
nextState = ResetState;
}
//The ModRM byte is consumed no matter what
consumeByte();
emi.modRM = modRM;
return nextState;
}
//Get the SIB byte. We don't do anything with it at this point, other
//than storing it in the ExtMachInst. Determine if we need to get a
//displacement or immediate next.
Decoder::State Decoder::doSIBState(uint8_t nextByte)
{
State nextState = ErrorState;
emi.sib = nextByte;
DPRINTF(Decoder, "Found SIB byte %#x.\n", nextByte);
consumeByte();
if (emi.modRM.mod == 0 && emi.sib.base == 5)
displacementSize = 4;
if (displacementSize) {
nextState = DisplacementState;
} else if(immediateSize) {
nextState = ImmediateState;
} else {
instDone = true;
nextState = ResetState;
}
return nextState;
}
//Gather up the displacement, or at least as much of it
//as we can get.
Decoder::State Decoder::doDisplacementState()
{
State nextState = ErrorState;
getImmediate(immediateCollected,
emi.displacement,
displacementSize);
DPRINTF(Decoder, "Collecting %d byte displacement, got %d bytes.\n",
displacementSize, immediateCollected);
if(displacementSize == immediateCollected) {
//Reset this for other immediates.
immediateCollected = 0;
//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");
}
DPRINTF(Decoder, "Collected displacement %#x.\n",
emi.displacement);
if(immediateSize) {
nextState = ImmediateState;
} else {
instDone = true;
nextState = ResetState;
}
emi.dispSize = displacementSize;
}
else
nextState = DisplacementState;
return nextState;
}
//Gather up the immediate, or at least as much of it
//as we can get
Decoder::State Decoder::doImmediateState()
{
State nextState = ErrorState;
getImmediate(immediateCollected,
emi.immediate,
immediateSize);
DPRINTF(Decoder, "Collecting %d byte immediate, got %d bytes.\n",
immediateSize, immediateCollected);
if(immediateSize == immediateCollected)
{
//Reset this for other immediates.
immediateCollected = 0;
//XXX Warning! The following is an observed pattern and might
//not always be true!
//Instructions which use 64 bit operands but 32 bit immediates
//need to have the immediate sign extended to 64 bits.
//Instructions which use true 64 bit immediates won't be
//affected, and instructions that use true 32 bit immediates
//won't notice.
switch(immediateSize)
{
case 4:
emi.immediate = sext<32>(emi.immediate);
break;
case 1:
emi.immediate = sext<8>(emi.immediate);
}
DPRINTF(Decoder, "Collected immediate %#x.\n",
emi.immediate);
instDone = true;
nextState = ResetState;
}
else
nextState = ImmediateState;
return nextState;
}
DecodeCache Decoder::defaultCache;

View file

@ -31,15 +31,192 @@
#ifndef __ARCH_X86_DECODER_HH__
#define __ARCH_X86_DECODER_HH__
#include "arch/types.hh"
#include <cassert>
#include "arch/x86/regs/misc.hh"
#include "arch/x86/types.hh"
#include "base/bitfield.hh"
#include "base/misc.hh"
#include "base/trace.hh"
#include "base/types.hh"
#include "cpu/decode_cache.hh"
#include "cpu/static_inst_fwd.hh"
#include "debug/Decoder.hh"
class ThreadContext;
namespace X86ISA
{
class Decoder
{
private:
//These are defined and documented in decoder_tables.cc
static const uint8_t Prefixes[256];
static const uint8_t UsesModRM[2][256];
static const uint8_t ImmediateType[2][256];
static const uint8_t SizeTypeToSize[3][10];
protected:
ThreadContext * tc;
//The bytes to be predecoded
MachInst fetchChunk;
//The pc of the start of fetchChunk
Addr basePC;
//The pc the current instruction started at
Addr origPC;
//The offset into fetchChunk of current processing
int offset;
//The extended machine instruction being generated
ExtMachInst emi;
HandyM5Reg m5Reg;
inline uint8_t getNextByte()
{
return ((uint8_t *)&fetchChunk)[offset];
}
void getImmediate(int &collected, uint64_t &current, int size)
{
//Figure out how many bytes we still need to get for the
//immediate.
int toGet = size - collected;
//Figure out how many bytes are left in our "buffer"
int 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
uint64_t partialImm = fetchChunk >> (offset * 8);
//Mask off what we don't want
partialImm &= mask(toGet * 8);
//Shift it over to overlay with our displacement.
partialImm <<= (immediateCollected * 8);
//Put it into our displacement
current |= partialImm;
//Update how many bytes we've collected.
collected += toGet;
consumeBytes(toGet);
}
inline void consumeByte()
{
offset++;
assert(offset <= sizeof(MachInst));
if(offset == sizeof(MachInst))
outOfBytes = true;
}
inline void consumeBytes(int numBytes)
{
offset += numBytes;
assert(offset <= sizeof(MachInst));
if(offset == sizeof(MachInst))
outOfBytes = true;
}
void doReset();
//State machine state
protected:
//Whether or not we're out of bytes
bool outOfBytes;
//Whether we've completed generating an ExtMachInst
bool instDone;
//The size of the displacement value
int displacementSize;
//The size of the immediate value
int immediateSize;
//This is how much of any immediate value we've gotten. This is used
//for both the actual immediate and the displacement.
int immediateCollected;
enum State {
ResetState,
PrefixState,
OpcodeState,
ModRMState,
SIBState,
DisplacementState,
ImmediateState,
//We should never get to this state. Getting here is an error.
ErrorState
};
State state;
//Functions to handle each of the states
State doPrefixState(uint8_t);
State doOpcodeState(uint8_t);
State doModRMState(uint8_t);
State doSIBState(uint8_t);
State doDisplacementState();
State doImmediateState();
public:
Decoder(ThreadContext * _tc) :
tc(_tc), basePC(0), origPC(0), offset(0),
outOfBytes(true), instDone(false),
state(ResetState)
{
emi.mode.mode = LongMode;
emi.mode.submode = SixtyFourBitMode;
m5Reg = 0;
}
void reset()
{
state = ResetState;
}
ThreadContext * getTC()
{
return tc;
}
void setTC(ThreadContext * _tc)
{
tc = _tc;
}
void process();
//Use this to give data to the decoder. This should be used
//when there is control flow.
void moreBytes(const PCState &pc, Addr fetchPC, MachInst data)
{
DPRINTF(Decoder, "Getting more bytes.\n");
basePC = fetchPC;
offset = (fetchPC >= pc.instAddr()) ? 0 : pc.instAddr() - fetchPC;
fetchChunk = data;
outOfBytes = false;
process();
}
bool needMoreBytes()
{
return outOfBytes;
}
bool instReady()
{
return instDone;
}
void
updateNPC(X86ISA::PCState &nextPC)
{
if (!nextPC.size()) {
int size = basePC + offset - origPC;
DPRINTF(Decoder,
"Calculating the instruction size: "
"basePC: %#x offset: %#x origPC: %#x size: %d\n",
basePC, offset, origPC, size);
nextPC.size(size);
nextPC.npc(nextPC.pc() + size);
}
}
protected:
/// A cache of decoded instruction objects.
static DecodeCache defaultCache;
@ -55,6 +232,16 @@ class Decoder
{
return defaultCache.decode(this, mach_inst, addr);
}
StaticInstPtr
decode(X86ISA::PCState &nextPC)
{
if (!instDone)
return NULL;
instDone = false;
updateNPC(nextPC);
return decode(emi, origPC);
}
};
} // namespace X86ISA

View file

@ -37,7 +37,7 @@
* Authors: Gabe Black
*/
#include "arch/x86/predecoder.hh"
#include "arch/x86/decoder.hh"
#include "arch/x86/types.hh"
namespace X86ISA
@ -58,7 +58,7 @@ namespace X86ISA
//This table identifies whether a byte is a prefix, and if it is,
//which prefix it is.
const uint8_t Predecoder::Prefixes[256] =
const uint8_t Decoder::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,
@ -80,7 +80,7 @@ namespace X86ISA
};
//This table identifies whether a particular opcode uses the ModRM byte
const uint8_t Predecoder::UsesModRM[2][256] =
const uint8_t Decoder::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
@ -147,7 +147,7 @@ namespace X86ISA
PO = Pointer
};
const uint8_t Predecoder::SizeTypeToSize[3][10] =
const uint8_t Decoder::SizeTypeToSize[3][10] =
{
// noimm byte word dword qword oword vword zword enter pointer
{0, 1, 2, 4, 8, 16, 2, 2, 3, 4 }, //16 bit
@ -159,7 +159,7 @@ namespace X86ISA
//number of bytes in the instruction, and the second is the meaningful
//byte of the opcode. I didn't use the NI constant here for the sake
//of clarity.
const uint8_t Predecoder::ImmediateType[2][256] =
const uint8_t Decoder::ImmediateType[2][256] =
{//For one byte instructions
{ //LSB
// MSB 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F

View file

@ -53,7 +53,7 @@ void EmulEnv::doModRM(const ExtMachInst & machInst)
index = machInst.sib.index | (machInst.rex.x << 3);
base = machInst.sib.base | (machInst.rex.b << 3);
//In this special case, we don't use a base. The displacement also
//changes, but that's managed by the predecoder.
//changes, but that's managed by the decoder.
if (machInst.sib.base == INTREG_RBP && machInst.modRM.mod == 0)
base = NUM_INTREGS;
//In -this- special case, we don't use an index.

View file

@ -396,7 +396,7 @@
0x4: int3();
0x5: decode FullSystemInt default int_Ib() {
0: decode IMMEDIATE {
// Really only the LSB matters, but the predecoder
// Really only the LSB matters, but the decoder
// will sign extend it, and there's no easy way to
// specify only checking the first byte.
-0x80: SyscallInst::int80('xc->syscall(Rax)',

View file

@ -1,419 +0,0 @@
/*
* Copyright (c) 2007-2008 The Hewlett-Packard Development Company
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* 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
*/
#include "arch/x86/regs/misc.hh"
#include "arch/x86/predecoder.hh"
#include "base/misc.hh"
#include "base/trace.hh"
#include "base/types.hh"
#include "cpu/thread_context.hh"
#include "debug/Predecoder.hh"
namespace X86ISA
{
void Predecoder::doReset()
{
origPC = basePC + offset;
DPRINTF(Predecoder, "Setting origPC to %#x\n", origPC);
emi.rex = 0;
emi.legacy = 0;
emi.opcode.num = 0;
emi.opcode.op = 0;
emi.opcode.prefixA = emi.opcode.prefixB = 0;
immediateCollected = 0;
emi.immediate = 0;
emi.displacement = 0;
emi.dispSize = 0;
emi.modRM = 0;
emi.sib = 0;
m5Reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
emi.mode.mode = m5Reg.mode;
emi.mode.submode = m5Reg.submode;
}
void Predecoder::process()
{
//This function drives the predecoder state machine.
//Some sanity checks. You shouldn't try to process more bytes if
//there aren't any, and you shouldn't overwrite an already
//predecoder ExtMachInst.
assert(!outOfBytes);
assert(!emiIsReady);
//While there's still something to do...
while(!emiIsReady && !outOfBytes)
{
uint8_t nextByte = getNextByte();
switch(state)
{
case ResetState:
doReset();
state = PrefixState;
case PrefixState:
state = doPrefixState(nextByte);
break;
case OpcodeState:
state = doOpcodeState(nextByte);
break;
case ModRMState:
state = doModRMState(nextByte);
break;
case SIBState:
state = doSIBState(nextByte);
break;
case DisplacementState:
state = doDisplacementState();
break;
case ImmediateState:
state = doImmediateState();
break;
case ErrorState:
panic("Went to the error state in the predecoder.\n");
default:
panic("Unrecognized state! %d\n", state);
}
}
}
//Either get a prefix and record it in the ExtMachInst, or send the
//state machine on to get the opcode(s).
Predecoder::State Predecoder::doPrefixState(uint8_t nextByte)
{
uint8_t prefix = Prefixes[nextByte];
State nextState = PrefixState;
// REX prefixes are only recognized in 64 bit mode.
if (prefix == RexPrefix && emi.mode.submode != SixtyFourBitMode)
prefix = 0;
if (prefix)
consumeByte();
switch(prefix)
{
//Operand size override prefixes
case OperandSizeOverride:
DPRINTF(Predecoder, "Found operand size override prefix.\n");
emi.legacy.op = true;
break;
case AddressSizeOverride:
DPRINTF(Predecoder, "Found address size override prefix.\n");
emi.legacy.addr = true;
break;
//Segment override prefixes
case CSOverride:
case DSOverride:
case ESOverride:
case FSOverride:
case GSOverride:
case SSOverride:
DPRINTF(Predecoder, "Found segment override.\n");
emi.legacy.seg = prefix;
break;
case Lock:
DPRINTF(Predecoder, "Found lock prefix.\n");
emi.legacy.lock = true;
break;
case Rep:
DPRINTF(Predecoder, "Found rep prefix.\n");
emi.legacy.rep = true;
break;
case Repne:
DPRINTF(Predecoder, "Found repne prefix.\n");
emi.legacy.repne = true;
break;
case RexPrefix:
DPRINTF(Predecoder, "Found Rex prefix %#x.\n", nextByte);
emi.rex = nextByte;
break;
case 0:
nextState = OpcodeState;
break;
default:
panic("Unrecognized prefix %#x\n", nextByte);
}
return nextState;
}
//Load all the opcodes (currently up to 2) and then figure out
//what immediate and/or ModRM is needed.
Predecoder::State Predecoder::doOpcodeState(uint8_t nextByte)
{
State nextState = ErrorState;
emi.opcode.num++;
//We can't handle 3+ byte opcodes right now
assert(emi.opcode.num < 4);
consumeByte();
if(emi.opcode.num == 1 && nextByte == 0x0f)
{
nextState = OpcodeState;
DPRINTF(Predecoder, "Found two byte opcode.\n");
emi.opcode.prefixA = nextByte;
}
else if(emi.opcode.num == 2 && (nextByte == 0x38 || nextByte == 0x3A))
{
nextState = OpcodeState;
DPRINTF(Predecoder, "Found three byte opcode.\n");
emi.opcode.prefixB = nextByte;
}
else
{
DPRINTF(Predecoder, "Found opcode %#x.\n", nextByte);
emi.opcode.op = nextByte;
//Figure out the effective operand size. This can be overriden to
//a fixed value at the decoder level.
int logOpSize;
if (emi.rex.w)
logOpSize = 3; // 64 bit operand size
else if (emi.legacy.op)
logOpSize = m5Reg.altOp;
else
logOpSize = m5Reg.defOp;
//Set the actual op size
emi.opSize = 1 << logOpSize;
//Figure out the effective address size. This can be overriden to
//a fixed value at the decoder level.
int logAddrSize;
if(emi.legacy.addr)
logAddrSize = m5Reg.altAddr;
else
logAddrSize = m5Reg.defAddr;
//Set the actual address size
emi.addrSize = 1 << logAddrSize;
//Figure out the effective stack width. This can be overriden to
//a fixed value at the decoder level.
emi.stackSize = 1 << m5Reg.stack;
//Figure out how big of an immediate we'll retreive based
//on the opcode.
int immType = ImmediateType[emi.opcode.num - 1][nextByte];
if (emi.opcode.num == 1 && nextByte >= 0xA0 && nextByte <= 0xA3)
immediateSize = SizeTypeToSize[logAddrSize - 1][immType];
else
immediateSize = SizeTypeToSize[logOpSize - 1][immType];
//Determine what to expect next
if (UsesModRM[emi.opcode.num - 1][nextByte]) {
nextState = ModRMState;
} else {
if(immediateSize) {
nextState = ImmediateState;
} else {
emiIsReady = true;
nextState = ResetState;
}
}
}
return nextState;
}
//Get the ModRM byte and determine what displacement, if any, there is.
//Also determine whether or not to get the SIB byte, displacement, or
//immediate next.
Predecoder::State Predecoder::doModRMState(uint8_t nextByte)
{
State nextState = ErrorState;
ModRM modRM;
modRM = nextByte;
DPRINTF(Predecoder, "Found modrm byte %#x.\n", nextByte);
if (m5Reg.defOp == 1) {
//figure out 16 bit displacement size
if ((modRM.mod == 0 && modRM.rm == 6) || modRM.mod == 2)
displacementSize = 2;
else if (modRM.mod == 1)
displacementSize = 1;
else
displacementSize = 0;
} else {
//figure out 32/64 bit displacement size
if ((modRM.mod == 0 && modRM.rm == 5) || modRM.mod == 2)
displacementSize = 4;
else if (modRM.mod == 1)
displacementSize = 1;
else
displacementSize = 0;
}
// The "test" instruction in group 3 needs an immediate, even though
// the other instructions with the same actual opcode don't.
if (emi.opcode.num == 1 && (modRM.reg & 0x6) == 0) {
if (emi.opcode.op == 0xF6)
immediateSize = 1;
else if (emi.opcode.op == 0xF7)
immediateSize = (emi.opSize == 8) ? 4 : emi.opSize;
}
//If there's an SIB, get that next.
//There is no SIB in 16 bit mode.
if (modRM.rm == 4 && modRM.mod != 3) {
// && in 32/64 bit mode)
nextState = SIBState;
} else if(displacementSize) {
nextState = DisplacementState;
} else if(immediateSize) {
nextState = ImmediateState;
} else {
emiIsReady = true;
nextState = ResetState;
}
//The ModRM byte is consumed no matter what
consumeByte();
emi.modRM = modRM;
return nextState;
}
//Get the SIB byte. We don't do anything with it at this point, other
//than storing it in the ExtMachInst. Determine if we need to get a
//displacement or immediate next.
Predecoder::State Predecoder::doSIBState(uint8_t nextByte)
{
State nextState = ErrorState;
emi.sib = nextByte;
DPRINTF(Predecoder, "Found SIB byte %#x.\n", nextByte);
consumeByte();
if (emi.modRM.mod == 0 && emi.sib.base == 5)
displacementSize = 4;
if (displacementSize) {
nextState = DisplacementState;
} else if(immediateSize) {
nextState = ImmediateState;
} else {
emiIsReady = true;
nextState = ResetState;
}
return nextState;
}
//Gather up the displacement, or at least as much of it
//as we can get.
Predecoder::State Predecoder::doDisplacementState()
{
State nextState = ErrorState;
getImmediate(immediateCollected,
emi.displacement,
displacementSize);
DPRINTF(Predecoder, "Collecting %d byte displacement, got %d bytes.\n",
displacementSize, immediateCollected);
if(displacementSize == immediateCollected) {
//Reset this for other immediates.
immediateCollected = 0;
//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");
}
DPRINTF(Predecoder, "Collected displacement %#x.\n",
emi.displacement);
if(immediateSize) {
nextState = ImmediateState;
} else {
emiIsReady = true;
nextState = ResetState;
}
emi.dispSize = displacementSize;
}
else
nextState = DisplacementState;
return nextState;
}
//Gather up the immediate, or at least as much of it
//as we can get
Predecoder::State Predecoder::doImmediateState()
{
State nextState = ErrorState;
getImmediate(immediateCollected,
emi.immediate,
immediateSize);
DPRINTF(Predecoder, "Collecting %d byte immediate, got %d bytes.\n",
immediateSize, immediateCollected);
if(immediateSize == immediateCollected)
{
//Reset this for other immediates.
immediateCollected = 0;
//XXX Warning! The following is an observed pattern and might
//not always be true!
//Instructions which use 64 bit operands but 32 bit immediates
//need to have the immediate sign extended to 64 bits.
//Instructions which use true 64 bit immediates won't be
//affected, and instructions that use true 32 bit immediates
//won't notice.
switch(immediateSize)
{
case 4:
emi.immediate = sext<32>(emi.immediate);
break;
case 1:
emi.immediate = sext<8>(emi.immediate);
}
DPRINTF(Predecoder, "Collected immediate %#x.\n",
emi.immediate);
emiIsReady = true;
nextState = ResetState;
}
else
nextState = ImmediateState;
return nextState;
}
}

View file

@ -1,239 +0,0 @@
/*
* Copyright (c) 2007 The Hewlett-Packard Development Company
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* 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_X86_PREDECODER_HH__
#define __ARCH_X86_PREDECODER_HH__
#include <cassert>
#include "arch/x86/regs/misc.hh"
#include "arch/x86/types.hh"
#include "base/bitfield.hh"
#include "base/misc.hh"
#include "base/trace.hh"
#include "base/types.hh"
#include "debug/Predecoder.hh"
class ThreadContext;
namespace X86ISA
{
class Predecoder
{
private:
//These are defined and documented in predecoder_tables.cc
static const uint8_t Prefixes[256];
static const uint8_t UsesModRM[2][256];
static const uint8_t ImmediateType[2][256];
static const uint8_t SizeTypeToSize[3][10];
protected:
ThreadContext * tc;
//The bytes to be predecoded
MachInst fetchChunk;
//The pc of the start of fetchChunk
Addr basePC;
//The pc the current instruction started at
Addr origPC;
//The offset into fetchChunk of current processing
int offset;
//The extended machine instruction being generated
ExtMachInst emi;
HandyM5Reg m5Reg;
inline uint8_t getNextByte()
{
return ((uint8_t *)&fetchChunk)[offset];
}
void getImmediate(int &collected, uint64_t &current, int size)
{
//Figure out how many bytes we still need to get for the
//immediate.
int toGet = size - collected;
//Figure out how many bytes are left in our "buffer"
int 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
uint64_t partialImm = fetchChunk >> (offset * 8);
//Mask off what we don't want
partialImm &= mask(toGet * 8);
//Shift it over to overlay with our displacement.
partialImm <<= (immediateCollected * 8);
//Put it into our displacement
current |= partialImm;
//Update how many bytes we've collected.
collected += toGet;
consumeBytes(toGet);
}
inline void consumeByte()
{
offset++;
assert(offset <= sizeof(MachInst));
if(offset == sizeof(MachInst))
outOfBytes = true;
}
inline void consumeBytes(int numBytes)
{
offset += numBytes;
assert(offset <= sizeof(MachInst));
if(offset == sizeof(MachInst))
outOfBytes = true;
}
void doReset();
//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;
//The size of the immediate value
int immediateSize;
//This is how much of any immediate value we've gotten. This is used
//for both the actual immediate and the displacement.
int immediateCollected;
enum State {
ResetState,
PrefixState,
OpcodeState,
ModRMState,
SIBState,
DisplacementState,
ImmediateState,
//We should never get to this state. Getting here is an error.
ErrorState
};
State state;
//Functions to handle each of the states
State doPrefixState(uint8_t);
State doOpcodeState(uint8_t);
State doModRMState(uint8_t);
State doSIBState(uint8_t);
State doDisplacementState();
State doImmediateState();
public:
Predecoder(ThreadContext * _tc) :
tc(_tc), basePC(0), origPC(0), offset(0),
outOfBytes(true), emiIsReady(false),
state(ResetState)
{
emi.mode.mode = LongMode;
emi.mode.submode = SixtyFourBitMode;
m5Reg = 0;
}
void reset()
{
state = ResetState;
}
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(const PCState &pc, Addr fetchPC, MachInst data)
{
DPRINTF(Predecoder, "Getting more bytes.\n");
basePC = fetchPC;
offset = (fetchPC >= pc.instAddr()) ? 0 : pc.instAddr() - fetchPC;
fetchChunk = data;
outOfBytes = false;
process();
}
bool needMoreBytes()
{
return outOfBytes;
}
bool extMachInstReady()
{
return emiIsReady;
}
int
getInstSize()
{
int size = basePC + offset - origPC;
DPRINTF(Predecoder,
"Calculating the instruction size: "
"basePC: %#x offset: %#x origPC: %#x size: %d\n",
basePC, offset, origPC, size);
return size;
}
//This returns a constant reference to the ExtMachInst to avoid a copy
const ExtMachInst &
getExtMachInst(X86ISA::PCState &nextPC)
{
assert(emiIsReady);
emiIsReady = false;
if (!nextPC.size()) {
Addr size = getInstSize();
nextPC.size(size);
nextPC.npc(nextPC.pc() + size);
}
return emi;
}
};
}
#endif // __ARCH_X86_PREDECODER_HH__

View file

@ -51,7 +51,7 @@
namespace X86ISA
{
//This really determines how many bytes are passed to the predecoder.
//This really determines how many bytes are passed to the decoder.
typedef uint64_t MachInst;
enum Prefixes {
@ -127,7 +127,7 @@ namespace X86ISA
RealMode
};
//The intermediate structure the x86 predecoder returns.
//The intermediate structure used by the x86 decoder.
struct ExtMachInst
{
//Prefixes

View file

@ -64,11 +64,6 @@ class CheckerCPU;
class ThreadContext;
class System;
namespace TheISA
{
class Predecoder;
}
class CPUProgressEvent : public Event
{
protected:
@ -257,7 +252,6 @@ class BaseCPU : public MemObject
protected:
std::vector<ThreadContext *> threadContexts;
std::vector<TheISA::Predecoder *> predecoders;
Trace::InstTracer * tracer;

View file

@ -47,7 +47,6 @@
#include <map>
#include <queue>
#include "arch/predecoder.hh"
#include "arch/types.hh"
#include "base/statistics.hh"
#include "cpu/base.hh"
@ -156,9 +155,6 @@ class CheckerCPU : public BaseCPU
// keep them all in a std::queue
std::queue<Result> result;
// current instruction
TheISA::MachInst machInst;
// Pointer to the one memory request.
RequestPtr memReq;
@ -401,8 +397,7 @@ class Checker : public CheckerCPU
public:
Checker(Params *p)
: CheckerCPU(p), updateThisCycle(false), unverifiedInst(NULL),
predecoder(NULL)
: CheckerCPU(p), updateThisCycle(false), unverifiedInst(NULL)
{ }
void switchOut();
@ -434,7 +429,6 @@ class Checker : public CheckerCPU
bool updateThisCycle;
DynInstPtr unverifiedInst;
TheISA::Predecoder predecoder;
std::list<DynInstPtr> instList;
typedef typename std::list<DynInstPtr>::iterator InstListIt;

View file

@ -69,7 +69,7 @@ Checker<Impl>::advancePC(Fault fault)
if (fault != NoFault) {
curMacroStaticInst = StaticInst::nullStaticInstPtr;
fault->invoke(tc, curStaticInst);
predecoder.reset();
thread->decoder.reset();
} else {
if (curStaticInst) {
if (curStaticInst->isLastMicroop())
@ -113,7 +113,7 @@ Checker<Impl>::handlePendingInt()
"a non-interuptable instruction!", curTick());
}
boundaryInst = NULL;
predecoder.reset();
thread->decoder.reset();
curMacroStaticInst = StaticInst::nullStaticInstPtr;
}
@ -239,6 +239,8 @@ Checker<Impl>::verify(DynInstPtr &completed_inst)
Addr fetch_PC = thread->instAddr();
fetch_PC = (fetch_PC & PCMask) + fetchOffset;
MachInst machInst;
// If not in the middle of a macro instruction
if (!curMacroStaticInst) {
// set up memory request for instruction fetch
@ -304,24 +306,18 @@ Checker<Impl>::verify(DynInstPtr &completed_inst)
StaticInstPtr instPtr = NULL;
//Predecode, ie bundle up an ExtMachInst
predecoder.setTC(thread->getTC());
thread->decoder.setTC(thread->getTC());
//If more fetch data is needed, pass it in.
Addr fetchPC = (pcState.instAddr() & PCMask) + fetchOffset;
predecoder.moreBytes(pcState, fetchPC, machInst);
thread->decoder.moreBytes(pcState, fetchPC, machInst);
//If an instruction is ready, decode it.
//Otherwise, we'll have to fetch beyond the
//MachInst at the current pc.
if (predecoder.extMachInstReady()) {
if (thread->decoder.instReady()) {
fetchDone = true;
ExtMachInst newMachInst =
predecoder.getExtMachInst(pcState);
instPtr = thread->decoder.decode(pcState);
thread->pcState(pcState);
instPtr = thread->decoder.decode(newMachInst,
pcState.instAddr());
#if THE_ISA != X86_ISA
machInst = newMachInst;
#endif
} else {
fetchDone = false;
fetchOffset += sizeof(TheISA::MachInst);
@ -344,8 +340,8 @@ Checker<Impl>::verify(DynInstPtr &completed_inst)
}
}
}
// reset predecoder on Checker
predecoder.reset();
// reset decoder on Checker
thread->decoder.reset();
// Check Checker and CPU get same instruction, and record
// any faults the CPU may have had.
@ -477,17 +473,9 @@ Checker<Impl>::validateInst(DynInstPtr &inst)
}
}
MachInst mi;
#if THE_ISA != X86_ISA
mi = static_cast<MachInst>(inst->staticInst->machInst);
#endif
if (mi != machInst) {
panic("%lli: Binary instructions do not match! Inst: %#x, "
"checker: %#x",
curTick(), mi, machInst);
handleError(inst);
if (curStaticInst != inst->staticInst) {
warn("%lli: StaticInstPtrs don't match. (%s, %s).\n", curTick(),
curStaticInst->getName(), inst->staticInst->getName());
}
}

View file

@ -1773,9 +1773,9 @@ InOrderCPU::getDTBPtr()
}
TheISA::Decoder *
InOrderCPU::getDecoderPtr()
InOrderCPU::getDecoderPtr(unsigned tid)
{
return &resPool->getInstUnit()->decoder;
return resPool->getInstUnit()->decoder[tid];
}
Fault

View file

@ -342,7 +342,7 @@ class InOrderCPU : public BaseCPU
TheISA::TLB *getITBPtr();
TheISA::TLB *getDTBPtr();
TheISA::Decoder *getDecoderPtr();
TheISA::Decoder *getDecoderPtr(unsigned tid);
/** Accessor Type for the SkedCache */
typedef uint32_t SkedID;

View file

@ -34,7 +34,6 @@
#include "arch/isa_traits.hh"
#include "arch/locked_mem.hh"
#include "arch/predecoder.hh"
#include "arch/utility.hh"
#include "config/the_isa.hh"
#include "cpu/inorder/resources/cache_unit.hh"

View file

@ -36,7 +36,6 @@
#include <string>
#include <vector>
#include "arch/predecoder.hh"
#include "arch/tlb.hh"
#include "base/hashmap.hh"
#include "config/the_isa.hh"

View file

@ -34,7 +34,6 @@
#include "arch/isa_traits.hh"
#include "arch/locked_mem.hh"
#include "arch/predecoder.hh"
#include "arch/utility.hh"
#include "config/the_isa.hh"
#include "cpu/inorder/resources/cache_unit.hh"
@ -60,7 +59,7 @@ FetchUnit::FetchUnit(string res_name, int res_id, int res_width,
instSize(sizeof(TheISA::MachInst)), fetchBuffSize(params->fetchBuffSize)
{
for (int tid = 0; tid < MaxThreads; tid++)
predecoder[tid] = new Predecoder(NULL);
decoder[tid] = new Decoder(NULL);
}
FetchUnit::~FetchUnit()
@ -92,7 +91,6 @@ void
FetchUnit::createMachInst(std::list<FetchBlock*>::iterator fetch_it,
DynInstPtr inst)
{
ExtMachInst ext_inst;
Addr block_addr = cacheBlockAlign(inst->getMemAddr());
Addr fetch_addr = inst->getMemAddr();
unsigned fetch_offset = (fetch_addr - block_addr) / instSize;
@ -111,13 +109,11 @@ FetchUnit::createMachInst(std::list<FetchBlock*>::iterator fetch_it,
MachInst mach_inst =
TheISA::gtoh(fetchInsts[fetch_offset]);
predecoder[tid]->setTC(cpu->thread[tid]->getTC());
predecoder[tid]->moreBytes(instPC, inst->instAddr(), mach_inst);
assert(predecoder[tid]->extMachInstReady());
ext_inst = predecoder[tid]->getExtMachInst(instPC);
decoder[tid]->setTC(cpu->thread[tid]->getTC());
decoder[tid]->moreBytes(instPC, inst->instAddr(), mach_inst);
assert(decoder[tid]->instReady());
inst->setStaticInst(decoder[tid]->decode(instPC));
inst->pcState(instPC);
inst->setStaticInst(decoder.decode(ext_inst, instPC.instAddr()));
}
void
@ -582,7 +578,7 @@ void
FetchUnit::trap(Fault fault, ThreadID tid, DynInstPtr inst)
{
//@todo: per thread?
predecoder[tid]->reset();
decoder[tid]->reset();
//@todo: squash using dummy inst seq num
squash(NULL, NumStages - 1, 0, tid);

View file

@ -37,7 +37,6 @@
#include <vector>
#include "arch/decoder.hh"
#include "arch/predecoder.hh"
#include "arch/tlb.hh"
#include "config/the_isa.hh"
#include "cpu/inorder/resources/cache_unit.hh"
@ -89,7 +88,7 @@ class FetchUnit : public CacheUnit
void trap(Fault fault, ThreadID tid, DynInstPtr inst);
TheISA::Decoder decoder;
TheISA::Decoder *decoder[ThePipeline::MaxThreads];
private:
void squashCacheRequest(CacheReqPtr req_ptr);
@ -129,8 +128,6 @@ class FetchUnit : public CacheUnit
int fetchBuffSize;
TheISA::Predecoder *predecoder[ThePipeline::MaxThreads];
/** Valid Cache Blocks*/
std::list<FetchBlock*> fetchBuffer;

View file

@ -83,7 +83,11 @@ class InOrderThreadContext : public ThreadContext
*/
CheckerCPU *getCheckerCpuPtr() { return NULL; }
TheISA::Decoder *getDecoderPtr() { return cpu->getDecoderPtr(); }
TheISA::Decoder *
getDecoderPtr()
{
return cpu->getDecoderPtr(thread->contextId());
}
System *getSystemPtr() { return cpu->system; }

View file

@ -43,7 +43,6 @@
#include <iomanip>
#include "arch/sparc/decoder.hh"
#include "arch/sparc/predecoder.hh"
#include "arch/sparc/registers.hh"
#include "arch/sparc/utility.hh"
#include "arch/tlb.hh"
@ -146,7 +145,6 @@ Trace::LegionTraceRecord::dump()
{
ostream &outs = Trace::output();
static TheISA::Predecoder predecoder(NULL);
// Compare
bool compared = false;
bool diffPC = false;
@ -423,15 +421,14 @@ Trace::LegionTraceRecord::dump()
<< staticInst->disassemble(m5Pc, debugSymbolTable)
<< endl;
predecoder.setTC(thread);
predecoder.moreBytes(m5Pc, m5Pc, shared_data->instruction);
TheISA::Decoder *decoder = thread->getDecoderPtr();
decoder->setTC(thread);
decoder->moreBytes(m5Pc, m5Pc, shared_data->instruction);
assert(predecoder.extMachInstReady());
assert(decoder->instReady());
PCState tempPC = pc;
StaticInstPtr legionInst =
thread->getDecoderPtr()->decode(
predecoder.getExtMachInst(tempPC), lgnPc);
StaticInstPtr legionInst = decoder->decode(tempPC);
outs << setfill(' ') << setw(15)
<< " Legion Inst: "
<< "0x" << setw(8) << setfill('0') << hex

View file

@ -45,7 +45,6 @@
#define __CPU_O3_FETCH_HH__
#include "arch/decoder.hh"
#include "arch/predecoder.hh"
#include "arch/utility.hh"
#include "base/statistics.hh"
#include "config/the_isa.hh"
@ -340,7 +339,7 @@ class DefaultFetch
}
/** The decoder. */
TheISA::Decoder decoder;
TheISA::Decoder *decoder[Impl::MaxThreads];
private:
DynInstPtr buildInst(ThreadID tid, StaticInstPtr staticInst,
@ -398,9 +397,6 @@ class DefaultFetch
/** BPredUnit. */
BPredUnit branchPred;
/** Predecoder. */
TheISA::Predecoder predecoder;
TheISA::PCState pc[Impl::MaxThreads];
Addr fetchOffset[Impl::MaxThreads];

View file

@ -73,7 +73,6 @@ template<class Impl>
DefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params)
: cpu(_cpu),
branchPred(params),
predecoder(NULL),
numInst(0),
decodeToFetchDelay(params->decodeToFetchDelay),
renameToFetchDelay(params->renameToFetchDelay),
@ -132,6 +131,9 @@ DefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params)
// Get the size of an instruction.
instSize = sizeof(TheISA::MachInst);
for (int i = 0; i < Impl::MaxThreads; i++)
decoder[i] = new TheISA::Decoder(NULL);
}
template <class Impl>
@ -660,7 +662,7 @@ DefaultFetch<Impl>::finishTranslation(Fault fault, RequestPtr mem_req)
DPRINTF(Fetch, "[tid:%i]: Translation faulted, building noop.\n", tid);
// We will use a nop in ordier to carry the fault.
DynInstPtr instruction = buildInst(tid,
decoder.decode(TheISA::NoopMachInst, fetchPC.instAddr()),
decoder[tid]->decode(TheISA::NoopMachInst, fetchPC.instAddr()),
NULL, fetchPC, fetchPC, false);
instruction->setPredTarg(fetchPC);
@ -693,7 +695,7 @@ DefaultFetch<Impl>::doSquash(const TheISA::PCState &newPC,
macroop[tid] = squashInst->macroop;
else
macroop[tid] = NULL;
predecoder.reset();
decoder[tid]->reset();
// Clear the icache miss if it's outstanding.
if (fetchStatus[tid] == IcacheWaitResponse) {
@ -1193,8 +1195,9 @@ DefaultFetch<Impl>::fetch(bool &status_change)
// We need to process more memory if we aren't going to get a
// StaticInst from the rom, the current macroop, or what's already
// in the predecoder.
bool needMem = !inRom && !curMacroop && !predecoder.extMachInstReady();
// in the decoder.
bool needMem = !inRom && !curMacroop &&
!decoder[tid]->instReady();
fetchAddr = (thisPC.instAddr() + pcOffset) & BaseCPU::PCMask;
Addr block_PC = icacheBlockAlignPC(fetchAddr);
@ -1222,10 +1225,10 @@ DefaultFetch<Impl>::fetch(bool &status_change)
}
MachInst inst = TheISA::gtoh(cacheInsts[blkOffset]);
predecoder.setTC(cpu->thread[tid]->getTC());
predecoder.moreBytes(thisPC, fetchAddr, inst);
decoder[tid]->setTC(cpu->thread[tid]->getTC());
decoder[tid]->moreBytes(thisPC, fetchAddr, inst);
if (predecoder.needMoreBytes()) {
if (decoder[tid]->needMoreBytes()) {
blkOffset++;
fetchAddr += instSize;
pcOffset += instSize;
@ -1236,11 +1239,8 @@ DefaultFetch<Impl>::fetch(bool &status_change)
// the memory we've processed so far.
do {
if (!(curMacroop || inRom)) {
if (predecoder.extMachInstReady()) {
ExtMachInst extMachInst =
predecoder.getExtMachInst(thisPC);
staticInst =
decoder.decode(extMachInst, thisPC.instAddr());
if (decoder[tid]->instReady()) {
staticInst = decoder[tid]->decode(thisPC);
// Increment stat of fetched instructions.
++fetchedInsts;
@ -1311,7 +1311,7 @@ DefaultFetch<Impl>::fetch(bool &status_change)
status_change = true;
break;
}
} while ((curMacroop || predecoder.extMachInstReady()) &&
} while ((curMacroop || decoder[tid]->instReady()) &&
numInst < fetchWidth);
}

View file

@ -85,7 +85,11 @@ class O3ThreadContext : public ThreadContext
CheckerCPU *getCheckerCpuPtr() { return NULL; }
TheISA::Decoder *getDecoderPtr() { return &cpu->fetch.decoder; }
TheISA::Decoder *
getDecoderPtr()
{
return cpu->fetch.decoder[thread->threadId()];
}
/** Returns a pointer to this CPU. */
virtual BaseCPU *getCpuPtr() { return cpu; }

View file

@ -465,12 +465,12 @@ AtomicSimpleCPU::tick()
dcache_access = false; // assume no dcache access
if (needToFetch) {
// This is commented out because the predecoder would act like
// This is commented out because the decoder would act like
// a tiny cache otherwise. It wouldn't be flushed when needed
// like the I cache. It should be flushed, and when that works
// this code should be uncommented.
//Fetch more instruction memory if necessary
//if(predecoder.needMoreBytes())
//if(decoder.needMoreBytes())
//{
icache_access = true;
Packet ifetch_pkt = Packet(&ifetch_req, MemCmd::ReadReq);

View file

@ -85,7 +85,7 @@ using namespace std;
using namespace TheISA;
BaseSimpleCPU::BaseSimpleCPU(BaseSimpleCPUParams *p)
: BaseCPU(p), traceData(NULL), thread(NULL), predecoder(NULL)
: BaseCPU(p), traceData(NULL), thread(NULL)
{
if (FullSystem)
thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb);
@ -332,7 +332,7 @@ BaseSimpleCPU::checkForInterrupts()
fetchOffset = 0;
interrupts->updateIntrInfo(tc);
interrupt->invoke(tc);
predecoder.reset();
thread->decoder.reset();
}
}
}
@ -378,23 +378,24 @@ BaseSimpleCPU::preExecute()
//We're not in the middle of a macro instruction
StaticInstPtr instPtr = NULL;
TheISA::Decoder *decoder = &(thread->decoder);
//Predecode, ie bundle up an ExtMachInst
//This should go away once the constructor can be set up properly
predecoder.setTC(thread->getTC());
decoder->setTC(thread->getTC());
//If more fetch data is needed, pass it in.
Addr fetchPC = (pcState.instAddr() & PCMask) + fetchOffset;
//if(predecoder.needMoreBytes())
predecoder.moreBytes(pcState, fetchPC, inst);
//if(decoder->needMoreBytes())
decoder->moreBytes(pcState, fetchPC, inst);
//else
// predecoder.process();
// decoder->process();
//If an instruction is ready, decode it. Otherwise, we'll have to
//Decode an instruction if one is ready. Otherwise, we'll have to
//fetch beyond the MachInst at the current pc.
if (predecoder.extMachInstReady()) {
instPtr = decoder->decode(pcState);
if (instPtr) {
stayAtPC = false;
ExtMachInst machInst = predecoder.getExtMachInst(pcState);
thread->pcState(pcState);
instPtr = thread->decoder.decode(machInst, pcState.instAddr());
} else {
stayAtPC = true;
fetchOffset += sizeof(MachInst);
@ -505,7 +506,7 @@ BaseSimpleCPU::advancePC(Fault fault)
if (fault != NoFault) {
curMacroStaticInst = StaticInst::nullStaticInstPtr;
fault->invoke(tc, curStaticInst);
predecoder.reset();
thread->decoder.reset();
} else {
if (curStaticInst) {
if (curStaticInst->isLastMicroop())

View file

@ -45,8 +45,6 @@
#ifndef __CPU_SIMPLE_BASE_HH__
#define __CPU_SIMPLE_BASE_HH__
#include "arch/decoder.hh"
#include "arch/predecoder.hh"
#include "base/statistics.hh"
#include "config/the_isa.hh"
#include "cpu/base.hh"
@ -71,7 +69,6 @@ namespace TheISA
{
class DTB;
class ITB;
class Predecoder;
}
namespace Trace {
@ -154,9 +151,6 @@ class BaseSimpleCPU : public BaseCPU
// current instruction
TheISA::MachInst inst;
// The predecoder
TheISA::Predecoder predecoder;
StaticInstPtr curStaticInst;
StaticInstPtr curMacroStaticInst;

View file

@ -63,7 +63,7 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys,
Process *_process, TheISA::TLB *_itb,
TheISA::TLB *_dtb)
: ThreadState(_cpu, _thread_num, _process), system(_sys), itb(_itb),
dtb(_dtb)
dtb(_dtb), decoder(NULL)
{
clearArchRegs();
tc = new ProxyThreadContext<SimpleThread>(this);
@ -71,7 +71,8 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys,
SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys,
TheISA::TLB *_itb, TheISA::TLB *_dtb,
bool use_kernel_stats)
: ThreadState(_cpu, _thread_num, NULL), system(_sys), itb(_itb), dtb(_dtb)
: ThreadState(_cpu, _thread_num, NULL), system(_sys), itb(_itb), dtb(_dtb),
decoder(NULL)
{
tc = new ProxyThreadContext<SimpleThread>(this);
@ -98,7 +99,7 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys,
}
SimpleThread::SimpleThread()
: ThreadState(NULL, -1, NULL)
: ThreadState(NULL, -1, NULL), decoder(NULL)
{
tc = new ProxyThreadContext<SimpleThread>(this);
}