diff options
author | Gabe Black <gblack@eecs.umich.edu> | 2012-05-26 13:44:46 -0700 |
---|---|---|
committer | Gabe Black <gblack@eecs.umich.edu> | 2012-05-26 13:44:46 -0700 |
commit | 0cba96ba6a5d7a4dab2a63b14149c49dfbfbb3bc (patch) | |
tree | 1e4e1372b76ed021060d560c2ee1a474f4b22ef0 /src/arch | |
parent | eae1e97fb002b44a9d8c46df2da1ddc1d0156ce4 (diff) | |
download | gem5-0cba96ba6a5d7a4dab2a63b14149c49dfbfbb3bc.tar.xz |
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
Diffstat (limited to 'src/arch')
25 files changed, 1049 insertions, 1440 deletions
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,6 +34,7 @@ #include "arch/types.hh" #include "cpu/decode_cache.hh" #include "cpu/static_inst_fwd.hh" +#include "sim/full_system.hh" namespace AlphaISA { @@ -41,6 +42,62 @@ namespace AlphaISA class Decoder { protected: + ThreadContext *tc; + + // The extended machine instruction being generated + ExtMachInst ext_inst; + bool instDone; + + public: + Decoder(ThreadContext * _tc) : tc(_tc), instDone(false) + {} + + ThreadContext * + getTC() + { + return tc; + } + + void + setTC(ThreadContext * _tc) + { + tc = _tc; + } + + void + process() + { } + + void + reset() + { + instDone = false; + } + + // Use this to give data to the predecoder. This should be used + // when there is control flow. + void + moreBytes(const PCState &pc, Addr fetchPC, MachInst inst) + { + ext_inst = inst; + instDone = true; + if (FullSystem) + ext_inst |= (static_cast<ExtMachInst>(pc.pc() & 0x1) << 32); + } + + bool + needMoreBytes() + { + return true; + } + + bool + instReady() + { + return instDone; + } + + protected: /// A cache of decoded instruction objects. static DecodeCache defaultCache; @@ -55,6 +112,15 @@ class Decoder { return defaultCache.decode(this, mach_inst, addr); } + + StaticInstPtr + decode(AlphaISA::PCState &nextPC) + { + if (!instDone) + return NULL; + instDone = false; + return decode(ext_inst, nextPC.instAddr()); + } }; } // namespace AlphaISA 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 <cmath> +#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<ExtMachInst>(pc.pc() & 0x1) << 32); - } - - bool - needMoreBytes() - { - return true; - } - - bool - extMachInstReady() - { - return emiIsReady; - } - - // This returns a constant reference to the ExtMachInst to avoid a copy - const ExtMachInst & - getExtMachInst(PCState &pc) - { - emiIsReady = false; - return ext_inst; - } -}; - -} // namespace AlphaISA - -#endif // __ARCH_ALPHA_PREDECODER_HH__ 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,9 +31,14 @@ #ifndef __ARCH_ARM_DECODER_HH__ #define __ARCH_ARM_DECODER_HH__ -#include "arch/types.hh" +#include <cassert> + +#include "arch/arm/miscregs.hh" +#include "arch/arm/types.hh" +#include "base/types.hh" #include "cpu/decode_cache.hh" -#include "cpu/static_inst_fwd.hh" + +class ThreadContext; namespace ArmISA { @@ -41,6 +46,81 @@ 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 <cassert> - -#include "arch/arm/miscregs.hh" -#include "arch/arm/types.hh" -#include "base/types.hh" - -class ThreadContext; - -namespace ArmISA -{ - class Predecoder - { - protected: - ThreadContext * tc; - //The extended machine instruction being generated - ExtMachInst emi; - MachInst data; - bool bigThumb; - bool emiReady; - bool outOfBytes; - int offset; - bool foundIt; - ITSTATE itBits; - - public: - void reset() - { - bigThumb = false; - offset = 0; - emi = 0; - emiReady = false; - outOfBytes = true; - foundIt = false; - } - - Predecoder(ThreadContext * _tc) : - tc(_tc), data(0) - { - reset(); - } - - ThreadContext * getTC() - { - return tc; - } - - void - setTC(ThreadContext * _tc) - { - tc = _tc; - } - - void process(); - - //Use this to give data to the predecoder. This should be used - //when there is control flow. - void moreBytes(const PCState &pc, Addr fetchPC, MachInst inst); - - //Use this to give data to the predecoder. This should be used - //when instructions are executed in order. - void moreBytes(MachInst machInst) - { - moreBytes(0, 0, machInst); - } - - inline void consumeBytes(int numBytes) - { - offset += numBytes; - assert(offset <= sizeof(MachInst)); - if (offset == sizeof(MachInst)) - outOfBytes = true; - } - - bool needMoreBytes() const - { - return outOfBytes; - } - - bool extMachInstReady() const - { - return emiReady; - } - - int getInstSize() const - { - return (!emi.thumb || emi.bigThumb) ? 4 : 2; - } - - //This returns a constant reference to the ExtMachInst to avoid a copy - ExtMachInst getExtMachInst(PCState &pc) - { - assert(emiReady); - ExtMachInst thisEmi = emi; - pc.npc(pc.pc() + getInstSize()); - if (foundIt) - pc.nextItstate(itBits); - thisEmi.itstate = pc.itstate(); - pc.size(getInstSize()); - emi = 0; - emiReady = false; - foundIt = false; - return thisEmi; - } - }; -} - -#endif // __ARCH_ARM_PREDECODER_HH__ 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,16 +31,73 @@ #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 @@ -41,6 +41,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,9 +31,13 @@ #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 { @@ -41,6 +45,69 @@ namespace SparcISA class Decoder { protected: + ThreadContext * tc; + // The extended machine instruction being generated + ExtMachInst emi; + bool instDone; + + public: + Decoder(ThreadContext * _tc) : tc(_tc), instDone(false) + {} + + ThreadContext * + getTC() + { + return tc; + } + + void + setTC(ThreadContext * _tc) + { + tc = _tc; + } + + void process() {} + + void + reset() + { + instDone = false; + } + + // Use this to give data to the predecoder. This should be used + // when there is control flow. + void + moreBytes(const PCState &pc, Addr fetchPC, MachInst inst) + { + emi = inst; + // The I bit, bit 13, is used to figure out where the ASI + // should come from. Use that in the ExtMachInst. This is + // slightly redundant, but it removes the need to put a condition + // into all the execute functions + if (inst & (1 << 13)) { + emi |= (static_cast<ExtMachInst>( + tc->readMiscRegNoEffect(MISCREG_ASI)) + << (sizeof(MachInst) * 8)); + } else { + emi |= (static_cast<ExtMachInst>(bits(inst, 12, 5)) + << (sizeof(MachInst) * 8)); + } + instDone = true; + } + + bool + needMoreBytes() + { + return true; + } + + bool + instReady() + { + return instDone; + } + + protected: /// A cache of decoded instruction objects. static DecodeCache defaultCache; @@ -55,6 +122,15 @@ class Decoder { return defaultCache.decode(this, mach_inst, addr); } + + StaticInstPtr + decode(SparcISA::PCState &nextPC) + { + if (!instDone) + return NULL; + instDone = false; + return decode(emi, nextPC.instAddr()); + } }; } // namespace SparcISA 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<ExtMachInst>( - tc->readMiscRegNoEffect(MISCREG_ASI)) - << (sizeof(MachInst) * 8)); - } else { - emi |= (static_cast<ExtMachInst>(bits(inst, 12, 5)) - << (sizeof(MachInst) * 8)); - } - emiIsReady = true; - } - - bool - needMoreBytes() - { - return true; - } - - bool - extMachInstReady() - { - return emiIsReady; - } - - // This returns a constant reference to the ExtMachInst to avoid a copy - const ExtMachInst & - getExtMachInst(PCState &pcState) - { - emiIsReady = false; - return emi; - } -}; -}; - -#endif // __ARCH_SPARC_PREDECODER_HH__ 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 <cassert> + +#include "arch/x86/regs/misc.hh" +#include "arch/x86/types.hh" +#include "base/bitfield.hh" +#include "base/misc.hh" +#include "base/trace.hh" +#include "base/types.hh" #include "cpu/decode_cache.hh" #include "cpu/static_inst_fwd.hh" +#include "debug/Decoder.hh" + +class ThreadContext; namespace X86ISA { class Decoder { + private: + //These are defined and documented in decoder_tables.cc + static const uint8_t Prefixes[256]; + static const uint8_t UsesModRM[2][256]; + static const uint8_t ImmediateType[2][256]; + static const uint8_t SizeTypeToSize[3][10]; + + protected: + ThreadContext * tc; + //The bytes to be predecoded + MachInst fetchChunk; + //The pc of the start of fetchChunk + Addr basePC; + //The pc the current instruction started at + Addr origPC; + //The offset into fetchChunk of current processing + int offset; + //The extended machine instruction being generated + ExtMachInst emi; + HandyM5Reg m5Reg; + + inline uint8_t getNextByte() + { + return ((uint8_t *)&fetchChunk)[offset]; + } + + void getImmediate(int &collected, uint64_t ¤t, int size) + { + //Figure out how many bytes we still need to get for the + //immediate. + int toGet = size - collected; + //Figure out how many bytes are left in our "buffer" + int remaining = sizeof(MachInst) - offset; + //Get as much as we need, up to the amount available. + toGet = toGet > remaining ? remaining : toGet; + + //Shift the bytes we want to be all the way to the right + uint64_t partialImm = fetchChunk >> (offset * 8); + //Mask off what we don't want + partialImm &= mask(toGet * 8); + //Shift it over to overlay with our displacement. + partialImm <<= (immediateCollected * 8); + //Put it into our displacement + current |= partialImm; + //Update how many bytes we've collected. + collected += toGet; + consumeBytes(toGet); + } + + inline void consumeByte() + { + offset++; + assert(offset <= sizeof(MachInst)); + if(offset == sizeof(MachInst)) + outOfBytes = true; + } + + inline void consumeBytes(int numBytes) + { + offset += numBytes; + assert(offset <= sizeof(MachInst)); + if(offset == sizeof(MachInst)) + outOfBytes = true; + } + + void doReset(); + + //State machine state + protected: + //Whether or not we're out of bytes + bool outOfBytes; + //Whether we've completed generating an ExtMachInst + bool instDone; + //The size of the displacement value + int displacementSize; + //The size of the immediate value + int immediateSize; + //This is how much of any immediate value we've gotten. This is used + //for both the actual immediate and the displacement. + int immediateCollected; + + enum State { + ResetState, + PrefixState, + OpcodeState, + ModRMState, + SIBState, + DisplacementState, + ImmediateState, + //We should never get to this state. Getting here is an error. + ErrorState + }; + + State state; + + //Functions to handle each of the states + State doPrefixState(uint8_t); + State doOpcodeState(uint8_t); + State doModRMState(uint8_t); + State doSIBState(uint8_t); + State doDisplacementState(); + State doImmediateState(); + + public: + Decoder(ThreadContext * _tc) : + tc(_tc), basePC(0), origPC(0), offset(0), + outOfBytes(true), instDone(false), + state(ResetState) + { + emi.mode.mode = LongMode; + emi.mode.submode = SixtyFourBitMode; + m5Reg = 0; + } + + void reset() + { + state = ResetState; + } + + ThreadContext * getTC() + { + return tc; + } + + void setTC(ThreadContext * _tc) + { + tc = _tc; + } + + void process(); + + //Use this to give data to the decoder. This should be used + //when there is control flow. + void moreBytes(const PCState &pc, Addr fetchPC, MachInst data) + { + DPRINTF(Decoder, "Getting more bytes.\n"); + basePC = fetchPC; + offset = (fetchPC >= pc.instAddr()) ? 0 : pc.instAddr() - fetchPC; + fetchChunk = data; + outOfBytes = false; + process(); + } + + bool needMoreBytes() + { + return outOfBytes; + } + + bool instReady() + { + return instDone; + } + + void + updateNPC(X86ISA::PCState &nextPC) + { + if (!nextPC.size()) { + int size = basePC + offset - origPC; + DPRINTF(Decoder, + "Calculating the instruction size: " + "basePC: %#x offset: %#x origPC: %#x size: %d\n", + basePC, offset, origPC, size); + nextPC.size(size); + nextPC.npc(nextPC.pc() + size); + } + } + protected: /// A cache of decoded instruction objects. static DecodeCache defaultCache; @@ -55,6 +232,16 @@ class Decoder { return defaultCache.decode(this, mach_inst, addr); } + + StaticInstPtr + decode(X86ISA::PCState &nextPC) + { + if (!instDone) + return NULL; + instDone = false; + updateNPC(nextPC); + return decode(emi, origPC); + } }; } // namespace X86ISA diff --git a/src/arch/x86/predecoder_tables.cc b/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 <cassert> - -#include "arch/x86/regs/misc.hh" -#include "arch/x86/types.hh" -#include "base/bitfield.hh" -#include "base/misc.hh" -#include "base/trace.hh" -#include "base/types.hh" -#include "debug/Predecoder.hh" - -class ThreadContext; - -namespace X86ISA -{ - class Predecoder - { - private: - //These are defined and documented in predecoder_tables.cc - static const uint8_t Prefixes[256]; - static const uint8_t UsesModRM[2][256]; - static const uint8_t ImmediateType[2][256]; - static const uint8_t SizeTypeToSize[3][10]; - - protected: - ThreadContext * tc; - //The bytes to be predecoded - MachInst fetchChunk; - //The pc of the start of fetchChunk - Addr basePC; - //The pc the current instruction started at - Addr origPC; - //The offset into fetchChunk of current processing - int offset; - //The extended machine instruction being generated - ExtMachInst emi; - HandyM5Reg m5Reg; - - inline uint8_t getNextByte() - { - return ((uint8_t *)&fetchChunk)[offset]; - } - - void getImmediate(int &collected, uint64_t ¤t, int size) - { - //Figure out how many bytes we still need to get for the - //immediate. - int toGet = size - collected; - //Figure out how many bytes are left in our "buffer" - int remaining = sizeof(MachInst) - offset; - //Get as much as we need, up to the amount available. - toGet = toGet > remaining ? remaining : toGet; - - //Shift the bytes we want to be all the way to the right - uint64_t partialImm = fetchChunk >> (offset * 8); - //Mask off what we don't want - partialImm &= mask(toGet * 8); - //Shift it over to overlay with our displacement. - partialImm <<= (immediateCollected * 8); - //Put it into our displacement - current |= partialImm; - //Update how many bytes we've collected. - collected += toGet; - consumeBytes(toGet); - } - - inline void consumeByte() - { - offset++; - assert(offset <= sizeof(MachInst)); - if(offset == sizeof(MachInst)) - outOfBytes = true; - } - - inline void consumeBytes(int numBytes) - { - offset += numBytes; - assert(offset <= sizeof(MachInst)); - if(offset == sizeof(MachInst)) - outOfBytes = true; - } - - void doReset(); - - //State machine state - protected: - //Whether or not we're out of bytes - bool outOfBytes; - //Whether we've completed generating an ExtMachInst - bool emiIsReady; - //The size of the displacement value - int displacementSize; - //The size of the immediate value - int immediateSize; - //This is how much of any immediate value we've gotten. This is used - //for both the actual immediate and the displacement. - int immediateCollected; - - enum State { - ResetState, - PrefixState, - OpcodeState, - ModRMState, - SIBState, - DisplacementState, - ImmediateState, - //We should never get to this state. Getting here is an error. - ErrorState - }; - - State state; - - //Functions to handle each of the states - State doPrefixState(uint8_t); - State doOpcodeState(uint8_t); - State doModRMState(uint8_t); - State doSIBState(uint8_t); - State doDisplacementState(); - State doImmediateState(); - - public: - Predecoder(ThreadContext * _tc) : - tc(_tc), basePC(0), origPC(0), offset(0), - outOfBytes(true), emiIsReady(false), - state(ResetState) - { - emi.mode.mode = LongMode; - emi.mode.submode = SixtyFourBitMode; - m5Reg = 0; - } - - void reset() - { - state = ResetState; - } - - ThreadContext * getTC() - { - return tc; - } - - void setTC(ThreadContext * _tc) - { - tc = _tc; - } - - void process(); - - //Use this to give data to the predecoder. This should be used - //when there is control flow. - void moreBytes(const PCState &pc, Addr fetchPC, MachInst data) - { - DPRINTF(Predecoder, "Getting more bytes.\n"); - basePC = fetchPC; - offset = (fetchPC >= pc.instAddr()) ? 0 : pc.instAddr() - fetchPC; - fetchChunk = data; - outOfBytes = false; - process(); - } - - bool needMoreBytes() - { - return outOfBytes; - } - - bool extMachInstReady() - { - return emiIsReady; - } - - int - getInstSize() - { - int size = basePC + offset - origPC; - DPRINTF(Predecoder, - "Calculating the instruction size: " - "basePC: %#x offset: %#x origPC: %#x size: %d\n", - basePC, offset, origPC, size); - return size; - } - - //This returns a constant reference to the ExtMachInst to avoid a copy - const ExtMachInst & - getExtMachInst(X86ISA::PCState &nextPC) - { - assert(emiIsReady); - emiIsReady = false; - if (!nextPC.size()) { - Addr size = getInstSize(); - nextPC.size(size); - nextPC.npc(nextPC.pc() + size); - } - return emi; - } - }; -} - -#endif // __ARCH_X86_PREDECODER_HH__ 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 |