diff options
Diffstat (limited to 'src')
29 files changed, 2060 insertions, 495 deletions
diff --git a/src/arch/SConscript b/src/arch/SConscript index c3ff69f46..0ac25b6c7 100644 --- a/src/arch/SConscript +++ b/src/arch/SConscript @@ -51,6 +51,7 @@ isa_switch_hdrs = Split(''' locked_mem.hh mmaped_ipr.hh process.hh + predecoder.hh regfile.hh remote_gdb.hh stacktrace.hh diff --git a/src/arch/alpha/predecoder.hh b/src/arch/alpha/predecoder.hh new file mode 100644 index 000000000..4e89f53a6 --- /dev/null +++ b/src/arch/alpha/predecoder.hh @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_ALPHA_PREDECODER_HH__ +#define __ARCH_ALPHA_PREDECODER_HH__ + +#include "arch/alpha/types.hh" +#include "base/misc.hh" +#include "sim/host.hh" + +class ThreadContext; + +namespace AlphaISA +{ + class Predecoder + { + protected: + ThreadContext * tc; + //The pc of the current instruction + Addr fetchPC; + //The extended machine instruction being generated + ExtMachInst ext_inst; + + public: + Predecoder(ThreadContext * _tc) : tc(_tc) + {} + + ThreadContext * getTC() + { + return tc; + } + + void setTC(ThreadContext * _tc) + { + tc = _tc; + } + + void process() + { + } + + //Use this to give data to the predecoder. This should be used + //when there is control flow. + void moreBytes(Addr pc, Addr off, MachInst inst) + { + fetchPC = pc; + assert(off == 0); + ext_inst = inst; +#if FULL_SYSTEM + if (pc && 0x1) + ext_inst|=(static_cast<ExtMachInst>(pc & 0x1) << 32); +#endif + } + + //Use this to give data to the predecoder. This should be used + //when instructions are executed in order. + void moreBytes(MachInst machInst) + { + moreBytes(fetchPC + sizeof(machInst), 0, machInst); + } + + bool needMoreBytes() + { + return true; + } + + bool extMachInstReady() + { + return true; + } + + //This returns a constant reference to the ExtMachInst to avoid a copy + const ExtMachInst & getExtMachInst() + { + return ext_inst; + } + }; +}; + +#endif // __ARCH_ALPHA_PREDECODER_HH__ diff --git a/src/arch/alpha/utility.hh b/src/arch/alpha/utility.hh index b7844c7eb..c20394a92 100644 --- a/src/arch/alpha/utility.hh +++ b/src/arch/alpha/utility.hh @@ -48,19 +48,6 @@ namespace AlphaISA return (tc->readMiscRegNoEffect(AlphaISA::IPR_DTB_CM) & 0x18) != 0; } - static inline ExtMachInst - makeExtMI(MachInst inst, Addr pc) { -#if FULL_SYSTEM - ExtMachInst ext_inst = inst; - if (pc && 0x1) - return ext_inst|=(static_cast<ExtMachInst>(pc & 0x1) << 32); - else - return ext_inst; -#else - return ExtMachInst(inst); -#endif - } - inline bool isCallerSaveIntegerRegister(unsigned int reg) { panic("register classification not implemented"); return (reg >= 1 && reg <= 8 || reg >= 22 && reg <= 25 || reg == 27); diff --git a/src/arch/mips/predecoder.hh b/src/arch/mips/predecoder.hh new file mode 100644 index 000000000..a25cce8a7 --- /dev/null +++ b/src/arch/mips/predecoder.hh @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_MIPS_PREDECODER_HH__ +#define __ARCH_MIPS_PREDECODER_HH__ + +#include "arch/mips/types.hh" +#include "base/misc.hh" +#include "sim/host.hh" + +class ThreadContext; + +namespace MipsISA +{ + class Predecoder + { + protected: + ThreadContext * tc; + //The extended machine instruction being generated + ExtMachInst emi; + + public: + Predecoder(ThreadContext * _tc) : tc(_tc) + {} + + ThreadContext * getTC() + { + return tc; + } + + void setTC(ThreadContext * _tc) + { + tc = _tc; + } + + void process() + { + } + + //Use this to give data to the predecoder. This should be used + //when there is control flow. + void moreBytes(Addr currPC, Addr off, MachInst inst) + { + assert(off == 0); + emi = inst; + } + + //Use this to give data to the predecoder. This should be used + //when instructions are executed in order. + void moreBytes(MachInst machInst) + { + moreBytes(0, 0, machInst); + } + + bool needMoreBytes() + { + return true; + } + + bool extMachInstReady() + { + return true; + } + + //This returns a constant reference to the ExtMachInst to avoid a copy + const ExtMachInst & getExtMachInst() + { + return emi; + } + }; +}; + +#endif // __ARCH_MIPS_PREDECODER_HH__ diff --git a/src/arch/mips/utility.hh b/src/arch/mips/utility.hh index b5c1e31e1..12db1de57 100644 --- a/src/arch/mips/utility.hh +++ b/src/arch/mips/utility.hh @@ -88,19 +88,6 @@ namespace MipsISA { return 0; } - static inline ExtMachInst - makeExtMI(MachInst inst, ThreadContext * xc) { -#if FULL_SYSTEM - ExtMachInst ext_inst = inst; - if (xc->readPC() && 0x1) - return ext_inst|=(static_cast<ExtMachInst>(xc->readPC() & 0x1) << 32); - else - return ext_inst; -#else - return ExtMachInst(inst); -#endif - } - inline void startupCPU(ThreadContext *tc, int cpuId) { tc->activate(0); diff --git a/src/arch/sparc/predecoder.hh b/src/arch/sparc/predecoder.hh new file mode 100644 index 000000000..71b14b020 --- /dev/null +++ b/src/arch/sparc/predecoder.hh @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_SPARC_PREDECODER_HH__ +#define __ARCH_SPARC_PREDECODER_HH__ + +#include "arch/sparc/types.hh" +#include "base/misc.hh" +#include "sim/host.hh" + +class ThreadContext; + +namespace SparcISA +{ + class Predecoder + { + protected: + ThreadContext * tc; + //The extended machine instruction being generated + ExtMachInst emi; + + public: + Predecoder(ThreadContext * _tc) : tc(_tc) + {} + + ThreadContext * getTC() + { + return tc; + } + + void setTC(ThreadContext * _tc) + { + tc = _tc; + } + + void process() + { + } + + //Use this to give data to the predecoder. This should be used + //when there is control flow. + void moreBytes(Addr currPC, Addr off, MachInst inst) + { + assert(off == 0); + + emi = inst; + //The I bit, bit 13, is used to figure out where the ASI + //should come from. Use that in the ExtMachInst. This is + //slightly redundant, but it removes the need to put a condition + //into all the execute functions + if(inst & (1 << 13)) + emi |= (static_cast<ExtMachInst>( + tc->readMiscRegNoEffect(MISCREG_ASI)) + << (sizeof(MachInst) * 8)); + else + emi |= (static_cast<ExtMachInst>(bits(inst, 12, 5)) + << (sizeof(MachInst) * 8)); + } + + //Use this to give data to the predecoder. This should be used + //when instructions are executed in order. + void moreBytes(MachInst machInst) + { + moreBytes(0, 0, machInst); + } + + bool needMoreBytes() + { + return true; + } + + bool extMachInstReady() + { + return true; + } + + //This returns a constant reference to the ExtMachInst to avoid a copy + const ExtMachInst & getExtMachInst() + { + return emi; + } + }; +}; + +#endif // __ARCH_SPARC_PREDECODER_HH__ diff --git a/src/arch/sparc/utility.hh b/src/arch/sparc/utility.hh index dc9201401..1458231f2 100644 --- a/src/arch/sparc/utility.hh +++ b/src/arch/sparc/utility.hh @@ -48,22 +48,6 @@ namespace SparcISA tc->readMiscRegNoEffect(MISCREG_HPSTATE & (1 << 2))); } - inline ExtMachInst - makeExtMI(MachInst inst, ThreadContext * xc) { - ExtMachInst emi = (MachInst) inst; - //The I bit, bit 13, is used to figure out where the ASI - //should come from. Use that in the ExtMachInst. This is - //slightly redundant, but it removes the need to put a condition - //into all the execute functions - if(inst & (1 << 13)) - emi |= (static_cast<ExtMachInst>(xc->readMiscRegNoEffect(MISCREG_ASI)) - << (sizeof(MachInst) * 8)); - else - emi |= (static_cast<ExtMachInst>(bits(inst, 12, 5)) - << (sizeof(MachInst) * 8)); - return emi; - } - inline bool isCallerSaveIntegerRegister(unsigned int reg) { panic("register classification not implemented"); return false; diff --git a/src/arch/x86/SConscript b/src/arch/x86/SConscript index f49225758..2e2c5b006 100644 --- a/src/arch/x86/SConscript +++ b/src/arch/x86/SConscript @@ -84,11 +84,12 @@ # Authors: Gabe Black Import('*') - if env['TARGET_ISA'] == 'x86': Source('floatregfile.cc') Source('intregfile.cc') Source('miscregfile.cc') + Source('predecoder.cc') + Source('predecoder_tables.cc') Source('regfile.cc') Source('remote_gdb.cc') diff --git a/src/arch/x86/isa/formats/unknown.isa b/src/arch/x86/isa/formats/unknown.isa index 605ddcb69..43ddc20c1 100644 --- a/src/arch/x86/isa/formats/unknown.isa +++ b/src/arch/x86/isa/formats/unknown.isa @@ -120,7 +120,8 @@ output exec {{ Fault Unknown::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const { - panic("No instructions are implemented for X86!\n"); + warn("No instructions are implemented for X86!\n"); + return NoFault; } }}; diff --git a/src/arch/x86/predecoder.cc b/src/arch/x86/predecoder.cc new file mode 100644 index 000000000..5ea960b36 --- /dev/null +++ b/src/arch/x86/predecoder.cc @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2007 The Hewlett-Packard Development Company + * All rights reserved. + * + * Redistribution and use of this software in source and binary forms, + * with or without modification, are permitted provided that the + * following conditions are met: + * + * The software must be used only for Non-Commercial Use which means any + * use which is NOT directed to receiving any direct monetary + * compensation for, or commercial advantage from such use. Illustrative + * examples of non-commercial use are academic research, personal study, + * teaching, education and corporate research & development. + * Illustrative examples of commercial use are distributing products for + * commercial advantage and providing services using the software for + * commercial advantage. + * + * If you wish to use this software or functionality therein that may be + * covered by patents for commercial use, please contact: + * Director of Intellectual Property Licensing + * Office of Strategy and Technology + * Hewlett-Packard Company + * 1501 Page Mill Road + * Palo Alto, California 94304 + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. Redistributions + * in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. Neither the name of + * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. No right of + * sublicense is granted herewith. Derivatives of the software and + * output created using the software may be prepared, but only for + * Non-Commercial Uses. Derivatives of the software may be shared with + * others provided: (i) the others agree to abide by the list of + * conditions herein which includes the Non-Commercial Use restrictions; + * and (ii) such Derivatives of the software include the above copyright + * notice to acknowledge the contribution from this software where + * applicable, this list of conditions and the disclaimer below. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "arch/x86/predecoder.hh" +#include "base/misc.hh" +#include "base/trace.hh" +#include "sim/host.hh" + +namespace X86ISA +{ + 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 Prefix: + state = doPrefixState(nextByte); + break; + case Opcode: + state = doOpcodeState(nextByte); + break; + case ModRM: + state = doModRMState(nextByte); + break; + case SIB: + state = doSIBState(nextByte); + break; + case Displacement: + state = doDisplacementState(); + break; + case Immediate: + 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 = Prefix; + if(prefix) + consumeByte(); + switch(prefix) + { + //Operand size override prefixes + case OperandSizeOverride: + DPRINTF(Predecoder, "Found operand size override prefix.\n"); + break; + case AddressSizeOverride: + DPRINTF(Predecoder, "Found address size override prefix.\n"); + break; + //Segment override prefixes + case CSOverride: + DPRINTF(Predecoder, "Found cs segment override.\n"); + break; + case DSOverride: + DPRINTF(Predecoder, "Found ds segment override.\n"); + break; + case ESOverride: + DPRINTF(Predecoder, "Found es segment override.\n"); + break; + case FSOverride: + DPRINTF(Predecoder, "Found fs segment override.\n"); + break; + case GSOverride: + DPRINTF(Predecoder, "Found gs segment override.\n"); + break; + case SSOverride: + DPRINTF(Predecoder, "Found ss segment override.\n"); + break; + case Lock: + DPRINTF(Predecoder, "Found lock prefix.\n"); + break; + case Rep: + DPRINTF(Predecoder, "Found rep prefix.\n"); + break; + case Repne: + DPRINTF(Predecoder, "Found repne prefix.\n"); + break; + case Rex: + DPRINTF(Predecoder, "Found Rex prefix %#x.\n", nextByte); + emi.rexPrefix = nextByte; + break; + case 0: + emi.numOpcodes = 0; + nextState = Opcode; + 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.numOpcodes++; + //We can't handle 3+ byte opcodes right now + assert(emi.numOpcodes < 2); + consumeByte(); + if(nextByte == 0xf0) + { + nextState = Opcode; + DPRINTF(Predecoder, "Found two byte opcode.\n"); + } + else + { + DPRINTF(Predecoder, "Found opcode %#x.\n", nextByte); + + //Prepare for any immediate/displacement we might need + immediateCollected = 0; + emi.immediate = 0; + displacementCollected = 0; + emi.displacement = 0; + + //Figure out how big of an immediate we'll retreive based + //on the opcode. + int immType = ImmediateType[ + emi.numOpcodes - 1][nextByte]; + if(0) //16 bit mode + immediateSize = ImmediateTypeToSize[0][immType]; + else if(!(emi.rexPrefix & 0x4)) //32 bit mode + immediateSize = ImmediateTypeToSize[1][immType]; + else //64 bit mode + immediateSize = ImmediateTypeToSize[2][immType]; + + //Determine what to expect next + if (UsesModRM[emi.numOpcodes - 1][nextByte]) { + nextState = ModRM; + } else if(immediateSize) { + nextState = Immediate; + } else { + emiIsReady = true; + nextState = Prefix; + } + } + 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; + DPRINTF(Predecoder, "Found modrm byte %#x.\n", nextByte); + if (0) {//FIXME in 16 bit mode + //figure out 16 bit displacement size + if(nextByte & 0xC7 == 0x06 || + nextByte & 0xC0 == 0x80) + displacementSize = 2; + else if(nextByte & 0xC0 == 0x40) + displacementSize = 1; + else + displacementSize = 0; + } else { + //figure out 32/64 bit displacement size + if(nextByte & 0xC7 == 0x05 || + nextByte & 0xC0 == 0x80) + displacementSize = 4; + else if(nextByte & 0xC0 == 0x40) + displacementSize = 2; + else + displacementSize = 0; + } + //If there's an SIB, get that next. + //There is no SIB in 16 bit mode. + if(nextByte & 0x7 == 4 && + nextByte & 0xC0 != 0xC0) { + // && in 32/64 bit mode) + nextState = SIB; + } else if(displacementSize) { + nextState = Displacement; + } else if(immediateSize) { + nextState = Immediate; + } else { + emiIsReady = true; + nextState = Prefix; + } + //The ModRM byte is consumed no matter what + consumeByte(); + 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; + DPRINTF(Predecoder, "Found SIB byte %#x.\n", nextByte); + consumeByte(); + if(displacementSize) { + nextState = Displacement; + } else if(immediateSize) { + nextState = Immediate; + } else { + emiIsReady = true; + nextState = Prefix; + } + 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(displacementCollected, + emi.displacement, + displacementSize); + + DPRINTF(Predecoder, "Collecting %d byte displacement, got %d bytes.\n", + displacementSize, displacementCollected); + + if(displacementSize == displacementCollected) { + //Sign extend the displacement + switch(displacementSize) + { + case 1: + emi.displacement = sext<8>(emi.displacement); + break; + case 2: + emi.displacement = sext<16>(emi.displacement); + break; + case 4: + emi.displacement = sext<32>(emi.displacement); + break; + default: + panic("Undefined displacement size!\n"); + } + DPRINTF(Predecoder, "Collected displacement %#x.\n", + emi.displacement); + if(immediateSize) { + nextState = Immediate; + } else { + emiIsReady = true; + nextState = Prefix; + } + } + else + nextState = Displacement; + 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) + { + DPRINTF(Predecoder, "Collected immediate %#x.\n", + emi.immediate); + emiIsReady = true; + nextState = Prefix; + } + else + nextState = Immediate; + return nextState; + } +} diff --git a/src/arch/x86/predecoder.hh b/src/arch/x86/predecoder.hh new file mode 100644 index 000000000..d7734be88 --- /dev/null +++ b/src/arch/x86/predecoder.hh @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2007 The Hewlett-Packard Development Company + * All rights reserved. + * + * Redistribution and use of this software in source and binary forms, + * with or without modification, are permitted provided that the + * following conditions are met: + * + * The software must be used only for Non-Commercial Use which means any + * use which is NOT directed to receiving any direct monetary + * compensation for, or commercial advantage from such use. Illustrative + * examples of non-commercial use are academic research, personal study, + * teaching, education and corporate research & development. + * Illustrative examples of commercial use are distributing products for + * commercial advantage and providing services using the software for + * commercial advantage. + * + * If you wish to use this software or functionality therein that may be + * covered by patents for commercial use, please contact: + * Director of Intellectual Property Licensing + * Office of Strategy and Technology + * Hewlett-Packard Company + * 1501 Page Mill Road + * Palo Alto, California 94304 + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. Redistributions + * in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. Neither the name of + * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. No right of + * sublicense is granted herewith. Derivatives of the software and + * output created using the software may be prepared, but only for + * Non-Commercial Uses. Derivatives of the software may be shared with + * others provided: (i) the others agree to abide by the list of + * conditions herein which includes the Non-Commercial Use restrictions; + * and (ii) such Derivatives of the software include the above copyright + * notice to acknowledge the contribution from this software where + * applicable, this list of conditions and the disclaimer below. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_X86_PREDECODER_HH__ +#define __ARCH_X86_PREDECODER_HH__ + +#include "arch/x86/types.hh" +#include "base/bitfield.hh" +#include "sim/host.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 ImmediateTypeToSize[3][10]; + + protected: + ThreadContext * tc; + //The bytes to be predecoded + MachInst fetchChunk; + //The pc of the start of fetchChunk + Addr basePC; + //The offset into fetchChunk of current processing + int offset; + //The extended machine instruction being generated + ExtMachInst emi; + + inline uint8_t getNextByte() + { + return (fetchChunk >> (offset * 8)) & 0xff; + } + + 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 partialDisp = fetchChunk >> (offset * 8); + //Mask off what we don't want + partialDisp &= mask(toGet * 8); + //Shift it over to overlay with our displacement. + partialDisp <<= (displacementCollected * 8); + //Put it into our displacement + current |= partialDisp; + //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; + } + + //State machine state + protected: + //Whether or not we're out of bytes + bool outOfBytes; + //Whether we've completed generating an ExtMachInst + bool emiIsReady; + //The size of the displacement value + int displacementSize; + int displacementCollected; + //The size of the immediate value + int immediateSize; + int immediateCollected; + + enum State { + Prefix, + Opcode, + ModRM, + SIB, + Displacement, + Immediate, + //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), offset(0), + outOfBytes(true), emiIsReady(false), + state(Prefix) + {} + + ThreadContext * getTC() + { + return tc; + } + + void setTC(ThreadContext * _tc) + { + tc = _tc; + } + + void process(); + + //Use this to give data to the predecoder. This should be used + //when there is control flow. + void moreBytes(Addr currPC, Addr off, MachInst data) + { + basePC = currPC; + offset = off; + fetchChunk = data; + assert(off < sizeof(MachInst)); + outOfBytes = false; + process(); + } + + //Use this to give data to the predecoder. This should be used + //when instructions are executed in order. + void moreBytes(MachInst machInst) + { + moreBytes(basePC + sizeof(machInst), 0, machInst); + } + + bool needMoreBytes() + { + return outOfBytes; + } + + bool extMachInstReady() + { + return emiIsReady; + } + + //This returns a constant reference to the ExtMachInst to avoid a copy + const ExtMachInst & getExtMachInst() + { + assert(emiIsReady); + emiIsReady = false; + return emi; + } + }; +}; + +#endif // __ARCH_X86_PREDECODER_HH__ diff --git a/src/arch/x86/predecoder_tables.cc b/src/arch/x86/predecoder_tables.cc new file mode 100644 index 000000000..0cebef61a --- /dev/null +++ b/src/arch/x86/predecoder_tables.cc @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2007 The Hewlett-Packard Development Company + * All rights reserved. + * + * Redistribution and use of this software in source and binary forms, + * with or without modification, are permitted provided that the + * following conditions are met: + * + * The software must be used only for Non-Commercial Use which means any + * use which is NOT directed to receiving any direct monetary + * compensation for, or commercial advantage from such use. Illustrative + * examples of non-commercial use are academic research, personal study, + * teaching, education and corporate research & development. + * Illustrative examples of commercial use are distributing products for + * commercial advantage and providing services using the software for + * commercial advantage. + * + * If you wish to use this software or functionality therein that may be + * covered by patents for commercial use, please contact: + * Director of Intellectual Property Licensing + * Office of Strategy and Technology + * Hewlett-Packard Company + * 1501 Page Mill Road + * Palo Alto, California 94304 + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. Redistributions + * in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. Neither the name of + * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. No right of + * sublicense is granted herewith. Derivatives of the software and + * output created using the software may be prepared, but only for + * Non-Commercial Uses. Derivatives of the software may be shared with + * others provided: (i) the others agree to abide by the list of + * conditions herein which includes the Non-Commercial Use restrictions; + * and (ii) such Derivatives of the software include the above copyright + * notice to acknowledge the contribution from this software where + * applicable, this list of conditions and the disclaimer below. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "arch/x86/predecoder.hh" +#include "arch/x86/types.hh" + +namespace X86ISA +{ + const uint8_t CS = CSOverride; + const uint8_t DS = DSOverride; + const uint8_t ES = ESOverride; + const uint8_t FS = FSOverride; + const uint8_t GS = GSOverride; + const uint8_t SS = SSOverride; + + const uint8_t OO = OperandSizeOverride; + const uint8_t AO = AddressSizeOverride; + const uint8_t LO = Lock; + const uint8_t RE = Rep; + const uint8_t RN = Repne; + const uint8_t RX = Rex; + + //This table identifies whether a byte is a prefix, and if it is, + //which prefix it is. + const uint8_t Predecoder::Prefixes[256] = + { //LSB +// MSB 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F +/* 0*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, +/* 1*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, +/* 2*/ 0 , 0 , 0 , 0 , 0 , 0 , ES, 0 , 0 , 0 , 0 , 0 , 0 , 0 , CS, 0, +/* 3*/ 0 , 0 , 0 , 0 , 0 , 0 , SS, 0 , 0 , 0 , 0 , 0 , 0 , 0 , DS, 0, +/* 4*/ RX, RX, RX, RX, RX, RX, RX, RX, RX, RX, RX, RX, RX, RX, RX, RX, +/* 5*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, +/* 6*/ 0 , 0 , 0 , 0 , FS, GS, OO, AO, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, +/* 7*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, +/* 8*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, +/* 9*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, +/* A*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, +/* B*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, +/* C*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, +/* D*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, +/* E*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, +/* F*/ LO, 0 , RN, RE, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 + }; + + //This table identifies whether a particular opcode uses the ModRM byte + const uint8_t Predecoder::UsesModRM[2][256] = + {//For one byte instructions + { //LSB +// MSB 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F +/* 0 */ 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0, +/* 1 */ 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0, +/* 2 */ 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0, +/* 3 */ 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0, +/* 4 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, +/* 5 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, +/* 6 */ 0 , 0 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 1 , 0 , 0 , 0 , 0, +/* 7 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, +/* 8 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1, +/* 9 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, +/* A */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, +/* B */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, +/* C */ 1 , 1 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, +/* D */ 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1, +/* E */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, +/* F */ 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 + }, + //For two byte instructions + { //LSB +// MSB 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F +/* 0 */ 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 1, +/* 1 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0, +/* 2 */ 1 , 1 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1, +/* 3 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, +/* 4 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1, +/* 5 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1, +/* 6 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1, +/* 7 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1, +/* 8 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, +/* 9 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1, +/* A */ 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1, +/* B */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1, +/* C */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, +/* D */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1, +/* E */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1, +/* F */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 + } + }; + + enum ImmediateTypes { + NoImm, + NI = NoImm, + ByteImm, + BY = ByteImm, + WordImm, + WO = WordImm, + DWordImm, + DW = DWordImm, + QWordImm, + QW = QWordImm, + OWordImm, + OW = OWordImm, + VWordImm, + VW = VWordImm, + ZWordImm, + ZW = ZWordImm, + Pointer, + PO = Pointer, + //The enter instruction takes -2- immediates for a total of 3 bytes + Enter, + EN = Enter + }; + + const uint8_t Predecoder::ImmediateTypeToSize[3][10] = + { +// noimm byte word dword qword oword vword zword enter + {0, 1, 2, 4, 8, 16, 2, 2, 3, 4}, //16 bit + {0, 1, 2, 4, 8, 16, 4, 4, 3, 6}, //32 bit + {0, 1, 2, 4, 8, 16, 4, 8, 3, 0} //64 bit + }; + + //This table determines the immediate type. The first index is the + //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] = + {//For one byte instructions + { //LSB +// MSB 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F +/* 0 */ 0 , 0 , 0 , 0 , BY, ZW, 0 , 0 , 0 , 0 , 0 , 0 , BY, ZW, 0 , 0 , +/* 1 */ 0 , 0 , 0 , 0 , BY, ZW, 0 , 0 , 0 , 0 , 0 , 0 , BY, ZW, 0 , 0 , +/* 2 */ 0 , 0 , 0 , 0 , BY, ZW, 0 , 0 , 0 , 0 , 0 , 0 , BY, ZW, 0 , 0 , +/* 3 */ 0 , 0 , 0 , 0 , BY, ZW, 0 , 0 , 0 , 0 , 0 , 0 , BY, ZW, 0 , 0 , +/* 4 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* 5 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* 6 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , ZW, ZW, BY, BY, 0 , 0 , 0 , 0 , +/* 7 */ BY, BY, BY, BY, BY, BY, BY, BY, BY, BY, BY, BY, BY, BY, BY, BY, +/* 8 */ BY, ZW, BY, BY, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* 9 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* A */ BY, VW, BY, VW, 0 , 0 , 0 , 0 , BY, ZW, 0 , 0 , 0 , 0 , 0 , 0 , +/* B */ BY, BY, BY, BY, BY, BY, BY, BY, VW, VW, VW, VW, VW, VW, VW, VW, +/* C */ BY, BY, WO, 0 , 0 , 0 , BY, ZW, EN, 0 , WO, 0 , 0 , BY, 0 , 0 , +/* D */ 0 , 0 , 0 , 0 , BY, BY, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* E */ BY, BY, BY, BY, BY, BY, BY, BY, ZW, ZW, PO, BY, 0 , 0 , 0 , 0 , +/* F */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 + }, + //For two byte instructions + { //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 , +/* 0 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* 2 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* 3 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* 4 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* 5 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* 6 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* 7 */ BY, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* 8 */ ZW, ZW, ZW, ZW, ZW, ZW, ZW, ZW, ZW, ZW, ZW, ZW, ZW, ZW, ZW, ZW, +/* 9 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* A */ 0 , 0 , 0 , 0 , BY, 0 , 0 , 0 , 0 , 0 , 0 , 0 , BY, 0 , 0 , 0 , +/* B */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , ZW, 0 , BY, 0 , 0 , 0 , 0 , 0 , +/* C */ 0 , 0 , BY, 0 , BY, BY, BY, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* D */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* E */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/* F */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 + } + }; +} diff --git a/src/arch/x86/types.hh b/src/arch/x86/types.hh index 63f65eee5..583f03d55 100644 --- a/src/arch/x86/types.hh +++ b/src/arch/x86/types.hh @@ -59,13 +59,80 @@ #define __ARCH_X86_TYPES_HH__ #include <inttypes.h> +#include <iostream> namespace X86ISA { - //XXX This won't work - typedef uint32_t MachInst; - //XXX This won't work either - typedef uint64_t ExtMachInst; + //This really determines how many bytes are passed to the predecoder. + typedef uint64_t MachInst; + + enum Prefixes { + NoOverride = 0, + CSOverride = 1, + DSOverride = 2, + ESOverride = 3, + FSOverride = 4, + GSOverride = 5, + SSOverride = 6, + //The Rex prefix obviously doesn't fit in with the above, but putting + //it here lets us save double the space the enums take up. + Rex = 7, + //There can be only one segment override, so they share the + //first 3 bits in the legacyPrefixes bitfield. + SegmentOverride = 0x7, + OperandSizeOverride = 8, + AddressSizeOverride = 16, + Lock = 32, + Rep = 64, + Repne = 128 + }; + + //The intermediate structure the x86 predecoder returns. + struct ExtMachInst + { + public: //XXX These should be hidden in the future + + uint8_t legacyPrefixes; + uint8_t rexPrefix; + //Right now, we ignore that this can be 3 in + //some cases + uint8_t numOpcodes; + //This will need to be decoded specially later + bool is3dnow; + uint8_t opcode; + uint64_t immediate; + uint64_t displacement; + + public: + + //These are to pacify the decoder for now. This will go away once + //it can handle non integer inputs, and in the mean time allow me to + //excercise the predecoder a little. + operator unsigned int() + { + return 0; + } + + ExtMachInst(unsigned int) + {;} + + ExtMachInst() + {;} + }; + + inline static std::ostream & + operator << (std::ostream & os, const ExtMachInst & emi) + { + os << "{X86 ExtMachInst}"; + return os; + } + + inline static bool + operator == (const ExtMachInst &emi1, const ExtMachInst &emi2) + { + //Since this is empty, it's always equal + return true; + } typedef uint64_t IntReg; //XXX Should this be a 128 bit structure for XMM memory ops? diff --git a/src/arch/x86/utility.hh b/src/arch/x86/utility.hh index 1fbe1fffe..d89e223de 100644 --- a/src/arch/x86/utility.hh +++ b/src/arch/x86/utility.hh @@ -59,11 +59,23 @@ #define __ARCH_X86_UTILITY_HH__ #include "arch/x86/types.hh" +#include "base/hashmap.hh" #include "base/misc.hh" +#include "cpu/thread_context.hh" #include "sim/host.hh" class ThreadContext; +namespace __hash_namespace { + template<> + struct hash<X86ISA::ExtMachInst> { + size_t operator()(const X86ISA::ExtMachInst &emi) const { + //Because these are all the same, return 0 + return 0; + }; + }; +} + namespace X86ISA { static inline bool @@ -72,11 +84,6 @@ namespace X86ISA return false; } - inline ExtMachInst - makeExtMI(MachInst inst, ThreadContext * xc) { - return inst; - } - inline bool isCallerSaveIntegerRegister(unsigned int reg) { panic("register classification not implemented"); return false; diff --git a/src/base/traceflags.py b/src/base/traceflags.py index a36db1963..e57bfa350 100644 --- a/src/base/traceflags.py +++ b/src/base/traceflags.py @@ -137,6 +137,7 @@ baseFlags = [ 'PciConfigAll', 'Pipeline', 'Printf', + 'Predecoder', 'Quiesce', 'ROB', 'Regs', diff --git a/src/cpu/base.hh b/src/cpu/base.hh index 7167bfde0..4d8300186 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -34,11 +34,11 @@ #include <vector> +#include "arch/isa_traits.hh" #include "base/statistics.hh" #include "config/full_system.hh" #include "sim/eventq.hh" #include "mem/mem_object.hh" -#include "arch/isa_traits.hh" #if FULL_SYSTEM #include "arch/interrupts.hh" @@ -50,6 +50,11 @@ class ThreadContext; class System; class Port; +namespace TheISA +{ + class Predecoder; +} + class CPUProgressEvent : public Event { protected: @@ -125,6 +130,7 @@ class BaseCPU : public MemObject protected: std::vector<ThreadContext *> threadContexts; + std::vector<TheISA::Predecoder *> predecoders; public: diff --git a/src/cpu/o3/fetch.hh b/src/cpu/o3/fetch.hh index 8347ed775..da7ce00f5 100644 --- a/src/cpu/o3/fetch.hh +++ b/src/cpu/o3/fetch.hh @@ -33,6 +33,7 @@ #define __CPU_O3_FETCH_HH__ #include "arch/utility.hh" +#include "arch/predecoder.hh" #include "base/statistics.hh" #include "base/timebuf.hh" #include "cpu/pc_event.hh" @@ -338,6 +339,9 @@ class DefaultFetch /** BPredUnit. */ BPredUnit branchPred; + /** Predecoder. */ + TheISA::Predecoder predecoder; + /** Per-thread fetch PC. */ Addr PC[Impl::MaxThreads]; diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh index ac0149d18..1256dd233 100644 --- a/src/cpu/o3/fetch_impl.hh +++ b/src/cpu/o3/fetch_impl.hh @@ -103,6 +103,7 @@ DefaultFetch<Impl>::IcachePort::recvRetry() template<class Impl> DefaultFetch<Impl>::DefaultFetch(Params *params) : branchPred(params), + predecoder(NULL), decodeToFetchDelay(params->decodeToFetchDelay), renameToFetchDelay(params->renameToFetchDelay), iewToFetchDelay(params->iewToFetchDelay), @@ -1117,13 +1118,10 @@ DefaultFetch<Impl>::fetch(bool &status_change) inst = TheISA::gtoh(*reinterpret_cast<TheISA::MachInst *> (&cacheData[tid][offset])); -#if THE_ISA == ALPHA_ISA - ext_inst = TheISA::makeExtMI(inst, fetch_PC); -#elif THE_ISA == SPARC_ISA - ext_inst = TheISA::makeExtMI(inst, cpu->thread[tid]->getTC()); -#elif THE_ISA == MIPS_ISA - ext_inst = TheISA::makeExtMI(inst, cpu->thread[tid]->getTC()); -#endif + predecoder.setTC(cpu->thread[tid]->getTC()); + predecoder.moreBytes(fetch_PC, 0, inst); + + ext_inst = predecoder.getExtMachInst(); // Create a new DynInst from the instruction fetched. DynInstPtr instruction = new DynInst(ext_inst, diff --git a/src/cpu/o3/thread_context_impl.hh b/src/cpu/o3/thread_context_impl.hh index d2acc6232..a145e046e 100755 --- a/src/cpu/o3/thread_context_impl.hh +++ b/src/cpu/o3/thread_context_impl.hh @@ -103,7 +103,7 @@ void O3ThreadContext<Impl>::delVirtPort(VirtualPort *vp) { if (vp != thread->getVirtPort()) { - delete vp->getPeer(); + vp->removeConn(); delete vp; } } diff --git a/src/cpu/ozone/cpu_impl.hh b/src/cpu/ozone/cpu_impl.hh index 4a76ae110..d78162243 100644 --- a/src/cpu/ozone/cpu_impl.hh +++ b/src/cpu/ozone/cpu_impl.hh @@ -748,7 +748,7 @@ template <class Impl> void OzoneCPU<Impl>::OzoneTC::delVirtPort(VirtualPort *vp) { - delete vp->getPeer(); + vp->removeConn(); delete vp; } #endif diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index 6a14a8aa5..6f69b5ac4 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -516,17 +516,28 @@ AtomicSimpleCPU::tick() Fault fault = setupFetchRequest(ifetch_req); if (fault == NoFault) { - ifetch_pkt->reinitFromRequest(); + Tick icache_latency = 0; + bool icache_access = false; + dcache_access = false; // assume no dcache access - Tick icache_latency = icachePort.sendAtomic(ifetch_pkt); - // ifetch_req is initialized to read the instruction directly - // into the CPU object's inst field. + //Fetch more instruction memory if necessary + if(predecoder.needMoreBytes()) + { + icache_access = true; + ifetch_pkt->reinitFromRequest(); + + icache_latency = icachePort.sendAtomic(ifetch_pkt); + // ifetch_req is initialized to read the instruction directly + // into the CPU object's inst field. + } - dcache_access = false; // assume no dcache access preExecute(); - fault = curStaticInst->execute(this, traceData); - postExecute(); + if(curStaticInst) + { + fault = curStaticInst->execute(this, traceData); + postExecute(); + } // @todo remove me after debugging with legion done if (curStaticInst && (!curStaticInst->isMicroOp() || @@ -534,7 +545,8 @@ AtomicSimpleCPU::tick() instCnt++; if (simulate_stalls) { - Tick icache_stall = icache_latency - cycles(1); + Tick icache_stall = + icache_access ? icache_latency - cycles(1) : 0; Tick dcache_stall = dcache_access ? dcache_latency - cycles(1) : 0; Tick stall_cycles = (icache_stall + dcache_stall) / cycles(1); @@ -545,8 +557,8 @@ AtomicSimpleCPU::tick() } } - - advancePC(fault); + if(predecoder.needMoreBytes()) + advancePC(fault); } if (_status != Idle) diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc index 9feb09851..cd139492a 100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@ -70,7 +70,7 @@ using namespace std; using namespace TheISA; BaseSimpleCPU::BaseSimpleCPU(Params *p) - : BaseCPU(p), thread(NULL) + : BaseCPU(p), thread(NULL), predecoder(NULL) { #if FULL_SYSTEM thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb); @@ -367,18 +367,23 @@ BaseSimpleCPU::preExecute() inst = gtoh(inst); //If we're not in the middle of a macro instruction if (!curMacroStaticInst) { -#if THE_ISA == ALPHA_ISA - StaticInstPtr instPtr = StaticInst::decode(makeExtMI(inst, thread->readPC())); -#elif THE_ISA == SPARC_ISA - StaticInstPtr instPtr = StaticInst::decode(makeExtMI(inst, thread->getTC())); -#elif THE_ISA == X86_ISA - StaticInstPtr instPtr = StaticInst::decode(makeExtMI(inst, thread->getTC())); -#elif THE_ISA == MIPS_ISA - //Mips doesn't do anything in it's MakeExtMI function right now, - //so it won't be called. - StaticInstPtr instPtr = StaticInst::decode(inst); -#endif - if (instPtr->isMacroOp()) { + StaticInstPtr instPtr = NULL; + + //Predecode, ie bundle up an ExtMachInst + //This should go away once the constructor can be set up properly + predecoder.setTC(thread->getTC()); + //If more fetch data is needed, pass it in. + if(predecoder.needMoreBytes()) + predecoder.moreBytes(thread->readPC(), 0, inst); + else + predecoder.process(); + //If an instruction is ready, decode it + if (predecoder.extMachInstReady()) + instPtr = StaticInst::decode(predecoder.getExtMachInst()); + + //If we decoded an instruction and it's microcoded, start pulling + //out micro ops + if (instPtr && instPtr->isMacroOp()) { curMacroStaticInst = instPtr; curStaticInst = curMacroStaticInst-> fetchMicroOp(thread->readMicroPC()); @@ -391,17 +396,19 @@ BaseSimpleCPU::preExecute() fetchMicroOp(thread->readMicroPC()); } + //If we decoded an instruction this "tick", record information about it. + if(curStaticInst) + { + traceData = Trace::getInstRecord(curTick, tc, curStaticInst, + thread->readPC()); - traceData = Trace::getInstRecord(curTick, tc, curStaticInst, - thread->readPC()); - - DPRINTF(Decode,"Decode: Decoded %s instruction (opcode: 0x%x): 0x%x\n", - curStaticInst->getName(), curStaticInst->getOpcode(), - curStaticInst->machInst); + DPRINTF(Decode,"Decode: Decoded %s instruction: 0x%x\n", + curStaticInst->getName(), curStaticInst->machInst); #if FULL_SYSTEM - thread->setInst(inst); + thread->setInst(inst); #endif // FULL_SYSTEM + } } void @@ -444,9 +451,9 @@ BaseSimpleCPU::advancePC(Fault fault) fault->invoke(tc); thread->setMicroPC(0); thread->setNextMicroPC(1); - } else { + } else if (predecoder.needMoreBytes()) { //If we're at the last micro op for this instruction - if (curStaticInst->isLastMicroOp()) { + if (curStaticInst && curStaticInst->isLastMicroOp()) { //We should be working with a macro op assert(curMacroStaticInst); //Close out this macro op, and clean up the @@ -465,13 +472,9 @@ BaseSimpleCPU::advancePC(Fault fault) } else { // go to the next instruction thread->setPC(thread->readNextPC()); -#if ISA_HAS_DELAY_SLOT thread->setNextPC(thread->readNextNPC()); thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst)); assert(thread->readNextPC() != thread->readNextNPC()); -#else - thread->setNextPC(thread->readNextPC() + sizeof(MachInst)); -#endif } } diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh index eae24014b..787259c96 100644 --- a/src/cpu/simple/base.hh +++ b/src/cpu/simple/base.hh @@ -33,6 +33,7 @@ #ifndef __CPU_SIMPLE_BASE_HH__ #define __CPU_SIMPLE_BASE_HH__ +#include "arch/predecoder.hh" #include "base/statistics.hh" #include "config/full_system.hh" #include "cpu/base.hh" @@ -63,6 +64,10 @@ class Process; class RemoteGDB; class GDBListener; +namespace TheISA +{ + class Predecoder; +} class ThreadContext; class Checkpoint; @@ -74,7 +79,6 @@ namespace Trace { class BaseSimpleCPU : public BaseCPU { protected: - typedef TheISA::MachInst MachInst; typedef TheISA::MiscReg MiscReg; typedef TheISA::FloatReg FloatReg; typedef TheISA::FloatRegBits FloatRegBits; @@ -122,7 +126,10 @@ class BaseSimpleCPU : public BaseCPU #endif // current instruction - MachInst inst; + TheISA::MachInst inst; + + // The predecoder + TheISA::Predecoder predecoder; // Static data storage TheISA::LargestRead dataReg; diff --git a/src/cpu/simple_thread.cc b/src/cpu/simple_thread.cc index 13d0e2e29..39f31782b 100644 --- a/src/cpu/simple_thread.cc +++ b/src/cpu/simple_thread.cc @@ -305,7 +305,7 @@ void SimpleThread::delVirtPort(VirtualPort *vp) { if (vp != virtPort) { - delete vp->getPeer(); + vp->removeConn(); delete vp; } } diff --git a/src/cpu/static_inst.hh b/src/cpu/static_inst.hh index 416c8ab56..a58ac85d6 100644 --- a/src/cpu/static_inst.hh +++ b/src/cpu/static_inst.hh @@ -35,6 +35,7 @@ #include <string> #include "arch/isa_traits.hh" +#include "arch/utility.hh" #include "sim/faults.hh" #include "base/bitfield.hh" #include "base/hashmap.hh" @@ -439,9 +440,6 @@ class StaticInst : public StaticInstBase //This is defined as inline below. static StaticInstPtr decode(ExtMachInst mach_inst); - /// Return opcode of machine instruction - uint32_t getOpcode() { return bits(machInst, 31, 26);} - /// Return name of machine instruction std::string getName() { return mnemonic; } }; @@ -474,7 +472,7 @@ class StaticInstPtr : public RefCountingPtr<StaticInst> /// Construct directly from machine instruction. /// Calls StaticInst::decode(). - StaticInstPtr(TheISA::ExtMachInst mach_inst) + explicit StaticInstPtr(TheISA::ExtMachInst mach_inst) : RefCountingPtr<StaticInst>(StaticInst::decode(mach_inst)) { } diff --git a/src/dev/SConscript b/src/dev/SConscript index 1ec83de4b..ea529b536 100644 --- a/src/dev/SConscript +++ b/src/dev/SConscript @@ -40,7 +40,7 @@ if env['FULL_SYSTEM']: Source('etherlink.cc') Source('etherpkt.cc') Source('ethertap.cc') - #Source('i8254xGBe.cc') + Source('i8254xGBe.cc') Source('ide_ctrl.cc') Source('ide_disk.cc') Source('io_device.cc') diff --git a/src/dev/i8254xGBe.cc b/src/dev/i8254xGBe.cc index 7fc68f4e7..5476ef9eb 100644 --- a/src/dev/i8254xGBe.cc +++ b/src/dev/i8254xGBe.cc @@ -46,29 +46,32 @@ using namespace iGbReg; IGbE::IGbE(Params *p) - : PciDev(p), etherInt(NULL) + : PciDev(p), etherInt(NULL), useFlowControl(p->use_flow_control) { // Initialized internal registers per Intel documentation - regs.tctl.reg = 0; - regs.rctl.reg = 0; - regs.ctrl.reg = 0; - regs.ctrl.fd = 1; - regs.ctrl.lrst = 1; - regs.ctrl.speed = 2; - regs.ctrl.frcspd = 1; - regs.sts.reg = 0; - regs.eecd.reg = 0; - regs.eecd.fwe = 1; - regs.eecd.ee_type = 1; - regs.eerd.reg = 0; - regs.icd.reg = 0; - regs.imc.reg = 0; - regs.rctl.reg = 0; - regs.tctl.reg = 0; - regs.manc.reg = 0; - - regs.pba.rxa = 0x30; - regs.pba.txa = 0x10; + regs.tctl(0); + regs.rctl(0); + regs.ctrl(0); + regs.ctrl.fd(1); + regs.ctrl.lrst(1); + regs.ctrl.speed(2); + regs.ctrl.frcspd(1); + regs.sts(0); + regs.sts.speed(3); // Say we're 1000Mbps + regs.sts.fd(1); // full duplex + regs.eecd(0); + regs.eecd.fwe(1); + regs.eecd.ee_type(1); + regs.eerd(0); + regs.icr(0); + regs.rctl(0); + regs.tctl(0); + regs.fcrtl(0); + regs.fcrth(1); + regs.manc(0); + + regs.pba.rxa(0x30); + regs.pba.txa(0x10); eeOpBits = 0; eeAddrBits = 0; @@ -78,8 +81,17 @@ IGbE::IGbE(Params *p) // clear all 64 16 bit words of the eeprom memset(&flash, 0, EEPROM_SIZE*2); + //We'll need to instert the MAC address into the flash + flash[0] = 0xA4A4; + flash[1] = 0xB6B6; + flash[2] = 0xC8C8; + + uint16_t csum = 0; + for (int x = 0; x < EEPROM_SIZE; x++) + csum += flash[x]; + // Magic happy checksum value - flash[0] = 0xBABA; + flash[EEPROM_SIZE-1] = htobe((uint16_t)(EEPROM_CSUM - csum)); } @@ -124,47 +136,112 @@ IGbE::read(PacketPtr pkt) switch (daddr) { - case CTRL: - pkt->set<uint32_t>(regs.ctrl.reg); - break; - case STATUS: - pkt->set<uint32_t>(regs.sts.reg); - break; - case EECD: - pkt->set<uint32_t>(regs.eecd.reg); - break; - case EERD: - pkt->set<uint32_t>(regs.eerd.reg); - break; - case ICR: - pkt->set<uint32_t>(regs.icd.reg); - break; - case IMC: - pkt->set<uint32_t>(regs.imc.reg); - break; - case RCTL: - pkt->set<uint32_t>(regs.rctl.reg); - break; - case TCTL: - pkt->set<uint32_t>(regs.tctl.reg); - break; - case PBA: - pkt->set<uint32_t>(regs.pba.reg); - break; - case WUC: - case LEDCTL: - pkt->set<uint32_t>(0); // We don't care, so just return 0 - break; - case MANC: - pkt->set<uint32_t>(regs.manc.reg); - break; + case REG_CTRL: + pkt->set<uint32_t>(regs.ctrl()); + break; + case REG_STATUS: + pkt->set<uint32_t>(regs.sts()); + break; + case REG_EECD: + pkt->set<uint32_t>(regs.eecd()); + break; + case REG_EERD: + pkt->set<uint32_t>(regs.eerd()); + break; + case REG_CTRL_EXT: + pkt->set<uint32_t>(regs.ctrl_ext()); + break; + case REG_MDIC: + pkt->set<uint32_t>(regs.mdic()); + break; + case REG_ICR: + pkt->set<uint32_t>(regs.icr()); + // handle auto setting mask from IAM + break; + case REG_ITR: + pkt->set<uint32_t>(regs.itr()); + break; + case REG_RCTL: + pkt->set<uint32_t>(regs.rctl()); + break; + case REG_FCTTV: + pkt->set<uint32_t>(regs.fcttv()); + break; + case REG_TCTL: + pkt->set<uint32_t>(regs.tctl()); + break; + case REG_PBA: + pkt->set<uint32_t>(regs.pba()); + break; + case REG_WUC: + case REG_LEDCTL: + pkt->set<uint32_t>(0); // We don't care, so just return 0 + break; + case REG_FCRTL: + pkt->set<uint32_t>(regs.fcrtl()); + break; + case REG_FCRTH: + pkt->set<uint32_t>(regs.fcrth()); + break; + case REG_RDBAL: + pkt->set<uint32_t>(regs.rdba.rdbal()); + break; + case REG_RDBAH: + pkt->set<uint32_t>(regs.rdba.rdbah()); + break; + case REG_RDLEN: + pkt->set<uint32_t>(regs.rdlen()); + break; + case REG_RDH: + pkt->set<uint32_t>(regs.rdh()); + break; + case REG_RDT: + pkt->set<uint32_t>(regs.rdt()); + break; + case REG_RDTR: + pkt->set<uint32_t>(regs.rdtr()); + break; + case REG_RADV: + pkt->set<uint32_t>(regs.radv()); + break; + case REG_TDBAL: + pkt->set<uint32_t>(regs.tdba.tdbal()); + break; + case REG_TDBAH: + pkt->set<uint32_t>(regs.tdba.tdbah()); + break; + case REG_TDLEN: + pkt->set<uint32_t>(regs.tdlen()); + break; + case REG_TDH: + pkt->set<uint32_t>(regs.tdh()); + break; + case REG_TDT: + pkt->set<uint32_t>(regs.tdt()); + break; + case REG_TIDV: + pkt->set<uint32_t>(regs.tidv()); + break; + case REG_TXDCTL: + pkt->set<uint32_t>(regs.txdctl()); + break; + case REG_TADV: + pkt->set<uint32_t>(regs.tadv()); + break; + case REG_RXCSUM: + pkt->set<uint32_t>(regs.rxcsum()); + break; + case REG_MANC: + pkt->set<uint32_t>(regs.manc()); + break; default: - if (!(daddr >= VFTA && daddr < (VFTA + VLAN_FILTER_TABLE_SIZE)*4) && - !(daddr >= RAL && daddr < (RAL + RCV_ADDRESS_TABLE_SIZE)*4) && - !(daddr >= MTA && daddr < (MTA + MULTICAST_TABLE_SIZE)*4)) - pkt->set<uint32_t>(0); - else - panic("Read request to unknown register number: %#x\n", daddr); + if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) && + !(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) && + !(daddr >= REG_MTA && daddr < (REG_MTA + MULTICAST_TABLE_SIZE*4)) && + !(daddr >= REG_CRCERRS && daddr < (REG_CRCERRS + STATS_REGS_SIZE))) + panic("Read request to unknown register number: %#x\n", daddr); + else + pkt->set<uint32_t>(0); }; pkt->result = Packet::Success; @@ -195,92 +272,211 @@ IGbE::write(PacketPtr pkt) uint32_t val = pkt->get<uint32_t>(); switch (daddr) { - case CTRL: - regs.ctrl.reg = val; - break; - case STATUS: - regs.sts.reg = val; - break; - case EECD: - int oldClk; - oldClk = regs.eecd.sk; - regs.eecd.reg = val; - // See if this is a eeprom access and emulate accordingly - if (!oldClk && regs.eecd.sk) { - if (eeOpBits < 8) { - eeOpcode = eeOpcode << 1 | regs.eecd.din; - eeOpBits++; - } else if (eeAddrBits < 8 && eeOpcode == EEPROM_READ_OPCODE_SPI) { - eeAddr = eeAddr << 1 | regs.eecd.din; - eeAddrBits++; - } else if (eeDataBits < 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) { - assert(eeAddr>>1 < EEPROM_SIZE); - DPRINTF(EthernetEEPROM, "EEPROM bit read: %d word: %#X\n", - flash[eeAddr>>1] >> eeDataBits & 0x1, flash[eeAddr>>1]); - regs.eecd.dout = (flash[eeAddr>>1] >> (15-eeDataBits)) & 0x1; - eeDataBits++; - } else if (eeDataBits < 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI) { - regs.eecd.dout = 0; - eeDataBits++; - } else - panic("What's going on with eeprom interface? opcode:" - " %#x:%d addr: %#x:%d, data: %d\n", (uint32_t)eeOpcode, - (uint32_t)eeOpBits, (uint32_t)eeAddr, - (uint32_t)eeAddrBits, (uint32_t)eeDataBits); - - // Reset everything for the next command - if ((eeDataBits == 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) || + case REG_CTRL: + regs.ctrl = val; + if (regs.ctrl.tfce()) + warn("TX Flow control enabled, should implement\n"); + if (regs.ctrl.rfce()) + warn("RX Flow control enabled, should implement\n"); + break; + case REG_CTRL_EXT: + regs.ctrl_ext = val; + break; + case REG_STATUS: + regs.sts = val; + break; + case REG_EECD: + int oldClk; + oldClk = regs.eecd.sk(); + regs.eecd = val; + // See if this is a eeprom access and emulate accordingly + if (!oldClk && regs.eecd.sk()) { + if (eeOpBits < 8) { + eeOpcode = eeOpcode << 1 | regs.eecd.din(); + eeOpBits++; + } else if (eeAddrBits < 8 && eeOpcode == EEPROM_READ_OPCODE_SPI) { + eeAddr = eeAddr << 1 | regs.eecd.din(); + eeAddrBits++; + } else if (eeDataBits < 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) { + assert(eeAddr>>1 < EEPROM_SIZE); + DPRINTF(EthernetEEPROM, "EEPROM bit read: %d word: %#X\n", + flash[eeAddr>>1] >> eeDataBits & 0x1, flash[eeAddr>>1]); + regs.eecd.dout((flash[eeAddr>>1] >> (15-eeDataBits)) & 0x1); + eeDataBits++; + } else if (eeDataBits < 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI) { + regs.eecd.dout(0); + eeDataBits++; + } else + panic("What's going on with eeprom interface? opcode:" + " %#x:%d addr: %#x:%d, data: %d\n", (uint32_t)eeOpcode, + (uint32_t)eeOpBits, (uint32_t)eeAddr, + (uint32_t)eeAddrBits, (uint32_t)eeDataBits); + + // Reset everything for the next command + if ((eeDataBits == 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) || (eeDataBits == 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI)) { - eeOpBits = 0; - eeAddrBits = 0; - eeDataBits = 0; + eeOpBits = 0; + eeAddrBits = 0; + eeDataBits = 0; eeOpcode = 0; - eeAddr = 0; - } + eeAddr = 0; + } DPRINTF(EthernetEEPROM, "EEPROM: opcode: %#X:%d addr: %#X:%d\n", - (uint32_t)eeOpcode, (uint32_t) eeOpBits, - (uint32_t)eeAddr>>1, (uint32_t)eeAddrBits); + (uint32_t)eeOpcode, (uint32_t) eeOpBits, + (uint32_t)eeAddr>>1, (uint32_t)eeAddrBits); if (eeOpBits == 8 && !(eeOpcode == EEPROM_READ_OPCODE_SPI || - eeOpcode == EEPROM_RDSR_OPCODE_SPI )) - panic("Unknown eeprom opcode: %#X:%d\n", (uint32_t)eeOpcode, - (uint32_t)eeOpBits); - - - } - // If driver requests eeprom access, immediately give it to it - regs.eecd.ee_gnt = regs.eecd.ee_req; - break; - case EERD: - regs.eerd.reg = val; - break; - case ICR: - regs.icd.reg = val; - break; - case IMC: - regs.imc.reg = val; - break; - case RCTL: - regs.rctl.reg = val; - break; - case TCTL: - regs.tctl.reg = val; - break; - case PBA: - regs.pba.rxa = val; - regs.pba.txa = 64 - regs.pba.rxa; - break; - case WUC: - case LEDCTL: - ; // We don't care, so don't store anything - break; - case MANC: - regs.manc.reg = val; - break; + eeOpcode == EEPROM_RDSR_OPCODE_SPI )) + panic("Unknown eeprom opcode: %#X:%d\n", (uint32_t)eeOpcode, + (uint32_t)eeOpBits); + + + } + // If driver requests eeprom access, immediately give it to it + regs.eecd.ee_gnt(regs.eecd.ee_req()); + break; + case REG_EERD: + regs.eerd = val; + break; + case REG_MDIC: + regs.mdic = val; + if (regs.mdic.i()) + panic("No support for interrupt on mdic complete\n"); + if (regs.mdic.phyadd() != 1) + panic("No support for reading anything but phy\n"); + DPRINTF(Ethernet, "%s phy address %x\n", regs.mdic.op() == 1 ? "Writing" + : "Reading", regs.mdic.regadd()); + switch (regs.mdic.regadd()) { + case PHY_PSTATUS: + regs.mdic.data(0x796D); // link up + break; + case PHY_PID: + regs.mdic.data(0x02A8); + break; + case PHY_EPID: + regs.mdic.data(0x0380); + break; + case PHY_GSTATUS: + regs.mdic.data(0x7C00); + break; + case PHY_EPSTATUS: + regs.mdic.data(0x3000); + break; + case PHY_AGC: + regs.mdic.data(0x180); // some random length + break; + default: + regs.mdic.data(0); + warn("Accessing unknown phy register %d\n", regs.mdic.regadd()); + } + regs.mdic.r(1); + break; + case REG_ICR: + regs.icr = val; + // handle auto setting mask from IAM + break; + case REG_ITR: + regs.itr = val; + break; + case REG_ICS: + regs.icr = val | regs.icr(); + // generate an interrupt if needed here + break; + case REG_IMS: + regs.imr |= val; + // handle interrupts if needed here + break; + case REG_IMC: + regs.imr |= ~val; + // handle interrupts if needed here + break; + case REG_IAM: + regs.iam = val; + break; + case REG_RCTL: + regs.rctl = val; + break; + case REG_FCTTV: + regs.fcttv = val; + break; + case REG_TCTL: + regs.tctl = val; + break; + case REG_PBA: + regs.pba.rxa(val); + regs.pba.txa(64 - regs.pba.rxa()); + break; + case REG_WUC: + case REG_LEDCTL: + case REG_FCAL: + case REG_FCAH: + case REG_FCT: + case REG_VET: + case REG_AIFS: + case REG_TIPG: + ; // We don't care, so don't store anything + break; + case REG_FCRTL: + regs.fcrtl = val; + break; + case REG_FCRTH: + regs.fcrth = val; + break; + case REG_RDBAL: + regs.rdba.rdbal( val & ~mask(4)); + break; + case REG_RDBAH: + regs.rdba.rdbah(val); + break; + case REG_RDLEN: + regs.rdlen = val & ~mask(7); + break; + case REG_RDH: + regs.rdh = val; + break; + case REG_RDT: + regs.rdt = val; + break; + case REG_RDTR: + regs.rdtr = val; + break; + case REG_RADV: + regs.radv = val; + break; + case REG_TDBAL: + regs.tdba.tdbal( val & ~mask(4)); + break; + case REG_TDBAH: + regs.tdba.tdbah(val); + break; + case REG_TDLEN: + regs.tdlen = val & ~mask(7); + break; + case REG_TDH: + regs.tdh = val; + break; + case REG_TDT: + regs.tdt = val; + break; + case REG_TIDV: + regs.tidv = val; + break; + case REG_TXDCTL: + regs.txdctl = val; + break; + case REG_TADV: + regs.tadv = val; + break; + case REG_RXCSUM: + regs.rxcsum = val; + break; + case REG_MANC: + regs.manc = val; + break; default: - if (!(daddr >= VFTA && daddr < (VFTA + VLAN_FILTER_TABLE_SIZE)*4) && - !(daddr >= RAL && daddr < (RAL + RCV_ADDRESS_TABLE_SIZE)*4) && - !(daddr >= MTA && daddr < (MTA + MULTICAST_TABLE_SIZE)*4)) + if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) && + !(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) && + !(daddr >= REG_MTA && daddr < (REG_MTA + MULTICAST_TABLE_SIZE*4))) panic("Write request to unknown register number: %#x\n", daddr); }; diff --git a/src/dev/i8254xGBe.hh b/src/dev/i8254xGBe.hh index ce4007263..fa9e65b22 100644 --- a/src/dev/i8254xGBe.hh +++ b/src/dev/i8254xGBe.hh @@ -54,13 +54,15 @@ class IGbE : public PciDev int eeOpBits, eeAddrBits, eeDataBits; uint8_t eeOpcode, eeAddr; + bool useFlowControl; + uint16_t flash[iGbReg::EEPROM_SIZE]; public: struct Params : public PciDev::Params { - ; + bool use_flow_control; }; IGbE(Params *params); diff --git a/src/dev/i8254xGBe_defs.hh b/src/dev/i8254xGBe_defs.hh index ae0925356..b59b34a67 100644 --- a/src/dev/i8254xGBe_defs.hh +++ b/src/dev/i8254xGBe_defs.hh @@ -31,47 +31,81 @@ /* @file * Register and structure descriptions for Intel's 8254x line of gigabit ethernet controllers. */ +#include "base/bitfield.hh" namespace iGbReg { -const uint32_t CTRL = 0x00000; //* -const uint32_t STATUS = 0x00008; //* -const uint32_t EECD = 0x00010; //* -const uint32_t EERD = 0x00014; //* -const uint32_t CTRL_EXT = 0x00018; -const uint32_t PBA = 0x01000; -const uint32_t ICR = 0x000C0; //* -const uint32_t ITR = 0x000C4; -const uint32_t ICS = 0x000C8; -const uint32_t IMS = 0x000D0; -const uint32_t IMC = 0x000D8; //* -const uint32_t RCTL = 0x00100; //* -const uint32_t RDBAL = 0x02800; -const uint32_t RDBAH = 0x02804; -const uint32_t RDLEN = 0x02808; -const uint32_t RDH = 0x02810; -const uint32_t RDT = 0x02818; -const uint32_t RDTR = 0x02820; -const uint32_t RADV = 0x0282C; -const uint32_t RSRPD = 0x02C00; -const uint32_t TCTL = 0x00400; //* -const uint32_t TDBAL = 0x03800; -const uint32_t TDBAH = 0x03804; -const uint32_t TDLEN = 0x03808; -const uint32_t TDH = 0x03810; -const uint32_t THT = 0x03818; -const uint32_t TIDV = 0x03820; -const uint32_t TXDMAC = 0x03000; -const uint32_t TXDCTL = 0x03828; -const uint32_t TADV = 0x0282C; -const uint32_t TSPMT = 0x03830; -const uint32_t RXDCTL = 0x02828; -const uint32_t RXCSUM = 0x05000; -const uint32_t MANC = 0x05820;//* +const uint32_t REG_CTRL = 0x00000; //* +const uint32_t REG_STATUS = 0x00008; //* +const uint32_t REG_EECD = 0x00010; //* +const uint32_t REG_EERD = 0x00014; //* +const uint32_t REG_CTRL_EXT = 0x00018; //*- +const uint32_t REG_MDIC = 0x00020; //* +const uint32_t REG_FCAL = 0x00028; //* +const uint32_t REG_FCAH = 0x0002C; //* +const uint32_t REG_FCT = 0x00030; //* +const uint32_t REG_VET = 0x00038; //* +const uint32_t REG_PBA = 0x01000; //* +const uint32_t REG_ICR = 0x000C0; //* +const uint32_t REG_ITR = 0x000C4; //* +const uint32_t REG_ICS = 0x000C8; //* +const uint32_t REG_IMS = 0x000D0; //* +const uint32_t REG_IMC = 0x000D8; //* +const uint32_t REG_IAM = 0x000E0; //* +const uint32_t REG_RCTL = 0x00100; //* +const uint32_t REG_FCTTV = 0x00170; //* +const uint32_t REG_TIPG = 0x00410; //* +const uint32_t REG_AIFS = 0x00458; //* +const uint32_t REG_LEDCTL = 0x00e00; //* +const uint32_t REG_FCRTL = 0x02160; //* +const uint32_t REG_FCRTH = 0x02168; //* +const uint32_t REG_RDBAL = 0x02800; //*- +const uint32_t REG_RDBAH = 0x02804; //*- +const uint32_t REG_RDLEN = 0x02808; //*- +const uint32_t REG_RDH = 0x02810; //*- +const uint32_t REG_RDT = 0x02818; //*- +const uint32_t REG_RDTR = 0x02820; //*- +const uint32_t REG_RXDCTL = 0x02828; //* +const uint32_t REG_RADV = 0x0282C; //*- +const uint32_t REG_RSRPD = 0x02C00; +const uint32_t REG_TCTL = 0x00400; //* +const uint32_t REG_TDBAL = 0x03800; //* +const uint32_t REG_TDBAH = 0x03804; //* +const uint32_t REG_TDLEN = 0x03808; //* +const uint32_t REG_TDH = 0x03810; //* +const uint32_t REG_TDT = 0x03818; //* +const uint32_t REG_TIDV = 0x03820; //* +const uint32_t REG_TXDMAC = 0x03000; +const uint32_t REG_TXDCTL = 0x03828; //* +const uint32_t REG_TADV = 0x0382C; //* +const uint32_t REG_TSPMT = 0x03830; +const uint32_t REG_CRCERRS = 0x04000; +const uint32_t REG_RXCSUM = 0x05000; //*- +const uint32_t REG_MTA = 0x05200; +const uint32_t REG_RAL = 0x05400; +const uint32_t REG_RAH = 0x05404; +const uint32_t REG_VFTA = 0x05600; + +const uint32_t REG_WUC = 0x05800;//* +const uint32_t REG_MANC = 0x05820;//* const uint8_t EEPROM_READ_OPCODE_SPI = 0x03; const uint8_t EEPROM_RDSR_OPCODE_SPI = 0x05; const uint8_t EEPROM_SIZE = 64; +const uint16_t EEPROM_CSUM = 0xBABA; + +const uint8_t VLAN_FILTER_TABLE_SIZE = 128; +const uint8_t RCV_ADDRESS_TABLE_SIZE = 16; +const uint8_t MULTICAST_TABLE_SIZE = 128; +const uint32_t STATS_REGS_SIZE = 0x124; + +const uint8_t PHY_PSTATUS = 0x1; +const uint8_t PHY_PID = 0x2; +const uint8_t PHY_EPID = 0x3; +const uint8_t PHY_GSTATUS = 10; +const uint8_t PHY_EPSTATUS = 15; +const uint8_t PHY_AGC = 18; + struct RxDesc { Addr buf; @@ -245,219 +279,377 @@ union TxDesc { } type; }; +#define ADD_FIELD32(NAME, OFFSET, BITS) \ + inline uint32_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \ + inline void NAME(uint32_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); } + +#define ADD_FIELD64(NAME, OFFSET, BITS) \ + inline uint64_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \ + inline void NAME(uint64_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); } + struct Regs { - union { // 0x0000 CTRL Register - uint32_t reg; - struct { - uint8_t fd:1; // full duplex - uint8_t bem:1; // big endian mode - uint8_t pcipr:1; // PCI priority - uint8_t lrst:1; // link reset - uint8_t tme:1; // test mode enable - uint8_t asde:1; // Auto-speed detection - uint8_t slu:1; // Set link up - uint8_t ilos:1; // invert los-of-signal - uint8_t speed:2; // speed selection bits - uint8_t be32:1; // big endian mode 32 - uint8_t frcspd:1; // force speed - uint8_t frcdpx:1; // force duplex - uint8_t duden:1; // dock/undock enable - uint8_t dudpol:1; // dock/undock polarity - uint8_t fphyrst:1; // force phy reset - uint8_t extlen:1; // external link status enable - uint8_t rsvd:1; // reserved - uint8_t sdp0d:1; // software controlled pin data - uint8_t sdp1d:1; // software controlled pin data - uint8_t sdp2d:1; // software controlled pin data - uint8_t sdp3d:1; // software controlled pin data - uint8_t sdp0i:1; // software controlled pin dir - uint8_t sdp1i:1; // software controlled pin dir - uint8_t sdp2i:1; // software controlled pin dir - uint8_t sdp3i:1; // software controlled pin dir - uint8_t rst:1; // reset - uint8_t rfce:1; // receive flow control enable - uint8_t tfce:1; // transmit flow control enable - uint8_t rte:1; // routing tag enable - uint8_t vme:1; // vlan enable - uint8_t phyrst:1; // phy reset - } ; - } ctrl; - - union { // 0x0008 STATUS - uint32_t reg; - struct { - uint8_t fd:1; // full duplex - uint8_t lu:1; // link up - uint8_t func:2; // function id - uint8_t txoff:1; // transmission paused - uint8_t tbimode:1; // tbi mode - uint8_t speed:2; // link speed - uint8_t asdv:2; // auto speed detection value - uint8_t mtxckok:1; // mtx clock running ok - uint8_t pci66:1; // In 66Mhz pci slot - uint8_t bus64:1; // in 64 bit slot - uint8_t pcix:1; // Pci mode - uint8_t pcixspd:1; // pci x speed - uint8_t reserved; // reserved - } ; - } sts; - - union { // 0x0010 EECD - uint32_t reg; - struct { - uint8_t sk:1; // clack input to the eeprom - uint8_t cs:1; // chip select to eeprom - uint8_t din:1; // data input to eeprom - uint8_t dout:1; // data output bit - uint8_t fwe:2; // flash write enable - uint8_t ee_req:1; // request eeprom access - uint8_t ee_gnt:1; // grant eeprom access - uint8_t ee_pres:1; // eeprom present - uint8_t ee_size:1; // eeprom size - uint8_t ee_sz1:1; // eeprom size - uint8_t rsvd:2; // reserved - uint8_t ee_type:1; // type of eeprom - } ; - } eecd; - - union { // 0x0014 EERD - uint32_t reg; - struct { - uint8_t start:1; // start read - uint8_t done:1; // done read - uint16_t addr:14; // address - uint16_t data; // data - }; - } eerd; + template<class T> + struct Reg { + T _data; + T operator()() { return _data; } + const Reg<T> &operator=(T d) { _data = d; return *this;} + bool operator==(T d) { return d == _data; } + void operator()(T d) { _data = d; } + }; - union { // 0x00C0 ICR - uint32_t reg; - struct { - uint8_t txdw:1; // tx descr witten back - uint8_t txqe:1; // tx queue empty - uint8_t lsc:1; // link status change - uint8_t rxseq:1; // rcv sequence error - uint8_t rxdmt0:1; // rcv descriptor min thresh - uint8_t rsvd1:1; // reserved - uint8_t rxo:1; // receive overrunn - uint8_t rxt0:1; // receiver timer interrupt - uint8_t rsvd2:1; // reserved - uint8_t mdac:1; // mdi/o access complete - uint8_t rxcfg:1; // recv /c/ ordered sets - uint8_t rsvd3:1; // reserved - uint8_t phyint:1; // phy interrupt - uint8_t gpi1:1; // gpi int 1 - uint8_t gpi2:1; // gpi int 2 - uint8_t txdlow:1; // transmit desc low thresh - uint8_t srpd:1; // small receive packet detected - uint16_t rsvd4:15; // reserved - } ; - } icd; - - union { // 0x00C0 IMC - uint32_t reg; - struct { - uint8_t txdw:1; // tx descr witten back - uint8_t txqe:1; // tx queue empty - uint8_t lsc:1; // link status change - uint8_t rxseq:1; // rcv sequence error - uint8_t rxdmt0:1; // rcv descriptor min thresh - uint8_t rsvd1:1; // reserved - uint8_t rxo:1; // receive overrunn - uint8_t rxt0:1; // receiver timer interrupt - uint8_t rsvd2:1; // reserved - uint8_t mdac:1; // mdi/o access complete - uint8_t rxcfg:1; // recv /c/ ordered sets - uint8_t rsvd3:1; // reserved - uint8_t phyint:1; // phy interrupt - uint8_t gpi1:1; // gpi int 1 - uint8_t gpi2:1; // gpi int 2 - uint8_t txdlow:1; // transmit desc low thresh - uint8_t srpd:1; // small receive packet detected - uint16_t rsvd4:15; // reserved - } ; - } imc; - - union { // 0x0100 RCTL - uint32_t reg; - struct { - uint8_t rst:1; // Reset - uint8_t en:1; // Enable - uint8_t sbp:1; // Store bad packets - uint8_t upe:1; // Unicast Promiscuous enabled - uint8_t mpe:1; // Multicast promiscuous enabled - uint8_t lpe:1; // long packet reception enabled - uint8_t lbm:2; // - uint8_t rdmts:2; // - uint8_t rsvd:2; // - uint8_t mo:2; // - uint8_t mdr:1; // - uint8_t bam:1; // - uint8_t bsize:2; // - uint8_t vpe:1; // - uint8_t cfien:1; // - uint8_t cfi:1; // - uint8_t rsvd2:1; // - uint8_t dpf:1; // discard pause frames - uint8_t pmcf:1; // pass mac control frames - uint8_t rsvd3:1; // reserved - uint8_t bsex:1; // buffer size extension - uint8_t secrc:1; // strip ethernet crc from incoming packet - uint8_t rsvd1:5; // reserved - } ; - } rctl; - - union { // 0x0400 TCTL - uint32_t reg; - struct { - uint8_t rst:1; // Reset - uint8_t en:1; // Enable - uint8_t bce:1; // busy check enable - uint8_t psp:1; // pad short packets - uint8_t ct:8; // collision threshold - uint16_t cold:10; // collision distance - uint8_t swxoff:1; // software xoff transmission - uint8_t pbe:1; // packet burst enable - uint8_t rtlc:1; // retransmit late collisions - uint8_t nrtu:1; // on underrun no TX - uint8_t mulr:1; // multiple request - uint8_t rsvd:5; // reserved - } ; - } tctl; - - union { // 0x5820 MANC - uint32_t reg; - struct { - uint8_t smbus:1; // SMBus enabled ##### - uint8_t asf:1; // ASF enabled ##### - uint8_t ronforce:1; // reset of force - uint8_t rsvd:5; // reserved - uint8_t rmcp1:1; // rcmp1 filtering - uint8_t rmcp2:1; // rcmp2 filtering - uint8_t ipv4:1; // enable ipv4 - uint8_t ipv6:1; // enable ipv6 - uint8_t snap:1; // accept snap - uint8_t arp:1; // filter arp ##### - uint8_t neighbor:1; // neighbor discovery - uint8_t arp_resp:1; // arp response - uint8_t tcorst:1; // tco reset happened - uint8_t rcvtco:1; // receive tco enabled ###### - uint8_t blkphyrst:1;// block phy resets ######## - uint8_t rcvall:1; // receive all - uint8_t macaddrfltr:1; // mac address filtering ###### - uint8_t mng2host:1; // mng2 host packets ####### - uint8_t ipaddrfltr:1; // ip address filtering - uint8_t xsumfilter:1; // checksum filtering - uint8_t brfilter:1; // broadcast filtering - uint8_t smbreq:1; // smb request - uint8_t smbgnt:1; // smb grant - uint8_t smbclkin:1; // smbclkin - uint8_t smbdatain:1; // smbdatain - uint8_t smbdataout:1; // smb data out - uint8_t smbclkout:1; // smb clock out - uint8_t rsvd2:2; - }; - } manc; + struct CTRL : public Reg<uint32_t> { // 0x0000 CTRL Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(fd,0,1); // full duplex + ADD_FIELD32(bem,1,1); // big endian mode + ADD_FIELD32(pcipr,2,1); // PCI priority + ADD_FIELD32(lrst,3,1); // link reset + ADD_FIELD32(tme,4,1); // test mode enable + ADD_FIELD32(asde,5,1); // Auto-speed detection + ADD_FIELD32(slu,6,1); // Set link up + ADD_FIELD32(ilos,7,1); // invert los-of-signal + ADD_FIELD32(speed,8,2); // speed selection bits + ADD_FIELD32(be32,10,1); // big endian mode 32 + ADD_FIELD32(frcspd,11,1); // force speed + ADD_FIELD32(frcdpx,12,1); // force duplex + ADD_FIELD32(duden,13,1); // dock/undock enable + ADD_FIELD32(dudpol,14,1); // dock/undock polarity + ADD_FIELD32(fphyrst,15,1); // force phy reset + ADD_FIELD32(extlen,16,1); // external link status enable + ADD_FIELD32(rsvd,17,1); // reserved + ADD_FIELD32(sdp0d,18,1); // software controlled pin data + ADD_FIELD32(sdp1d,19,1); // software controlled pin data + ADD_FIELD32(sdp2d,20,1); // software controlled pin data + ADD_FIELD32(sdp3d,21,1); // software controlled pin data + ADD_FIELD32(sdp0i,22,1); // software controlled pin dir + ADD_FIELD32(sdp1i,23,1); // software controlled pin dir + ADD_FIELD32(sdp2i,24,1); // software controlled pin dir + ADD_FIELD32(sdp3i,25,1); // software controlled pin dir + ADD_FIELD32(rst,26,1); // reset + ADD_FIELD32(rfce,27,1); // receive flow control enable + ADD_FIELD32(tfce,28,1); // transmit flow control enable + ADD_FIELD32(rte,29,1); // routing tag enable + ADD_FIELD32(vme,30,1); // vlan enable + ADD_FIELD32(phyrst,31,1); // phy reset + }; + CTRL ctrl; + + struct STATUS : public Reg<uint32_t> { // 0x0008 STATUS Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(fd,0,1); // full duplex + ADD_FIELD32(lu,1,1); // link up + ADD_FIELD32(func,2,2); // function id + ADD_FIELD32(txoff,4,1); // transmission paused + ADD_FIELD32(tbimode,5,1); // tbi mode + ADD_FIELD32(speed,6,2); // link speed + ADD_FIELD32(asdv,8,2); // auto speed detection value + ADD_FIELD32(mtxckok,10,1); // mtx clock running ok + ADD_FIELD32(pci66,11,1); // In 66Mhz pci slot + ADD_FIELD32(bus64,12,1); // in 64 bit slot + ADD_FIELD32(pcix,13,1); // Pci mode + ADD_FIELD32(pcixspd,14,2); // pci x speed + }; + STATUS sts; + + struct EECD : public Reg<uint32_t> { // 0x0010 EECD Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(sk,0,1); // clack input to the eeprom + ADD_FIELD32(cs,1,1); // chip select to eeprom + ADD_FIELD32(din,2,1); // data input to eeprom + ADD_FIELD32(dout,3,1); // data output bit + ADD_FIELD32(fwe,4,2); // flash write enable + ADD_FIELD32(ee_req,6,1); // request eeprom access + ADD_FIELD32(ee_gnt,7,1); // grant eeprom access + ADD_FIELD32(ee_pres,8,1); // eeprom present + ADD_FIELD32(ee_size,9,1); // eeprom size + ADD_FIELD32(ee_sz1,10,1); // eeprom size + ADD_FIELD32(rsvd,11,2); // reserved + ADD_FIELD32(ee_type,13,1); // type of eeprom + } ; + EECD eecd; + + struct EERD : public Reg<uint32_t> { // 0x0014 EERD Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(start,0,1); // start read + ADD_FIELD32(done,4,1); // done read + ADD_FIELD32(addr,8,8); // address + ADD_FIELD32(data,16,16); // data + }; + EERD eerd; + + struct CTRL_EXT : public Reg<uint32_t> { // 0x0018 CTRL_EXT Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(gpi_en,0,4); // enable interrupts from gpio + ADD_FIELD32(phyint,5,1); // reads the phy internal int status + ADD_FIELD32(sdp2_data,6,1); // data from gpio sdp + ADD_FIELD32(spd3_data,7,1); // data frmo gpio sdp + ADD_FIELD32(spd2_iodir,10,1); // direction of sdp2 + ADD_FIELD32(spd3_iodir,11,1); // direction of sdp2 + ADD_FIELD32(asdchk,12,1); // initiate auto-speed-detection + ADD_FIELD32(eerst,13,1); // reset the eeprom + ADD_FIELD32(spd_byps,15,1); // bypass speed select + ADD_FIELD32(ro_dis,17,1); // disable relaxed memory ordering + ADD_FIELD32(vreg,21,1); // power down the voltage regulator + ADD_FIELD32(link_mode,22,2); // interface to talk to the link + ADD_FIELD32(iame, 27,1); // interrupt acknowledge auto-mask ?? + ADD_FIELD32(drv_loaded, 28,1);// driver is loaded and incharge of device + ADD_FIELD32(timer_clr, 29,1); // clear interrupt timers after IMS clear ?? + }; + CTRL_EXT ctrl_ext; + + struct MDIC : public Reg<uint32_t> { // 0x0020 MDIC Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(data,0,16); // data + ADD_FIELD32(regadd,16,5); // register address + ADD_FIELD32(phyadd,21,5); // phy addresses + ADD_FIELD32(op,26,2); // opcode + ADD_FIELD32(r,28,1); // ready + ADD_FIELD32(i,29,1); // interrupt + ADD_FIELD32(e,30,1); // error + }; + MDIC mdic; + + struct ICR : public Reg<uint32_t> { // 0x00C0 ICR Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(txdw,0,1) // tx descr witten back + ADD_FIELD32(txqe,1,1) // tx queue empty + ADD_FIELD32(lsc,2,1) // link status change + ADD_FIELD32(rxseq,3,1) // rcv sequence error + ADD_FIELD32(rxdmt0,4,1) // rcv descriptor min thresh + ADD_FIELD32(rsvd1,5,1) // reserved + ADD_FIELD32(rxo,6,1) // receive overrunn + ADD_FIELD32(rxt0,7,1) // receiver timer interrupt + ADD_FIELD32(mdac,9,1) // mdi/o access complete + ADD_FIELD32(rxcfg,10,1) // recv /c/ ordered sets + ADD_FIELD32(phyint,12,1) // phy interrupt + ADD_FIELD32(gpi1,13,1) // gpi int 1 + ADD_FIELD32(gpi2,14,1) // gpi int 2 + ADD_FIELD32(txdlow,15,1) // transmit desc low thresh + ADD_FIELD32(srpd,16,1) // small receive packet detected + ADD_FIELD32(ack,17,1); // receive ack frame + ADD_FIELD32(int_assert, 31,0); // interrupt caused a system interrupt + }; + ICR icr; + + uint32_t imr; // register that contains the current interrupt mask + + struct ITR : public Reg<uint32_t> { // 0x00C4 ITR Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(interval, 0,16); // minimum inter-interrutp inteval + // specified in 256ns interrupts + }; + ITR itr; + + // When CTRL_EXT.IAME and the ICR.INT_ASSERT is 1 an ICR read or write + // causes the IAM register contents to be written into the IMC + // automatically clearing all interrupts that have a bit in the IAM set + uint32_t iam; + + struct RCTL : public Reg<uint32_t> { // 0x0100 RCTL Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(rst,0,1); // Reset + ADD_FIELD32(en,1,1); // Enable + ADD_FIELD32(sbp,2,1); // Store bad packets + ADD_FIELD32(upe,3,1); // Unicast Promiscuous enabled + ADD_FIELD32(mpe,4,1); // Multicast promiscuous enabled + ADD_FIELD32(lpe,5,1); // long packet reception enabled + ADD_FIELD32(lbm,6,2); // + ADD_FIELD32(rdmts,8,2); // + ADD_FIELD32(rsvd,10,2); // + ADD_FIELD32(mo,12,2); // + ADD_FIELD32(mdr,14,1); // + ADD_FIELD32(bam,15,1); // + ADD_FIELD32(bsize,16,2); // + ADD_FIELD32(vfe,18,1); // + ADD_FIELD32(cfien,19,1); // + ADD_FIELD32(cfi,20,1); // + ADD_FIELD32(rsvd2,21,1); // + ADD_FIELD32(dpf,22,1); // discard pause frames + ADD_FIELD32(pmcf,23,1); // pass mac control frames + ADD_FIELD32(bsex,25,1); // buffer size extension + ADD_FIELD32(secrc,26,1); // strip ethernet crc from incoming packet + }; + RCTL rctl; + + struct FCTTV : public Reg<uint32_t> { // 0x0170 FCTTV + using Reg<uint32_t>::operator=; + ADD_FIELD32(ttv,0,16); // Transmit Timer Value + }; + FCTTV fcttv; + + struct TCTL : public Reg<uint32_t> { // 0x0400 TCTL Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(rst,0,1); // Reset + ADD_FIELD32(en,1,1); // Enable + ADD_FIELD32(bce,2,1); // busy check enable + ADD_FIELD32(psp,3,1); // pad short packets + ADD_FIELD32(ct,4,8); // collision threshold + ADD_FIELD32(cold,12,10); // collision distance + ADD_FIELD32(swxoff,22,1); // software xoff transmission + ADD_FIELD32(pbe,23,1); // packet burst enable + ADD_FIELD32(rtlc,24,1); // retransmit late collisions + ADD_FIELD32(nrtu,25,1); // on underrun no TX + ADD_FIELD32(mulr,26,1); // multiple request + }; + TCTL tctl; + + struct PBA : public Reg<uint32_t> { // 0x1000 PBA Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(rxa,0,16); + ADD_FIELD32(txa,16,16); + }; + PBA pba; + + struct FCRTL : public Reg<uint32_t> { // 0x2160 FCRTL Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(rtl,3,28); // make this bigger than the spec so we can have + // a larger buffer + ADD_FIELD32(xone, 31,1); + }; + FCRTL fcrtl; + + struct FCRTH : public Reg<uint32_t> { // 0x2168 FCRTL Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(rth,3,13); // make this bigger than the spec so we can have + //a larger buffer + ADD_FIELD32(xfce, 31,1); + }; + FCRTH fcrth; + + struct RDBA : public Reg<uint64_t> { // 0x2800 RDBA Register + using Reg<uint64_t>::operator=; + ADD_FIELD64(rdbal,4,28); // base address of rx descriptor ring + ADD_FIELD64(rdbah,32,32); // base address of rx descriptor ring + }; + RDBA rdba; + + struct RDLEN : public Reg<uint32_t> { // 0x2808 RDLEN Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(len,7,13); // number of bytes in the descriptor buffer + }; + RDLEN rdlen; + + struct RDH : public Reg<uint32_t> { // 0x2810 RDH Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(rdh,0,16); // head of the descriptor ring + }; + RDH rdh; + + struct RDT : public Reg<uint32_t> { // 0x2818 RDT Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(rdt,0,16); // tail of the descriptor ring + }; + RDT rdt; + + struct RDTR : public Reg<uint32_t> { // 0x2820 RDTR Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(delay,0,16); // receive delay timer + ADD_FIELD32(fpd, 31,); // flush partial descriptor block ?? + }; + RDTR rdtr; + + struct RADV : public Reg<uint32_t> { // 0x282C RADV Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(idv,0,16); // absolute interrupt delay + }; + RADV radv; + + struct RSRPD : public Reg<uint32_t> { // 0x2C00 RSRPD Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(idv,0,12); // size to interrutp on small packets + }; + RSRPD rsrpd; + + struct TDBA : public Reg<uint64_t> { // 0x3800 TDBAL Register + using Reg<uint64_t>::operator=; + ADD_FIELD64(tdbal,4,28); // base address of transmit descriptor ring + ADD_FIELD64(tdbah,32,32); // base address of transmit descriptor ring + }; + TDBA tdba; + + struct TDLEN : public Reg<uint32_t> { // 0x3808 TDLEN Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(len,7,13); // number of bytes in the descriptor buffer + }; + TDLEN tdlen; + + struct TDH : public Reg<uint32_t> { // 0x3810 TDH Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(tdh,0,16); // head of the descriptor ring + }; + TDH tdh; + + struct TDT : public Reg<uint32_t> { // 0x3818 TDT Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(tdt,0,16); // tail of the descriptor ring + }; + TDT tdt; + + struct TIDV : public Reg<uint32_t> { // 0x3820 TIDV Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(idv,0,16); // interrupt delay + }; + TIDV tidv; + + struct TXDCTL : public Reg<uint32_t> { // 0x3828 TXDCTL Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(pthresh, 0,6); // if number of descriptors control has is + // below this number, a prefetch is considered + ADD_FIELD32(hthresh,8,8); // number of valid descriptors is host memory + // before a prefetch is considered + ADD_FIELD32(wthresh,16,6); // number of descriptors to keep until + // writeback is considered + ADD_FIELD32(gran, 24,1); // granulatiry of above values (0 = cacheline, + // 1 == desscriptor) + ADD_FIELD32(lwthresh,25,7); // xmit descriptor low thresh, interrupt + // below this level + }; + TXDCTL txdctl; + + struct TADV : public Reg<uint32_t> { // 0x382C TADV Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(idv,0,16); // absolute interrupt delay + }; + TADV tadv; + + struct RXCSUM : public Reg<uint32_t> { // 0x5000 RXCSUM Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(pcss,0,8); + ADD_FIELD32(ipofld,8,1); + ADD_FIELD32(tuofld,9,1); + }; + RXCSUM rxcsum; + + struct MANC : public Reg<uint32_t> { // 0x5820 MANC Register + using Reg<uint32_t>::operator=; + ADD_FIELD32(smbus,0,1); // SMBus enabled ##### + ADD_FIELD32(asf,1,1); // ASF enabled ##### + ADD_FIELD32(ronforce,2,1); // reset of force + ADD_FIELD32(rsvd,3,5); // reserved + ADD_FIELD32(rmcp1,8,1); // rcmp1 filtering + ADD_FIELD32(rmcp2,9,1); // rcmp2 filtering + ADD_FIELD32(ipv4,10,1); // enable ipv4 + ADD_FIELD32(ipv6,11,1); // enable ipv6 + ADD_FIELD32(snap,12,1); // accept snap + ADD_FIELD32(arp,13,1); // filter arp ##### + ADD_FIELD32(neighbor,14,1); // neighbor discovery + ADD_FIELD32(arp_resp,15,1); // arp response + ADD_FIELD32(tcorst,16,1); // tco reset happened + ADD_FIELD32(rcvtco,17,1); // receive tco enabled ###### + ADD_FIELD32(blkphyrst,18,1);// block phy resets ######## + ADD_FIELD32(rcvall,19,1); // receive all + ADD_FIELD32(macaddrfltr,20,1); // mac address filtering ###### + ADD_FIELD32(mng2host,21,1); // mng2 host packets ####### + ADD_FIELD32(ipaddrfltr,22,1); // ip address filtering + ADD_FIELD32(xsumfilter,23,1); // checksum filtering + ADD_FIELD32(brfilter,24,1); // broadcast filtering + ADD_FIELD32(smbreq,25,1); // smb request + ADD_FIELD32(smbgnt,26,1); // smb grant + ADD_FIELD32(smbclkin,27,1); // smbclkin + ADD_FIELD32(smbdatain,28,1); // smbdatain + ADD_FIELD32(smbdataout,29,1); // smb data out + ADD_FIELD32(smbclkout,30,1); // smb clock out + }; + MANC manc; }; }; // iGbReg namespace |