From 0cba96ba6a5d7a4dab2a63b14149c49dfbfbb3bc Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sat, 26 May 2012 13:44:46 -0700 Subject: [PATCH] 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 --- src/arch/SConscript | 1 - src/arch/alpha/decoder.hh | 66 +++ src/arch/alpha/isa/main.isa | 1 + src/arch/alpha/predecoder.hh | 113 ----- src/arch/arm/SConscript | 5 +- src/arch/arm/decoder.cc | 88 +++- src/arch/arm/decoder.hh | 103 ++++- src/arch/arm/predecoder.cc | 135 ------ src/arch/arm/predecoder.hh | 154 ------- src/arch/arm/types.hh | 6 +- src/arch/mips/decoder.hh | 68 ++- src/arch/mips/predecoder.hh | 110 ----- src/arch/power/decoder.hh | 72 +++ src/arch/power/predecoder.hh | 125 ------ src/arch/sparc/decoder.hh | 76 ++++ src/arch/sparc/predecoder.hh | 121 ----- src/arch/x86/SConscript | 5 +- src/arch/x86/decoder.cc | 375 ++++++++++++++++ src/arch/x86/decoder.hh | 189 +++++++- ...predecoder_tables.cc => decoder_tables.cc} | 10 +- src/arch/x86/emulenv.cc | 2 +- src/arch/x86/isa/decoder/one_byte_opcodes.isa | 2 +- src/arch/x86/predecoder.cc | 419 ------------------ src/arch/x86/predecoder.hh | 239 ---------- src/arch/x86/types.hh | 4 +- src/cpu/base.hh | 6 - src/cpu/checker/cpu.hh | 8 +- src/cpu/checker/cpu_impl.hh | 38 +- src/cpu/inorder/cpu.cc | 4 +- src/cpu/inorder/cpu.hh | 2 +- src/cpu/inorder/resources/cache_unit.cc | 1 - src/cpu/inorder/resources/cache_unit.hh | 1 - src/cpu/inorder/resources/fetch_unit.cc | 16 +- src/cpu/inorder/resources/fetch_unit.hh | 5 +- src/cpu/inorder/thread_context.hh | 6 +- src/cpu/legiontrace.cc | 13 +- src/cpu/o3/fetch.hh | 6 +- src/cpu/o3/fetch_impl.hh | 28 +- src/cpu/o3/thread_context.hh | 6 +- src/cpu/simple/atomic.cc | 4 +- src/cpu/simple/base.cc | 23 +- src/cpu/simple/base.hh | 6 - src/cpu/simple_thread.cc | 7 +- 43 files changed, 1121 insertions(+), 1548 deletions(-) delete mode 100644 src/arch/alpha/predecoder.hh delete mode 100644 src/arch/arm/predecoder.cc delete mode 100644 src/arch/arm/predecoder.hh delete mode 100644 src/arch/mips/predecoder.hh delete mode 100644 src/arch/power/predecoder.hh delete mode 100644 src/arch/sparc/predecoder.hh rename src/arch/x86/{predecoder_tables.cc => decoder_tables.cc} (97%) delete mode 100644 src/arch/x86/predecoder.cc delete mode 100644 src/arch/x86/predecoder.hh diff --git a/src/arch/SConscript b/src/arch/SConscript index f271f487f..b4f94a65f 100644 --- a/src/arch/SConscript +++ b/src/arch/SConscript @@ -54,7 +54,6 @@ isa_switch_hdrs = Split(''' mmapped_ipr.hh mt.hh process.hh - predecoder.hh registers.hh remote_gdb.hh stacktrace.hh diff --git a/src/arch/alpha/decoder.hh b/src/arch/alpha/decoder.hh index a41ed06bb..4233c2d44 100644 --- a/src/arch/alpha/decoder.hh +++ b/src/arch/alpha/decoder.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(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 diff --git a/src/arch/alpha/isa/main.isa b/src/arch/alpha/isa/main.isa index 1bc00e753..cb43c1357 100644 --- a/src/arch/alpha/isa/main.isa +++ b/src/arch/alpha/isa/main.isa @@ -73,6 +73,7 @@ using namespace AlphaISA; output exec {{ #include +#include "arch/alpha/decoder.hh" #include "arch/alpha/registers.hh" #include "arch/alpha/regredir.hh" #include "arch/generic/memhelpers.hh" diff --git a/src/arch/alpha/predecoder.hh b/src/arch/alpha/predecoder.hh deleted file mode 100644 index a08cddaec..000000000 --- a/src/arch/alpha/predecoder.hh +++ /dev/null @@ -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(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__ diff --git a/src/arch/arm/SConscript b/src/arch/arm/SConscript index 0f94455bd..44b6286a0 100644 --- a/src/arch/arm/SConscript +++ b/src/arch/arm/SConscript @@ -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') diff --git a/src/arch/arm/decoder.cc b/src/arch/arm/decoder.cc index be46ff540..65badbc49 100644 --- a/src/arch/arm/decoder.cc +++ b/src/arch/arm/decoder.cc @@ -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(); +} + } diff --git a/src/arch/arm/decoder.hh b/src/arch/arm/decoder.hh index a91d70f48..dd51fd082 100644 --- a/src/arch/arm/decoder.hh +++ b/src/arch/arm/decoder.hh @@ -31,15 +31,95 @@ #ifndef __ARCH_ARM_DECODER_HH__ #define __ARCH_ARM_DECODER_HH__ -#include "arch/types.hh" +#include + +#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 diff --git a/src/arch/arm/predecoder.cc b/src/arch/arm/predecoder.cc deleted file mode 100644 index a221f4e30..000000000 --- a/src/arch/arm/predecoder.cc +++ /dev/null @@ -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(); -} - -} diff --git a/src/arch/arm/predecoder.hh b/src/arch/arm/predecoder.hh deleted file mode 100644 index 87ba1777c..000000000 --- a/src/arch/arm/predecoder.hh +++ /dev/null @@ -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 - -#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__ diff --git a/src/arch/arm/types.hh b/src/arch/arm/types.hh index 31dec7bcb..ebebbcc46 100644 --- a/src/arch/arm/types.hh +++ b/src/arch/arm/types.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; diff --git a/src/arch/mips/decoder.hh b/src/arch/mips/decoder.hh index f5940daad..95385961d 100644 --- a/src/arch/mips/decoder.hh +++ b/src/arch/mips/decoder.hh @@ -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 diff --git a/src/arch/mips/predecoder.hh b/src/arch/mips/predecoder.hh deleted file mode 100644 index 4220b768c..000000000 --- a/src/arch/mips/predecoder.hh +++ /dev/null @@ -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__ diff --git a/src/arch/power/decoder.hh b/src/arch/power/decoder.hh index 34537bb56..c45473a90 100644 --- a/src/arch/power/decoder.hh +++ b/src/arch/power/decoder.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 diff --git a/src/arch/power/predecoder.hh b/src/arch/power/predecoder.hh deleted file mode 100644 index 8b1089095..000000000 --- a/src/arch/power/predecoder.hh +++ /dev/null @@ -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__ diff --git a/src/arch/sparc/decoder.hh b/src/arch/sparc/decoder.hh index 9c8e740b8..999a605a7 100644 --- a/src/arch/sparc/decoder.hh +++ b/src/arch/sparc/decoder.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( + tc->readMiscRegNoEffect(MISCREG_ASI)) + << (sizeof(MachInst) * 8)); + } else { + emi |= (static_cast(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 diff --git a/src/arch/sparc/predecoder.hh b/src/arch/sparc/predecoder.hh deleted file mode 100644 index a7a543621..000000000 --- a/src/arch/sparc/predecoder.hh +++ /dev/null @@ -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( - tc->readMiscRegNoEffect(MISCREG_ASI)) - << (sizeof(MachInst) * 8)); - } else { - emi |= (static_cast(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__ diff --git a/src/arch/x86/SConscript b/src/arch/x86/SConscript index 27b12fe20..92b30ced1 100644 --- a/src/arch/x86/SConscript +++ b/src/arch/x86/SConscript @@ -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 = ( diff --git a/src/arch/x86/decoder.cc b/src/arch/x86/decoder.cc index 469858301..d7199fa82 100644 --- a/src/arch/x86/decoder.cc +++ b/src/arch/x86/decoder.cc @@ -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; diff --git a/src/arch/x86/decoder.hh b/src/arch/x86/decoder.hh index 769284adb..300e2238c 100644 --- a/src/arch/x86/decoder.hh +++ b/src/arch/x86/decoder.hh @@ -31,15 +31,192 @@ #ifndef __ARCH_X86_DECODER_HH__ #define __ARCH_X86_DECODER_HH__ -#include "arch/types.hh" +#include + +#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 diff --git a/src/arch/x86/predecoder_tables.cc b/src/arch/x86/decoder_tables.cc similarity index 97% rename from src/arch/x86/predecoder_tables.cc rename to src/arch/x86/decoder_tables.cc index 3931e4c30..a132cb864 100644 --- a/src/arch/x86/predecoder_tables.cc +++ b/src/arch/x86/decoder_tables.cc @@ -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 diff --git a/src/arch/x86/emulenv.cc b/src/arch/x86/emulenv.cc index e6c170d0f..49df32eca 100644 --- a/src/arch/x86/emulenv.cc +++ b/src/arch/x86/emulenv.cc @@ -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. diff --git a/src/arch/x86/isa/decoder/one_byte_opcodes.isa b/src/arch/x86/isa/decoder/one_byte_opcodes.isa index 66a0c8c46..040f5d04f 100644 --- a/src/arch/x86/isa/decoder/one_byte_opcodes.isa +++ b/src/arch/x86/isa/decoder/one_byte_opcodes.isa @@ -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)', diff --git a/src/arch/x86/predecoder.cc b/src/arch/x86/predecoder.cc deleted file mode 100644 index a4aa93b48..000000000 --- a/src/arch/x86/predecoder.cc +++ /dev/null @@ -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; - } -} diff --git a/src/arch/x86/predecoder.hh b/src/arch/x86/predecoder.hh deleted file mode 100644 index f7c63684d..000000000 --- a/src/arch/x86/predecoder.hh +++ /dev/null @@ -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 - -#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__ diff --git a/src/arch/x86/types.hh b/src/arch/x86/types.hh index 6d9f600ff..a604c3efc 100644 --- a/src/arch/x86/types.hh +++ b/src/arch/x86/types.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 diff --git a/src/cpu/base.hh b/src/cpu/base.hh index 5d88e064b..b99b25d17 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -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 threadContexts; - std::vector predecoders; Trace::InstTracer * tracer; diff --git a/src/cpu/checker/cpu.hh b/src/cpu/checker/cpu.hh index d816578ae..72dc2ce3e 100644 --- a/src/cpu/checker/cpu.hh +++ b/src/cpu/checker/cpu.hh @@ -47,7 +47,6 @@ #include #include -#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; - // 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 instList; typedef typename std::list::iterator InstListIt; diff --git a/src/cpu/checker/cpu_impl.hh b/src/cpu/checker/cpu_impl.hh index dcc6b01f9..40f1cef6a 100644 --- a/src/cpu/checker/cpu_impl.hh +++ b/src/cpu/checker/cpu_impl.hh @@ -69,7 +69,7 @@ Checker::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::handlePendingInt() "a non-interuptable instruction!", curTick()); } boundaryInst = NULL; - predecoder.reset(); + thread->decoder.reset(); curMacroStaticInst = StaticInst::nullStaticInstPtr; } @@ -239,6 +239,8 @@ Checker::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::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::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::validateInst(DynInstPtr &inst) } } - - MachInst mi; -#if THE_ISA != X86_ISA - mi = static_cast(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()); } } diff --git a/src/cpu/inorder/cpu.cc b/src/cpu/inorder/cpu.cc index 9ad0a2680..3c27cf4b2 100644 --- a/src/cpu/inorder/cpu.cc +++ b/src/cpu/inorder/cpu.cc @@ -1773,9 +1773,9 @@ InOrderCPU::getDTBPtr() } TheISA::Decoder * -InOrderCPU::getDecoderPtr() +InOrderCPU::getDecoderPtr(unsigned tid) { - return &resPool->getInstUnit()->decoder; + return resPool->getInstUnit()->decoder[tid]; } Fault diff --git a/src/cpu/inorder/cpu.hh b/src/cpu/inorder/cpu.hh index 29fe6bc3b..615d0eb90 100644 --- a/src/cpu/inorder/cpu.hh +++ b/src/cpu/inorder/cpu.hh @@ -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; diff --git a/src/cpu/inorder/resources/cache_unit.cc b/src/cpu/inorder/resources/cache_unit.cc index a4dc23d47..21d7bb6e2 100644 --- a/src/cpu/inorder/resources/cache_unit.cc +++ b/src/cpu/inorder/resources/cache_unit.cc @@ -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" diff --git a/src/cpu/inorder/resources/cache_unit.hh b/src/cpu/inorder/resources/cache_unit.hh index f0878d24d..dda39a7a5 100644 --- a/src/cpu/inorder/resources/cache_unit.hh +++ b/src/cpu/inorder/resources/cache_unit.hh @@ -36,7 +36,6 @@ #include #include -#include "arch/predecoder.hh" #include "arch/tlb.hh" #include "base/hashmap.hh" #include "config/the_isa.hh" diff --git a/src/cpu/inorder/resources/fetch_unit.cc b/src/cpu/inorder/resources/fetch_unit.cc index cc4b8b53e..07669ef2a 100644 --- a/src/cpu/inorder/resources/fetch_unit.cc +++ b/src/cpu/inorder/resources/fetch_unit.cc @@ -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::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::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); diff --git a/src/cpu/inorder/resources/fetch_unit.hh b/src/cpu/inorder/resources/fetch_unit.hh index eb99cd570..82d5d99e0 100644 --- a/src/cpu/inorder/resources/fetch_unit.hh +++ b/src/cpu/inorder/resources/fetch_unit.hh @@ -37,7 +37,6 @@ #include #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 fetchBuffer; diff --git a/src/cpu/inorder/thread_context.hh b/src/cpu/inorder/thread_context.hh index b7d0dda9c..9b588cde0 100644 --- a/src/cpu/inorder/thread_context.hh +++ b/src/cpu/inorder/thread_context.hh @@ -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; } diff --git a/src/cpu/legiontrace.cc b/src/cpu/legiontrace.cc index 34c732c54..c000f57fc 100644 --- a/src/cpu/legiontrace.cc +++ b/src/cpu/legiontrace.cc @@ -43,7 +43,6 @@ #include #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 diff --git a/src/cpu/o3/fetch.hh b/src/cpu/o3/fetch.hh index 474834889..6bf5f4588 100644 --- a/src/cpu/o3/fetch.hh +++ b/src/cpu/o3/fetch.hh @@ -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]; diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh index f4ce77f22..b6eb25c08 100644 --- a/src/cpu/o3/fetch_impl.hh +++ b/src/cpu/o3/fetch_impl.hh @@ -73,7 +73,6 @@ template DefaultFetch::DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params) : cpu(_cpu), branchPred(params), - predecoder(NULL), numInst(0), decodeToFetchDelay(params->decodeToFetchDelay), renameToFetchDelay(params->renameToFetchDelay), @@ -132,6 +131,9 @@ DefaultFetch::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 @@ -660,7 +662,7 @@ DefaultFetch::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::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::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::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::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::fetch(bool &status_change) status_change = true; break; } - } while ((curMacroop || predecoder.extMachInstReady()) && + } while ((curMacroop || decoder[tid]->instReady()) && numInst < fetchWidth); } diff --git a/src/cpu/o3/thread_context.hh b/src/cpu/o3/thread_context.hh index b4108e25c..5c236ee0c 100755 --- a/src/cpu/o3/thread_context.hh +++ b/src/cpu/o3/thread_context.hh @@ -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; } diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index 87f41a721..f12c2c174 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -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); diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc index ca4090870..bdc4b0f44 100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@ -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()) diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh index 34b039fc0..9bf144326 100644 --- a/src/cpu/simple/base.hh +++ b/src/cpu/simple/base.hh @@ -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; diff --git a/src/cpu/simple_thread.cc b/src/cpu/simple_thread.cc index 1781c2850..c114d04ac 100644 --- a/src/cpu/simple_thread.cc +++ b/src/cpu/simple_thread.cc @@ -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(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(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(this); } -- 2.30.2