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:
parent
eae1e97fb0
commit
0cba96ba6a
43 changed files with 1121 additions and 1548 deletions
|
@ -54,7 +54,6 @@ isa_switch_hdrs = Split('''
|
|||
mmapped_ipr.hh
|
||||
mt.hh
|
||||
process.hh
|
||||
predecoder.hh
|
||||
registers.hh
|
||||
remote_gdb.hh
|
||||
stacktrace.hh
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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__
|
|
@ -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')
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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__
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__
|
|
@ -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
|
||||
|
|
|
@ -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__
|
|
@ -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
|
||||
|
|
|
@ -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__
|
|
@ -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 = (
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 ¤t, 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
|
||||
|
|
|
@ -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
|
|
@ -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.
|
||||
|
|
|
@ -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)',
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 ¤t, 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__
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1773,9 +1773,9 @@ InOrderCPU::getDTBPtr()
|
|||
}
|
||||
|
||||
TheISA::Decoder *
|
||||
InOrderCPU::getDecoderPtr()
|
||||
InOrderCPU::getDecoderPtr(unsigned tid)
|
||||
{
|
||||
return &resPool->getInstUnit()->decoder;
|
||||
return resPool->getInstUnit()->decoder[tid];
|
||||
}
|
||||
|
||||
Fault
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue