diff --git a/LICENSE b/LICENSE index 88190f1f55..78875df735 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2000-2008 The Regents of The University of Michigan +Copyright (c) 2000-2011 The Regents of The University of Michigan All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/README b/README index f8eef7417d..3b6a3f6bd9 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is release 2.0_beta6 of the M5 simulator. +This is the M5 simulator. For detailed information about building the simulator and getting started please refer to http://www.m5sim.org. @@ -9,13 +9,16 @@ http://www.m5sim.org/wiki/index.php/Running_M5 Short version: -1. If you don't have SCons version 0.96.91 or newer, get it from +1. If you don't have SCons version 0.98.1 or newer, get it from http://wwww.scons.org. -2. If you don't have SWIG version 1.3.28 or newer, get it from +2. If you don't have SWIG version 1.3.31 or newer, get it from http://wwww.swig.org. -3. In this directory, type 'scons build/ALPHA_SE/tests/debug/quick'. This +3. Make sure you also have gcc version 3.4.6 or newer, Python 2.4 or newer +(the dev version with header files), zlib, and the m4 preprocessor. + +4. In this directory, type 'scons build/ALPHA_SE/tests/debug/quick'. This will build the debug version of the m5 binary (m5.debug) for the Alpha syscall emulation target, and run the quick regression tests on it. @@ -25,18 +28,21 @@ WHAT'S INCLUDED (AND NOT) ------------------------- The basic source release includes these subdirectories: - - m5: - - src: source code of the m5 simulator - - tests: regression tests + - m5: + - configs: simulation configuration scripts - ext: less-common external packages needed to build m5 + - src: source code of the m5 simulator + - system: source for some optional system software for simulated systems + - tests: regression tests + - util: useful utility programs and files -To run full-system simulations, you will need compiled console, -PALcode, and kernel binaries and one or more disk images. These files -are collected in a separate archive, m5_system.tar.bz2. This file -can he downloaded separately. +To run full-system simulations, you will need compiled system firmware +(console and PALcode for Alpha), kernel binaries and one or more disk images. +These files for Alpha are collected in a separate archive, m5_system.tar.bz2. +This file can he downloaded separately. -M5 supports Linux 2.4/2.6, FreeBSD, and the proprietary Compaq/HP -Tru64 version of Unix. We are able to distribute Linux and FreeBSD -bootdisks, but we are unable to distribute bootable disk images of +Depending on the ISA used, M5 may support Linux 2.4/2.6, FreeBSD, and the +proprietary Compaq/HP Tru64 version of Unix. We are able to distribute Linux +and FreeBSD bootdisks, but we are unable to distribute bootable disk images of Tru64 Unix. If you have a Tru64 license and are interested in obtaining disk images, contact us at m5-users@m5sim.org diff --git a/RELEASE_NOTES b/RELEASE_NOTES deleted file mode 100644 index f10ffddae6..0000000000 --- a/RELEASE_NOTES +++ /dev/null @@ -1,149 +0,0 @@ -October 6, 2008: m5_2.0_beta6 --------------------- -New Features -1. Support for gcc 4.3 -2. Core m5 code in libm5 for integration with other simulators -3. Preliminary support for X86 SE mode -4. Additional system calls emulated -5. m5term updated to work on OS X -6. Ability to disable listen sockets -7. Event queue performance improvements and rewrite -8. Better errors for unconnected memory ports - -Bug fixes -1. ALPHA_SE O3 perlbmk benchmark -2. Translation bug where O3 could fetch from uncachable memory -3. Many minor bugs - -Outstanding issues for 2.0 release: --------------------- -1. Statistics cleanup -2. Improve regression system -3. Testing -4. Validation - -March 1, 2008: m5_2.0_beta5 --------------------- -New Features -1. Rick Strong's Simpoints config changes -2. Support for FSU ARM port -3. EXTRAS= option allow architectures to be specified - -Bug fixes -1. Bus timing more realistic -2. Cache writeback, LL/SC fixes -3. Minor IGbE NIC fixes -4. O3 op latency fix -5. SPARC TLB demap fixes -6. SPARC SE memory layout fixes -7. Variety of MIPS fixes - -Nov 4, 2007: m5_2.0_beta4 --------------------- -New Features -1. New cache model -2. Use of a I/O cache between devices and memory -3. Ability to include compiled code with EXTRAS= -4. Python creation of params structures for initialization -5. Ability to remotely debug in SE - -Bug fixes: -1. Fix SE serialization -2. SPARC_FS booting with TimingSimpleCPU -3. Rename cycles() to ticks() -4. Various SPARC ISA fixes -5. Draining code for checkpointing -6. Various performance improvements - -Possible Incompatibilities: -1. Real TLBs are now used in SE mode. This is more accurate however it could - cause some problems if you've modified the way page handling is done in - SE mode. -2. There have been many changes to the way the SCons files work. SimObjects, - sources files, and trace flags are all specified in the SConscript files. - To see how to add your sources take a look at one of them. -3. Python is now used to created the parameter structs that were created - manually before. The parameters listed in a py file are turned into - a header file with the same name (e.g. BadDevice.py -> BadDevice.hh). - With this change the structs can be populated automatically and the - ugly macros to define and create SimObjects at the bottem of source - files are gone. The parameter structs also automatically inherit - parameters from their parents. - -May 16, 2007: m5_2.0_beta3 --------------------- -New Features -1. Some support for SPARC full-system simulation -2. Reworking of trace facitities (parameter names changed, variadic macros - removed) -3. Scons script cleanups -4. Some support for compiling with Intel CC - -Bug fixes since beta 2: -1. Many SPARC linux syscall emulation support fixes -2. Multiprocessor linux boot using the detailed O3 CPU module -3. Workaround for DMA bug (final solution to be released with 2.0f) -4. Simulator performance and memory leak fixes -5. Fixed issue where console could stop printing in ALPHA_FS -6. Fix issues with remote debugging -7. Several compile fixes, including gcc 4.1 -8. Many other minor fixes and enhancements - -Nov. 28, 2006: m5_2.0_beta2 --------------------- -Bug fixes since beta 1: -1. Many cache issues resolved -2. Uni-coherence fixes in full-system -3. LL/SC Support -4. Draining/Switchover -5. Functional Accesses -6. Bus now has real timing -7. Single config file for all SpecCPU2000 benchmarks -8. Several other minor bug fixes and enhancements - -Aug. 25, 2006: m5_2.0_beta patch 1 --------------------- -Handful of minor bug fixes for m5_2.0_beta, -along with a few new regression tests. - -Aug. 15, 2006: m5_2.0_beta --------------------- -Major update to M5 including: -- New CPU model -- New memory system -- More extensive python integration -- Preliminary syscall emulation support for MIPS and SPARC -This is a *beta* release, meaning that some features are not complete, -and some features from M5 1.X aren't currently supported (e.g., MP -coherence). We are working to address these limitations and hope to -have a complete 2.0 release soon. - -Oct. 8, 2005: m5_1.1 --------------------- -Update release for IOSCA workshop mini-tutorial. New features include: -- Preliminary FreeBSD support -- Integration of regression tests into scons build framework -- Several bug fixes and better compatibility for Cygwin hosts -- Major cleanup of Alpha system code (console, PAL, etc.) to make - it easier for others to build/modify -- Fixes to enable compilation under g++ 4.0 -- Numerous minor bug fixes - -June 10, 2005: m5_1.0_web -------------------------- -The 1.0 release posted on Sourceforge after the ISCA tutorial contains -just a few very minor fixes relative to the CD. - -June 5, 2005: m5_1.0_tutorial ------------------------------ -First non-beta release. This release was on the CD distributed at the -ISCA tutorial. Major enhancements relative to beta releases include -Linux support and Python-based configuration language. - -June 17, 2004: m5_1.0_beta2 ---------------------------- -Stealth-mode beta bug-fix update, not widely advertised. - -Oct. 17, 2003: m5_1.0_beta1 ---------------------------- -Early beta release. diff --git a/configs/common/FSConfig.py b/configs/common/FSConfig.py index 9e5fd3a0b1..f58fd3d2e9 100644 --- a/configs/common/FSConfig.py +++ b/configs/common/FSConfig.py @@ -238,6 +238,7 @@ def makeLinuxArmSystem(mem_mode, mdesc = None, bare_metal=False, self.intrctrl = IntrControl() self.terminal = Terminal() + self.vncserver = VncServer() self.kernel = binary('vmlinux.arm') self.boot_osflags = 'earlyprintk mem=128MB console=ttyAMA0 lpj=19988480' + \ ' norandmaps slram=slram0,0x8000000,+0x8000000' + \ diff --git a/src/SConscript b/src/SConscript index cad0736c54..0ee1447476 100755 --- a/src/SConscript +++ b/src/SConscript @@ -446,7 +446,7 @@ def makeInfoPyFile(target, source, env): # Generate a file that wraps the basic top level files env.Command('python/m5/info.py', - [ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ], + [ '#/AUTHORS', '#/LICENSE', '#/README', ], MakeAction(makeInfoPyFile, Transform("INFO"))) PySource('m5', 'python/m5/info.py') diff --git a/src/arch/arm/table_walker.cc b/src/arch/arm/table_walker.cc index 6b2113639a..e6dd728dda 100644 --- a/src/arch/arm/table_walker.cc +++ b/src/arch/arm/table_walker.cc @@ -208,19 +208,20 @@ TableWalker::processWalk() return f; } + Request::Flags flag = 0; + if (currState->sctlr.c == 0) { + flag = Request::UNCACHEABLE; + } + if (currState->timing) { port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t), &doL1DescEvent, (uint8_t*)&currState->l1Desc.data, - currState->tc->getCpuPtr()->ticks(1)); + currState->tc->getCpuPtr()->ticks(1), flag); DPRINTF(TLBVerbose, "Adding to walker fifo: queue size before adding: %d\n", stateQueueL1.size()); stateQueueL1.push_back(currState); currState = NULL; } else { - Request::Flags flag = 0; - if (currState->sctlr.c == 0){ - flag = Request::UNCACHEABLE; - } port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t), NULL, (uint8_t*)&currState->l1Desc.data, currState->tc->getCpuPtr()->ticks(1), flag); @@ -472,7 +473,7 @@ TableWalker::doL1Descriptor() switch (currState->l1Desc.type()) { case L1Descriptor::Ignore: case L1Descriptor::Reserved: - if (!currState->delayed) { + if (!currState->timing) { currState->tc = NULL; currState->req = NULL; } @@ -577,7 +578,7 @@ TableWalker::doL2Descriptor() if (currState->l2Desc.invalid()) { DPRINTF(TLB, "L2 descriptor invalid, causing fault\n"); - if (!currState->delayed) { + if (!currState->timing) { currState->tc = NULL; currState->req = NULL; } @@ -622,7 +623,7 @@ TableWalker::doL2Descriptor() memAttrs(currState->tc, te, currState->sctlr, currState->l2Desc.texcb(), currState->l2Desc.shareable()); - if (!currState->delayed) { + if (!currState->timing) { currState->tc = NULL; currState->req = NULL; } diff --git a/src/arch/arm/table_walker.hh b/src/arch/arm/table_walker.hh index 267a7ad260..96a39cc619 100644 --- a/src/arch/arm/table_walker.hh +++ b/src/arch/arm/table_walker.hh @@ -93,14 +93,14 @@ class TableWalker : public MemObject { if (supersection()) panic("Super sections not implemented\n"); - return mbits(data, 31,20); + return mbits(data, 31, 20); } /** Return the physcal address of the entry, bits in position*/ Addr paddr(Addr va) const { if (supersection()) panic("Super sections not implemented\n"); - return mbits(data, 31,20) | mbits(va, 20, 0); + return mbits(data, 31, 20) | mbits(va, 19, 0); } @@ -109,7 +109,7 @@ class TableWalker : public MemObject { if (supersection()) panic("Super sections not implemented\n"); - return bits(data, 31,20); + return bits(data, 31, 20); } /** Is the translation global (no asid used)? */ @@ -127,19 +127,19 @@ class TableWalker : public MemObject /** Three bit access protection flags */ uint8_t ap() const { - return (bits(data, 15) << 2) | bits(data,11,10); + return (bits(data, 15) << 2) | bits(data, 11, 10); } /** Domain Client/Manager: ARM DDI 0406B: B3-31 */ uint8_t domain() const { - return bits(data,8,5); + return bits(data, 8, 5); } /** Address of L2 descriptor if it exists */ Addr l2Addr() const { - return mbits(data, 31,10); + return mbits(data, 31, 10); } /** Memory region attributes: ARM DDI 0406B: B3-32. @@ -149,7 +149,7 @@ class TableWalker : public MemObject */ uint8_t texcb() const { - return bits(data, 2) | bits(data,3) << 1 | bits(data, 14, 12) << 2; + return bits(data, 2) | bits(data, 3) << 1 | bits(data, 14, 12) << 2; } /** If the section is shareable. See texcb() comment. */ @@ -187,7 +187,7 @@ class TableWalker : public MemObject /** Is the entry invalid */ bool invalid() const { - return bits(data, 1,0) == 0;; + return bits(data, 1, 0) == 0; } /** What is the size of the mapping? */ @@ -218,8 +218,8 @@ class TableWalker : public MemObject uint8_t texcb() const { return large() ? - (bits(data, 2) | (bits(data,3) << 1) | (bits(data, 14, 12) << 2)) : - (bits(data, 2) | (bits(data,3) << 1) | (bits(data, 8, 6) << 2)); + (bits(data, 2) | (bits(data, 3) << 1) | (bits(data, 14, 12) << 2)) : + (bits(data, 2) | (bits(data, 3) << 1) | (bits(data, 8, 6) << 2)); } /** Return the physical frame, bits shifted right */ diff --git a/src/arch/arm/tlb.cc b/src/arch/arm/tlb.cc index e5f5b36f63..230c562001 100644 --- a/src/arch/arm/tlb.cc +++ b/src/arch/arm/tlb.cc @@ -696,6 +696,8 @@ TLB::translateTiming(RequestPtr req, ThreadContext *tc, #endif if (!delay) translation->finish(fault, req, tc, mode); + else + translation->markDelayed(); return fault; } diff --git a/src/arch/generic/debugfaults.hh b/src/arch/generic/debugfaults.hh new file mode 100644 index 0000000000..acffadc343 --- /dev/null +++ b/src/arch/generic/debugfaults.hh @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2010 Advanced Micro Devices + * All rights reserved. + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_GENERIC_DEBUGFAULTS_HH__ +#define __ARCH_GENERIC_DEBUGFAULTS_HH__ + +#include "base/misc.hh" +#include "sim/faults.hh" + +#include + +namespace GenericISA +{ +class M5DebugFault : public FaultBase +{ + public: + enum DebugFunc + { + PanicFunc, + FatalFunc, + WarnFunc, + WarnOnceFunc + }; + + protected: + std::string message; + DebugFunc func; + + public: + M5DebugFault(DebugFunc _func, std::string _message) : + message(_message), func(_func) + {} + + FaultName + name() const + { + switch (func) { + case PanicFunc: + return "panic fault"; + case FatalFunc: + return "fatal fault"; + case WarnFunc: + return "warn fault"; + case WarnOnceFunc: + return "warn_once fault"; + default: + panic("unrecognized debug function number\n"); + } + } + + void + invoke(ThreadContext *tc, + StaticInstPtr inst = StaticInst::nullStaticInstPtr) + { + switch (func) { + case PanicFunc: + panic(message); + break; + case FatalFunc: + fatal(message); + break; + case WarnFunc: + warn(message); + break; + case WarnOnceFunc: + warn_once(message); + break; + default: + panic("unrecognized debug function number\n"); + } + } +}; +} // namespace GenericISA + +#endif // __ARCH_GENERIC_DEBUGFAULTS_HH__ diff --git a/src/arch/mips/isa/decoder.isa b/src/arch/mips/isa/decoder.isa index 173fa89dfc..d97a141de4 100644 --- a/src/arch/mips/isa/decoder.isa +++ b/src/arch/mips/isa/decoder.isa @@ -367,21 +367,7 @@ decode OPCODE_HI default Unknown::unknown() { }}); 0x1: addiu({{ Rt.sw = Rs.sw + imm; }}); 0x2: slti({{ Rt.sw = (Rs.sw < imm) ? 1 : 0 }}); - - //Edited to include MIPS AVP Pass/Fail instructions and - //default to the sltiu instruction - 0x3: decode RS_RT_INTIMM { - 0xabc1: BasicOp::fail({{ - exitSimLoop("AVP/SRVP Test Failed"); - }}); - 0xabc2: BasicOp::pass({{ - exitSimLoop("AVP/SRVP Test Passed"); - }}); - default: sltiu({{ - Rt.uw = (Rs.uw < (uint32_t)sextImm) ? 1 : 0; - }}); - } - + 0x3: sltiu({{ Rt.uw = (Rs.uw < (uint32_t)sextImm) ? 1 : 0;}}); 0x4: andi({{ Rt.sw = Rs.sw & zextImm; }}); 0x5: ori({{ Rt.sw = Rs.sw | zextImm; }}); 0x6: xori({{ Rt.sw = Rs.sw ^ zextImm; }}); diff --git a/src/arch/x86/SConscript b/src/arch/x86/SConscript index 27de9da11a..9cb7746475 100644 --- a/src/arch/x86/SConscript +++ b/src/arch/x86/SConscript @@ -46,6 +46,7 @@ if env['TARGET_ISA'] == 'x86': Source('cpuid.cc') Source('emulenv.cc') Source('faults.cc') + Source('insts/badmicroop.cc') Source('insts/microfpop.cc') Source('insts/microldstop.cc') Source('insts/micromediaop.cc') diff --git a/src/arch/x86/insts/badmicroop.cc b/src/arch/x86/insts/badmicroop.cc new file mode 100644 index 0000000000..ef493f250d --- /dev/null +++ b/src/arch/x86/insts/badmicroop.cc @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2011 Advanced Micro Devices + * All rights reserved. + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "arch/x86/insts/badmicroop.hh" +#include "arch/x86/isa_traits.hh" +#include "arch/x86/decoder.hh" + +namespace X86ISA +{ + +// This microop needs to be allocated on the heap even though it could +// theoretically be statically allocated. The reference counted pointer would +// try to delete the static memory when it was destructed. +const StaticInstPtr badMicroop = + new X86ISAInst::MicroPanic(NoopMachInst, "BAD", + StaticInst::IsMicroop | StaticInst::IsLastMicroop, + "Invalid microop!", 0); + +} // namespace X86ISA diff --git a/src/arch/x86/insts/badmicroop.hh b/src/arch/x86/insts/badmicroop.hh new file mode 100644 index 0000000000..57fe242c49 --- /dev/null +++ b/src/arch/x86/insts/badmicroop.hh @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2011 Advanced Micro Devices + * All rights reserved. + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_X86_INSTS_BADMICROOP_HH__ +#define __ARCH_X86_INSTS_BADMICROOP_HH__ + +class StaticInstPtr; + +namespace X86ISA +{ + +extern const StaticInstPtr badMicroop; + +} // namespace X86ISA + +#endif //__ARCH_X86_INSTS_BADMICROOP_HH__ diff --git a/src/arch/x86/insts/macroop.hh b/src/arch/x86/insts/macroop.hh index fcf051a371..4f4176b770 100644 --- a/src/arch/x86/insts/macroop.hh +++ b/src/arch/x86/insts/macroop.hh @@ -41,6 +41,7 @@ #define __ARCH_X86_INSTS_MACROOP_HH__ #include "arch/x86/emulenv.hh" +#include "arch/x86/insts/badmicroop.hh" #include "arch/x86/types.hh" #include "arch/x86/insts/static_inst.hh" @@ -76,8 +77,10 @@ class MacroopBase : public X86StaticInst StaticInstPtr fetchMicroop(MicroPC microPC) const { - assert(microPC < numMicroops); - return microops[microPC]; + if (microPC >= numMicroops) + return badMicroop; + else + return microops[microPC]; } std::string diff --git a/src/arch/x86/insts/microregop.cc b/src/arch/x86/insts/microregop.cc index 6aee874493..dedea0f3d6 100644 --- a/src/arch/x86/insts/microregop.cc +++ b/src/arch/x86/insts/microregop.cc @@ -50,9 +50,6 @@ namespace X86ISA bool subtract) const { DPRINTF(X86, "flagMask = %#x\n", flagMask); - if (_destRegIdx[0] & IntFoldBit) { - _dest >>= 8; - } uint64_t flags = oldFlags & ~flagMask; if(flagMask & (ECFBit | CFBit)) { diff --git a/src/arch/x86/isa/includes.isa b/src/arch/x86/isa/includes.isa index 58b1fbc626..674e69e982 100644 --- a/src/arch/x86/isa/includes.isa +++ b/src/arch/x86/isa/includes.isa @@ -53,6 +53,7 @@ output header {{ #include #include +#include "arch/generic/debugfaults.hh" #include "arch/x86/emulenv.hh" #include "arch/x86/insts/macroop.hh" #include "arch/x86/insts/microfpop.hh" @@ -113,6 +114,7 @@ output exec {{ #include "arch/x86/regs/misc.hh" #include "arch/x86/tlb.hh" #include "base/bigint.hh" +#include "base/compiler.hh" #include "base/condcodes.hh" #include "cpu/base.hh" #include "cpu/exetrace.hh" diff --git a/src/arch/x86/isa/microops/debug.isa b/src/arch/x86/isa/microops/debug.isa index 4b2ecdd5aa..220c1af972 100644 --- a/src/arch/x86/isa/microops/debug.isa +++ b/src/arch/x86/isa/microops/debug.isa @@ -45,16 +45,29 @@ output header {{ class MicroDebugBase : public X86ISA::X86MicroopBase { protected: + typedef GenericISA::M5DebugFault::DebugFunc DebugFunc; + DebugFunc func; std::string message; uint8_t cc; public: - MicroDebugBase(ExtMachInst _machInst, const char * mnem, + MicroDebugBase(ExtMachInst machInst, const char * mnem, const char * instMnem, uint64_t setFlags, - std::string _message, uint8_t _cc); + DebugFunc _func, std::string _message, uint8_t _cc) : + X86MicroopBase(machInst, mnem, instMnem, setFlags, No_OpClass), + func(_func), message(_message), cc(_cc) + {} - std::string generateDisassembly(Addr pc, - const SymbolTable *symtab) const; + std::string + generateDisassembly(Addr pc, const SymbolTable *symtab) const + { + std::stringstream response; + + printMnemonic(response, instMnem, mnemonic); + response << "\"" << message << "\""; + + return response.str(); + } }; }}; @@ -70,53 +83,31 @@ def template MicroDebugDeclare {{ }}; def template MicroDebugExecute {{ - Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Fault + %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const { %(op_decl)s %(op_rd)s if (%(cond_test)s) { - %(func)s("%s\n", message); + return new GenericISA::M5DebugFault(func, message); + } else { + return NoFault; } - return NoFault; } }}; -output decoder {{ - inline MicroDebugBase::MicroDebugBase( - ExtMachInst machInst, const char * mnem, const char * instMnem, - uint64_t setFlags, std::string _message, uint8_t _cc) : - X86MicroopBase(machInst, mnem, instMnem, - setFlags, No_OpClass), - message(_message), cc(_cc) - { - } -}}; - def template MicroDebugConstructor {{ - inline %(class_name)s::%(class_name)s( + %(class_name)s::%(class_name)s( ExtMachInst machInst, const char * instMnem, uint64_t setFlags, std::string _message, uint8_t _cc) : %(base_class)s(machInst, "%(func)s", instMnem, - setFlags, _message, _cc) + setFlags, %(func_num)s, _message, _cc) { %(constructor)s; } }}; -output decoder {{ - std::string MicroDebugBase::generateDisassembly(Addr pc, - const SymbolTable *symtab) const - { - std::stringstream response; - - printMnemonic(response, instMnem, mnemonic); - response << "\"" << message << "\""; - - return response.str(); - } -}}; - let {{ class MicroDebug(X86Microop): def __init__(self, message, flags=None): @@ -142,13 +133,14 @@ let {{ header_output = "" decoder_output = "" - def buildDebugMicro(func): + def buildDebugMicro(func, func_num): global exec_output, header_output, decoder_output iop = InstObjParams(func, "Micro%sFlags" % func.capitalize(), "MicroDebugBase", {"code": "", "func": func, + "func_num": "GenericISA::M5DebugFault::%s" % func_num, "cond_test": "checkCondition(ccFlagBits, cc)"}) exec_output += MicroDebugExecute.subst(iop) header_output += MicroDebugDeclare.subst(iop) @@ -158,6 +150,7 @@ let {{ "MicroDebugBase", {"code": "", "func": func, + "func_num": "GenericISA::M5DebugFault::%s" % func_num, "cond_test": "true"}) exec_output += MicroDebugExecute.subst(iop) header_output += MicroDebugDeclare.subst(iop) @@ -169,8 +162,8 @@ let {{ global microopClasses microopClasses[func] = MicroDebugChild - buildDebugMicro("panic") - buildDebugMicro("fatal") - buildDebugMicro("warn") - buildDebugMicro("warn_once") + buildDebugMicro("panic", "PanicFunc") + buildDebugMicro("fatal", "FatalFunc") + buildDebugMicro("warn", "WarnFunc") + buildDebugMicro("warn_once", "WarnOnceFunc") }}; diff --git a/src/arch/x86/isa/microops/ldstop.isa b/src/arch/x86/isa/microops/ldstop.isa index 216a74c6cb..cd649d6447 100644 --- a/src/arch/x86/isa/microops/ldstop.isa +++ b/src/arch/x86/isa/microops/ldstop.isa @@ -301,6 +301,46 @@ let {{ "dataSize" : self.dataSize, "addressSize" : self.addressSize, "memFlags" : self.memFlags} return allocator + + class BigLdStOp(X86Microop): + def __init__(self, data, segment, addr, disp, + dataSize, addressSize, baseFlags, atCPL0, prefetch): + self.data = data + [self.scale, self.index, self.base] = addr + self.disp = disp + self.segment = segment + self.dataSize = dataSize + self.addressSize = addressSize + self.memFlags = baseFlags + if atCPL0: + self.memFlags += " | (CPL0FlagBit << FlagShift)" + if prefetch: + self.memFlags += " | Request::PREFETCH" + self.memFlags += " | (machInst.legacy.addr ? " + \ + "(AddrSizeFlagBit << FlagShift) : 0)" + + def getAllocator(self, microFlags): + allocString = ''' + (%(dataSize)s >= 4) ? + (StaticInstPtr)(new %(class_name)sBig(machInst, + macrocodeBlock, %(flags)s, %(scale)s, %(index)s, + %(base)s, %(disp)s, %(segment)s, %(data)s, + %(dataSize)s, %(addressSize)s, %(memFlags)s)) : + (StaticInstPtr)(new %(class_name)s(machInst, + macrocodeBlock, %(flags)s, %(scale)s, %(index)s, + %(base)s, %(disp)s, %(segment)s, %(data)s, + %(dataSize)s, %(addressSize)s, %(memFlags)s)) + ''' + allocator = allocString % { + "class_name" : self.className, + "flags" : self.microFlagsText(microFlags), + "scale" : self.scale, "index" : self.index, + "base" : self.base, + "disp" : self.disp, + "segment" : self.segment, "data" : self.data, + "dataSize" : self.dataSize, "addressSize" : self.addressSize, + "memFlags" : self.memFlags} + return allocator }}; let {{ @@ -315,7 +355,8 @@ let {{ EA = bits(SegBase + scale * Index + Base + disp, addressSize * 8 - 1, 0); ''' - def defineMicroLoadOp(mnemonic, code, mem_flags="0"): + def defineMicroLoadOp(mnemonic, code, bigCode='', + mem_flags="0", big=True): global header_output global decoder_output global exec_output @@ -324,16 +365,22 @@ let {{ name = mnemonic.lower() # Build up the all register version of this micro op - iop = InstObjParams(name, Name, 'X86ISA::LdStOp', - {"code": code, - "ea_code": calculateEA}) - header_output += MicroLdStOpDeclare.subst(iop) - decoder_output += MicroLdStOpConstructor.subst(iop) - exec_output += MicroLoadExecute.subst(iop) - exec_output += MicroLoadInitiateAcc.subst(iop) - exec_output += MicroLoadCompleteAcc.subst(iop) + iops = [InstObjParams(name, Name, 'X86ISA::LdStOp', + {"code": code, "ea_code": calculateEA})] + if big: + iops += [InstObjParams(name, Name + "Big", 'X86ISA::LdStOp', + {"code": bigCode, "ea_code": calculateEA})] + for iop in iops: + header_output += MicroLdStOpDeclare.subst(iop) + decoder_output += MicroLdStOpConstructor.subst(iop) + exec_output += MicroLoadExecute.subst(iop) + exec_output += MicroLoadInitiateAcc.subst(iop) + exec_output += MicroLoadCompleteAcc.subst(iop) - class LoadOp(LdStOp): + base = LdStOp + if big: + base = BigLdStOp + class LoadOp(base): def __init__(self, data, segment, addr, disp = 0, dataSize="env.dataSize", addressSize="env.addressSize", @@ -346,12 +393,15 @@ let {{ microopClasses[name] = LoadOp - defineMicroLoadOp('Ld', 'Data = merge(Data, Mem, dataSize);') + defineMicroLoadOp('Ld', 'Data = merge(Data, Mem, dataSize);', + 'Data = Mem & mask(dataSize * 8);') defineMicroLoadOp('Ldst', 'Data = merge(Data, Mem, dataSize);', - '(StoreCheck << FlagShift)') + 'Data = Mem & mask(dataSize * 8);', + '(StoreCheck << FlagShift)') defineMicroLoadOp('Ldstl', 'Data = merge(Data, Mem, dataSize);', - '(StoreCheck << FlagShift) | Request::LOCKED') - defineMicroLoadOp('Ldfp', 'FpData.uqw = Mem;') + 'Data = Mem & mask(dataSize * 8);', + '(StoreCheck << FlagShift) | Request::LOCKED') + defineMicroLoadOp('Ldfp', 'FpData.uqw = Mem;', big = False) def defineMicroStoreOp(mnemonic, code, \ postCode="", completeCode="", mem_flags="0"): diff --git a/src/arch/x86/isa/microops/limmop.isa b/src/arch/x86/isa/microops/limmop.isa index 2871d5a892..ac78b090dd 100644 --- a/src/arch/x86/isa/microops/limmop.isa +++ b/src/arch/x86/isa/microops/limmop.isa @@ -114,8 +114,16 @@ let {{ self.dataSize = dataSize def getAllocator(self, microFlags): - allocator = '''new %(class_name)s(machInst, macrocodeBlock, - %(flags)s, %(dest)s, %(imm)s, %(dataSize)s)''' % { + allocString = ''' + (%(dataSize)s >= 4) ? + (StaticInstPtr)(new %(class_name)sBig(machInst, + macrocodeBlock, %(flags)s, %(dest)s, %(imm)s, + %(dataSize)s)) : + (StaticInstPtr)(new %(class_name)s(machInst, + macrocodeBlock, %(flags)s, %(dest)s, %(imm)s, + %(dataSize)s)) + ''' + allocator = allocString % { "class_name" : self.className, "mnemonic" : self.mnemonic, "flags" : self.microFlagsText(microFlags), @@ -152,12 +160,15 @@ let {{ let {{ # Build up the all register version of this micro op - iop = InstObjParams("limm", "Limm", 'X86MicroopBase', - {"code" : "DestReg = merge(DestReg, imm, dataSize);"}) - header_output += MicroLimmOpDeclare.subst(iop) - decoder_output += MicroLimmOpConstructor.subst(iop) - decoder_output += MicroLimmOpDisassembly.subst(iop) - exec_output += MicroLimmOpExecute.subst(iop) + iops = [InstObjParams("limm", "Limm", 'X86MicroopBase', + {"code" : "DestReg = merge(DestReg, imm, dataSize);"}), + InstObjParams("limm", "LimmBig", 'X86MicroopBase', + {"code" : "DestReg = imm & mask(dataSize * 8);"})] + for iop in iops: + header_output += MicroLimmOpDeclare.subst(iop) + decoder_output += MicroLimmOpConstructor.subst(iop) + decoder_output += MicroLimmOpDisassembly.subst(iop) + exec_output += MicroLimmOpExecute.subst(iop) iop = InstObjParams("lfpimm", "Lfpimm", 'X86MicroopBase', {"code" : "FpDestReg.uqw = imm"}) diff --git a/src/arch/x86/isa/microops/regop.isa b/src/arch/x86/isa/microops/regop.isa index ccfcb3a69a..e2a51c1271 100644 --- a/src/arch/x86/isa/microops/regop.isa +++ b/src/arch/x86/isa/microops/regop.isa @@ -51,6 +51,8 @@ def template MicroRegOpExecute {{ %(op_decl)s; %(op_rd)s; + IntReg result M5_VAR_USED; + if(%(cond_check)s) { %(code)s; @@ -79,6 +81,8 @@ def template MicroRegOpImmExecute {{ %(op_decl)s; %(op_rd)s; + IntReg result M5_VAR_USED; + if(%(cond_check)s) { %(code)s; @@ -224,8 +228,8 @@ let {{ MicroRegOpExecute) class RegOpMeta(type): - def buildCppClasses(self, name, Name, suffix, \ - code, flag_code, cond_check, else_code, cond_control_flag_init): + def buildCppClasses(self, name, Name, suffix, code, big_code, \ + flag_code, cond_check, else_code, cond_control_flag_init): # Globals to stick the output in global header_output @@ -235,11 +239,13 @@ let {{ # Stick all the code together so it can be searched at once allCode = "|".join((code, flag_code, cond_check, else_code, cond_control_flag_init)) + allBigCode = "|".join((big_code, flag_code, cond_check, else_code, + cond_control_flag_init)) # If op2 is used anywhere, make register and immediate versions # of this code. matcher = re.compile("(?s?)op2(?P\\.\\w+)?") - match = matcher.search(allCode) + match = matcher.search(allCode + allBigCode) if match: typeQual = "" if match.group("typeQual"): @@ -247,6 +253,7 @@ let {{ src2_name = "%spsrc2%s" % (match.group("prefix"), typeQual) self.buildCppClasses(name, Name, suffix, matcher.sub(src2_name, code), + matcher.sub(src2_name, big_code), matcher.sub(src2_name, flag_code), matcher.sub(src2_name, cond_check), matcher.sub(src2_name, else_code), @@ -254,6 +261,7 @@ let {{ imm_name = "%simm8" % match.group("prefix") self.buildCppClasses(name + "i", Name, suffix + "Imm", matcher.sub(imm_name, code), + matcher.sub(imm_name, big_code), matcher.sub(imm_name, flag_code), matcher.sub(imm_name, cond_check), matcher.sub(imm_name, else_code), @@ -264,27 +272,32 @@ let {{ # a version without it and fix up this version to use it. if flag_code != "" or cond_check != "true": self.buildCppClasses(name, Name, suffix, - code, "", "true", else_code, "") + code, big_code, "", "true", else_code, "") suffix = "Flags" + suffix # If psrc1 or psrc2 is used, we need to actually insert code to # compute it. - matcher = re.compile("(?= 4) ? + (StaticInstPtr)(new %(class_name)sBig(machInst, + macrocodeBlock, %(flags)s, %(src1)s, %(op2)s, + %(dest)s, %(dataSize)s, %(ext)s)) : + (StaticInstPtr)(new %(class_name)s(machInst, + macrocodeBlock, %(flags)s, %(src1)s, %(op2)s, + %(dest)s, %(dataSize)s, %(ext)s)) + ''' + allocator = allocString % { + "class_name" : className, + "flags" : self.microFlagsText(microFlags), + "src1" : self.src1, "op2" : self.op2, + "dest" : self.dest, + "dataSize" : self.dataSize, + "ext" : self.ext} + return allocator + else: + className = self.className + if self.mnemonic == self.base_mnemonic + 'i': + className += "Imm" + allocator = '''new %(class_name)s(machInst, macrocodeBlock, + %(flags)s, %(src1)s, %(op2)s, %(dest)s, + %(dataSize)s, %(ext)s)''' % { + "class_name" : className, + "flags" : self.microFlagsText(microFlags), + "src1" : self.src1, "op2" : self.op2, + "dest" : self.dest, + "dataSize" : self.dataSize, + "ext" : self.ext} + return allocator class LogicRegOp(RegOp): abstract = True flag_code = ''' //Don't have genFlags handle the OF or CF bits uint64_t mask = CFBit | ECFBit | OFBit; - ccFlagBits = genFlags(ccFlagBits, ext & ~mask, DestReg, psrc1, op2); + ccFlagBits = genFlags(ccFlagBits, ext & ~mask, result, psrc1, op2); //If a logic microop wants to set these, it wants to set them to 0. ccFlagBits &= ~(CFBit & ext); ccFlagBits &= ~(ECFBit & ext); @@ -401,12 +448,12 @@ let {{ class FlagRegOp(RegOp): abstract = True flag_code = \ - "ccFlagBits = genFlags(ccFlagBits, ext, DestReg, psrc1, op2);" + "ccFlagBits = genFlags(ccFlagBits, ext, result, psrc1, op2);" class SubRegOp(RegOp): abstract = True flag_code = \ - "ccFlagBits = genFlags(ccFlagBits, ext, DestReg, psrc1, ~op2, true);" + "ccFlagBits = genFlags(ccFlagBits, ext, result, psrc1, ~op2, true);" class CondRegOp(RegOp): abstract = True @@ -428,31 +475,44 @@ let {{ src1, src2, flags, dataSize) class Add(FlagRegOp): - code = 'DestReg = merge(DestReg, psrc1 + op2, dataSize);' + code = 'DestReg = merge(DestReg, result = (psrc1 + op2), dataSize);' + big_code = 'DestReg = result = (psrc1 + op2) & mask(dataSize * 8);' class Or(LogicRegOp): - code = 'DestReg = merge(DestReg, psrc1 | op2, dataSize);' + code = 'DestReg = merge(DestReg, result = (psrc1 | op2), dataSize);' + big_code = 'DestReg = result = (psrc1 | op2) & mask(dataSize * 8);' class Adc(FlagRegOp): code = ''' CCFlagBits flags = ccFlagBits; - DestReg = merge(DestReg, psrc1 + op2 + flags.cf, dataSize); + DestReg = merge(DestReg, result = (psrc1 + op2 + flags.cf), dataSize); + ''' + big_code = ''' + CCFlagBits flags = ccFlagBits; + DestReg = result = (psrc1 + op2 + flags.cf) & mask(dataSize * 8); ''' class Sbb(SubRegOp): code = ''' CCFlagBits flags = ccFlagBits; - DestReg = merge(DestReg, psrc1 - op2 - flags.cf, dataSize); + DestReg = merge(DestReg, result = (psrc1 - op2 - flags.cf), dataSize); + ''' + big_code = ''' + CCFlagBits flags = ccFlagBits; + DestReg = result = (psrc1 - op2 - flags.cf) & mask(dataSize * 8); ''' class And(LogicRegOp): - code = 'DestReg = merge(DestReg, psrc1 & op2, dataSize)' + code = 'DestReg = merge(DestReg, result = (psrc1 & op2), dataSize)' + big_code = 'DestReg = result = (psrc1 & op2) & mask(dataSize * 8)' class Sub(SubRegOp): - code = 'DestReg = merge(DestReg, psrc1 - op2, dataSize)' + code = 'DestReg = merge(DestReg, result = (psrc1 - op2), dataSize)' + big_code = 'DestReg = result = (psrc1 - op2) & mask(dataSize * 8)' class Xor(LogicRegOp): - code = 'DestReg = merge(DestReg, psrc1 ^ op2, dataSize)' + code = 'DestReg = merge(DestReg, result = (psrc1 ^ op2), dataSize)' + big_code = 'DestReg = result = (psrc1 ^ op2) & mask(dataSize * 8)' class Mul1s(WrRegOp): code = ''' @@ -505,6 +565,7 @@ let {{ class Mulel(RdRegOp): code = 'DestReg = merge(SrcReg1, ProdLow, dataSize);' + big_code = 'DestReg = ProdLow & mask(dataSize * 8);' class Muleh(RdRegOp): def __init__(self, dest, src1=None, flags=None, dataSize="env.dataSize"): @@ -513,6 +574,7 @@ let {{ super(RdRegOp, self).__init__(dest, src1, \ "InstRegIndex(NUM_INTREGS)", flags, dataSize) code = 'DestReg = merge(SrcReg1, ProdHi, dataSize);' + big_code = 'DestReg = ProdHi & mask(dataSize * 8);' # One or two bit divide class Div1(WrRegOp): @@ -540,7 +602,7 @@ let {{ # Step divide class Div2(RegOp): - code = ''' + divCode = ''' uint64_t dividend = Remainder; uint64_t divisor = Divisor; uint64_t quotient = Quotient; @@ -587,11 +649,13 @@ let {{ } } //Keep track of how many bits there are still to pull in. - DestReg = merge(DestReg, remaining, dataSize); + %s //Record the final results Remainder = remainder; Quotient = quotient; ''' + code = divCode % "DestReg = merge(DestReg, remaining, dataSize);" + big_code = divCode % "DestReg = remaining & mask(dataSize * 8);" flag_code = ''' if (remaining == 0) ccFlagBits = ccFlagBits | (ext & EZFBit); @@ -601,9 +665,11 @@ let {{ class Divq(RdRegOp): code = 'DestReg = merge(SrcReg1, Quotient, dataSize);' + big_code = 'DestReg = Quotient & mask(dataSize * 8);' class Divr(RdRegOp): code = 'DestReg = merge(SrcReg1, Remainder, dataSize);' + big_code = 'DestReg = Remainder & mask(dataSize * 8);' class Mov(CondRegOp): code = 'DestReg = merge(SrcReg1, op2, dataSize)' @@ -616,6 +682,10 @@ let {{ uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5))); DestReg = merge(DestReg, psrc1 << shiftAmt, dataSize); ''' + big_code = ''' + uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5))); + DestReg = (psrc1 << shiftAmt) & mask(dataSize * 8); + ''' flag_code = ''' // If the shift amount is zero, no flags should be modified. if (shiftAmt) { @@ -641,14 +711,19 @@ let {{ ''' class Srl(RegOp): + # Because what happens to the bits shift -in- on a right shift + # is not defined in the C/C++ standard, we have to mask them out + # to be sure they're zero. code = ''' uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5))); - // Because what happens to the bits shift -in- on a right shift - // is not defined in the C/C++ standard, we have to mask them out - // to be sure they're zero. uint64_t logicalMask = mask(dataSize * 8 - shiftAmt); DestReg = merge(DestReg, (psrc1 >> shiftAmt) & logicalMask, dataSize); ''' + big_code = ''' + uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5))); + uint64_t logicalMask = mask(dataSize * 8 - shiftAmt); + DestReg = (psrc1 >> shiftAmt) & logicalMask; + ''' flag_code = ''' // If the shift amount is zero, no flags should be modified. if (shiftAmt) { @@ -671,15 +746,21 @@ let {{ ''' class Sra(RegOp): + # Because what happens to the bits shift -in- on a right shift + # is not defined in the C/C++ standard, we have to sign extend + # them manually to be sure. code = ''' uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5))); - // Because what happens to the bits shift -in- on a right shift - // is not defined in the C/C++ standard, we have to sign extend - // them manually to be sure. uint64_t arithMask = (shiftAmt == 0) ? 0 : -bits(psrc1, dataSize * 8 - 1) << (dataSize * 8 - shiftAmt); DestReg = merge(DestReg, (psrc1 >> shiftAmt) | arithMask, dataSize); ''' + big_code = ''' + uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5))); + uint64_t arithMask = (shiftAmt == 0) ? 0 : + -bits(psrc1, dataSize * 8 - 1) << (dataSize * 8 - shiftAmt); + DestReg = ((psrc1 >> shiftAmt) | arithMask) & mask(dataSize * 8); + ''' flag_code = ''' // If the shift amount is zero, no flags should be modified. if (shiftAmt) { @@ -704,13 +785,11 @@ let {{ uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5))); uint8_t realShiftAmt = shiftAmt % (dataSize * 8); - if(realShiftAmt) - { + if (realShiftAmt) { uint64_t top = psrc1 << (dataSize * 8 - realShiftAmt); uint64_t bottom = bits(psrc1, dataSize * 8, realShiftAmt); DestReg = merge(DestReg, top | bottom, dataSize); - } - else + } else DestReg = merge(DestReg, DestReg, dataSize); ''' flag_code = ''' @@ -739,16 +818,14 @@ let {{ uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5))); uint8_t realShiftAmt = shiftAmt % (dataSize * 8 + 1); - if(realShiftAmt) - { + if (realShiftAmt) { CCFlagBits flags = ccFlagBits; uint64_t top = flags.cf << (dataSize * 8 - realShiftAmt); if (realShiftAmt > 1) top |= psrc1 << (dataSize * 8 - realShiftAmt + 1); uint64_t bottom = bits(psrc1, dataSize * 8 - 1, realShiftAmt); DestReg = merge(DestReg, top | bottom, dataSize); - } - else + } else DestReg = merge(DestReg, DestReg, dataSize); ''' flag_code = ''' @@ -780,14 +857,12 @@ let {{ uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5))); uint8_t realShiftAmt = shiftAmt % (dataSize * 8); - if(realShiftAmt) - { + if (realShiftAmt) { uint64_t top = psrc1 << realShiftAmt; uint64_t bottom = bits(psrc1, dataSize * 8 - 1, dataSize * 8 - realShiftAmt); DestReg = merge(DestReg, top | bottom, dataSize); - } - else + } else DestReg = merge(DestReg, DestReg, dataSize); ''' flag_code = ''' @@ -816,8 +891,7 @@ let {{ uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5))); uint8_t realShiftAmt = shiftAmt % (dataSize * 8 + 1); - if(realShiftAmt) - { + if (realShiftAmt) { CCFlagBits flags = ccFlagBits; uint64_t top = psrc1 << realShiftAmt; uint64_t bottom = flags.cf << (realShiftAmt - 1); @@ -826,8 +900,7 @@ let {{ bits(psrc1, dataSize * 8 - 1, dataSize * 8 - realShiftAmt + 1); DestReg = merge(DestReg, top | bottom, dataSize); - } - else + } else DestReg = merge(DestReg, DestReg, dataSize); ''' flag_code = ''' @@ -853,10 +926,10 @@ let {{ ''' class Sld(RegOp): - code = ''' + sldCode = ''' uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5))); uint8_t dataBits = dataSize * 8; - uint8_t realShiftAmt = shiftAmt % (2 * dataBits); + uint8_t realShiftAmt = shiftAmt %% (2 * dataBits); uint64_t result; if (realShiftAmt == 0) { result = psrc1; @@ -867,8 +940,10 @@ let {{ result = (DoubleBits << (realShiftAmt - dataBits)) | (psrc1 >> (2 * dataBits - realShiftAmt)); } - DestReg = merge(DestReg, result, dataSize); + %s ''' + code = sldCode % "DestReg = merge(DestReg, result, dataSize);" + big_code = sldCode % "DestReg = result & mask(dataSize * 8);" flag_code = ''' // If the shift amount is zero, no flags should be modified. if (shiftAmt) { @@ -899,10 +974,10 @@ let {{ ''' class Srd(RegOp): - code = ''' + srdCode = ''' uint8_t shiftAmt = (op2 & ((dataSize == 8) ? mask(6) : mask(5))); uint8_t dataBits = dataSize * 8; - uint8_t realShiftAmt = shiftAmt % (2 * dataBits); + uint8_t realShiftAmt = shiftAmt %% (2 * dataBits); uint64_t result; if (realShiftAmt == 0) { result = psrc1; @@ -919,8 +994,10 @@ let {{ logicalMask) | (psrc1 << (2 * dataBits - realShiftAmt)); } - DestReg = merge(DestReg, result, dataSize); + %s ''' + code = srdCode % "DestReg = merge(DestReg, result, dataSize);" + big_code = srdCode % "DestReg = result & mask(dataSize * 8);" flag_code = ''' // If the shift amount is zero, no flags should be modified. if (shiftAmt) { @@ -986,6 +1063,12 @@ let {{ ccFlagBits = (flag == 0) ? (ccFlagBits | EZFBit) : (ccFlagBits & ~EZFBit); ''' + big_code = ''' + int flag = bits(ccFlagBits, imm8); + DestReg = flag & mask(dataSize * 8); + ccFlagBits = (flag == 0) ? (ccFlagBits | EZFBit) : + (ccFlagBits & ~EZFBit); + ''' def __init__(self, dest, imm, flags=None, \ dataSize="env.dataSize"): super(Ruflag, self).__init__(dest, \ @@ -1000,6 +1083,14 @@ let {{ ccFlagBits = (flag == 0) ? (ccFlagBits | EZFBit) : (ccFlagBits & ~EZFBit); ''' + big_code = ''' + MiscReg flagMask = 0x3F7FDD5; + MiscReg flags = (nccFlagBits | ccFlagBits) & flagMask; + int flag = bits(flags, imm8); + DestReg = flag & mask(dataSize * 8); + ccFlagBits = (flag == 0) ? (ccFlagBits | EZFBit) : + (ccFlagBits & ~EZFBit); + ''' def __init__(self, dest, imm, flags=None, \ dataSize="env.dataSize"): super(Rflag, self).__init__(dest, \ @@ -1015,6 +1106,15 @@ let {{ val = sign_bit ? (val | ~maskVal) : (val & maskVal); DestReg = merge(DestReg, val, dataSize); ''' + big_code = ''' + IntReg val = psrc1; + // Mask the bit position so that it wraps. + int bitPos = op2 & (dataSize * 8 - 1); + int sign_bit = bits(val, bitPos, bitPos); + uint64_t maskVal = mask(bitPos+1); + val = sign_bit ? (val | ~maskVal) : (val & maskVal); + DestReg = val & mask(dataSize * 8); + ''' flag_code = ''' if (!sign_bit) ccFlagBits = ccFlagBits & @@ -1026,12 +1126,13 @@ let {{ class Zext(RegOp): code = 'DestReg = merge(DestReg, bits(psrc1, op2, 0), dataSize);' + big_code = 'DestReg = bits(psrc1, op2, 0) & mask(dataSize * 8);' class Rddr(RegOp): def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"): super(Rddr, self).__init__(dest, \ src1, "InstRegIndex(NUM_INTREGS)", flags, dataSize) - code = ''' + rdrCode = ''' CR4 cr4 = CR4Op; DR7 dr7 = DR7Op; if ((cr4.de == 1 && (src1 == 4 || src1 == 5)) || src1 >= 8) { @@ -1039,9 +1140,11 @@ let {{ } else if (dr7.gd) { fault = new DebugException(); } else { - DestReg = merge(DestReg, DebugSrc1, dataSize); + %s } ''' + code = rdrCode % "DestReg = merge(DestReg, DebugSrc1, dataSize);" + big_code = rdrCode % "DestReg = DebugSrc1 & mask(dataSize * 8);" class Wrdr(RegOp): def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"): @@ -1066,13 +1169,15 @@ let {{ def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"): super(Rdcr, self).__init__(dest, \ src1, "InstRegIndex(NUM_INTREGS)", flags, dataSize) - code = ''' + rdcrCode = ''' if (src1 == 1 || (src1 > 4 && src1 < 8) || (src1 > 8)) { fault = new InvalidOpcode(); } else { - DestReg = merge(DestReg, ControlSrc1, dataSize); + %s } ''' + code = rdcrCode % "DestReg = merge(DestReg, ControlSrc1, dataSize);" + big_code = rdcrCode % "DestReg = ControlSrc1 & mask(dataSize * 8);" class Wrcr(RegOp): def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"): @@ -1154,24 +1259,20 @@ let {{ ''' class Rdbase(SegOp): - code = ''' - DestReg = merge(DestReg, SegBaseSrc1, dataSize); - ''' + code = 'DestReg = merge(DestReg, SegBaseSrc1, dataSize);' + big_code = 'DestReg = SegBaseSrc1 & mask(dataSize * 8);' class Rdlimit(SegOp): - code = ''' - DestReg = merge(DestReg, SegLimitSrc1, dataSize); - ''' + code = 'DestReg = merge(DestReg, SegLimitSrc1, dataSize);' + big_code = 'DestReg = SegLimitSrc1 & mask(dataSize * 8);' class RdAttr(SegOp): - code = ''' - DestReg = merge(DestReg, SegAttrSrc1, dataSize); - ''' + code = 'DestReg = merge(DestReg, SegAttrSrc1, dataSize);' + big_code = 'DestReg = SegAttrSrc1 & mask(dataSize * 8);' class Rdsel(SegOp): - code = ''' - DestReg = merge(DestReg, SegSelSrc1, dataSize); - ''' + code = 'DestReg = merge(DestReg, SegSelSrc1, dataSize);' + big_code = 'DestReg = SegSelSrc1 & mask(dataSize * 8);' class Rdval(RegOp): def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"): diff --git a/src/arch/x86/microcode_rom.hh b/src/arch/x86/microcode_rom.hh index f8ad410ce4..84c503bb9f 100644 --- a/src/arch/x86/microcode_rom.hh +++ b/src/arch/x86/microcode_rom.hh @@ -32,6 +32,7 @@ #define __ARCH_X86_MICROCODE_ROM_HH__ #include "arch/x86/emulenv.hh" +#include "arch/x86/insts/badmicroop.hh" #include "cpu/static_inst.hh" namespace X86ISAInst @@ -60,8 +61,10 @@ namespace X86ISAInst fetchMicroop(MicroPC microPC, StaticInstPtr curMacroop) { microPC = normalMicroPC(microPC); - assert(microPC < numMicroops); - return genFuncs[microPC](curMacroop); + if (microPC >= numMicroops) + return X86ISA::badMicroop; + else + return genFuncs[microPC](curMacroop); } }; } diff --git a/src/arch/x86/predecoder.hh b/src/arch/x86/predecoder.hh index c06ec18bcc..5c67e28e19 100644 --- a/src/arch/x86/predecoder.hh +++ b/src/arch/x86/predecoder.hh @@ -225,7 +225,11 @@ namespace X86ISA { assert(emiIsReady); emiIsReady = false; - nextPC.npc(nextPC.pc() + getInstSize()); + if (!nextPC.size()) { + Addr size = getInstSize(); + nextPC.size(size); + nextPC.npc(nextPC.pc() + size); + } return emi; } }; diff --git a/src/arch/x86/types.hh b/src/arch/x86/types.hh index 5a208446a5..4641141d35 100644 --- a/src/arch/x86/types.hh +++ b/src/arch/x86/types.hh @@ -222,7 +222,61 @@ namespace X86ISA return true; } - typedef GenericISA::UPCState PCState; + class PCState : public GenericISA::UPCState + { + protected: + typedef GenericISA::UPCState Base; + + uint8_t _size; + + public: + void + set(Addr val) + { + Base::set(val); + _size = 0; + } + + PCState() {} + PCState(Addr val) { set(val); } + + uint8_t size() const { return _size; } + void size(uint8_t newSize) { _size = newSize; } + + bool + branching() const + { + return this->npc() != this->pc() + size(); + } + + void + advance() + { + Base::advance(); + _size = 0; + } + + void + uEnd() + { + Base::uEnd(); + _size = 0; + } + + void + serialize(std::ostream &os) + { + Base::serialize(os); + SERIALIZE_SCALAR(_size); + } + + void + unserialize(Checkpoint *cp, const std::string §ion) + { + Base::unserialize(cp, section); + UNSERIALIZE_SCALAR(_size); + } + }; struct CoreSpecific { int core_type; diff --git a/src/base/SConscript b/src/base/SConscript index 2bb6b13ab8..3f069bf9ee 100644 --- a/src/base/SConscript +++ b/src/base/SConscript @@ -35,6 +35,7 @@ if env['CP_ANNOTATE']: Source('cp_annotate.cc') Source('atomicio.cc') Source('bigint.cc') +Source('bitmap.cc') Source('callback.cc') Source('circlebuf.cc') Source('cprintf.cc') diff --git a/src/base/bitmap.cc b/src/base/bitmap.cc new file mode 100644 index 0000000000..0d2a9302ba --- /dev/null +++ b/src/base/bitmap.cc @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2010 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * 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: William Wang + * Ali Saidi + */ + +#include + +#include "base/bitmap.hh" +#include "base/misc.hh" + +// bitmap class ctor +Bitmap::Bitmap(VideoConvert::Mode _mode, uint16_t w, uint16_t h, uint8_t *d) + : mode(_mode), height(h), width(w), data(d), + vc(mode, VideoConvert::rgb8888, width, height) +{ +} + +void +Bitmap::write(std::ostream *bmp) +{ + assert(data); + + // For further information see: http://en.wikipedia.org/wiki/BMP_file_format + Magic magic = {{'B','M'}}; + Header header = {sizeof(VideoConvert::Rgb8888) * width * height , 0, 0, 54}; + Info info = {sizeof(Info), width, height, 1, + sizeof(VideoConvert::Rgb8888) * 8, 0, + sizeof(VideoConvert::Rgb8888) * width * height, 1, 1, 0, 0}; + + bmp->write(reinterpret_cast(&magic), sizeof(magic)); + bmp->write(reinterpret_cast(&header), sizeof(header)); + bmp->write(reinterpret_cast(&info), sizeof(info)); + + uint8_t *tmp = vc.convert(data); + uint32_t *tmp32 = (uint32_t*)tmp; + + // BMP start store data left to right starting with the bottom row + // so we need to do some creative flipping + for (int i = height - 1; i >= 0; i--) + for (int j = 0; j < width; j++) + bmp->write((char*)&tmp32[i * width + j], sizeof(uint32_t)); + + bmp->flush(); + + delete [] tmp; +} + diff --git a/src/base/bitmap.hh b/src/base/bitmap.hh new file mode 100644 index 0000000000..9dfaa87a1c --- /dev/null +++ b/src/base/bitmap.hh @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2010 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * 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: William Wang + * Ali Saidi + */ +#ifndef __BASE_BITMAP_HH__ +#define __BASE_BITMAP_HH__ + +#include + +#include "base/vnc/convert.hh" + +/** + * @file Declaration of a class that writes a frame buffer to a bitmap + */ + + +// write frame buffer into a bitmap picture +class Bitmap +{ + public: + /** Create a Bitmap creator that takes data in the given mode & size + * and outputs to an fstream + * @param mode the type of data that is being provided + * @param h the hight of the image + * @param w the width of the image + * @param d the data for the image in mode + */ + Bitmap(VideoConvert::Mode mode, uint16_t w, uint16_t h, uint8_t *d); + + /** Provide the converter with the data that should be output. It will be + * converted into rgb8888 and write out when write() is called. + * @param d the data + */ + void rawData(uint8_t* d) { data = d; } + + /** Write the provided data into the fstream provided + * @param bmp stream to write to + */ + void write(std::ostream *bmp); + + private: + VideoConvert::Mode mode; + uint16_t height; + uint16_t width; + uint8_t *data; + + VideoConvert vc; + + struct Magic + { + unsigned char magic_number[2]; + }; + + struct Header + { + uint32_t size; + uint16_t reserved1; + uint16_t reserved2; + uint32_t offset; + }; + + struct Info + { + uint32_t Size; + uint32_t Width; + uint32_t Height; + uint16_t Planes; + uint16_t BitCount; + uint32_t Compression; + uint32_t SizeImage; + uint32_t XPelsPerMeter; + uint32_t YPelsPerMeter; + uint32_t ClrUsed; + uint32_t ClrImportant; + }; +}; + +#endif // __BASE_BITMAP_HH__ + diff --git a/src/base/compiler.hh b/src/base/compiler.hh index 2c655af608..3315fb2f74 100644 --- a/src/base/compiler.hh +++ b/src/base/compiler.hh @@ -41,6 +41,7 @@ #define M5_PRAGMA_NORETURN(x) #define M5_DUMMY_RETURN #define M5_VAR_USED __attribute__((unused)) +#define M5_ATTR_PACKED __attribute__ ((__packed__)) #elif defined(__SUNPRO_CC) // this doesn't do anything with sun cc, but why not #define M5_ATTR_NORETURN __sun_attr__((__noreturn__)) @@ -48,6 +49,7 @@ #define DO_PRAGMA(x) _Pragma(#x) #define M5_VAR_USED #define M5_PRAGMA_NORETURN(x) DO_PRAGMA(does_not_return(x)) +#define M5_ATTR_PACKED __attribute__ ((__packed__)) #else #error "Need to define compiler options in base/compiler.hh" #endif diff --git a/src/base/vnc/SConscript b/src/base/vnc/SConscript new file mode 100644 index 0000000000..c926765556 --- /dev/null +++ b/src/base/vnc/SConscript @@ -0,0 +1,48 @@ +# -*- mode:python -*- + +# Copyright (c) 2010 ARM Limited +# All rights reserved. +# +# The license below extends only to copyright in the software and shall +# not be construed as granting a license to any other intellectual +# property including but not limited to intellectual property relating +# to a hardware implementation of the functionality of the software +# licensed hereunder. You may use the software subject to the license +# terms below provided that you ensure that this notice is replicated +# unmodified and in its entirety in all distributions of the software, +# modified or unmodified, in source code or in binary form. +# +# 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: William Wang + +Import('*') + +if env['FULL_SYSTEM']: + SimObject('VncServer.py') + Source('vncserver.cc') + TraceFlag('VNC') + +Source('convert.cc') + diff --git a/src/base/vnc/VncServer.py b/src/base/vnc/VncServer.py new file mode 100644 index 0000000000..21eb3ed28a --- /dev/null +++ b/src/base/vnc/VncServer.py @@ -0,0 +1,45 @@ +# Copyright (c) 2010 ARM Limited +# All rights reserved. +# +# The license below extends only to copyright in the software and shall +# not be construed as granting a license to any other intellectual +# property including but not limited to intellectual property relating +# to a hardware implementation of the functionality of the software +# licensed hereunder. You may use the software subject to the license +# terms below provided that you ensure that this notice is replicated +# unmodified and in its entirety in all distributions of the software, +# modified or unmodified, in source code or in binary form. +# +# 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: William Wang + +from m5.SimObject import SimObject +from m5.params import * +from m5.proxy import * + +class VncServer(SimObject): + type = 'VncServer' + port = Param.TcpPort(5900, "listen port") + number = Param.Int(0, "vnc client number") diff --git a/src/base/vnc/convert.cc b/src/base/vnc/convert.cc new file mode 100644 index 0000000000..ea7a9b1c59 --- /dev/null +++ b/src/base/vnc/convert.cc @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2011 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * 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: Ali Saidi + * William Wang + */ + +#include + +#include "base/misc.hh" +#include "base/vnc/convert.hh" + +/** @file + * This file provides conversion functions for a variety of video modes + */ + +VideoConvert::VideoConvert(Mode input_mode, Mode output_mode, int _width, + int _height) + : inputMode(input_mode), outputMode(output_mode), width(_width), + height(_height) +{ + if (inputMode != bgr565 && inputMode != rgb565 && inputMode != bgr8888) + fatal("Only support converting from bgr565, rdb565, and bgr8888\n"); + + if (outputMode != rgb8888) + fatal("Only support converting to rgb8888\n"); + + assert(0 < height && height < 4000); + assert(0 < width && width < 4000); +} + +VideoConvert::~VideoConvert() +{ +} + +uint8_t* +VideoConvert::convert(uint8_t *fb) +{ + switch (inputMode) { + case bgr565: + return m565rgb8888(fb, true); + case rgb565: + return m565rgb8888(fb, false); + case bgr8888: + return bgr8888rgb8888(fb); + default: + panic("Unimplemented Mode\n"); + } +} + +uint8_t* +VideoConvert::m565rgb8888(uint8_t *fb, bool bgr) +{ + uint8_t *out = new uint8_t[area() * sizeof(uint32_t)]; + uint32_t *out32 = (uint32_t*)out; + + uint16_t *in16 = (uint16_t*)fb; + + for (int x = 0; x < area(); x++) { + Bgr565 inpx; + Rgb8888 outpx = 0; + + inpx = in16[x]; + + if (bgr) { + outpx.red = inpx.blue << 3; + outpx.green = inpx.green << 2; + outpx.blue = inpx.red << 3; + } else { + outpx.blue = inpx.blue << 3; + outpx.green = inpx.green << 2; + outpx.red = inpx.red << 3; + } + + out32[x] = outpx; + } + + return out; +} + + +uint8_t* +VideoConvert::bgr8888rgb8888(uint8_t *fb) +{ + uint8_t *out = new uint8_t[area() * sizeof(uint32_t)]; + uint32_t *out32 = (uint32_t*)out; + + uint32_t *in32 = (uint32_t*)fb; + + for (int x = 0; x < area(); x++) { + Rgb8888 outpx = 0; + Bgr8888 inpx; + + + inpx = in32[x]; + + outpx.red = inpx.blue; + outpx.green = inpx.green; + outpx.blue = inpx.red; + + out32[x] = outpx; + } + + return out; +} + diff --git a/src/base/vnc/convert.hh b/src/base/vnc/convert.hh new file mode 100644 index 0000000000..68a21d677c --- /dev/null +++ b/src/base/vnc/convert.hh @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2011 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * 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: Ali Saidi + */ + +/** @file + * This file provides conversion functions for a variety of video modes + */ + +#ifndef __BASE_VNC_CONVERT_HH__ +#define __BASE_VNC_CONVERT_HH__ + +#include "base/bitunion.hh" + +class VideoConvert +{ + public: + enum Mode { + UnknownMode, + bgr565, + rgb565, + bgr8888, + rgb8888, + rgb888, + bgr888, + bgr444, + bgr4444, + rgb444, + rgb4444, + }; + + // supports bpp32 RGB (bmp) and bpp16 5:6:5 mode BGR (linux) + BitUnion32(Rgb8888) + Bitfield<7,0> blue; + Bitfield<15,8> green; + Bitfield<23,16> red; + Bitfield<31,24> alpha; + EndBitUnion(Rgb8888) + + BitUnion32(Bgr8888) + Bitfield<7,0> red; + Bitfield<15,8> green; + Bitfield<23,16> blue; + Bitfield<31,24> alpha; + EndBitUnion(Bgr8888) + + BitUnion16(Bgr565) + Bitfield<4,0> red; + Bitfield<10,5> green; + Bitfield<15,11> blue; + EndBitUnion(Bgr565) + + BitUnion16(Rgb565) + Bitfield<4,0> red; + Bitfield<10,5> green; + Bitfield<15,11> blue; + EndBitUnion(Rgb565) + + /** Setup the converter with the given parameters + * @param input_mode type of data that will be provided + * @param output_mode type of data that should be output + * @param _width width of the frame buffer + * @param _height height of the frame buffer + */ + VideoConvert(Mode input_mode, Mode output_mode, int _width, int _height); + + /** Destructor + */ + ~VideoConvert(); + + /** Convert the provided frame buffer data into the format specified in the + * constructor. + * @param fb the frame buffer to convert + * @return the converted data (user must free) + */ + uint8_t* convert(uint8_t *fb); + + /** Return the number of pixels that this buffer specifies + * @return number of pixels + */ + int area() { return width * height; } + + private: + + /** + * Convert a bgr8888 input to rgb8888. + * @param fb the data to convert + * @return converted data + */ + uint8_t* bgr8888rgb8888(uint8_t *fb); + + /** + * Convert a bgr565 or rgb565 input to rgb8888. + * @param fb the data to convert + * @param bgr true if the input data is bgr565 + * @return converted data + */ + uint8_t* m565rgb8888(uint8_t *fb, bool bgr); + + Mode inputMode; + Mode outputMode; + int width; + int height; +}; + +#endif // __BASE_VNC_CONVERT_HH__ + diff --git a/src/base/vnc/vncserver.cc b/src/base/vnc/vncserver.cc new file mode 100644 index 0000000000..8936fa67b5 --- /dev/null +++ b/src/base/vnc/vncserver.cc @@ -0,0 +1,703 @@ +/* + * Copyright (c) 2010 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * 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: Ali Saidi + * William Wang + */ + +/** @file + * Implementiation of a VNC server + */ + +#include + +#include +#include +#include +#include +#include + +#include "base/atomicio.hh" +#include "base/misc.hh" +#include "base/socket.hh" +#include "base/trace.hh" +#include "base/vnc/vncserver.hh" +#include "sim/byteswap.hh" + +using namespace std; + +/** + * Poll event for the listen socket + */ +VncServer::ListenEvent::ListenEvent(VncServer *vs, int fd, int e) + : PollEvent(fd, e), vncserver(vs) +{ +} + +void +VncServer::ListenEvent::process(int revent) +{ + vncserver->accept(); +} + +/** + * Poll event for the data socket + */ +VncServer::DataEvent::DataEvent(VncServer *vs, int fd, int e) + : PollEvent(fd, e), vncserver(vs) +{ +} + +void +VncServer::DataEvent::process(int revent) +{ + if (revent & POLLIN) + vncserver->data(); + else if (revent & POLLNVAL) + vncserver->detach(); +} + +/** + * VncServer + */ +VncServer::VncServer(const Params *p) + : SimObject(p), listenEvent(NULL), dataEvent(NULL), number(p->number), + dataFd(-1), _videoWidth(1), _videoHeight(1), clientRfb(0), keyboard(NULL), + mouse(NULL), sendUpdate(false), videoMode(VideoConvert::UnknownMode), + vc(NULL) +{ + if (p->port) + listen(p->port); + + curState = WaitForProtocolVersion; + + + // currently we only support this one pixel format + // unpacked 32bit rgb (rgb888 + 8 bits of nothing/alpha) + // keep it around for telling the client and making + // sure the client cooperates + pixelFormat.bpp = 32; + pixelFormat.depth = 24; + pixelFormat.bigendian = 0; + pixelFormat.truecolor = 1; + pixelFormat.redmax = 0xff; + pixelFormat.greenmax = 0xff; + pixelFormat.bluemax = 0xff; + pixelFormat.redshift = 16; + pixelFormat.greenshift = 8; + pixelFormat.blueshift = 0; + + + DPRINTF(VNC, "Vnc server created at port %d\n", p->port); +} + +VncServer::~VncServer() +{ + if (dataFd != -1) + ::close(dataFd); + + if (listenEvent) + delete listenEvent; + + if (dataEvent) + delete dataEvent; +} + + +//socket creation and vnc client attach +void +VncServer::listen(int port) +{ + if (ListenSocket::allDisabled()) { + warn_once("Sockets disabled, not accepting vnc client connections"); + return; + } + + while (!listener.listen(port, true)) { + DPRINTF(VNC, + "can't bind address vnc server port %d in use PID %d\n", + port, getpid()); + port++; + } + + int p1, p2; + p2 = name().rfind('.') - 1; + p1 = name().rfind('.', p2); + ccprintf(cerr, "Listening for %s connection on port %d\n", + name().substr(p1 + 1, p2 - p1), port); + + listenEvent = new ListenEvent(this, listener.getfd(), POLLIN); + pollQueue.schedule(listenEvent); +} + +// attach a vnc client +void +VncServer::accept() +{ + if (!listener.islistening()) + panic("%s: cannot accept a connection if not listening!", name()); + + int fd = listener.accept(true); + if (dataFd != -1) { + char message[] = "vnc server already attached!\n"; + atomic_write(fd, message, sizeof(message)); + ::close(fd); + return; + } + + dataFd = fd; + + // Send our version number to the client + write((uint8_t*)vncVersion(), strlen(vncVersion())); + + // read the client response + dataEvent = new DataEvent(this, dataFd, POLLIN); + pollQueue.schedule(dataEvent); + + inform("VNC client attached\n"); +} + +// data called by data event +void +VncServer::data() +{ + // We have new data, see if we can handle it + size_t len; + DPRINTF(VNC, "Vnc client message recieved\n"); + + switch (curState) { + case WaitForProtocolVersion: + checkProtocolVersion(); + break; + case WaitForSecurityResponse: + checkSecurity(); + break; + case WaitForClientInit: + // Don't care about shared, just need to read it out of the socket + uint8_t shared; + len = read(&shared); + assert(len == 1); + + // Send our idea of the frame buffer + sendServerInit(); + + break; + case NormalPhase: + uint8_t message_type; + len = read(&message_type); + if (!len) { + detach(); + return; + } + assert(len == 1); + + switch (message_type) { + case ClientSetPixelFormat: + setPixelFormat(); + break; + case ClientSetEncodings: + setEncodings(); + break; + case ClientFrameBufferUpdate: + requestFbUpdate(); + break; + case ClientKeyEvent: + recvKeyboardInput(); + break; + case ClientPointerEvent: + recvPointerInput(); + break; + case ClientCutText: + recvCutText(); + break; + default: + panic("Unimplemented message type recv from client: %d\n", + message_type); + break; + } + break; + default: + panic("Unknown vnc server state\n"); + } +} + + +// read from socket +size_t +VncServer::read(uint8_t *buf, size_t len) +{ + if (dataFd < 0) + panic("vnc not properly attached.\n"); + + size_t ret; + do { + ret = ::read(dataFd, buf, len); + } while (ret == -1 && errno == EINTR); + + + if (ret <= 0){ + DPRINTF(VNC, "Read failed.\n"); + detach(); + return 0; + } + + return ret; +} + +size_t +VncServer::read1(uint8_t *buf, size_t len) +{ + size_t read_len M5_VAR_USED; + read_len = read(buf + 1, len - 1); + assert(read_len == len - 1); + return read_len; +} + + +template +size_t +VncServer::read(T* val) +{ + return read((uint8_t*)val, sizeof(T)); +} + +// write to socket +size_t +VncServer::write(const uint8_t *buf, size_t len) +{ + if (dataFd < 0) + panic("Vnc client not properly attached.\n"); + + ssize_t ret; + ret = atomic_write(dataFd, buf, len); + + if (ret < len) + detach(); + + return ret; +} + +template +size_t +VncServer::write(T* val) +{ + return write((uint8_t*)val, sizeof(T)); +} + +size_t +VncServer::write(const char* str) +{ + return write((uint8_t*)str, strlen(str)); +} + +// detach a vnc client +void +VncServer::detach() +{ + if (dataFd != -1) { + ::close(dataFd); + dataFd = -1; + } + + if (!dataEvent || !dataEvent->queued()) + return; + + pollQueue.remove(dataEvent); + delete dataEvent; + dataEvent = NULL; + curState = WaitForProtocolVersion; + + inform("VNC client detached\n"); + DPRINTF(VNC, "detach vnc client %d\n", number); +} + +void +VncServer::sendError(const char* error_msg) +{ + uint32_t len = strlen(error_msg); + write(&len); + write(error_msg); +} + +void +VncServer::checkProtocolVersion() +{ + assert(curState == WaitForProtocolVersion); + + size_t len M5_VAR_USED; + char version_string[13]; + + // Null terminate the message so it's easier to work with + version_string[12] = 0; + + len = read((uint8_t*)version_string, 12); + assert(len == 12); + + uint32_t major, minor; + + // Figure out the major/minor numbers + if (sscanf(version_string, "RFB %03d.%03d\n", &major, &minor) != 2) { + warn(" Malformed protocol version %s\n", version_string); + sendError("Malformed protocol version\n"); + detach(); + } + + DPRINTF(VNC, "Client request protocol version %d.%d\n", major, minor); + + // If it's not 3.X we don't support it + if (major != 3 || minor < 2) { + warn("Unsupported VNC client version... disconnecting\n"); + uint8_t err = AuthInvalid; + write(&err); + detach(); + } + // Auth is different based on version number + if (minor < 7) { + uint32_t sec_type = htobe((uint32_t)AuthNone); + write(&sec_type); + } else { + uint8_t sec_cnt = 1; + uint8_t sec_type = htobe((uint8_t)AuthNone); + write(&sec_cnt); + write(&sec_type); + } + + // Wait for client to respond + curState = WaitForSecurityResponse; +} + +void +VncServer::checkSecurity() +{ + assert(curState == WaitForSecurityResponse); + + uint8_t security_type; + size_t len M5_VAR_USED = read(&security_type); + + assert(len == 1); + + if (security_type != AuthNone) { + warn("Unknown VNC security type\n"); + sendError("Unknown security type\n"); + } + + DPRINTF(VNC, "Sending security auth OK\n"); + + uint32_t success = htobe(VncOK); + write(&success); + curState = WaitForClientInit; +} + +void +VncServer::sendServerInit() +{ + ServerInitMsg msg; + + DPRINTF(VNC, "Sending server init message to client\n"); + + msg.fbWidth = htobe(videoWidth()); + msg.fbHeight = htobe(videoHeight()); + + msg.px.bpp = htobe(pixelFormat.bpp); + msg.px.depth = htobe(pixelFormat.depth); + msg.px.bigendian = htobe(pixelFormat.bigendian); + msg.px.truecolor = htobe(pixelFormat.truecolor); + msg.px.redmax = htobe(pixelFormat.redmax); + msg.px.greenmax = htobe(pixelFormat.greenmax); + msg.px.bluemax = htobe(pixelFormat.bluemax); + msg.px.redshift = htobe(pixelFormat.redshift); + msg.px.greenshift = htobe(pixelFormat.greenshift); + msg.px.blueshift = htobe(pixelFormat.blueshift); + memset(msg.px.padding, 0, 3); + msg.namelen = 2; + msg.namelen = htobe(msg.namelen); + memcpy(msg.name, "M5", 2); + + write(&msg); + curState = NormalPhase; +} + + +void +VncServer::setPixelFormat() +{ + DPRINTF(VNC, "Received pixel format from client message\n"); + + PixelFormatMessage pfm; + read1((uint8_t*)&pfm, sizeof(PixelFormatMessage)); + + DPRINTF(VNC, " -- bpp = %d; depth = %d; be = %d\n", pfm.px.bpp, + pfm.px.depth, pfm.px.bigendian); + DPRINTF(VNC, " -- true color = %d red,green,blue max = %d,%d,%d\n", + pfm.px.truecolor, betoh(pfm.px.redmax), betoh(pfm.px.greenmax), + betoh(pfm.px.bluemax)); + DPRINTF(VNC, " -- red,green,blue shift = %d,%d,%d\n", pfm.px.redshift, + pfm.px.greenshift, pfm.px.blueshift); + + if (betoh(pfm.px.bpp) != pixelFormat.bpp || + betoh(pfm.px.depth) != pixelFormat.depth || + betoh(pfm.px.bigendian) != pixelFormat.bigendian || + betoh(pfm.px.truecolor) != pixelFormat.truecolor || + betoh(pfm.px.redmax) != pixelFormat.redmax || + betoh(pfm.px.greenmax) != pixelFormat.greenmax || + betoh(pfm.px.bluemax) != pixelFormat.bluemax || + betoh(pfm.px.redshift) != pixelFormat.redshift || + betoh(pfm.px.greenshift) != pixelFormat.greenshift || + betoh(pfm.px.blueshift) != pixelFormat.blueshift) + fatal("VNC client doesn't support true color raw encoding\n"); +} + +void +VncServer::setEncodings() +{ + DPRINTF(VNC, "Received supported encodings from client\n"); + + PixelEncodingsMessage pem; + read1((uint8_t*)&pem, sizeof(PixelEncodingsMessage)); + + pem.num_encodings = betoh(pem.num_encodings); + + DPRINTF(VNC, " -- %d encoding present\n", pem.num_encodings); + supportsRawEnc = supportsResizeEnc = false; + + for (int x = 0; x < pem.num_encodings; x++) { + int32_t encoding; + size_t len M5_VAR_USED; + len = read(&encoding); + assert(len == sizeof(encoding)); + DPRINTF(VNC, " -- supports %d\n", betoh(encoding)); + + switch (betoh(encoding)) { + case EncodingRaw: + supportsRawEnc = true; + break; + case EncodingDesktopSize: + supportsResizeEnc = true; + break; + } + } + + if (!supportsRawEnc) + fatal("VNC clients must always support raw encoding\n"); +} + +void +VncServer::requestFbUpdate() +{ + DPRINTF(VNC, "Received frame buffer update request from client\n"); + + FrameBufferUpdateReq fbr; + read1((uint8_t*)&fbr, sizeof(FrameBufferUpdateReq)); + + fbr.x = betoh(fbr.x); + fbr.y = betoh(fbr.y); + fbr.width = betoh(fbr.width); + fbr.height = betoh(fbr.height); + + DPRINTF(VNC, " -- x = %d y = %d w = %d h = %d\n", fbr.x, fbr.y, fbr.width, + fbr.height); + + sendFrameBufferUpdate(); +} + +void +VncServer::recvKeyboardInput() +{ + DPRINTF(VNC, "Received keyboard input from client\n"); + KeyEventMessage kem; + read1((uint8_t*)&kem, sizeof(KeyEventMessage)); + + kem.key = betoh(kem.key); + DPRINTF(VNC, " -- received key code %d (%s)\n", kem.key, kem.down_flag ? + "down" : "up"); + + if (keyboard) + keyboard->keyPress(kem.key, kem.down_flag); +} + +void +VncServer::recvPointerInput() +{ + DPRINTF(VNC, "Received pointer input from client\n"); + PointerEventMessage pem; + + read1((uint8_t*)&pem, sizeof(PointerEventMessage));; + + pem.x = betoh(pem.x); + pem.y = betoh(pem.y); + DPRINTF(VNC, " -- pointer at x = %d y = %d buttons = %#x\n", pem.x, pem.y, + pem.button_mask); + + if (mouse) + mouse->mouseAt(pem.x, pem.y, pem.button_mask); +} + +void +VncServer::recvCutText() +{ + DPRINTF(VNC, "Received client copy buffer message\n"); + + ClientCutTextMessage cct; + read1((uint8_t*)&cct, sizeof(ClientCutTextMessage)); + + char str[1025]; + size_t data_len = betoh(cct.length); + DPRINTF(VNC, "String length %d\n", data_len); + while (data_len > 0) { + size_t len; + size_t bytes_to_read = data_len > 1024 ? 1024 : data_len; + len = read((uint8_t*)&str, bytes_to_read); + str[bytes_to_read] = 0; + data_len -= len; + assert(data_len >= 0); + DPRINTF(VNC, "Buffer: %s\n", str); + } + +} + + +void +VncServer::sendFrameBufferUpdate() +{ + + if (!clientRfb || dataFd <= 0 || curState != NormalPhase || !sendUpdate) { + DPRINTF(VNC, "NOT sending framebuffer update\n"); + return; + } + + assert(vc); + + // The client will request data constantly, unless we throttle it + sendUpdate = false; + + DPRINTF(VNC, "Sending framebuffer update\n"); + + FrameBufferUpdate fbu; + FrameBufferRect fbr; + + fbu.type = ServerFrameBufferUpdate; + fbu.num_rects = 1; + fbr.x = 0; + fbr.y = 0; + fbr.width = videoWidth(); + fbr.height = videoHeight(); + fbr.encoding = EncodingRaw; + + // fix up endian + fbu.num_rects = htobe(fbu.num_rects); + fbr.x = htobe(fbr.x); + fbr.y = htobe(fbr.y); + fbr.width = htobe(fbr.width); + fbr.height = htobe(fbr.height); + fbr.encoding = htobe(fbr.encoding); + + // send headers to client + write(&fbu); + write(&fbr); + + assert(clientRfb); + + uint8_t *tmp = vc->convert(clientRfb); + write(tmp, videoWidth() * videoHeight() * sizeof(uint32_t)); + delete [] tmp; + +} + +void +VncServer::sendFrameBufferResized() +{ + assert(clientRfb && dataFd > 0 && curState == NormalPhase); + DPRINTF(VNC, "Sending framebuffer resize\n"); + + FrameBufferUpdate fbu; + FrameBufferRect fbr; + + fbu.type = ServerFrameBufferUpdate; + fbu.num_rects = 1; + fbr.x = 0; + fbr.y = 0; + fbr.width = videoWidth(); + fbr.height = videoHeight(); + fbr.encoding = EncodingDesktopSize; + + // fix up endian + fbu.num_rects = htobe(fbu.num_rects); + fbr.x = htobe(fbr.x); + fbr.y = htobe(fbr.y); + fbr.width = htobe(fbr.width); + fbr.height = htobe(fbr.height); + fbr.encoding = htobe(fbr.encoding); + + // send headers to client + write(&fbu); + write(&fbr); + + // No actual data is sent in this message +} + +void +VncServer::setFrameBufferParams(VideoConvert::Mode mode, int width, int height) +{ + DPRINTF(VNC, "Updating video params: mode: %d width: %d height: %d\n", mode, + width, height); + + if (mode != videoMode || width != videoWidth() || height != videoHeight()) { + videoMode = mode; + _videoWidth = width; + _videoHeight = height; + + if (vc) + delete vc; + + vc = new VideoConvert(mode, VideoConvert::rgb8888, videoWidth(), + videoHeight()); + + if (dataFd > 0 && clientRfb && curState == NormalPhase) { + if (supportsResizeEnc) + sendFrameBufferResized(); + else + // The frame buffer changed size and we can't update the client + detach(); + } + } +} + +// create the VNC server object +VncServer * +VncServerParams::create() +{ + return new VncServer(this); +} diff --git a/src/base/vnc/vncserver.hh b/src/base/vnc/vncserver.hh new file mode 100644 index 0000000000..23b097b111 --- /dev/null +++ b/src/base/vnc/vncserver.hh @@ -0,0 +1,475 @@ +/* + * Copyright (c) 2010 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * 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: Ali Saidi + * William Wang + */ + +/** @file + * Declaration of a VNC server + */ + +#ifndef __DEV_VNC_SERVER_HH__ +#define __DEV_VNC_SERVER_HH__ + +#include + +#include "base/circlebuf.hh" +#include "base/pollevent.hh" +#include "base/socket.hh" +#include "base/vnc/convert.hh" +#include "cpu/intr_control.hh" +#include "sim/sim_object.hh" +#include "params/VncServer.hh" + +/** + * A device that expects to receive input from the vnc server should derrive + * (through mulitple inheritence if necessary from VncKeyboard or VncMouse + * and call setKeyboard() or setMouse() respectively on the vnc server. + */ +class VncKeyboard +{ + public: + /** + * Called when the vnc server receives a key press event from the + * client. + * @param key the key passed is an x11 keysym + * @param down is the key now down or up? + */ + virtual void keyPress(uint32_t key, bool down) = 0; +}; + +class VncMouse +{ + public: + /** + * called whenever the mouse moves or it's button state changes + * buttons is a simple mask with each button (0-8) corresponding to + * a bit position in the byte with 1 being down and 0 being up + * @param x the x position of the mouse + * @param y the y position of the mouse + * @param buttos the button state as described above + */ + virtual void mouseAt(uint16_t x, uint16_t y, uint8_t buttons) = 0; +}; + +class VncServer : public SimObject +{ + public: + + /** + * \defgroup VncConstants A set of constants and structs from the VNC spec + * @{ + */ + /** Authentication modes */ + const static uint32_t AuthInvalid = 0; + const static uint32_t AuthNone = 1; + + /** Error conditions */ + const static uint32_t VncOK = 0; + + /** Client -> Server message IDs */ + enum ClientMessages { + ClientSetPixelFormat = 0, + ClientSetEncodings = 2, + ClientFrameBufferUpdate = 3, + ClientKeyEvent = 4, + ClientPointerEvent = 5, + ClientCutText = 6 + }; + + /** Server -> Client message IDs */ + enum ServerMessages { + ServerFrameBufferUpdate = 0, + ServerSetColorMapEntries = 1, + ServerBell = 2, + ServerCutText = 3 + }; + + /** Encoding types */ + enum EncodingTypes { + EncodingRaw = 0, + EncodingCopyRect = 1, + EncodingHextile = 5, + EncodingDesktopSize = -223 + }; + + /** keyboard/mouse support */ + enum MouseEvents { + MouseLeftButton = 0x1, + MouseRightButton = 0x2, + MouseMiddleButton = 0x4 + }; + + const char* vncVersion() const + { + return "RFB 003.008\n"; + } + + enum ConnectionState { + WaitForProtocolVersion, + WaitForSecurityResponse, + WaitForClientInit, + InitializationPhase, + NormalPhase + }; + + struct PixelFormat { + uint8_t bpp; + uint8_t depth; + uint8_t bigendian; + uint8_t truecolor; + uint16_t redmax; + uint16_t greenmax; + uint16_t bluemax; + uint8_t redshift; + uint8_t greenshift; + uint8_t blueshift; + uint8_t padding[3]; + } M5_ATTR_PACKED; + + struct ServerInitMsg { + uint16_t fbWidth; + uint16_t fbHeight; + PixelFormat px; + uint32_t namelen; + char name[2]; // just to put M5 in here + } M5_ATTR_PACKED; + + struct PixelFormatMessage { + uint8_t type; + uint8_t padding[3]; + PixelFormat px; + } M5_ATTR_PACKED; + + struct PixelEncodingsMessage { + uint8_t type; + uint8_t padding; + uint16_t num_encodings; + } M5_ATTR_PACKED; + + struct FrameBufferUpdateReq { + uint8_t type; + uint8_t incremental; + uint16_t x; + uint16_t y; + uint16_t width; + uint16_t height; + } M5_ATTR_PACKED; + + struct KeyEventMessage { + uint8_t type; + uint8_t down_flag; + uint8_t padding[2]; + uint32_t key; + } M5_ATTR_PACKED; + + struct PointerEventMessage { + uint8_t type; + uint8_t button_mask; + uint16_t x; + uint16_t y; + } M5_ATTR_PACKED; + + struct ClientCutTextMessage { + uint8_t type; + uint8_t padding[3]; + uint32_t length; + } M5_ATTR_PACKED; + + struct FrameBufferUpdate { + uint8_t type; + uint8_t padding; + uint16_t num_rects; + } M5_ATTR_PACKED; + + struct FrameBufferRect { + uint16_t x; + uint16_t y; + uint16_t width; + uint16_t height; + int32_t encoding; + } M5_ATTR_PACKED; + + struct ServerCutText { + uint8_t type; + uint8_t padding[3]; + uint32_t length; + } M5_ATTR_PACKED; + + /** @} */ + + protected: + /** ListenEvent to accept a vnc client connection */ + class ListenEvent: public PollEvent + { + protected: + VncServer *vncserver; + + public: + ListenEvent(VncServer *vs, int fd, int e); + void process(int revent); + }; + + friend class ListenEvent; + ListenEvent *listenEvent; + + /** DataEvent to read data from vnc */ + class DataEvent: public PollEvent + { + protected: + VncServer *vncserver; + + public: + DataEvent(VncServer *vs, int fd, int e); + void process(int revent); + }; + + friend class DataEvent; + DataEvent *dataEvent; + + int number; + int dataFd; // data stream file describer + + ListenSocket listener; + + void listen(int port); + void accept(); + void data(); + void detach(); + + public: + typedef VncServerParams Params; + VncServer(const Params *p); + ~VncServer(); + + // RFB + protected: + + /** The rfb prototol state the connection is in */ + ConnectionState curState; + + /** the width of the frame buffer we are sending to the client */ + uint16_t _videoWidth; + + /** the height of the frame buffer we are sending to the client */ + uint16_t _videoHeight; + + /** pointer to the actual data that is stored in the frame buffer device */ + uint8_t* clientRfb; + + /** The device to notify when we get key events */ + VncKeyboard *keyboard; + + /** The device to notify when we get mouse events */ + VncMouse *mouse; + + /** An update needs to be sent to the client. Without doing this the + * client will constantly request data that is pointless */ + bool sendUpdate; + + /** The one and only pixel format we support */ + PixelFormat pixelFormat; + + /** If the vnc client supports receiving raw data. It always should */ + bool supportsRawEnc; + + /** If the vnc client supports the desktop resize command */ + bool supportsResizeEnc; + + /** The mode of data we're getting frame buffer in */ + VideoConvert::Mode videoMode; + + /** The video converter that transforms data for us */ + VideoConvert *vc; + + protected: + /** + * vnc client Interface + */ + + /** Send an error message to the client + * @param error_msg text to send describing the error + */ + void sendError(const char* error_msg); + + /** Read some data from the client + * @param buf the data to read + * @param len the amount of data to read + * @return length read + */ + size_t read(uint8_t *buf, size_t len); + + /** Read len -1 bytes from the client into the buffer provided + 1 + * assert that we read enough bytes. This function exists to handle + * reading all of the protocol structs above when we've already read + * the first byte which describes which one we're reading + * @param buf the address of the buffer to add one to and read data into + * @param len the amount of data + 1 to read + * @return length read + */ + size_t read1(uint8_t *buf, size_t len); + + + /** Templated version of the read function above to + * read simple data to the client + * @param val data to recv from the client + */ + template size_t read(T* val); + + + /** Write a buffer to the client. + * @param buf buffer to send + * @param len length of the buffer + * @return number of bytes sent + */ + size_t write(const uint8_t *buf, size_t len); + + /** Templated version of the write function above to + * write simple data to the client + * @param val data to send to the client + */ + template size_t write(T* val); + + /** Send a string to the client + * @param str string to transmit + */ + size_t write(const char* str); + + /** Check the client's protocol verion for compatibility and send + * the security types we support + */ + void checkProtocolVersion(); + + /** Check that the security exchange was successful + */ + void checkSecurity(); + + /** Send client our idea about what the frame buffer looks like */ + void sendServerInit(); + + /** Send an error message to the client when something goes wrong + * @param error_msg error to send + */ + void sendError(std::string error_msg); + + /** Send a updated frame buffer to the client. + * @todo this doesn't do anything smart and just sends the entire image + */ + void sendFrameBufferUpdate(); + + /** Receive pixel foramt message from client and process it. */ + void setPixelFormat(); + + /** Receive encodings message from client and process it. */ + void setEncodings(); + + /** Receive message from client asking for updated frame buffer */ + void requestFbUpdate(); + + /** Receive message from client providing new keyboard input */ + void recvKeyboardInput(); + + /** Recv message from client providing new mouse movement or button click */ + void recvPointerInput(); + + /** Receive message from client that there is text in it's paste buffer. + * This is a no-op at the moment, but perhaps we would want to be able to + * paste it at some point. + */ + void recvCutText(); + + /** Tell the client that the frame buffer resized. This happens when the + * simulated system changes video modes (E.g. X11 starts). + */ + void sendFrameBufferResized(); + + public: + /** Set the address of the frame buffer we are going to show. + * To avoid copying, just have the display controller + * tell us where the data is instead of constanly copying it around + * @param rfb frame buffer that we're going to use + */ + void + setFramebufferAddr(uint8_t* rfb) + { + clientRfb = rfb; + } + + /** Set up the device that would like to receive notifications when keys are + * pressed in the vnc client keyboard + * @param _keyboard an object that derrives from VncKeyboard + */ + void setKeyboard(VncKeyboard *_keyboard) { keyboard = _keyboard; } + + /** Setup the device that would like to receive notifications when mouse + * movements or button presses are received from the vnc client. + * @param _mouse an object that derrives from VncMouse + */ + void setMouse(VncMouse *_mouse) { mouse = _mouse; } + + /** The frame buffer uses this call to notify the vnc server that + * the frame buffer has been updated and a new image needs to be sent to the + * client + */ + void + setDirty() + { + sendUpdate = true; + sendFrameBufferUpdate(); + } + + /** What is the width of the screen we're displaying. + * This is used for pointer/tablet devices that need to know to calculate + * the correct value to send to the device driver. + * @return the width of the simulated screen + */ + uint16_t videoWidth() { return _videoWidth; } + + /** What is the height of the screen we're displaying. + * This is used for pointer/tablet devices that need to know to calculate + * the correct value to send to the device driver. + * @return the height of the simulated screen + */ + uint16_t videoHeight() { return _videoHeight; } + + /** Set the mode of the data the frame buffer will be sending us + * @param mode the mode + */ + void setFrameBufferParams(VideoConvert::Mode mode, int width, int height); +}; + +#endif diff --git a/src/cpu/base_dyn_inst.hh b/src/cpu/base_dyn_inst.hh index 0c566ec656..8b6662d700 100644 --- a/src/cpu/base_dyn_inst.hh +++ b/src/cpu/base_dyn_inst.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2011 ARM Limited + * All rights reserved. + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * * Copyright (c) 2004-2006 The Regents of The University of Michigan * Copyright (c) 2009 The University of Edinburgh * All rights reserved. @@ -150,6 +162,29 @@ class BaseDynInst : public FastAlloc, public RefCounted /** Finish a DTB address translation. */ void finishTranslation(WholeTranslationState *state); + /** True if the DTB address translation has started. */ + bool translationStarted; + + /** True if the DTB address translation has completed. */ + bool translationCompleted; + + /** + * Returns true if the DTB address translation is being delayed due to a hw + * page table walk. + */ + bool isTranslationDelayed() const + { + return (translationStarted && !translationCompleted); + } + + /** + * Saved memory requests (needed when the DTB address translation is + * delayed due to a hw page table walk). + */ + RequestPtr savedReq; + RequestPtr savedSreqLow; + RequestPtr savedSreqHigh; + /** @todo: Consider making this private. */ public: /** The sequence number of the instruction. */ @@ -835,33 +870,42 @@ BaseDynInst::readBytes(Addr addr, uint8_t *data, unsigned size, unsigned flags) { reqMade = true; - Request *req = new Request(asid, addr, size, flags, this->pc.instAddr(), - thread->contextId(), threadNumber); - + Request *req = NULL; Request *sreqLow = NULL; Request *sreqHigh = NULL; - // Only split the request if the ISA supports unaligned accesses. - if (TheISA::HasUnalignedMemAcc) { - splitRequest(req, sreqLow, sreqHigh); - } - initiateTranslation(req, sreqLow, sreqHigh, NULL, BaseTLB::Read); - - if (fault == NoFault) { - effAddr = req->getVaddr(); - effAddrValid = true; - fault = cpu->read(req, sreqLow, sreqHigh, data, lqIdx); + if (reqMade && translationStarted) { + req = savedReq; + sreqLow = savedSreqLow; + sreqHigh = savedSreqHigh; } else { - // Commit will have to clean up whatever happened. Set this - // instruction as executed. - this->setExecuted(); + req = new Request(asid, addr, size, flags, this->pc.instAddr(), + thread->contextId(), threadNumber); + + // Only split the request if the ISA supports unaligned accesses. + if (TheISA::HasUnalignedMemAcc) { + splitRequest(req, sreqLow, sreqHigh); + } + initiateTranslation(req, sreqLow, sreqHigh, NULL, BaseTLB::Read); } - if (fault != NoFault) { - // Return a fixed value to keep simulation deterministic even - // along misspeculated paths. - if (data) - bzero(data, size); + if (translationCompleted) { + if (fault == NoFault) { + effAddr = req->getVaddr(); + effAddrValid = true; + fault = cpu->read(req, sreqLow, sreqHigh, data, lqIdx); + } else { + // Commit will have to clean up whatever happened. Set this + // instruction as executed. + this->setExecuted(); + } + + if (fault != NoFault) { + // Return a fixed value to keep simulation deterministic even + // along misspeculated paths. + if (data) + bzero(data, size); + } } if (traceData) { @@ -897,19 +941,26 @@ BaseDynInst::writeBytes(uint8_t *data, unsigned size, } reqMade = true; - Request *req = new Request(asid, addr, size, flags, this->pc.instAddr(), - thread->contextId(), threadNumber); - + Request *req = NULL; Request *sreqLow = NULL; Request *sreqHigh = NULL; - // Only split the request if the ISA supports unaligned accesses. - if (TheISA::HasUnalignedMemAcc) { - splitRequest(req, sreqLow, sreqHigh); - } - initiateTranslation(req, sreqLow, sreqHigh, res, BaseTLB::Write); + if (reqMade && translationStarted) { + req = savedReq; + sreqLow = savedSreqLow; + sreqHigh = savedSreqHigh; + } else { + req = new Request(asid, addr, size, flags, this->pc.instAddr(), + thread->contextId(), threadNumber); - if (fault == NoFault) { + // Only split the request if the ISA supports unaligned accesses. + if (TheISA::HasUnalignedMemAcc) { + splitRequest(req, sreqLow, sreqHigh); + } + initiateTranslation(req, sreqLow, sreqHigh, res, BaseTLB::Write); + } + + if (fault == NoFault && translationCompleted) { effAddr = req->getVaddr(); effAddrValid = true; fault = cpu->write(req, sreqLow, sreqHigh, data, sqIdx); @@ -953,6 +1004,8 @@ BaseDynInst::initiateTranslation(RequestPtr req, RequestPtr sreqLow, RequestPtr sreqHigh, uint64_t *res, BaseTLB::Mode mode) { + translationStarted = true; + if (!TheISA::HasUnalignedMemAcc || sreqLow == NULL) { WholeTranslationState *state = new WholeTranslationState(req, NULL, res, mode); @@ -961,6 +1014,12 @@ BaseDynInst::initiateTranslation(RequestPtr req, RequestPtr sreqLow, DataTranslation > *trans = new DataTranslation >(this, state); cpu->dtb->translateTiming(req, thread->getTC(), trans, mode); + if (!translationCompleted) { + // Save memory requests. + savedReq = state->mainReq; + savedSreqLow = state->sreqLow; + savedSreqHigh = state->sreqHigh; + } } else { WholeTranslationState *state = new WholeTranslationState(req, sreqLow, sreqHigh, NULL, res, mode); @@ -973,6 +1032,12 @@ BaseDynInst::initiateTranslation(RequestPtr req, RequestPtr sreqLow, cpu->dtb->translateTiming(sreqLow, thread->getTC(), stransLow, mode); cpu->dtb->translateTiming(sreqHigh, thread->getTC(), stransHigh, mode); + if (!translationCompleted) { + // Save memory requests. + savedReq = state->mainReq; + savedSreqLow = state->sreqLow; + savedSreqHigh = state->sreqHigh; + } } } @@ -998,6 +1063,8 @@ BaseDynInst::finishTranslation(WholeTranslationState *state) state->deleteReqs(); } delete state; + + translationCompleted = true; } #endif // __CPU_BASE_DYN_INST_HH__ diff --git a/src/cpu/base_dyn_inst_impl.hh b/src/cpu/base_dyn_inst_impl.hh index 74f199d5f6..7e4d25322b 100644 --- a/src/cpu/base_dyn_inst_impl.hh +++ b/src/cpu/base_dyn_inst_impl.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2011 ARM Limited + * All rights reserved. + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * * Copyright (c) 2004-2006 The Regents of The University of Michigan * All rights reserved. * @@ -107,6 +119,9 @@ BaseDynInst::initVars() effAddrValid = false; physEffAddr = 0; + translationStarted = false; + translationCompleted = false; + isUncacheable = false; reqMade = false; readyRegs = 0; diff --git a/src/cpu/inorder/SConscript b/src/cpu/inorder/SConscript index ae5ec02571..b9c526763b 100644 --- a/src/cpu/inorder/SConscript +++ b/src/cpu/inorder/SConscript @@ -55,7 +55,7 @@ if 'InOrderCPU' in env['CPU_MODELS']: TraceFlag('ThreadModel') TraceFlag('RefCount') TraceFlag('AddrDep') - + TraceFlag('SkedCache') CompoundFlag('InOrderCPUAll', [ 'InOrderStage', 'InOrderStall', 'InOrderCPU', 'InOrderMDU', 'InOrderAGEN', 'InOrderFetchSeq', 'InOrderTLB', 'InOrderBPred', @@ -63,7 +63,6 @@ if 'InOrderCPU' in env['CPU_MODELS']: 'InOrderGraduation', 'InOrderCachePort', 'RegDepMap', 'Resource', 'ThreadModel', 'AddrDep']) - Source('pipeline_traits.cc') Source('inorder_dyn_inst.cc') Source('inorder_cpu_builder.cc') Source('inorder_trace.cc') diff --git a/src/cpu/inorder/cpu.cc b/src/cpu/inorder/cpu.cc index ffdcae7df8..0ec4c98619 100644 --- a/src/cpu/inorder/cpu.cc +++ b/src/cpu/inorder/cpu.cc @@ -324,19 +324,19 @@ InOrderCPU::InOrderCPU(Params *params) tid, asid[tid]); - dummyReq[tid] = new ResourceRequest(resPool->getResource(0), - dummyInst[tid], - 0, - 0, - 0, - 0); + dummyReq[tid] = new ResourceRequest(resPool->getResource(0)); } dummyReqInst = new InOrderDynInst(this, NULL, 0, 0, 0); dummyReqInst->setSquashed(); + dummyReqInst->resetInstCount(); dummyBufferInst = new InOrderDynInst(this, NULL, 0, 0, 0); dummyBufferInst->setSquashed(); + dummyBufferInst->resetInstCount(); + + endOfSkedIt = skedCache.end(); + frontEndSked = createFrontEndSked(); lastRunningCycle = curTick(); @@ -348,7 +348,6 @@ InOrderCPU::InOrderCPU(Params *params) reset(); #endif - dummyBufferInst->resetInstCount(); // Schedule First Tick Event, CPU will reschedule itself from here on out. scheduleTickEvent(0); @@ -357,8 +356,131 @@ InOrderCPU::InOrderCPU(Params *params) InOrderCPU::~InOrderCPU() { delete resPool; + + std::map::iterator sked_it = + skedCache.begin(); + std::map::iterator sked_end = + skedCache.end(); + + while (sked_it != sked_end) { + delete (*sked_it).second; + sked_it++; + } + skedCache.clear(); } +std::map InOrderCPU::skedCache; + +RSkedPtr +InOrderCPU::createFrontEndSked() +{ + RSkedPtr res_sked = new ResourceSked(); + int stage_num = 0; + StageScheduler F(res_sked, stage_num++); + StageScheduler D(res_sked, stage_num++); + + // FETCH + F.needs(FetchSeq, FetchSeqUnit::AssignNextPC); + F.needs(ICache, FetchUnit::InitiateFetch); + + // DECODE + D.needs(ICache, FetchUnit::CompleteFetch); + D.needs(Decode, DecodeUnit::DecodeInst); + D.needs(BPred, BranchPredictor::PredictBranch); + D.needs(FetchSeq, FetchSeqUnit::UpdateTargetPC); + + + DPRINTF(SkedCache, "Resource Sked created for instruction \"front_end\"\n"); + + return res_sked; +} + +RSkedPtr +InOrderCPU::createBackEndSked(DynInstPtr inst) +{ + RSkedPtr res_sked = lookupSked(inst); + if (res_sked != NULL) { + DPRINTF(SkedCache, "Found %s in sked cache.\n", + inst->instName()); + return res_sked; + } else { + res_sked = new ResourceSked(); + } + + int stage_num = ThePipeline::BackEndStartStage; + StageScheduler X(res_sked, stage_num++); + StageScheduler M(res_sked, stage_num++); + StageScheduler W(res_sked, stage_num++); + + if (!inst->staticInst) { + warn_once("Static Instruction Object Not Set. Can't Create" + " Back End Schedule"); + return NULL; + } + + // EXECUTE + for (int idx=0; idx < inst->numSrcRegs(); idx++) { + if (!idx || !inst->isStore()) { + X.needs(RegManager, UseDefUnit::ReadSrcReg, idx); + } + } + + if ( inst->isNonSpeculative() ) { + // skip execution of non speculative insts until later + } else if ( inst->isMemRef() ) { + if ( inst->isLoad() ) { + X.needs(AGEN, AGENUnit::GenerateAddr); + } + } else if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) { + X.needs(MDU, MultDivUnit::StartMultDiv); + } else { + X.needs(ExecUnit, ExecutionUnit::ExecuteInst); + } + + if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) { + X.needs(MDU, MultDivUnit::EndMultDiv); + } + + // MEMORY + if ( inst->isLoad() ) { + M.needs(DCache, CacheUnit::InitiateReadData); + } else if ( inst->isStore() ) { + if ( inst->numSrcRegs() >= 2 ) { + M.needs(RegManager, UseDefUnit::ReadSrcReg, 1); + } + M.needs(AGEN, AGENUnit::GenerateAddr); + M.needs(DCache, CacheUnit::InitiateWriteData); + } + + + // WRITEBACK + if ( inst->isLoad() ) { + W.needs(DCache, CacheUnit::CompleteReadData); + } else if ( inst->isStore() ) { + W.needs(DCache, CacheUnit::CompleteWriteData); + } + + if ( inst->isNonSpeculative() ) { + if ( inst->isMemRef() ) fatal("Non-Speculative Memory Instruction"); + W.needs(ExecUnit, ExecutionUnit::ExecuteInst); + } + + W.needs(Grad, GraduationUnit::GraduateInst); + + for (int idx=0; idx < inst->numDestRegs(); idx++) { + W.needs(RegManager, UseDefUnit::WriteDestReg, idx); + } + + // Insert Back Schedule into our cache of + // resource schedules + addToSkedCache(inst, res_sked); + + DPRINTF(SkedCache, "Back End Sked Created for instruction: %s (%08p)\n", + inst->instName(), inst->getMachInst()); + res_sked->print(); + + return res_sked; +} void InOrderCPU::regStats() @@ -520,8 +642,7 @@ InOrderCPU::tick() } activityRec.advance(); - // Any squashed requests, events, or insts then remove them now - cleanUpRemovedReqs(); + // Any squashed events, or insts then remove them now cleanUpRemovedEvents(); cleanUpRemovedInsts(); @@ -1299,14 +1420,6 @@ InOrderCPU::cleanUpRemovedInsts() DynInstPtr inst = *removeList.front(); ThreadID tid = inst->threadNumber; - // Make Sure Resource Schedule Is Emptied Out - ThePipeline::ResSchedule *inst_sched = &inst->resSched; - while (!inst_sched->empty()) { - ScheduleEntry* sch_entry = inst_sched->top(); - inst_sched->pop(); - delete sch_entry; - } - // Remove From Register Dependency Map, If Necessary archRegDepMap[(*removeList.front())->threadNumber]. remove((*removeList.front())); @@ -1314,8 +1427,8 @@ InOrderCPU::cleanUpRemovedInsts() // Clear if Non-Speculative if (inst->staticInst && - inst->seqNum == nonSpecSeqNum[tid] && - nonSpecInstActive[tid] == true) { + inst->seqNum == nonSpecSeqNum[tid] && + nonSpecInstActive[tid] == true) { nonSpecInstActive[tid] = false; } @@ -1327,28 +1440,6 @@ InOrderCPU::cleanUpRemovedInsts() removeInstsThisCycle = false; } -void -InOrderCPU::cleanUpRemovedReqs() -{ - while (!reqRemoveList.empty()) { - ResourceRequest *res_req = reqRemoveList.front(); - - DPRINTF(RefCount, "[tid:%i] [sn:%lli]: Removing Request " - "[stage_num:%i] [res:%s] [slot:%i] [completed:%i].\n", - res_req->inst->threadNumber, - res_req->inst->seqNum, - res_req->getStageNum(), - res_req->res->name(), - (res_req->isCompleted()) ? - res_req->getComplSlot() : res_req->getSlot(), - res_req->isCompleted()); - - reqRemoveList.pop(); - - delete res_req; - } -} - void InOrderCPU::cleanUpRemovedEvents() { diff --git a/src/cpu/inorder/cpu.hh b/src/cpu/inorder/cpu.hh index 9ff0f12ce5..2fa6bdc593 100644 --- a/src/cpu/inorder/cpu.hh +++ b/src/cpu/inorder/cpu.hh @@ -296,6 +296,92 @@ class InOrderCPU : public BaseCPU TheISA::TLB *getITBPtr(); TheISA::TLB *getDTBPtr(); + /** Accessor Type for the SkedCache */ + typedef uint32_t SkedID; + + /** Cache of Instruction Schedule using the instruction's name as a key */ + static std::map skedCache; + + typedef std::map::iterator SkedCacheIt; + + /** Initialized to last iterator in map, signifying a invalid entry + on map searches + */ + SkedCacheIt endOfSkedIt; + + ThePipeline::RSkedPtr frontEndSked; + + /** Add a new instruction schedule to the schedule cache */ + void addToSkedCache(DynInstPtr inst, ThePipeline::RSkedPtr inst_sked) + { + SkedID sked_id = genSkedID(inst); + assert(skedCache.find(sked_id) == skedCache.end()); + skedCache[sked_id] = inst_sked; + } + + + /** Find a instruction schedule */ + ThePipeline::RSkedPtr lookupSked(DynInstPtr inst) + { + SkedID sked_id = genSkedID(inst); + SkedCacheIt lookup_it = skedCache.find(sked_id); + + if (lookup_it != endOfSkedIt) { + return (*lookup_it).second; + } else { + return NULL; + } + } + + static const uint8_t INST_OPCLASS = 26; + static const uint8_t INST_LOAD = 25; + static const uint8_t INST_STORE = 24; + static const uint8_t INST_CONTROL = 23; + static const uint8_t INST_NONSPEC = 22; + static const uint8_t INST_DEST_REGS = 18; + static const uint8_t INST_SRC_REGS = 14; + + inline SkedID genSkedID(DynInstPtr inst) + { + SkedID id = 0; + id = (inst->opClass() << INST_OPCLASS) | + (inst->isLoad() << INST_LOAD) | + (inst->isStore() << INST_STORE) | + (inst->isControl() << INST_CONTROL) | + (inst->isNonSpeculative() << INST_NONSPEC) | + (inst->numDestRegs() << INST_DEST_REGS) | + (inst->numSrcRegs() << INST_SRC_REGS); + return id; + } + + ThePipeline::RSkedPtr createFrontEndSked(); + ThePipeline::RSkedPtr createBackEndSked(DynInstPtr inst); + + class StageScheduler { + private: + ThePipeline::RSkedPtr rsked; + int stageNum; + int nextTaskPriority; + + public: + StageScheduler(ThePipeline::RSkedPtr _rsked, int stage_num) + : rsked(_rsked), stageNum(stage_num), + nextTaskPriority(0) + { } + + void needs(int unit, int request) { + rsked->push(new ScheduleEntry( + stageNum, nextTaskPriority++, unit, request + )); + } + + void needs(int unit, int request, int param) { + rsked->push(new ScheduleEntry( + stageNum, nextTaskPriority++, unit, request, param + )); + } + }; + public: /** Registers statistics. */ @@ -508,10 +594,7 @@ class InOrderCPU : public BaseCPU /** Cleans up all instructions on the instruction remove list. */ void cleanUpRemovedInsts(); - /** Cleans up all instructions on the request remove list. */ - void cleanUpRemovedReqs(); - - /** Cleans up all instructions on the CPU event remove list. */ + /** Cleans up all events on the CPU event remove list. */ void cleanUpRemovedEvents(); /** Debug function to print all instructions on the list. */ @@ -541,11 +624,6 @@ class InOrderCPU : public BaseCPU */ std::queue removeList; - /** List of all the resource requests that will be removed at the end - * of this cycle. - */ - std::queue reqRemoveList; - /** List of all the cpu event requests that will be removed at the end of * the current cycle. */ diff --git a/src/cpu/inorder/first_stage.cc b/src/cpu/inorder/first_stage.cc index 71c6ec3e05..b656ca1c75 100644 --- a/src/cpu/inorder/first_stage.cc +++ b/src/cpu/inorder/first_stage.cc @@ -181,7 +181,7 @@ FirstStage::processInsts(ThreadID tid) inst->setInstListIt(cpu->addInst(inst)); // Create Front-End Resource Schedule For Instruction - ThePipeline::createFrontEndSchedule(inst); + inst->setFrontSked(cpu->frontEndSked); } int reqs_processed = 0; diff --git a/src/cpu/inorder/inorder_dyn_inst.cc b/src/cpu/inorder/inorder_dyn_inst.cc index 6afe35862f..e9deb76255 100644 --- a/src/cpu/inorder/inorder_dyn_inst.cc +++ b/src/cpu/inorder/inorder_dyn_inst.cc @@ -51,7 +51,7 @@ InOrderDynInst::InOrderDynInst(TheISA::ExtMachInst machInst, const TheISA::PCState &instPC, const TheISA::PCState &_predPC, InstSeqNum seq_num, InOrderCPU *cpu) - : staticInst(machInst, instPC.instAddr()), traceData(NULL), cpu(cpu) + : staticInst(machInst, instPC.instAddr()), traceData(NULL), cpu(cpu) { seqNum = seq_num; @@ -108,6 +108,8 @@ InOrderDynInst::setMachInst(ExtMachInst machInst) void InOrderDynInst::initVars() { + inFrontEnd = true; + fetchMemReq = NULL; dataMemReq = NULL; splitMemData = NULL; @@ -123,7 +125,6 @@ InOrderDynInst::initVars() readyRegs = 0; nextStage = 0; - nextInstStageNum = 0; for(int i = 0; i < MaxInstDestRegs; i++) instResult[i].val.integer = 0; @@ -206,8 +207,6 @@ InOrderDynInst::~InOrderDynInst() --instcount; - deleteStages(); - DPRINTF(InOrderDynInst, "DynInst: [tid:%i] [sn:%lli] Instruction destroyed" " (active insts: %i)\n", threadNumber, seqNum, instcount); } @@ -282,29 +281,6 @@ InOrderDynInst::completeAcc(Packet *pkt) return this->fault; } -InstStage *InOrderDynInst::addStage() -{ - this->currentInstStage = new InstStage(this, nextInstStageNum++); - instStageList.push_back( this->currentInstStage ); - return this->currentInstStage; -} - -InstStage *InOrderDynInst::addStage(int stage_num) -{ - nextInstStageNum = stage_num; - return InOrderDynInst::addStage(); -} - -void InOrderDynInst::deleteStages() { - std::list::iterator list_it = instStageList.begin(); - std::list::iterator list_end = instStageList.end(); - - while(list_it != list_end) { - delete *list_it; - list_it++; - } -} - Fault InOrderDynInst::memAccess() { diff --git a/src/cpu/inorder/inorder_dyn_inst.hh b/src/cpu/inorder/inorder_dyn_inst.hh index 1c0ee43844..0e6be3da22 100644 --- a/src/cpu/inorder/inorder_dyn_inst.hh +++ b/src/cpu/inorder/inorder_dyn_inst.hh @@ -210,9 +210,6 @@ class InOrderDynInst : public FastAlloc, public RefCounted /** Data used for a store for operation. */ uint64_t storeData; - /** The resource schedule for this inst */ - ThePipeline::ResSchedule resSched; - /** List of active resource requests for this instruction */ std::list reqList; @@ -304,11 +301,6 @@ class InOrderDynInst : public FastAlloc, public RefCounted int nextStage; - /* vars to keep track of InstStage's - used for resource sched defn */ - int nextInstStageNum; - ThePipeline::InstStage *currentInstStage; - std::list instStageList; - private: /** Function to initialize variables in the constructors. */ void initVars(); @@ -337,9 +329,10 @@ class InOrderDynInst : public FastAlloc, public RefCounted //////////////////////////////////////////////////////////// std::string instName() { return staticInst->getName(); } - void setMachInst(ExtMachInst inst); + ExtMachInst getMachInst() { return staticInst->machInst; } + /** Sets the StaticInst. */ void setStaticInst(StaticInstPtr &static_inst); @@ -411,68 +404,88 @@ class InOrderDynInst : public FastAlloc, public RefCounted // RESOURCE SCHEDULING // ///////////////////////////////////////////// + typedef ThePipeline::RSkedPtr RSkedPtr; + bool inFrontEnd; + + RSkedPtr frontSked; + RSkedIt frontSked_end; + + RSkedPtr backSked; + RSkedIt backSked_end; + + RSkedIt curSkedEntry; + + void setFrontSked(RSkedPtr front_sked) + { + frontSked = front_sked; + frontSked_end.init(frontSked); + frontSked_end = frontSked->end(); + //DPRINTF(InOrderDynInst, "Set FrontSked End to : %x \n" , + // frontSked_end.getIt()/*, frontSked->end()*/); + //assert(frontSked_end == frontSked->end()); + + // This initializes instruction to be able + // to walk the resource schedule + curSkedEntry.init(frontSked); + curSkedEntry = frontSked->begin(); + } + + void setBackSked(RSkedPtr back_sked) + { + backSked = back_sked; + backSked_end.init(backSked); + backSked_end = backSked->end(); + } void setNextStage(int stage_num) { nextStage = stage_num; } int getNextStage() { return nextStage; } - ThePipeline::InstStage *addStage(); - ThePipeline::InstStage *addStage(int stage); - ThePipeline::InstStage *currentStage() { return currentInstStage; } - void deleteStages(); - - /** Add A Entry To Reource Schedule */ - void addToSched(ScheduleEntry* sched_entry) - { resSched.push(sched_entry); } - - /** Print Resource Schedule */ - /** @NOTE: DEBUG ONLY */ - void printSched() + void printSked() { - ThePipeline::ResSchedule tempSched; - std::cerr << "\tInst. Res. Schedule: "; - while (!resSched.empty()) { - std::cerr << '\t' << resSched.top()->stageNum << "-" - << resSched.top()->resNum << ", "; - - tempSched.push(resSched.top()); - resSched.pop(); + if (frontSked != NULL) { + frontSked->print(); } - std::cerr << std::endl; - resSched = tempSched; + if (backSked != NULL) { + backSked->print(); + } } /** Return Next Resource Stage To Be Used */ int nextResStage() { - if (resSched.empty()) - return -1; - else - return resSched.top()->stageNum; + assert((inFrontEnd && curSkedEntry != frontSked_end) || + (!inFrontEnd && curSkedEntry != backSked_end)); + + return curSkedEntry->stageNum; } /** Return Next Resource To Be Used */ int nextResource() { - if (resSched.empty()) - return -1; - else - return resSched.top()->resNum; + assert((inFrontEnd && curSkedEntry != frontSked_end) || + (!inFrontEnd && curSkedEntry != backSked_end)); + + return curSkedEntry->resNum; } - /** Remove & Deallocate a schedule entry */ - void popSchedEntry() + /** Finish using a schedule entry, increment to next entry */ + bool finishSkedEntry() { - if (!resSched.empty()) { - ScheduleEntry* sked = resSched.top(); - resSched.pop(); - if (sked != 0) { - delete sked; - - } + curSkedEntry++; + + if (inFrontEnd && curSkedEntry == frontSked_end) { + assert(backSked != NULL); + curSkedEntry.init(backSked); + curSkedEntry = backSked->begin(); + inFrontEnd = false; + } else if (!inFrontEnd && curSkedEntry == backSked_end) { + return true; } + + return false; } /** Release a Resource Request (Currently Unused) */ diff --git a/src/cpu/inorder/pipeline_stage.cc b/src/cpu/inorder/pipeline_stage.cc index 744ffd4d2b..b267ac00e4 100644 --- a/src/cpu/inorder/pipeline_stage.cc +++ b/src/cpu/inorder/pipeline_stage.cc @@ -44,12 +44,17 @@ PipelineStage::PipelineStage(Params *params, unsigned stage_num) stageBufferMax(params->stageWidth), prevStageValid(false), nextStageValid(false), idle(false) { - switchedOutBuffer.resize(ThePipeline::MaxThreads); - switchedOutValid.resize(ThePipeline::MaxThreads); - init(params); } +PipelineStage::~PipelineStage() +{ + for(ThreadID tid = 0; tid < numThreads; tid++) { + skidBuffer[tid].clear(); + stalls[tid].resources.clear(); + } +} + void PipelineStage::init(Params *params) { @@ -66,6 +71,12 @@ PipelineStage::init(Params *params) else lastStallingStage[tid] = NumStages - 1; } + + if ((InOrderCPU::ThreadModel) params->threadModel == + InOrderCPU::SwitchOnCacheMiss) { + switchedOutBuffer.resize(ThePipeline::MaxThreads); + switchedOutValid.resize(ThePipeline::MaxThreads); + } } @@ -190,9 +201,6 @@ PipelineStage::takeOverFrom() stalls[tid].resources.clear(); - while (!insts[tid].empty()) - insts[tid].pop(); - skidBuffer[tid].clear(); } wroteToTimeBuffer = false; @@ -938,17 +946,24 @@ PipelineStage::processInstSchedule(DynInstPtr inst,int &reqs_processed) "\n", tid, inst->seqNum, cpu->resPool->name(res_num)); ResReqPtr req = cpu->resPool->request(res_num, inst); + assert(req->valid); - if (req->isCompleted()) { + bool req_completed = req->isCompleted(); + bool done_in_pipeline = false; + if (req_completed) { DPRINTF(InOrderStage, "[tid:%i]: [sn:%i] request to %s " "completed.\n", tid, inst->seqNum, cpu->resPool->name(res_num)); - inst->popSchedEntry(); - reqs_processed++; req->stagePasses++; + + done_in_pipeline = inst->finishSkedEntry(); + if (done_in_pipeline) { + DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] finished " + "in pipeline.\n", tid, inst->seqNum); + } } else { DPRINTF(InOrderStage, "[tid:%i]: [sn:%i] request to %s failed." "\n", tid, inst->seqNum, cpu->resPool->name(res_num)); @@ -982,23 +997,20 @@ PipelineStage::processInstSchedule(DynInstPtr inst,int &reqs_processed) // Activate Next Ready Thread at end of cycle DPRINTF(ThreadModel, "Attempting to activate next ready " "thread due to cache miss.\n"); - cpu->activateNextReadyContext(); + cpu->activateNextReadyContext(); } - - // Mark request for deletion - // if it isnt currently being used by a resource - if (!req->hasSlot()) { - DPRINTF(InOrderStage, "[sn:%i] Deleting Request, has no " - "slot in resource.\n", inst->seqNum); - - cpu->reqRemoveList.push(req); - } else { - DPRINTF(InOrderStage, "[sn:%i] Ignoring Request Deletion, " - "in resource [slot:%i].\n", inst->seqNum, - req->getSlot()); - } - - + } + + // If this request is no longer needs to take up bandwidth in the + // resource, go ahead and free that bandwidth up + if (req->doneInResource) { + req->freeSlot(); + } + + // No longer need to process this instruction if the last + // request it had wasn't completed or if there is nothing + // else for it to do in the pipeline + if (done_in_pipeline || !req_completed) { break; } diff --git a/src/cpu/inorder/pipeline_stage.hh b/src/cpu/inorder/pipeline_stage.hh index dfa88de87c..ec70fefc5d 100644 --- a/src/cpu/inorder/pipeline_stage.hh +++ b/src/cpu/inorder/pipeline_stage.hh @@ -91,10 +91,7 @@ class PipelineStage public: PipelineStage(Params *params, unsigned stage_num); - /** MUST use init() function if this constructor is used. */ - PipelineStage() { } - - virtual ~PipelineStage() { } + virtual ~PipelineStage(); /** PipelineStage initialization. */ void init(Params *params); @@ -268,16 +265,6 @@ class PipelineStage */ unsigned instsProcessed; - /** Queue of all instructions coming from previous stage on this cycle. */ - std::queue insts[ThePipeline::MaxThreads]; - - /** Queue of instructions that are finished processing and ready to go - * next stage. This is used to prevent from processing an instrution more - * than once on any stage. NOTE: It is up to the PROGRAMMER must manage - * this as a queue - */ - std::list instsToNextStage; - /** Skid buffer between previous stage and this one. */ std::list skidBuffer[ThePipeline::MaxThreads]; diff --git a/src/cpu/inorder/pipeline_traits.cc b/src/cpu/inorder/pipeline_traits.cc deleted file mode 100644 index a6fad68f71..0000000000 --- a/src/cpu/inorder/pipeline_traits.cc +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2007 MIPS Technologies, Inc. - * 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: Korey Sewell - * - */ - -#include "cpu/inorder/pipeline_traits.hh" -#include "cpu/inorder/inorder_dyn_inst.hh" -#include "cpu/inorder/resources/resource_list.hh" - -using namespace std; - -namespace ThePipeline { - -//@TODO: create my own Instruction Schedule Class -//that operates as a Priority QUEUE -int getNextPriority(DynInstPtr &inst, int stage_num) -{ - int cur_pri = 20; - - /* - std::priority_queue, - entryCompare>::iterator sked_it = inst->resSched.begin(); - - std::priority_queue, - entryCompare>::iterator sked_end = inst->resSched.end(); - - while (sked_it != sked_end) { - - if (sked_it.top()->stageNum == stage_num) { - cur_pri = sked_it.top()->priority; - } - - sked_it++; - } - */ - - return cur_pri; -} - -void createFrontEndSchedule(DynInstPtr &inst) -{ - InstStage *F = inst->addStage(); - InstStage *D = inst->addStage(); - - // FETCH - F->needs(FetchSeq, FetchSeqUnit::AssignNextPC); - F->needs(ICache, FetchUnit::InitiateFetch); - - // DECODE - D->needs(ICache, FetchUnit::CompleteFetch); - D->needs(Decode, DecodeUnit::DecodeInst); - D->needs(BPred, BranchPredictor::PredictBranch); - D->needs(FetchSeq, FetchSeqUnit::UpdateTargetPC); - - inst->resSched.init(); -} - -bool createBackEndSchedule(DynInstPtr &inst) -{ - if (!inst->staticInst) { - return false; - } - - InstStage *X = inst->addStage(); - InstStage *M = inst->addStage(); - InstStage *W = inst->addStage(); - - // EXECUTE - for (int idx=0; idx < inst->numSrcRegs(); idx++) { - if (!idx || !inst->isStore()) { - X->needs(RegManager, UseDefUnit::ReadSrcReg, idx); - } - } - - if ( inst->isNonSpeculative() ) { - // skip execution of non speculative insts until later - } else if ( inst->isMemRef() ) { - if ( inst->isLoad() ) { - X->needs(AGEN, AGENUnit::GenerateAddr); - } - } else if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) { - X->needs(MDU, MultDivUnit::StartMultDiv); - } else { - X->needs(ExecUnit, ExecutionUnit::ExecuteInst); - } - - if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) { - X->needs(MDU, MultDivUnit::EndMultDiv); - } - - // MEMORY - if ( inst->isLoad() ) { - M->needs(DCache, CacheUnit::InitiateReadData); - } else if ( inst->isStore() ) { - if ( inst->numSrcRegs() >= 2 ) { - M->needs(RegManager, UseDefUnit::ReadSrcReg, 1); - } - M->needs(AGEN, AGENUnit::GenerateAddr); - M->needs(DCache, CacheUnit::InitiateWriteData); - } - - - // WRITEBACK - if ( inst->isLoad() ) { - W->needs(DCache, CacheUnit::CompleteReadData); - } else if ( inst->isStore() ) { - W->needs(DCache, CacheUnit::CompleteWriteData); - } - - if ( inst->isNonSpeculative() ) { - if ( inst->isMemRef() ) fatal("Non-Speculative Memory Instruction"); - W->needs(ExecUnit, ExecutionUnit::ExecuteInst); - } - - for (int idx=0; idx < inst->numDestRegs(); idx++) { - W->needs(RegManager, UseDefUnit::WriteDestReg, idx); - } - - W->needs(Grad, GraduationUnit::GraduateInst); - - return true; -} - -InstStage::InstStage(DynInstPtr inst, int stage_num) -{ - stageNum = stage_num; - nextTaskPriority = 0; - instSched = &inst->resSched; -} - -void -InstStage::needs(int unit, int request) { - instSched->push( new ScheduleEntry( - stageNum, nextTaskPriority++, unit, request - )); -} - -void -InstStage::needs(int unit, int request, int param) { - instSched->push( new ScheduleEntry( - stageNum, nextTaskPriority++, unit, request, param - )); -} - -}; diff --git a/src/cpu/inorder/pipeline_traits.hh b/src/cpu/inorder/pipeline_traits.hh index df964e2544..573c0200ab 100644 --- a/src/cpu/inorder/pipeline_traits.hh +++ b/src/cpu/inorder/pipeline_traits.hh @@ -51,7 +51,7 @@ class ResourceSked; namespace ThePipeline { // Pipeline Constants const unsigned NumStages = 5; - const ThreadID MaxThreads = 8; + const ThreadID MaxThreads = 1; const unsigned BackEndStartStage = 2; // List of Resources The Pipeline Uses @@ -77,23 +77,7 @@ namespace ThePipeline { // RESOURCE SCHEDULING ////////////////////////// typedef ResourceSked ResSchedule; - - void createFrontEndSchedule(DynInstPtr &inst); - bool createBackEndSchedule(DynInstPtr &inst); - int getNextPriority(DynInstPtr &inst, int stage_num); - - class InstStage { - private: - int nextTaskPriority; - int stageNum; - ResSchedule *instSched; - - public: - InstStage(DynInstPtr inst, int stage_num); - - void needs(int unit, int request); - void needs(int unit, int request, int param); - }; + typedef ResourceSked* RSkedPtr; }; diff --git a/src/cpu/inorder/reg_dep_map.cc b/src/cpu/inorder/reg_dep_map.cc index 98a0727a9a..48820b50e5 100644 --- a/src/cpu/inorder/reg_dep_map.cc +++ b/src/cpu/inorder/reg_dep_map.cc @@ -45,6 +45,14 @@ RegDepMap::RegDepMap(int size) regMap.resize(size); } +RegDepMap::~RegDepMap() +{ + for (int i = 0; i < regMap.size(); i++) { + regMap[i].clear(); + } + regMap.clear(); +} + string RegDepMap::name() { diff --git a/src/cpu/inorder/reg_dep_map.hh b/src/cpu/inorder/reg_dep_map.hh index fa4fe45f37..047e4d1291 100644 --- a/src/cpu/inorder/reg_dep_map.hh +++ b/src/cpu/inorder/reg_dep_map.hh @@ -48,7 +48,7 @@ class RegDepMap public: RegDepMap(int size = TheISA::TotalNumRegs); - ~RegDepMap() { } + ~RegDepMap(); std::string name(); diff --git a/src/cpu/inorder/resource.cc b/src/cpu/inorder/resource.cc index 51beb5aa0e..24211532ef 100644 --- a/src/cpu/inorder/resource.cc +++ b/src/cpu/inorder/resource.cc @@ -31,6 +31,8 @@ #include #include + +#include "base/str.hh" #include "cpu/inorder/resource.hh" #include "cpu/inorder/cpu.hh" using namespace std; @@ -40,22 +42,42 @@ Resource::Resource(string res_name, int res_id, int res_width, : resName(res_name), id(res_id), width(res_width), latency(res_latency), cpu(_cpu) { + reqs.resize(width); + // Use to deny a instruction a resource. - deniedReq = new ResourceRequest(this, NULL, 0, 0, 0, 0); + deniedReq = new ResourceRequest(this); + deniedReq->valid = true; } Resource::~Resource() { - delete [] resourceEvent; - delete deniedReq; + if (resourceEvent) { + delete [] resourceEvent; + } + + delete deniedReq; + + for (int i = 0; i < width; i++) { + delete reqs[i]; + } } void Resource::init() { - // Set Up Resource Events to Appropriate Resource BandWidth - resourceEvent = new ResourceEvent[width]; + // If the resource has a zero-cycle (no latency) + // function, then no reason to have events + // that will process them for the right tick + if (latency > 0) { + resourceEvent = new ResourceEvent[width]; + } else { + resourceEvent = NULL; + } + + for (int i = 0; i < width; i++) { + reqs[i] = new ResourceRequest(this); + } initSlots(); } @@ -66,7 +88,10 @@ Resource::initSlots() // Add available slot numbers for resource for (int slot_idx = 0; slot_idx < width; slot_idx++) { availSlots.push_back(slot_idx); - resourceEvent[slot_idx].init(this, slot_idx); + + if (resourceEvent) { + resourceEvent[slot_idx].init(this, slot_idx); + } } } @@ -91,42 +116,34 @@ Resource::slotsInUse() void Resource::freeSlot(int slot_idx) { + DPRINTF(Resource, "Deallocating [slot:%i].\n", + slot_idx); + // Put slot number on this resource's free list availSlots.push_back(slot_idx); - // Erase Request Pointer From Request Map - std::map::iterator req_it = reqMap.find(slot_idx); - - assert(req_it != reqMap.end()); - reqMap.erase(req_it); - + // Invalidate Request & Reset it's flags + reqs[slot_idx]->clearRequest(); } -// TODO: More efficiently search for instruction's slot within -// resource. int Resource::findSlot(DynInstPtr inst) { - map::iterator map_it = reqMap.begin(); - map::iterator map_end = reqMap.end(); - int slot_num = -1; - while (map_it != map_end) { - if ((*map_it).second->getInst()->seqNum == - inst->seqNum) { - slot_num = (*map_it).second->getSlot(); + for (int i = 0; i < width; i++) { + if (reqs[i]->valid && + reqs[i]->getInst()->seqNum == inst->seqNum) { + slot_num = reqs[i]->getSlot(); } - map_it++; } - return slot_num; } int Resource::getSlot(DynInstPtr inst) { - int slot_num; + int slot_num = -1; if (slotsAvail() != 0) { slot_num = availSlots[0]; @@ -136,24 +153,6 @@ Resource::getSlot(DynInstPtr inst) assert(slot_num == *vect_it); availSlots.erase(vect_it); - } else { - DPRINTF(Resource, "[tid:%i]: No slots in resource " - "available to service [sn:%i].\n", inst->readTid(), - inst->seqNum); - slot_num = -1; - - map::iterator map_it = reqMap.begin(); - map::iterator map_end = reqMap.end(); - - while (map_it != map_end) { - if ((*map_it).second) { - DPRINTF(Resource, "Currently Serving request from: " - "[tid:%i] [sn:%i].\n", - (*map_it).second->getInst()->readTid(), - (*map_it).second->getInst()->seqNum); - } - map_it++; - } } return slot_num; @@ -183,9 +182,12 @@ Resource::request(DynInstPtr inst) slot_num = getSlot(inst); if (slot_num != -1) { + DPRINTF(Resource, "Allocating [slot:%i] for [tid:%i]: [sn:%i]\n", + slot_num, inst->readTid(), inst->seqNum); + // Get Stage # from Schedule Entry - stage_num = inst->resSched.top()->stageNum; - unsigned cmd = inst->resSched.top()->cmd; + stage_num = inst->curSkedEntry->stageNum; + unsigned cmd = inst->curSkedEntry->cmd; // Generate Resource Request inst_req = getRequest(inst, stage_num, id, slot_num, cmd); @@ -200,10 +202,12 @@ Resource::request(DynInstPtr inst) inst->readTid()); } - reqMap[slot_num] = inst_req; - try_request = true; + } else { + DPRINTF(Resource, "No slot available for [tid:%i]: [sn:%i]\n", + inst->readTid(), inst->seqNum); } + } if (try_request) { @@ -236,32 +240,21 @@ ResReqPtr Resource::getRequest(DynInstPtr inst, int stage_num, int res_idx, int slot_num, unsigned cmd) { - return new ResourceRequest(this, inst, stage_num, id, slot_num, - cmd); + reqs[slot_num]->setRequest(inst, stage_num, id, slot_num, cmd); + return reqs[slot_num]; } ResReqPtr Resource::findRequest(DynInstPtr inst) { - map::iterator map_it = reqMap.begin(); - map::iterator map_end = reqMap.end(); - - bool found = false; - ResReqPtr req = NULL; - - while (map_it != map_end) { - if ((*map_it).second && - (*map_it).second->getInst() == inst) { - req = (*map_it).second; - //return (*map_it).second; - assert(found == false); - found = true; + for (int i = 0; i < width; i++) { + if (reqs[i]->valid && + reqs[i]->getInst() == inst) { + return reqs[i]; } - map_it++; } - return req; - //return NULL; + return NULL; } void @@ -275,9 +268,9 @@ void Resource::execute(int slot_idx) { DPRINTF(Resource, "[tid:%i]: Executing %s resource.\n", - reqMap[slot_idx]->getTid(), name()); - reqMap[slot_idx]->setCompleted(true); - reqMap[slot_idx]->done(); + reqs[slot_idx]->getTid(), name()); + reqs[slot_idx]->setCompleted(true); + reqs[slot_idx]->done(); } void @@ -293,15 +286,10 @@ void Resource::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, ThreadID tid) { - std::vector slot_remove_list; + for (int i = 0; i < width; i++) { + ResReqPtr req_ptr = reqs[i]; - map::iterator map_it = reqMap.begin(); - map::iterator map_end = reqMap.end(); - - while (map_it != map_end) { - ResReqPtr req_ptr = (*map_it).second; - - if (req_ptr && + if (req_ptr->valid && req_ptr->getInst()->readTid() == tid && req_ptr->getInst()->seqNum > squash_seq_num) { @@ -316,19 +304,8 @@ Resource::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, if (resourceEvent[req_slot_num].scheduled()) unscheduleEvent(req_slot_num); - // Mark request for later removal - cpu->reqRemoveList.push(req_ptr); - - // Mark slot for removal from resource - slot_remove_list.push_back(req_ptr->getSlot()); + freeSlot(req_slot_num); } - - map_it++; - } - - // Now Delete Slot Entry from Req. Map - for (int i = 0; i < slot_remove_list.size(); i++) { - freeSlot(slot_remove_list[i]); } } @@ -350,10 +327,8 @@ Resource::ticks(int num_cycles) void Resource::scheduleExecution(int slot_num) { - int res_latency = getLatency(slot_num); - - if (res_latency >= 1) { - scheduleEvent(slot_num, res_latency); + if (latency >= 1) { + scheduleEvent(slot_num, latency); } else { execute(slot_num); } @@ -363,8 +338,8 @@ void Resource::scheduleEvent(int slot_idx, int delay) { DPRINTF(Resource, "[tid:%i]: Scheduling event for [sn:%i] on tick %i.\n", - reqMap[slot_idx]->inst->readTid(), - reqMap[slot_idx]->inst->seqNum, + reqs[slot_idx]->inst->readTid(), + reqs[slot_idx]->inst->seqNum, cpu->ticks(delay) + curTick()); resourceEvent[slot_idx].scheduleEvent(delay); } @@ -401,32 +376,11 @@ int ResourceRequest::resReqID = 0; int ResourceRequest::maxReqCount = 0; -ResourceRequest::ResourceRequest(Resource *_res, DynInstPtr _inst, - int stage_num, int res_idx, int slot_num, - unsigned _cmd) - : res(_res), inst(_inst), cmd(_cmd), stageNum(stage_num), - resIdx(res_idx), slotNum(slot_num), completed(false), - squashed(false), processing(false), memStall(false) +ResourceRequest::ResourceRequest(Resource *_res) + : res(_res), inst(NULL), stagePasses(0), valid(false), doneInResource(false), + completed(false), squashed(false), processing(false), + memStall(false) { -#ifdef DEBUG - reqID = resReqID++; - res->cpu->resReqCount++; - DPRINTF(ResReqCount, "Res. Req %i created. resReqCount=%i.\n", reqID, - res->cpu->resReqCount); - - if (res->cpu->resReqCount > 100) { - fatal("Too many undeleted resource requests. Memory leak?\n"); - } - - if (res->cpu->resReqCount > maxReqCount) { - maxReqCount = res->cpu->resReqCount; - } - -#endif - - stagePasses = 0; - complSlotNum = -1; - } ResourceRequest::~ResourceRequest() @@ -436,6 +390,46 @@ ResourceRequest::~ResourceRequest() DPRINTF(ResReqCount, "Res. Req %i deleted. resReqCount=%i.\n", reqID, res->cpu->resReqCount); #endif + inst = NULL; +} + +std::string +ResourceRequest::name() +{ + return res->name() + "." + to_string(slotNum); +} + +void +ResourceRequest::setRequest(DynInstPtr _inst, int stage_num, + int res_idx, int slot_num, unsigned _cmd) +{ + valid = true; + inst = _inst; + stageNum = stage_num; + resIdx = res_idx; + slotNum = slot_num; + cmd = _cmd; +} + +void +ResourceRequest::clearRequest() +{ + valid = false; + inst = NULL; + stagePasses = 0; + completed = false; + doneInResource = false; + squashed = false; + memStall = false; +} + +void +ResourceRequest::freeSlot() +{ + assert(res); + + // Free Slot So Another Instruction Can Use This Resource + res->freeSlot(slotNum); } void @@ -447,25 +441,7 @@ ResourceRequest::done(bool completed) setCompleted(completed); - // Used for debugging purposes - if (completed) { - complSlotNum = slotNum; - - // Would like to start a convention such as all requests deleted in - // resources/pipeline - // but a little more complex then it seems... - // For now, all COMPLETED requests deleted in resource.. - // all FAILED requests deleted in pipeline stage - // *all SQUASHED requests deleted in resource - res->cpu->reqRemoveList.push(res->reqMap[slotNum]); - } - - // Free Slot So Another Instruction Can Use This Resource - res->freeSlot(slotNum); - - // change slot # to -1, since we check slotNum to see if request is - // still valid - slotNum = -1; + doneInResource = true; } ResourceEvent::ResourceEvent() @@ -493,7 +469,8 @@ ResourceEvent::process() const char * ResourceEvent::description() { - string desc = resource->name() + " event"; + string desc = resource->name() + "-event:slot[" + to_string(slotIdx) + + "]"; return desc.c_str(); } diff --git a/src/cpu/inorder/resource.hh b/src/cpu/inorder/resource.hh index bd9ec48ca3..7899a215fe 100644 --- a/src/cpu/inorder/resource.hh +++ b/src/cpu/inorder/resource.hh @@ -221,8 +221,10 @@ class Resource { const int latency; public: - /** Mapping of slot-numbers to the resource-request pointers */ - std::map reqMap; + /** List of all Requests the Resource is Servicing. Each request + represents part of the resource's bandwidth + */ + std::vector reqs; /** A list of all the available execution slots for this resource. * This correlates with the actual resource event idx. @@ -245,7 +247,7 @@ class Resource { class ResourceEvent : public Event { public: - /** Pointer to the CPU. */ + /** Pointer to the Resource this is an event for */ Resource *resource; @@ -297,21 +299,29 @@ class ResourceRequest static int maxReqCount; + friend class Resource; + public: - ResourceRequest(Resource *_res, DynInstPtr _inst, int stage_num, - int res_idx, int slot_num, unsigned _cmd); + ResourceRequest(Resource *_res); virtual ~ResourceRequest(); + + std::string name(); int reqID; + virtual void setRequest(DynInstPtr _inst, int stage_num, + int res_idx, int slot_num, unsigned _cmd); + + virtual void clearRequest(); + /** Acknowledge that this is a request is done and remove * from resource. */ void done(bool completed = true); - - short stagePasses; + void freeSlot(); + ///////////////////////////////////////////// // // GET RESOURCE REQUEST IDENTIFICATION / INFO @@ -319,11 +329,9 @@ class ResourceRequest ///////////////////////////////////////////// /** Get Resource Index */ int getResIdx() { return resIdx; } - /** Get Slot Number */ int getSlot() { return slotNum; } - int getComplSlot() { return complSlotNum; } bool hasSlot() { return slotNum >= 0; } /** Get Stage Number */ @@ -353,6 +361,12 @@ class ResourceRequest /** Command For This Resource */ unsigned cmd; + short stagePasses; + + bool valid; + + bool doneInResource; + //////////////////////////////////////// // // GET RESOURCE REQUEST STATUS FROM VARIABLES @@ -380,7 +394,6 @@ class ResourceRequest int stageNum; int resIdx; int slotNum; - int complSlotNum; /** Resource Request Status */ bool completed; diff --git a/src/cpu/inorder/resource_pool.cc b/src/cpu/inorder/resource_pool.cc index a037cbe9ed..4e2f930ab5 100644 --- a/src/cpu/inorder/resource_pool.cc +++ b/src/cpu/inorder/resource_pool.cc @@ -55,7 +55,7 @@ ResourcePool::ResourcePool(InOrderCPU *_cpu, ThePipeline::Params *params) memObjects.push_back(ICache); resources.push_back(new FetchUnit("icache_port", ICache, - stage_width * MaxThreads, 0, _cpu, + stage_width * 2 + MaxThreads, 0, _cpu, params)); resources.push_back(new DecodeUnit("Decode-Unit", Decode, @@ -68,7 +68,7 @@ ResourcePool::ResourcePool(InOrderCPU *_cpu, ThePipeline::Params *params) 0, _cpu, params)); resources.push_back(new UseDefUnit("RegFile-Manager", RegManager, - stage_width * MaxThreads, 0, _cpu, + stage_width * 3, 0, _cpu, params)); resources.push_back(new AGENUnit("AGEN-Unit", AGEN, @@ -77,20 +77,21 @@ ResourcePool::ResourcePool(InOrderCPU *_cpu, ThePipeline::Params *params) resources.push_back(new ExecutionUnit("Execution-Unit", ExecUnit, stage_width, 0, _cpu, params)); - resources.push_back(new MultDivUnit("Mult-Div-Unit", MDU, 5, 0, _cpu, - params)); + resources.push_back(new MultDivUnit("Mult-Div-Unit", MDU, + stage_width * 2, 0, _cpu, params)); memObjects.push_back(DCache); resources.push_back(new CacheUnit("dcache_port", DCache, - stage_width * MaxThreads, 0, _cpu, + stage_width * 2 + MaxThreads, 0, _cpu, params)); resources.push_back(new GraduationUnit("Graduation-Unit", Grad, - stage_width * MaxThreads, 0, _cpu, + stage_width, 0, _cpu, params)); resources.push_back(new InstBuffer("Fetch-Buffer-T1", FetchBuff2, 4, 0, _cpu, params)); + } ResourcePool::~ResourcePool() @@ -122,6 +123,16 @@ ResourcePool::name() return cpu->name() + ".ResourcePool"; } +void +ResourcePool::print() +{ + for (int i=0; i < resources.size(); i++) { + DPRINTF(InOrderDynInst, "Res:%i %s\n", + i, resources[i]->name()); + } + +} + void ResourcePool::regStats() diff --git a/src/cpu/inorder/resource_pool.hh b/src/cpu/inorder/resource_pool.hh index e8061d3ffa..fde38b4e9a 100644 --- a/src/cpu/inorder/resource_pool.hh +++ b/src/cpu/inorder/resource_pool.hh @@ -130,6 +130,8 @@ class ResourcePool { void init(); + void print(); + /** Register Statistics in All Resources */ void regStats(); diff --git a/src/cpu/inorder/resource_sked.cc b/src/cpu/inorder/resource_sked.cc index 4104e69898..4cf791228f 100644 --- a/src/cpu/inorder/resource_sked.cc +++ b/src/cpu/inorder/resource_sked.cc @@ -34,30 +34,30 @@ #include #include -#include +#include using namespace std; using namespace ThePipeline; ResourceSked::ResourceSked() { - sked.resize(NumStages); + stages.resize(NumStages); } void ResourceSked::init() { - assert(!sked[0].empty()); + assert(!stages[0].empty()); - curSkedEntry = sked[0].begin(); + curSkedEntry = stages[0].begin(); } int ResourceSked::size() { int total = 0; - for (int i = 0; i < sked.size(); i++) { - total += sked[i].size(); + for (int i = 0; i < stages.size(); i++) { + total += stages[i].size(); } return total; @@ -69,6 +69,26 @@ ResourceSked::empty() return size() == 0; } + +ResourceSked::SkedIt +ResourceSked::begin() +{ + int num_stages = stages.size(); + for (int i = 0; i < num_stages; i++) { + if (stages[i].size() > 0) + return stages[i].begin(); + } + + return stages[num_stages - 1].end(); +} + +ResourceSked::SkedIt +ResourceSked::end() +{ + int num_stages = stages.size(); + return stages[num_stages - 1].end(); +} + ScheduleEntry* ResourceSked::top() { @@ -82,18 +102,18 @@ ResourceSked::pop() { int stage_num = (*curSkedEntry)->stageNum; - sked[stage_num].erase(curSkedEntry); + stages[stage_num].erase(curSkedEntry); - if (!sked[stage_num].empty()) { - curSkedEntry = sked[stage_num].begin(); + if (!stages[stage_num].empty()) { + curSkedEntry = stages[stage_num].begin(); } else { int next_stage = stage_num + 1; while (next_stage < NumStages) { - if (sked[next_stage].empty()) { + if (stages[next_stage].empty()) { next_stage++; } else { - curSkedEntry = sked[next_stage].begin(); + curSkedEntry = stages[next_stage].begin(); break; } } @@ -108,7 +128,7 @@ ResourceSked::push(ScheduleEntry* sked_entry) SkedIt pri_iter = findIterByPriority(sked_entry, stage_num); - sked[stage_num].insert(pri_iter, sked_entry); + stages[stage_num].insert(pri_iter, sked_entry); } void @@ -122,23 +142,23 @@ ResourceSked::pushBefore(ScheduleEntry* sked_entry, int sked_cmd, SkedIt pri_iter = findIterByCommand(sked_entry, stage_num, sked_cmd, sked_cmd_idx); - assert(pri_iter != sked[stage_num].end() && + assert(pri_iter != stages[stage_num].end() && "Could not find command to insert in front of."); - sked[stage_num].insert(pri_iter, sked_entry); + stages[stage_num].insert(pri_iter, sked_entry); } ResourceSked::SkedIt ResourceSked::findIterByPriority(ScheduleEntry* sked_entry, int stage_num) { - if (sked[stage_num].empty()) { - return sked[stage_num].end(); + if (stages[stage_num].empty()) { + return stages[stage_num].end(); } int priority = sked_entry->priority; - SkedIt sked_it = sked[stage_num].begin(); - SkedIt sked_end = sked[stage_num].end(); + SkedIt sked_it = stages[stage_num].begin(); + SkedIt sked_end = stages[stage_num].end(); while (sked_it != sked_end) { if ((*sked_it)->priority > priority) @@ -154,12 +174,12 @@ ResourceSked::SkedIt ResourceSked::findIterByCommand(ScheduleEntry* sked_entry, int stage_num, int sked_cmd, int sked_cmd_idx) { - if (sked[stage_num].empty()) { - return sked[stage_num].end(); + if (stages[stage_num].empty()) { + return stages[stage_num].end(); } - SkedIt sked_it = sked[stage_num].begin(); - SkedIt sked_end = sked[stage_num].end(); + SkedIt sked_it = stages[stage_num].begin(); + SkedIt sked_end = stages[stage_num].end(); while (sked_it != sked_end) { if ((*sked_it)->cmd == sked_cmd && @@ -175,12 +195,16 @@ ResourceSked::findIterByCommand(ScheduleEntry* sked_entry, int stage_num, void ResourceSked::print() { - for (int i = 0; i < sked.size(); i++) { - cprintf("Stage %i\n====\n", i); - SkedIt sked_it = sked[i].begin(); - SkedIt sked_end = sked[i].end(); + for (int i = 0; i < stages.size(); i++) { + //ccprintf(cerr, "Stage %i\n====\n", i); + SkedIt sked_it = stages[i].begin(); + SkedIt sked_end = stages[i].end(); while (sked_it != sked_end) { - cprintf("\t res:%i cmd:%i idx:%i\n", (*sked_it)->resNum, (*sked_it)->cmd, (*sked_it)->idx); + DPRINTF(SkedCache, "\t stage:%i res:%i cmd:%i idx:%i\n", + (*sked_it)->stageNum, + (*sked_it)->resNum, + (*sked_it)->cmd, + (*sked_it)->idx); sked_it++; } } diff --git a/src/cpu/inorder/resource_sked.hh b/src/cpu/inorder/resource_sked.hh index 22e29d7285..bd002e161e 100644 --- a/src/cpu/inorder/resource_sked.hh +++ b/src/cpu/inorder/resource_sked.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 The Regents of The University of Michigan + * Copyright (c) 2010-2011 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,7 +34,19 @@ #include #include +#include +/** ScheduleEntry class represents a single function that an instruction + wants to do at any pipeline stage. For example, if an instruction + needs to be decoded and do a branch prediction all in one stage + then each of those tasks would need it's own ScheduleEntry. + + Each schedule entry corresponds to some resource that the instruction + wants to interact with. + + The file pipeline_traits.cc shows how a typical instruction schedule is + made up of these schedule entries. +*/ class ScheduleEntry { public: ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0, @@ -43,45 +55,225 @@ class ScheduleEntry { idx(_idx), priority(_priority) { } - // Stage number to perform this service. + /** Stage number to perform this service. */ int stageNum; - // Resource ID to access + /** Resource ID to access */ int resNum; - // See specific resource for meaning + /** See specific resource for meaning */ unsigned cmd; - // See specific resource for meaning + /** See specific resource for meaning */ unsigned idx; - // Some Resources May Need Priority + /** Some Resources May Need Priority */ int priority; }; +/** The ResourceSked maintains the complete schedule + for an instruction. That schedule includes what + resources an instruction wants to acquire at each + pipeline stage and is represented by a collection + of ScheduleEntry objects (described above) that + must be executed in-order. + + In every pipeline stage, the InOrder model will + process all entries on the resource schedule for + that stage and then send the instruction to the next + stage if and only if the instruction successfully + completed each ScheduleEntry. +*/ class ResourceSked { public: typedef std::list::iterator SkedIt; + typedef std::vector > StageList; ResourceSked(); + /** Initializee the current entry pointer to + pipeline stage 0 and the 1st schedule entry + */ void init(); + /** Goes through the remaining stages on the schedule + and sums all the remaining entries left to be + processed + */ int size(); + + /** Is the schedule empty? */ bool empty(); + + /** Beginning Entry of this schedule */ + SkedIt begin(); + + /** Ending Entry of this schedule */ + SkedIt end(); + + /** What is the next task for this instruction schedule? */ ScheduleEntry* top(); + + /** Top() Task is completed, remove it from schedule */ void pop(); + + /** Add To Schedule based on stage num and priority of + Schedule Entry + */ void push(ScheduleEntry* sked_entry); + + /** Add Schedule Entry to be in front of another Entry */ void pushBefore(ScheduleEntry* sked_entry, int sked_cmd, int sked_cmd_idx); + + /** Print what's left on the instruction schedule */ void print(); - private: - SkedIt curSkedEntry; - std::vector > sked; + StageList *getStages() + { + return &stages; + } + private: + /** Current Schedule Entry Pointer */ + SkedIt curSkedEntry; + + /** The Stage-by-Stage Resource Schedule: + Resized to Number of Stages in the constructor + */ + StageList stages; + + /** Find a place to insert the instruction using the + schedule entries priority + */ SkedIt findIterByPriority(ScheduleEntry *sked_entry, int stage_num); + + /** Find a place to insert the instruction using a particular command + to look for. + */ SkedIt findIterByCommand(ScheduleEntry *sked_entry, int stage_num, int sked_cmd, int sked_cmd_idx = -1); }; +/** Wrapper class around the SkedIt iterator in the Resource Sked so that + we can use ++ operator to automatically go to the next available + resource schedule entry but otherwise maintain same functionality + as a normal iterator. +*/ +class RSkedIt +{ + public: + RSkedIt() + : curStage(0), numStages(0) + { } + + + /** init() must be called before the use of any other member + in the RSkedIt class. + */ + void init(ResourceSked* rsked) + { + stages = rsked->getStages(); + numStages = stages->size(); + } + + /* Update the encapsulated "myIt" iterator, but only + update curStage/curStage_end if the iterator is valid. + The iterator could be invalid in the case where + someone is saving the end of a list (i.e. std::list->end()) + */ + RSkedIt operator=(ResourceSked::SkedIt const &rhs) + { + myIt = rhs; + if (myIt != (*stages)[numStages-1].end()) { + curStage = (*myIt)->stageNum; + curStage_end = (*stages)[curStage].end(); + } + return *this; + } + + /** Increment to the next entry in current stage. + If no more entries then find the next stage that has + resource schedule to complete. + If no more stages, then return the end() iterator from + the last stage to indicate we are done. + */ + RSkedIt &operator++(int unused) + { + if (++myIt == curStage_end) { + curStage++; + while (curStage < numStages) { + if ((*stages)[curStage].empty()) { + curStage++; + } else { + myIt = (*stages)[curStage].begin(); + curStage_end = (*stages)[curStage].end(); + return *this; + } + } + + myIt = (*stages)[numStages - 1].end(); + } + + return *this; + } + + /** The "pointer" operator can be used on a RSkedIt and it + will use the encapsulated iterator + */ + ScheduleEntry* operator->() + { + return *myIt; + } + + /** Dereferencing a RSKedIt will access the encapsulated + iterator + */ + ScheduleEntry* operator*() + { + return *myIt; + } + + /** Equality for RSkedIt only compares the "myIt" iterators, + as the other members are just ancillary + */ + bool operator==(RSkedIt const &rhs) + { + return this->myIt == rhs.myIt; + } + + /** Inequality for RSkedIt only compares the "myIt" iterators, + as the other members are just ancillary + */ + bool operator!=(RSkedIt const &rhs) + { + return this->myIt != rhs.myIt; + } + + /* The == and != operator overloads should be sufficient + here if need otherwise direct access to the schedule + iterator, then this can be used */ + ResourceSked::SkedIt getIt() + { + return myIt; + } + + private: + /** Schedule Iterator that this class is encapsulating */ + ResourceSked::SkedIt myIt; + + /** Ptr to resource schedule that the 'myIt' iterator + belongs to + */ + ResourceSked::StageList *stages; + + /** The last iterator in the current stage. */ + ResourceSked::SkedIt curStage_end; + + /** Current Stage that "myIt" refers to. */ + int curStage; + + /** Number of stages in the "*stages" object. */ + int numStages; +}; + #endif //__CPU_INORDER_RESOURCE_SKED_HH__ diff --git a/src/cpu/inorder/resources/agen_unit.cc b/src/cpu/inorder/resources/agen_unit.cc index f1862b94a7..764cd9446e 100644 --- a/src/cpu/inorder/resources/agen_unit.cc +++ b/src/cpu/inorder/resources/agen_unit.cc @@ -50,8 +50,8 @@ AGENUnit::regStats() void AGENUnit::execute(int slot_num) { - ResourceRequest* agen_req = reqMap[slot_num]; - DynInstPtr inst = reqMap[slot_num]->inst; + ResourceRequest* agen_req = reqs[slot_num]; + DynInstPtr inst = reqs[slot_num]->inst; #if TRACING_ON ThreadID tid = inst->readTid(); #endif diff --git a/src/cpu/inorder/resources/branch_predictor.cc b/src/cpu/inorder/resources/branch_predictor.cc index 8ca5a97186..5a22e40ebf 100644 --- a/src/cpu/inorder/resources/branch_predictor.cc +++ b/src/cpu/inorder/resources/branch_predictor.cc @@ -66,7 +66,7 @@ BranchPredictor::execute(int slot_num) { // After this is working, change this to a reinterpret cast // for performance considerations - ResourceRequest* bpred_req = reqMap[slot_num]; + ResourceRequest* bpred_req = reqs[slot_num]; DynInstPtr inst = bpred_req->inst; ThreadID tid = inst->readTid(); int seq_num = inst->seqNum; diff --git a/src/cpu/inorder/resources/cache_unit.cc b/src/cpu/inorder/resources/cache_unit.cc index 8b4dd4402c..b17e5b3da4 100644 --- a/src/cpu/inorder/resources/cache_unit.cc +++ b/src/cpu/inorder/resources/cache_unit.cc @@ -133,6 +133,10 @@ CacheUnit::getPort(const string &if_name, int idx) void CacheUnit::init() { + for (int i = 0; i < width; i++) { + reqs[i] = new CacheRequest(this); + } + // Currently Used to Model TLB Latency. Eventually // Switch to Timing TLB translations. resourceEvent = new CacheUnitEvent[width]; @@ -250,20 +254,16 @@ CacheUnit::removeAddrDependency(DynInstPtr inst) ResReqPtr CacheUnit::findRequest(DynInstPtr inst) { - map::iterator map_it = reqMap.begin(); - map::iterator map_end = reqMap.end(); - - while (map_it != map_end) { + for (int i = 0; i < width; i++) { CacheRequest* cache_req = - dynamic_cast((*map_it).second); + dynamic_cast(reqs[i]); assert(cache_req); - if (cache_req && + if (cache_req->valid && cache_req->getInst() == inst && - cache_req->instIdx == inst->resSched.top()->idx) { + cache_req->instIdx == inst->curSkedEntry->idx) { return cache_req; } - map_it++; } return NULL; @@ -272,20 +272,16 @@ CacheUnit::findRequest(DynInstPtr inst) ResReqPtr CacheUnit::findRequest(DynInstPtr inst, int idx) { - map::iterator map_it = reqMap.begin(); - map::iterator map_end = reqMap.end(); - - while (map_it != map_end) { + for (int i = 0; i < width; i++) { CacheRequest* cache_req = - dynamic_cast((*map_it).second); + dynamic_cast(reqs[i]); assert(cache_req); - if (cache_req && + if (cache_req->valid && cache_req->getInst() == inst && cache_req->instIdx == idx) { return cache_req; } - map_it++; } return NULL; @@ -296,7 +292,8 @@ ResReqPtr CacheUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx, int slot_num, unsigned cmd) { - ScheduleEntry* sched_entry = inst->resSched.top(); + ScheduleEntry* sched_entry = *inst->curSkedEntry; + CacheRequest* cache_req = dynamic_cast(reqs[slot_num]); if (!inst->validMemAddr()) { panic("Mem. Addr. must be set before requesting cache access\n"); @@ -343,10 +340,10 @@ CacheUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx, sched_entry->cmd, name()); } - return new CacheRequest(this, inst, stage_num, id, slot_num, - sched_entry->cmd, 0, pkt_cmd, - 0/*flags*/, this->cpu->readCpuId(), - inst->resSched.top()->idx); + cache_req->setRequest(inst, stage_num, id, slot_num, + sched_entry->cmd, pkt_cmd, + inst->curSkedEntry->idx); + return cache_req; } void @@ -357,17 +354,17 @@ CacheUnit::requestAgain(DynInstPtr inst, bool &service_request) // Check to see if this instruction is requesting the same command // or a different one - if (cache_req->cmd != inst->resSched.top()->cmd && - cache_req->instIdx == inst->resSched.top()->idx) { + if (cache_req->cmd != inst->curSkedEntry->cmd && + cache_req->instIdx == inst->curSkedEntry->idx) { // If different, then update command in the request - cache_req->cmd = inst->resSched.top()->cmd; + cache_req->cmd = inst->curSkedEntry->cmd; DPRINTF(InOrderCachePort, "[tid:%i]: [sn:%i]: Updating the command for this " "instruction\n ", inst->readTid(), inst->seqNum); service_request = true; - } else if (inst->resSched.top()->idx != CacheUnit::InitSecondSplitRead && - inst->resSched.top()->idx != CacheUnit::InitSecondSplitWrite) { + } else if (inst->curSkedEntry->idx != CacheUnit::InitSecondSplitRead && + inst->curSkedEntry->idx != CacheUnit::InitSecondSplitWrite) { // If same command, just check to see if memory access was completed // but dont try to re-execute DPRINTF(InOrderCachePort, @@ -487,14 +484,20 @@ CacheUnit::read(DynInstPtr inst, Addr addr, inst->splitMemData = new uint8_t[size]; if (!inst->splitInstSked) { + assert(0 && "Split Requests Not Supported for Now..."); + // Schedule Split Read/Complete for Instruction // ============================== int stage_num = cache_req->getStageNum(); - - int stage_pri = ThePipeline::getNextPriority(inst, stage_num); + RSkedPtr inst_sked = (stage_num >= ThePipeline::BackEndStartStage) ? + inst->backSked : inst->frontSked; + + // this is just an arbitrarily high priority to ensure that this + // gets pushed to the back of the list + int stage_pri = 20; int isplit_cmd = CacheUnit::InitSecondSplitRead; - inst->resSched.push(new + inst_sked->push(new ScheduleEntry(stage_num, stage_pri, cpu->resPool->getResIdx(DCache), @@ -502,7 +505,7 @@ CacheUnit::read(DynInstPtr inst, Addr addr, 1)); int csplit_cmd = CacheUnit::CompleteSecondSplitRead; - inst->resSched.push(new + inst_sked->push(new ScheduleEntry(stage_num + 1, 1/*stage_pri*/, cpu->resPool->getResIdx(DCache), @@ -590,27 +593,33 @@ CacheUnit::write(DynInstPtr inst, uint8_t *data, unsigned size, inst->splitInst = true; if (!inst->splitInstSked) { + assert(0 && "Split Requests Not Supported for Now..."); + // Schedule Split Read/Complete for Instruction // ============================== int stage_num = cache_req->getStageNum(); + RSkedPtr inst_sked = (stage_num >= ThePipeline::BackEndStartStage) ? + inst->backSked : inst->frontSked; - int stage_pri = ThePipeline::getNextPriority(inst, stage_num); + // this is just an arbitrarily high priority to ensure that this + // gets pushed to the back of the list + int stage_pri = 20; int isplit_cmd = CacheUnit::InitSecondSplitWrite; - inst->resSched.push(new - ScheduleEntry(stage_num, - stage_pri, - cpu->resPool->getResIdx(DCache), - isplit_cmd, - 1)); + inst_sked->push(new + ScheduleEntry(stage_num, + stage_pri, + cpu->resPool->getResIdx(DCache), + isplit_cmd, + 1)); int csplit_cmd = CacheUnit::CompleteSecondSplitWrite; - inst->resSched.push(new - ScheduleEntry(stage_num + 1, - 1/*stage_pri*/, - cpu->resPool->getResIdx(DCache), - csplit_cmd, - 1)); + inst_sked->push(new + ScheduleEntry(stage_num + 1, + 1/*stage_pri*/, + cpu->resPool->getResIdx(DCache), + csplit_cmd, + 1)); inst->splitInstSked = true; } else { DPRINTF(InOrderCachePort, "[tid:%i] sn:%i] Retrying Split Read " @@ -639,8 +648,6 @@ CacheUnit::write(DynInstPtr inst, uint8_t *data, unsigned size, if (inst->fault == NoFault) { if (!cache_req->splitAccess) { - // Remove this line since storeData is saved in INST? - cache_req->reqData = new uint8_t[size]; doCacheAccess(inst, write_res); } else { doCacheAccess(inst, write_res, cache_req); @@ -655,16 +662,19 @@ CacheUnit::write(DynInstPtr inst, uint8_t *data, unsigned size, void CacheUnit::execute(int slot_num) { - CacheReqPtr cache_req = dynamic_cast(reqMap[slot_num]); + CacheReqPtr cache_req = dynamic_cast(reqs[slot_num]); assert(cache_req); - if (cachePortBlocked) { + if (cachePortBlocked && + (cache_req->cmd == InitiateReadData || + cache_req->cmd == InitiateWriteData || + cache_req->cmd == InitSecondSplitRead || + cache_req->cmd == InitSecondSplitWrite)) { DPRINTF(InOrderCachePort, "Cache Port Blocked. Cannot Access\n"); - cache_req->setCompleted(false); + cache_req->done(false); return; } - DynInstPtr inst = cache_req->inst; #if TRACING_ON ThreadID tid = inst->readTid(); @@ -681,7 +691,12 @@ CacheUnit::execute(int slot_num) acc_type = "read"; #endif case InitiateWriteData: - + if (cachePortBlocked) { + DPRINTF(InOrderCachePort, "Cache Port Blocked. Cannot Access\n"); + cache_req->done(false); + return; + } + DPRINTF(InOrderCachePort, "[tid:%u]: [sn:%i] Initiating data %s access to %s for " "addr. %08p\n", tid, inst->seqNum, acc_type, name(), @@ -796,7 +811,7 @@ CacheUnit::doCacheAccess(DynInstPtr inst, uint64_t *write_res, CacheReqPtr cache_req; if (split_req == NULL) { - cache_req = dynamic_cast(reqMap[inst->getCurResSlot()]); + cache_req = dynamic_cast(reqs[inst->getCurResSlot()]); } else{ cache_req = split_req; } @@ -855,7 +870,7 @@ CacheUnit::doCacheAccess(DynInstPtr inst, uint64_t *write_res, "[tid:%i] [sn:%i] cannot access cache, because port " "is blocked. now waiting to retry request\n", tid, inst->seqNum); - cache_req->setCompleted(false); + cache_req->done(false); cachePortBlocked = true; } else { DPRINTF(InOrderCachePort, @@ -879,7 +894,7 @@ CacheUnit::doCacheAccess(DynInstPtr inst, uint64_t *write_res, // Make cache request again since access due to // inability to access DPRINTF(InOrderStall, "STALL: \n"); - cache_req->setCompleted(false); + cache_req->done(false); } } @@ -902,7 +917,7 @@ CacheUnit::processCacheCompletion(PacketPtr pkt) cache_pkt->cacheReq->getTid(), cache_pkt->cacheReq->seqNum); - cache_pkt->cacheReq->done(); + cache_pkt->cacheReq->freeSlot(); delete cache_pkt; cpu->wakeCPU(); @@ -1047,10 +1062,10 @@ CacheUnitEvent::CacheUnitEvent() void CacheUnitEvent::process() { - DynInstPtr inst = resource->reqMap[slotIdx]->inst; - int stage_num = resource->reqMap[slotIdx]->getStageNum(); + DynInstPtr inst = resource->reqs[slotIdx]->inst; + int stage_num = resource->reqs[slotIdx]->getStageNum(); ThreadID tid = inst->threadNumber; - CacheReqPtr req_ptr = dynamic_cast(resource->reqMap[slotIdx]); + CacheReqPtr req_ptr = dynamic_cast(resource->reqs[slotIdx]); DPRINTF(InOrderTLB, "Waking up from TLB Miss caused by [sn:%i].\n", inst->seqNum); @@ -1061,13 +1076,15 @@ CacheUnitEvent::process() tlb_res->tlbBlocked[tid] = false; tlb_res->cpu->pipelineStage[stage_num]-> - unsetResStall(tlb_res->reqMap[slotIdx], tid); + unsetResStall(tlb_res->reqs[slotIdx], tid); req_ptr->tlbStall = false; if (req_ptr->isSquashed()) { - req_ptr->done(); + req_ptr->freeSlot(); } + + tlb_res->cpu->wakeCPU(); } void @@ -1112,15 +1129,10 @@ void CacheUnit::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, ThreadID tid) { - vector slot_remove_list; + for (int i = 0; i < width; i++) { + ResReqPtr req_ptr = reqs[i]; - map::iterator map_it = reqMap.begin(); - map::iterator map_end = reqMap.end(); - - while (map_it != map_end) { - ResReqPtr req_ptr = (*map_it).second; - - if (req_ptr && + if (req_ptr->valid && req_ptr->getInst()->readTid() == tid && req_ptr->getInst()->seqNum > squash_seq_num) { @@ -1133,7 +1145,6 @@ CacheUnit::squash(DynInstPtr inst, int stage_num, "squashed, ignoring squash process.\n", req_ptr->getInst()->readTid(), req_ptr->getInst()->seqNum); - map_it++; continue; } @@ -1147,18 +1158,14 @@ CacheUnit::squash(DynInstPtr inst, int stage_num, if (cache_req->tlbStall) { tlbBlocked[tid] = false; - int stall_stage = reqMap[req_slot_num]->getStageNum(); + int stall_stage = reqs[req_slot_num]->getStageNum(); cpu->pipelineStage[stall_stage]-> - unsetResStall(reqMap[req_slot_num], tid); + unsetResStall(reqs[req_slot_num], tid); } if (!cache_req->tlbStall && !cache_req->isMemAccPending()) { - // Mark request for later removal - cpu->reqRemoveList.push(req_ptr); - - // Mark slot for removal from resource - slot_remove_list.push_back(req_ptr->getSlot()); + freeSlot(req_slot_num); } else { DPRINTF(InOrderCachePort, "[tid:%i] Request from [sn:%i] squashed, but still " @@ -1170,14 +1177,8 @@ CacheUnit::squash(DynInstPtr inst, int stage_num, req_ptr->getInst()->readTid(), req_ptr->getInst()->seqNum, req_ptr->getInst()->splitInst); } - } - - map_it++; } - // Now Delete Slot Entry from Req. Map - for (int i = 0; i < slot_remove_list.size(); i++) - freeSlot(slot_remove_list[i]); } diff --git a/src/cpu/inorder/resources/cache_unit.hh b/src/cpu/inorder/resources/cache_unit.hh index afcb36a24a..097b6fa7ab 100644 --- a/src/cpu/inorder/resources/cache_unit.hh +++ b/src/cpu/inorder/resources/cache_unit.hh @@ -219,20 +219,18 @@ class CacheUnitEvent : public ResourceEvent { void process(); }; +//@todo: Move into CacheUnit Class for private access to "valid" field class CacheRequest : public ResourceRequest { public: - CacheRequest(CacheUnit *cres, DynInstPtr inst, int stage_num, int res_idx, - int slot_num, unsigned cmd, int req_size, - MemCmd::Command pkt_cmd, unsigned flags, int cpu_id, int idx) - : ResourceRequest(cres, inst, stage_num, res_idx, slot_num, cmd), - pktCmd(pkt_cmd), memReq(NULL), reqData(NULL), dataPkt(NULL), - retryPkt(NULL), memAccComplete(false), memAccPending(false), - tlbStall(false), splitAccess(false), splitAccessNum(-1), - split2ndAccess(false), instIdx(idx), fetchBufferFill(false) + CacheRequest(CacheUnit *cres) + : ResourceRequest(cres), memReq(NULL), reqData(NULL), + dataPkt(NULL), retryPkt(NULL), memAccComplete(false), + memAccPending(false), tlbStall(false), splitAccess(false), + splitAccessNum(-1), split2ndAccess(false), + fetchBufferFill(false) { } - virtual ~CacheRequest() { if (reqData && !splitAccess) { @@ -240,6 +238,37 @@ class CacheRequest : public ResourceRequest } } + void setRequest(DynInstPtr _inst, int stage_num, int res_idx, int slot_num, + unsigned _cmd, MemCmd::Command pkt_cmd, int idx) + { + pktCmd = pkt_cmd; + instIdx = idx; + + ResourceRequest::setRequest(_inst, stage_num, res_idx, slot_num, _cmd); + } + + void clearRequest() + { + if (reqData && !splitAccess) { + delete [] reqData; + } + + memReq = NULL; + reqData = NULL; + dataPkt = NULL; + retryPkt = NULL; + memAccComplete = false; + memAccPending = false; + tlbStall = false; + splitAccess = false; + splitAccessNum = -1; + split2ndAccess = false; + instIdx = 0; + fetchBufferFill = false; + + ResourceRequest::clearRequest(); + } + virtual PacketDataPtr getData() { return reqData; } diff --git a/src/cpu/inorder/resources/decode_unit.cc b/src/cpu/inorder/resources/decode_unit.cc index c2f7ae22d8..71d33ab90d 100644 --- a/src/cpu/inorder/resources/decode_unit.cc +++ b/src/cpu/inorder/resources/decode_unit.cc @@ -49,21 +49,24 @@ DecodeUnit::DecodeUnit(std::string res_name, int res_id, int res_width, void DecodeUnit::execute(int slot_num) { - ResourceRequest* decode_req = reqMap[slot_num]; - DynInstPtr inst = reqMap[slot_num]->inst; + ResourceRequest* decode_req = reqs[slot_num]; + DynInstPtr inst = reqs[slot_num]->inst; ThreadID tid = inst->readTid(); switch (decode_req->cmd) { case DecodeInst: { - bool done_sked = ThePipeline::createBackEndSchedule(inst); + inst->setBackSked(cpu->createBackEndSked(inst)); - if (done_sked) { + if (inst->backSked != NULL) { DPRINTF(InOrderDecode, "[tid:%i]: Setting Destination Register(s) for [sn:%i].\n", tid, inst->seqNum); regDepMap[tid]->insert(inst); + + //inst->printSked(); + decode_req->done(); } else { DPRINTF(Resource, diff --git a/src/cpu/inorder/resources/execution_unit.cc b/src/cpu/inorder/resources/execution_unit.cc index 36bf2a4dcc..b2540cff8b 100644 --- a/src/cpu/inorder/resources/execution_unit.cc +++ b/src/cpu/inorder/resources/execution_unit.cc @@ -42,7 +42,7 @@ ExecutionUnit::ExecutionUnit(string res_name, int res_id, int res_width, int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) : Resource(res_name, res_id, res_width, res_latency, _cpu), - lastExecuteTick(0), lastControlTick(0) + lastExecuteTick(0), lastControlTick(0), serializeTick(0) { } void @@ -82,27 +82,52 @@ ExecutionUnit::regStats() void ExecutionUnit::execute(int slot_num) { - ResourceRequest* exec_req = reqMap[slot_num]; - DynInstPtr inst = reqMap[slot_num]->inst; + ResourceRequest* exec_req = reqs[slot_num]; + DynInstPtr inst = reqs[slot_num]->inst; Fault fault = NoFault; int seq_num = inst->seqNum; + Tick cur_tick = curTick(); + + if (cur_tick == serializeTick) { + DPRINTF(InOrderExecute, "Can not execute [tid:%i][sn:%i][PC:%s] %s. " + "All instructions are being serialized this cycle\n", + inst->readTid(), seq_num, inst->pcState(), inst->instName()); + exec_req->done(false); + return; + } - DPRINTF(InOrderExecute, "[tid:%i] Executing [sn:%i] [PC:%s] %s.\n", - inst->readTid(), seq_num, inst->pcState(), inst->instName()); switch (exec_req->cmd) { case ExecuteInst: { - if (curTick() != lastExecuteTick) { - lastExecuteTick = curTick(); + if (inst->isNop()) { + DPRINTF(InOrderExecute, "[tid:%i] [sn:%i] [PC:%s] Ignoring execution" + "of %s.\n", inst->readTid(), seq_num, inst->pcState(), + inst->instName()); + inst->setExecuted(); + exec_req->done(); + return; + } else { + DPRINTF(InOrderExecute, "[tid:%i] Executing [sn:%i] [PC:%s] %s.\n", + inst->readTid(), seq_num, inst->pcState(), inst->instName()); } + if (cur_tick != lastExecuteTick) { + lastExecuteTick = cur_tick; + } - if (inst->isMemRef()) { - panic("%s not configured to handle memory ops.\n", resName); - } else if (inst->isControl()) { - if (lastControlTick == curTick()) { + assert(!inst->isMemRef()); + + if (inst->isSerializeAfter()) { + serializeTick = cur_tick; + DPRINTF(InOrderExecute, "Serializing execution after [tid:%i] " + "[sn:%i] [PC:%s] %s.\n", inst->readTid(), seq_num, + inst->pcState(), inst->instName()); + } + + if (inst->isControl()) { + if (lastControlTick == cur_tick) { DPRINTF(InOrderExecute, "Can not Execute More than One Control " "Inst Per Cycle. Blocking Request.\n"); exec_req->done(false); diff --git a/src/cpu/inorder/resources/execution_unit.hh b/src/cpu/inorder/resources/execution_unit.hh index a6694ddb5e..b03a6655e5 100644 --- a/src/cpu/inorder/resources/execution_unit.hh +++ b/src/cpu/inorder/resources/execution_unit.hh @@ -76,6 +76,7 @@ class ExecutionUnit : public Resource { Stats::Scalar executions; Tick lastExecuteTick; Tick lastControlTick; + Tick serializeTick; }; diff --git a/src/cpu/inorder/resources/fetch_seq_unit.cc b/src/cpu/inorder/resources/fetch_seq_unit.cc index 6f84a333dc..d23ea0a826 100644 --- a/src/cpu/inorder/resources/fetch_seq_unit.cc +++ b/src/cpu/inorder/resources/fetch_seq_unit.cc @@ -62,13 +62,17 @@ FetchSeqUnit::init() { resourceEvent = new FetchSeqEvent[width]; + for (int i = 0; i < width; i++) { + reqs[i] = new ResourceRequest(this); + } + initSlots(); } void FetchSeqUnit::execute(int slot_num) { - ResourceRequest* fs_req = reqMap[slot_num]; + ResourceRequest* fs_req = reqs[slot_num]; DynInstPtr inst = fs_req->inst; ThreadID tid = inst->readTid(); int stage_num = fs_req->getStageNum(); @@ -96,7 +100,7 @@ FetchSeqUnit::execute(int slot_num) fs_req->done(); } else { DPRINTF(InOrderStall, "STALL: [tid:%i]: NPC not valid\n", tid); - fs_req->setCompleted(false); + fs_req->done(false); } } break; diff --git a/src/cpu/inorder/resources/fetch_unit.cc b/src/cpu/inorder/resources/fetch_unit.cc index 0e98667086..a0d830ecf1 100644 --- a/src/cpu/inorder/resources/fetch_unit.cc +++ b/src/cpu/inorder/resources/fetch_unit.cc @@ -56,6 +56,31 @@ FetchUnit::FetchUnit(string res_name, int res_id, int res_width, predecoder(NULL) { } +FetchUnit::~FetchUnit() +{ + std::list::iterator fetch_it = fetchBuffer.begin(); + std::list::iterator end_it = fetchBuffer.end(); + while (fetch_it != end_it) { + delete (*fetch_it)->block; + delete *fetch_it; + fetch_it++; + } + fetchBuffer.clear(); + + + std::list::iterator pend_it = pendingFetch.begin(); + std::list::iterator pend_end = pendingFetch.end(); + while (pend_it != pend_end) { + if ((*pend_it)->block) { + delete (*pend_it)->block; + } + + delete *pend_it; + pend_it++; + } + pendingFetch.clear(); +} + void FetchUnit::createMachInst(std::list::iterator fetch_it, DynInstPtr inst) @@ -118,33 +143,24 @@ ResReqPtr FetchUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx, int slot_num, unsigned cmd) { - ScheduleEntry* sched_entry = inst->resSched.top(); + ScheduleEntry* sched_entry = *inst->curSkedEntry; + CacheRequest* cache_req = dynamic_cast(reqs[slot_num]); if (!inst->validMemAddr()) { panic("Mem. Addr. must be set before requesting cache access\n"); } - MemCmd::Command pkt_cmd; + assert(sched_entry->cmd == InitiateFetch); - switch (sched_entry->cmd) - { - case InitiateFetch: - pkt_cmd = MemCmd::ReadReq; + DPRINTF(InOrderCachePort, + "[tid:%i]: Fetch request from [sn:%i] for addr %08p\n", + inst->readTid(), inst->seqNum, inst->getMemAddr()); - DPRINTF(InOrderCachePort, - "[tid:%i]: Fetch request from [sn:%i] for addr %08p\n", - inst->readTid(), inst->seqNum, inst->getMemAddr()); - break; + cache_req->setRequest(inst, stage_num, id, slot_num, + sched_entry->cmd, MemCmd::ReadReq, + inst->curSkedEntry->idx); - default: - panic("%i: Unexpected request type (%i) to %s", curTick(), - sched_entry->cmd, name()); - } - - return new CacheRequest(this, inst, stage_num, id, slot_num, - sched_entry->cmd, 0, pkt_cmd, - 0/*flags*/, this->cpu->readCpuId(), - inst->resSched.top()->idx); + return cache_req; } void @@ -214,12 +230,12 @@ FetchUnit::markBlockUsed(std::list::iterator block_it) void FetchUnit::execute(int slot_num) { - CacheReqPtr cache_req = dynamic_cast(reqMap[slot_num]); + CacheReqPtr cache_req = dynamic_cast(reqs[slot_num]); assert(cache_req); - if (cachePortBlocked) { + if (cachePortBlocked && cache_req->cmd == InitiateFetch) { DPRINTF(InOrderCachePort, "Cache Port Blocked. Cannot Access\n"); - cache_req->setCompleted(false); + cache_req->done(false); return; } @@ -270,7 +286,7 @@ FetchUnit::execute(int slot_num) // If not, block this request. if (pendingFetch.size() >= fetchBuffSize) { DPRINTF(InOrderCachePort, "No room available in fetch buffer.\n"); - cache_req->setCompleted(false); + cache_req->done(); return; } @@ -337,6 +353,8 @@ FetchUnit::execute(int slot_num) return; } + delete [] (*repl_it)->block; + delete *repl_it; fetchBuffer.erase(repl_it); } @@ -414,6 +432,7 @@ FetchUnit::processCacheCompletion(PacketPtr pkt) cache_pkt->cacheReq->seqNum); cache_pkt->cacheReq->done(); + cache_pkt->cacheReq->freeSlot(); delete cache_pkt; cpu->wakeCPU(); @@ -447,7 +466,7 @@ FetchUnit::processCacheCompletion(PacketPtr pkt) short asid = cpu->asid[tid]; assert(!cache_req->isSquashed()); - assert(inst->resSched.top()->cmd == CompleteFetch); + assert(inst->curSkedEntry->cmd == CompleteFetch); DPRINTF(InOrderCachePort, "[tid:%u]: [sn:%i]: Processing fetch access for block %#x\n", @@ -514,6 +533,10 @@ FetchUnit::squashCacheRequest(CacheReqPtr req_ptr) DPRINTF(InOrderCachePort, "[sn:%i] Removing Pending Fetch " "for block %08p (cnt=%i)\n", inst->seqNum, block_addr, (*block_it)->cnt); + if ((*block_it)->block) { + delete [] (*block_it)->block; + } + delete *block_it; pendingFetch.erase(block_it); } } diff --git a/src/cpu/inorder/resources/fetch_unit.hh b/src/cpu/inorder/resources/fetch_unit.hh index 035f3f4a17..fa133b9eb1 100644 --- a/src/cpu/inorder/resources/fetch_unit.hh +++ b/src/cpu/inorder/resources/fetch_unit.hh @@ -55,6 +55,8 @@ class FetchUnit : public CacheUnit FetchUnit(std::string res_name, int res_id, int res_width, int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + virtual ~FetchUnit(); + typedef ThePipeline::DynInstPtr DynInstPtr; typedef TheISA::ExtMachInst ExtMachInst; diff --git a/src/cpu/inorder/resources/graduation_unit.cc b/src/cpu/inorder/resources/graduation_unit.cc index 8ccdaa36a9..edc2fb3ff7 100644 --- a/src/cpu/inorder/resources/graduation_unit.cc +++ b/src/cpu/inorder/resources/graduation_unit.cc @@ -37,8 +37,7 @@ GraduationUnit::GraduationUnit(std::string res_name, int res_id, int res_width, int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params) : Resource(res_name, res_id, res_width, res_latency, _cpu), - lastCycleGrad(0), numCycleGrad(0) - + lastNonSpecTick(0) { for (ThreadID tid = 0; tid < ThePipeline::MaxThreads; tid++) { nonSpecInstActive[tid] = &cpu->nonSpecInstActive[tid]; @@ -49,23 +48,27 @@ GraduationUnit::GraduationUnit(std::string res_name, int res_id, int res_width, void GraduationUnit::execute(int slot_num) { - ResourceRequest* grad_req = reqMap[slot_num]; - DynInstPtr inst = reqMap[slot_num]->inst; + ResourceRequest* grad_req = reqs[slot_num]; + DynInstPtr inst = reqs[slot_num]->inst; ThreadID tid = inst->readTid(); - int stage_num = inst->resSched.top()->stageNum; + int stage_num = inst->curSkedEntry->stageNum; switch (grad_req->cmd) { case GraduateInst: { - // Make sure this is the last thing on the resource schedule - assert(inst->resSched.size() == 1); + if (lastNonSpecTick == curTick()) { + DPRINTF(InOrderGraduation, "Unable to graduate [sn:%i]. " + "Only 1 nonspec inst. per cycle can graduate.\n"); + grad_req->done(false); + return; + } - // Handle Any Faults Before Graduating Instruction + // Handle Any Faults Before Graduating Instruction if (inst->fault != NoFault) { cpu->trap(inst->fault, tid, inst); grad_req->setCompleted(false); - return; + return; } DPRINTF(InOrderGraduation, @@ -80,6 +83,7 @@ GraduationUnit::execute(int slot_num) DPRINTF(InOrderGraduation, "[tid:%i] Non-speculative inst [sn:%i] graduated\n", tid, inst->seqNum); + lastNonSpecTick = curTick(); } if (inst->traceData) { diff --git a/src/cpu/inorder/resources/graduation_unit.hh b/src/cpu/inorder/resources/graduation_unit.hh index aae41993fc..59631bfcbb 100644 --- a/src/cpu/inorder/resources/graduation_unit.hh +++ b/src/cpu/inorder/resources/graduation_unit.hh @@ -57,9 +57,7 @@ class GraduationUnit : public Resource { void execute(int slot_num); protected: - Tick lastCycleGrad; - int numCycleGrad; - + Tick lastNonSpecTick; bool *nonSpecInstActive[ThePipeline::MaxThreads]; InstSeqNum *nonSpecSeqNum[ThePipeline::MaxThreads]; diff --git a/src/cpu/inorder/resources/inst_buffer.cc b/src/cpu/inorder/resources/inst_buffer.cc index 18dd26a78f..46f5cce729 100644 --- a/src/cpu/inorder/resources/inst_buffer.cc +++ b/src/cpu/inorder/resources/inst_buffer.cc @@ -62,7 +62,7 @@ InstBuffer::regStats() void InstBuffer::execute(int slot_idx) { - ResReqPtr ib_req = reqMap[slot_idx]; + ResReqPtr ib_req = reqs[slot_idx]; DynInstPtr inst = ib_req->inst; ThreadID tid = inst->readTid(); int stage_num = ib_req->getStageNum(); @@ -99,19 +99,22 @@ InstBuffer::execute(int slot_idx) inst->seqNum, next_stage); // Add to schedule: Insert into buffer in next stage - int stage_pri = ThePipeline::getNextPriority(inst, - next_stage); + int stage_pri = 20; + RSkedPtr insert_sked = (stage_num >= ThePipeline::BackEndStartStage) ? + inst->backSked : inst->frontSked; - inst->resSched.push(new ScheduleEntry(next_stage, + insert_sked->push(new ScheduleEntry(next_stage, stage_pri, id, InstBuffer::InsertInst)); // Add to schedule: Remove from buffer in next next (bypass) // stage - stage_pri = ThePipeline::getNextPriority(inst, bypass_stage); + stage_pri = 20; + RSkedPtr bypass_sked = (stage_num >= ThePipeline::BackEndStartStage) ? + inst->backSked : inst->frontSked; - inst->resSched.push(new ScheduleEntry(bypass_stage, + bypass_sked->push(new ScheduleEntry(bypass_stage, stage_pri, id, InstBuffer::RemoveInst)); diff --git a/src/cpu/inorder/resources/inst_buffer_new.cc b/src/cpu/inorder/resources/inst_buffer_new.cc deleted file mode 100644 index 2e5a9666a5..0000000000 --- a/src/cpu/inorder/resources/inst_buffer_new.cc +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2007 MIPS Technologies, Inc. - * 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: Korey Sewell - * - */ - -#include -#include - -#include "arch/isa_traits.hh" -#include "config/the_isa.hh" -#include "cpu/inorder/pipeline_traits.hh" -#include "cpu/inorder/resources/inst_buffer.hh" -#include "cpu/inorder/cpu.hh" - -using namespace std; -using namespace TheISA; -using namespace ThePipeline; - -InstBuffer::InstBuffer(string res_name, int res_id, int res_width, - int res_latency, InOrderCPU *_cpu) - : Resource(res_name, res_id, res_width, res_latency, _cpu) -{ } - -ResReqPtr -InstBuffer::getRequest(DynInstPtr inst, int stage_num, int res_idx, - int slot_num) -{ - // After this is working, change this to a reinterpret cast - // for performance considerations - InstBufferEntry* ib_entry = dynamic_cast(inst->resSched.top()); - assert(ib_entry); - - return new InstBufferRequest(this, inst, stage_num, id, slot_num, - ib_entry->cmd); -} - -void -InstBuffer::execute(int slot_idx) -{ - // After this is working, change this to a reinterpret cast - // for performance considerations - InstBufferRequest* ib_req = dynamic_cast(reqMap[slot_idx]); - assert(ib_req); - - DynInstPtr inst = ib_req->inst; - ThreadID tid = inst->readTid(); - int seq_num = inst->seqNum; - ib_req->fault = NoFault; - - switch (ib_req->cmd) - { - case InsertInst: - { - DPRINTF(Resource, "[tid:%i]: Inserting [sn:%i] into buffer.\n", - tid, seq_num); - insert(inst); - ib_req->done(); - } - break; - - case RemoveInst: - { - DPRINTF(Resource, "[tid:%i]: Removing [sn:%i] from buffer.\n", - tid, seq_num); - remove(inst); - ib_req->done(); - } - break; - - default: - fatal("Unrecognized command to %s", resName); - } - - DPRINTF(Resource, "Buffer now contains %i insts.\n", instList.size()); -} - -void -InstBuffer::insert(DynInstPtr inst) -{ - instList.push_back(inst); -} - -void -InstBuffer::remove(DynInstPtr inst) -{ - std::list::iterator list_it = instList.begin(); - std::list::iterator list_end = instList.end(); - - while (list_it != list_end) { - if((*list_it) == inst) { - instList.erase(list_it); - break; - } - list_it++; - } -} - -void -InstBuffer::pop() -{ instList.pop_front(); } - -ThePipeline::DynInstPtr -InstBuffer::top() -{ return instList.front(); } - -void -InstBuffer::squash(InstSeqNum squash_seq_num, ThreadID tid) -{ - list::iterator list_it = instList.begin(); - list::iterator list_end = instList.end(); - queue::iterator> remove_list; - - // Collect All Instructions to be Removed in Remove List - while (list_it != list_end) { - if((*list_it)->seqNum > squash_seq_num) { - DPRINTF(Resource, "[tid:%i]: Squashing [sn:%i] in resource.\n", - tid, (*list_it)->seqNum); - (*list_it)->setSquashed(); - remove_list.push(list_it); - } - - list_it++; - } - - // Removed Instructions from InstList & Clear Remove List - while (!remove_list.empty()) { - instList.erase(remove_list.front()); - remove_list.pop(); - } - - Resource::squash(squash_seq_num, tid); -} diff --git a/src/cpu/inorder/resources/inst_buffer_new.hh b/src/cpu/inorder/resources/inst_buffer_new.hh deleted file mode 100644 index b1d5a7b09a..0000000000 --- a/src/cpu/inorder/resources/inst_buffer_new.hh +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2007 MIPS Technologies, Inc. - * 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: Korey Sewell - * - */ - -#ifndef __CPU_INORDER_INST_BUFF_UNIT_HH__ -#define __CPU_INORDER_INST_BUFF_UNIT_HH__ - -#include -#include -#include - -#include "cpu/inorder/resource.hh" -#include "cpu/inorder/inorder_dyn_inst.hh" -#include "cpu/inorder/pipeline_traits.hh" -#include "cpu/inorder/cpu.hh" - -class InstBuffer : public Resource { - public: - typedef InOrderDynInst::DynInstPtr DynInstPtr; - - public: - enum Command { - InsertInst, - InsertAddr, - RemoveInst, - RemoveAddr - }; - - public: - InstBuffer(std::string res_name, int res_id, int res_width, - int res_latency, InOrderCPU *_cpu); - virtual ~InstBuffer() {} - - virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num, - int res_idx, int slot_num); - - virtual void execute(int slot_num); - - virtual void insert(DynInstPtr inst); - - virtual void remove(DynInstPtr inst); - - virtual void pop(); - - virtual DynInstPtr top(); - - virtual void squash(InstSeqNum squash_seq_num, ThreadID tid); - - protected: - /** List of instructions this resource is currently - * processing. - */ - std::list instList; - - /** @todo: Add Resource Stats Here */ - -}; - -struct InstBufferEntry : public ThePipeline::ScheduleEntry { - InstBufferEntry(int stage_num, int res_num, InstBuffer::Command _cmd) : - ScheduleEntry(stage_num, res_num), cmd(_cmd) - { } - - InstBuffer::Command cmd; -}; - -class InstBufferRequest : public ResourceRequest { - public: - typedef InOrderDynInst::DynInstPtr DynInstPtr; - - public: - InstBufferRequest(InstBuffer *res, DynInstPtr inst, int stage_num, int res_idx, int slot_num, - InstBuffer::Command _cmd) - : ResourceRequest(res, inst, stage_num, res_idx, slot_num), - cmd(_cmd) - { } - - InstBuffer::Command cmd; -}; - - -#endif //__CPU_INORDER_INST_BUFF_UNIT_HH__ diff --git a/src/cpu/inorder/resources/mult_div_unit.cc b/src/cpu/inorder/resources/mult_div_unit.cc index 5aa0b0aa18..ad8b2b47bc 100644 --- a/src/cpu/inorder/resources/mult_div_unit.cc +++ b/src/cpu/inorder/resources/mult_div_unit.cc @@ -76,6 +76,10 @@ MultDivUnit::init() // Set Up Resource Events to Appropriate Resource BandWidth resourceEvent = new MDUEvent[width]; + for (int i = 0; i < width; i++) { + reqs[i] = new ResourceRequest(this); + } + initSlots(); } @@ -92,7 +96,7 @@ void MultDivUnit::freeSlot(int slot_idx) { DPRINTF(InOrderMDU, "Freeing slot for inst:%i\n | slots-free:%i | " - "slots-used:%i\n", reqMap[slot_idx]->getInst()->seqNum, + "slots-used:%i\n", reqs[slot_idx]->getInst()->seqNum, slotsAvail(), slotsInUse()); Resource::freeSlot(slot_idx); @@ -110,9 +114,9 @@ MultDivUnit::requestAgain(DynInstPtr inst, bool &service_request) // Check to see if this instruction is requesting the same command // or a different one - if (mult_div_req->cmd != inst->resSched.top()->cmd) { + if (mult_div_req->cmd != inst->curSkedEntry->cmd) { // If different, then update command in the request - mult_div_req->cmd = inst->resSched.top()->cmd; + mult_div_req->cmd = inst->curSkedEntry->cmd; DPRINTF(InOrderMDU, "[tid:%i]: [sn:%i]: Updating the command for this " "instruction\n", inst->readTid(), inst->seqNum); @@ -132,7 +136,7 @@ MultDivUnit::getSlot(DynInstPtr inst) // If we have this instruction's request already then return if (slot_num != -1 && - inst->resSched.top()->cmd == reqMap[slot_num]->cmd) + inst->curSkedEntry->cmd == reqs[slot_num]->cmd) return slot_num; unsigned repeat_rate = 0; @@ -202,8 +206,8 @@ MultDivUnit::getDivOpSize(DynInstPtr inst) void MultDivUnit::execute(int slot_num) { - ResourceRequest* mult_div_req = reqMap[slot_num]; - DynInstPtr inst = reqMap[slot_num]->inst; + ResourceRequest* mult_div_req = reqs[slot_num]; + DynInstPtr inst = reqs[slot_num]->inst; switch (mult_div_req->cmd) { @@ -275,8 +279,8 @@ MultDivUnit::execute(int slot_num) void MultDivUnit::exeMulDiv(int slot_num) { - ResourceRequest* mult_div_req = reqMap[slot_num]; - DynInstPtr inst = reqMap[slot_num]->inst; + ResourceRequest* mult_div_req = reqs[slot_num]; + DynInstPtr inst = reqs[slot_num]->inst; inst->fault = inst->execute(); @@ -310,7 +314,7 @@ MDUEvent::process() mdu_res->exeMulDiv(slotIdx); - ResourceRequest* mult_div_req = resource->reqMap[slotIdx]; + ResourceRequest* mult_div_req = resource->reqs[slotIdx]; mult_div_req->done(); } diff --git a/src/cpu/inorder/resources/tlb_unit.cc b/src/cpu/inorder/resources/tlb_unit.cc index 59840d15bb..37aec22091 100644 --- a/src/cpu/inorder/resources/tlb_unit.cc +++ b/src/cpu/inorder/resources/tlb_unit.cc @@ -72,6 +72,10 @@ TLBUnit::init() { resourceEvent = new TLBUnitEvent[width]; + for (int i = 0; i < width; i++) { + reqs[i] = new TLBUnitRequest(this); + } + initSlots(); } @@ -90,8 +94,9 @@ TLBUnit::getRequest(DynInstPtr _inst, int stage_num, int res_idx, int slot_num, unsigned cmd) { - return new TLBUnitRequest(this, _inst, stage_num, res_idx, slot_num, - cmd); + TLBUnitRequest *tlb_req = dynamic_cast(reqs[slot_num]); + tlb_req->setRequest(inst, stage_num, id, slot_num, cmd); + return ud_req; } void @@ -99,7 +104,7 @@ TLBUnit::execute(int slot_idx) { // After this is working, change this to a reinterpret cast // for performance considerations - TLBUnitRequest* tlb_req = dynamic_cast(reqMap[slot_idx]); + TLBUnitRequest* tlb_req = dynamic_cast(reqs[slot_idx]); assert(tlb_req != 0x0); DynInstPtr inst = tlb_req->inst; @@ -200,8 +205,8 @@ TLBUnitEvent::TLBUnitEvent() void TLBUnitEvent::process() { - DynInstPtr inst = resource->reqMap[slotIdx]->inst; - int stage_num = resource->reqMap[slotIdx]->getStageNum(); + DynInstPtr inst = resource->reqs[slotIdx]->inst; + int stage_num = resource->reqs[slotIdx]->getStageNum(); ThreadID tid = inst->threadNumber; DPRINTF(InOrderTLB, "Waking up from TLB Miss caused by [sn:%i].\n", @@ -212,31 +217,18 @@ TLBUnitEvent::process() tlb_res->tlbBlocked[tid] = false; - tlb_res->cpu->pipelineStage[stage_num]->unsetResStall(tlb_res->reqMap[slotIdx], tid); - - // Effectively NOP the instruction but still allow it - // to commit - //while (!inst->resSched.empty() && - // inst->resSched.top()->stageNum != ThePipeline::NumStages - 1) { - //inst->resSched.pop(); - //} + tlb_res->cpu->pipelineStage[stage_num]-> + unsetResStall(tlb_res->reqs[slotIdx], tid); } void TLBUnit::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, ThreadID tid) { - //@TODO: Figure out a way to consolidate common parts - // of this squash code - std::vector slot_remove_list; + for (int i = 0; i < width; i++) { + ResReqPtr req_ptr = reqs[i]; - map::iterator map_it = reqMap.begin(); - map::iterator map_end = reqMap.end(); - - while (map_it != map_end) { - ResReqPtr req_ptr = (*map_it).second; - - if (req_ptr && + if (req_ptr->valid && req_ptr->getInst()->readTid() == tid && req_ptr->getInst()->seqNum > squash_seq_num) { @@ -250,26 +242,16 @@ TLBUnit::squash(DynInstPtr inst, int stage_num, tlbBlocked[tid] = false; - int stall_stage = reqMap[req_slot_num]->getStageNum(); + int stall_stage = reqs[req_slot_num]->getStageNum(); - cpu->pipelineStage[stall_stage]->unsetResStall(reqMap[req_slot_num], tid); + cpu->pipelineStage[stall_stage]-> + unsetResStall(reqs[req_slot_num], tid); if (resourceEvent[req_slot_num].scheduled()) unscheduleEvent(req_slot_num); - // Mark request for later removal - cpu->reqRemoveList.push(req_ptr); - - // Mark slot for removal from resource - slot_remove_list.push_back(req_ptr->getSlot()); + freeSlot(req_slot_num); } - - map_it++; - } - - // Now Delete Slot Entry from Req. Map - for (int i = 0; i < slot_remove_list.size(); i++) { - freeSlot(slot_remove_list[i]); } } diff --git a/src/cpu/inorder/resources/tlb_unit.hh b/src/cpu/inorder/resources/tlb_unit.hh index eb1bf55f08..904ac3eba2 100644 --- a/src/cpu/inorder/resources/tlb_unit.hh +++ b/src/cpu/inorder/resources/tlb_unit.hh @@ -99,9 +99,15 @@ class TLBUnitRequest : public ResourceRequest { typedef ThePipeline::DynInstPtr DynInstPtr; public: - TLBUnitRequest(TLBUnit *res, DynInstPtr inst, int stage_num, int res_idx, int slot_num, - unsigned _cmd) - : ResourceRequest(res, inst, stage_num, res_idx, slot_num, _cmd) + TLBUnitRequest(TLBUnit *res) + : ResourceRequest(res), memReq(NULL) + { + } + + RequestPtr memReq; + + void setRequest(DynInstPtr inst, int stage_num, int res_idx, int slot_num, + unsigned _cmd) { Addr aligned_addr; int req_size; @@ -131,9 +137,10 @@ class TLBUnitRequest : public ResourceRequest { inst->readTid()); memReq = inst->dataMemReq; } + + ResourceRequest::setRequest(inst, stage_num, res_idx, slot_num, _cmd); } - RequestPtr memReq; }; diff --git a/src/cpu/inorder/resources/use_def.cc b/src/cpu/inorder/resources/use_def.cc index 7430115738..19246a30bd 100644 --- a/src/cpu/inorder/resources/use_def.cc +++ b/src/cpu/inorder/resources/use_def.cc @@ -88,33 +88,48 @@ UseDefUnit::regStats() Resource::regStats(); } +void +UseDefUnit::init() +{ + // Set Up Resource Events to Appropriate Resource BandWidth + if (latency > 0) { + resourceEvent = new ResourceEvent[width]; + } else { + resourceEvent = NULL; + } + + for (int i = 0; i < width; i++) { + reqs[i] = new UseDefRequest(this); + } + + initSlots(); +} + ResReqPtr UseDefUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx, int slot_num, unsigned cmd) { - return new UseDefRequest(this, inst, stage_num, id, slot_num, cmd, - inst->resSched.top()->idx); + UseDefRequest *ud_req = dynamic_cast(reqs[slot_num]); + ud_req->setRequest(inst, stage_num, id, slot_num, cmd, + inst->curSkedEntry->idx); + return ud_req; } ResReqPtr UseDefUnit::findRequest(DynInstPtr inst) { - map::iterator map_it = reqMap.begin(); - map::iterator map_end = reqMap.end(); - - while (map_it != map_end) { - UseDefRequest* ud_req = - dynamic_cast((*map_it).second); + for (int i = 0; i < width; i++) { + UseDefRequest* ud_req = + dynamic_cast(reqs[i]); assert(ud_req); - if (ud_req && + if (ud_req->valid && ud_req->getInst() == inst && - ud_req->cmd == inst->resSched.top()->cmd && - ud_req->useDefIdx == inst->resSched.top()->idx) { + ud_req->cmd == inst->curSkedEntry->cmd && + ud_req->useDefIdx == inst->curSkedEntry->idx) { return ud_req; } - map_it++; } return NULL; @@ -125,7 +140,7 @@ UseDefUnit::execute(int slot_idx) { // After this is working, change this to a reinterpret cast // for performance considerations - UseDefRequest* ud_req = dynamic_cast(reqMap[slot_idx]); + UseDefRequest* ud_req = dynamic_cast(reqs[slot_idx]); assert(ud_req); DynInstPtr inst = ud_req->inst; @@ -408,15 +423,10 @@ UseDefUnit::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, DPRINTF(InOrderUseDef, "[tid:%i]: Updating Due To Squash After [sn:%i].\n", tid, squash_seq_num); - std::vector slot_remove_list; + for (int i = 0; i < width; i++) { + ResReqPtr req_ptr = reqs[i]; - map::iterator map_it = reqMap.begin(); - map::iterator map_end = reqMap.end(); - - while (map_it != map_end) { - ResReqPtr req_ptr = (*map_it).second; - - if (req_ptr && + if (req_ptr->valid && req_ptr->getInst()->readTid() == tid && req_ptr->getInst()->seqNum > squash_seq_num) { @@ -431,20 +441,9 @@ UseDefUnit::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unscheduleEvent(req_slot_num); } - - // Mark request for later removal - cpu->reqRemoveList.push(req_ptr); - // Mark slot for removal from resource - slot_remove_list.push_back(req_ptr->getSlot()); + freeSlot(req_slot_num); } - - map_it++; - } - - // Now Delete Slot Entry from Req. Map - for (int i = 0; i < slot_remove_list.size(); i++) { - freeSlot(slot_remove_list[i]); } if (outReadSeqNum[tid] >= squash_seq_num) { diff --git a/src/cpu/inorder/resources/use_def.hh b/src/cpu/inorder/resources/use_def.hh index d2cc55315b..21770cec6d 100644 --- a/src/cpu/inorder/resources/use_def.hh +++ b/src/cpu/inorder/resources/use_def.hh @@ -56,6 +56,8 @@ class UseDefUnit : public Resource { UseDefUnit(std::string res_name, int res_id, int res_width, int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params); + void init(); + ResourceRequest* getRequest(DynInstPtr _inst, int stage_num, int res_idx, int slot_num, unsigned cmd); @@ -96,14 +98,20 @@ class UseDefUnit : public Resource { typedef ThePipeline::DynInstPtr DynInstPtr; public: - UseDefRequest(UseDefUnit *res, DynInstPtr inst, int stage_num, - int res_idx, int slot_num, unsigned cmd, - int use_def_idx) - : ResourceRequest(res, inst, stage_num, res_idx, slot_num, cmd), - useDefIdx(use_def_idx) + UseDefRequest(UseDefUnit *res) + : ResourceRequest(res) { } int useDefIdx; + + void setRequest(DynInstPtr _inst, int stage_num, int res_idx, + int slot_num, unsigned _cmd, int idx) + { + useDefIdx = idx; + + ResourceRequest::setRequest(_inst, stage_num, res_idx, slot_num, + _cmd); + } }; protected: diff --git a/src/cpu/o3/fetch.hh b/src/cpu/o3/fetch.hh index 92691720be..647c48a763 100644 --- a/src/cpu/o3/fetch.hh +++ b/src/cpu/o3/fetch.hh @@ -136,6 +136,10 @@ class DefaultFetch : fetch(_fetch) {} + void + markDelayed() + {} + void finish(Fault fault, RequestPtr req, ThreadContext *tc, BaseTLB::Mode mode) diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh index d0c83d586e..d2cde496e5 100644 --- a/src/cpu/o3/fetch_impl.hh +++ b/src/cpu/o3/fetch_impl.hh @@ -604,6 +604,9 @@ DefaultFetch::finishTranslation(Fault fault, RequestPtr mem_req) ThreadID tid = mem_req->threadId(); Addr block_PC = mem_req->getVaddr(); + // Wake up CPU if it was idle + cpu->wakeCPU(); + // If translation was successful, attempt to read the icache block. if (fault == NoFault) { // Build packet here. @@ -654,6 +657,9 @@ DefaultFetch::finishTranslation(Fault fault, RequestPtr mem_req) instruction->fault = fault; wroteToTimeBuffer = true; + DPRINTF(Activity, "Activity this cycle.\n"); + cpu->activityThisCycle(); + fetchStatus[tid] = TrapPending; DPRINTF(Fetch, "[tid:%i]: Blocked, need to handle the trap.\n", tid); @@ -1064,6 +1070,8 @@ DefaultFetch::fetch(bool &status_change) Addr pcOffset = fetchOffset[tid]; Addr fetchAddr = (thisPC.instAddr() + pcOffset) & BaseCPU::PCMask; + bool inRom = isRomMicroPC(thisPC.microPC()); + // If returning from the delay of a cache miss, then update the status // to running, otherwise do the cache access. Possibly move this up // to tick() function. @@ -1077,7 +1085,7 @@ DefaultFetch::fetch(bool &status_change) Addr block_PC = icacheBlockAlignPC(fetchAddr); // Unless buffer already got the block, fetch it from icache. - if (!cacheDataValid[tid] || block_PC != cacheDataPC[tid]) { + if (!(cacheDataValid[tid] && block_PC == cacheDataPC[tid]) && !inRom) { DPRINTF(Fetch, "[tid:%i]: Attempting to translate and read " "instruction, starting at PC %s.\n", tid, thisPC); @@ -1149,7 +1157,7 @@ DefaultFetch::fetch(bool &status_change) !predictedBranch) { // If we need to process more memory, do it now. - if (!curMacroop && !predecoder.extMachInstReady()) { + if (!(curMacroop || inRom) && !predecoder.extMachInstReady()) { if (ISA_HAS_DELAY_SLOT && pcOffset == 0) { // Walk past any annulled delay slot instructions. Addr pcAddr = thisPC.instAddr() & BaseCPU::PCMask; @@ -1175,7 +1183,7 @@ DefaultFetch::fetch(bool &status_change) // Extract as many instructions and/or microops as we can from // the memory we've processed so far. do { - if (!curMacroop) { + if (!(curMacroop || inRom)) { if (predecoder.extMachInstReady()) { ExtMachInst extMachInst; @@ -1196,8 +1204,13 @@ DefaultFetch::fetch(bool &status_change) break; } } - if (curMacroop) { - staticInst = curMacroop->fetchMicroop(thisPC.microPC()); + if (curMacroop || inRom) { + if (inRom) { + staticInst = cpu->microcodeRom.fetchMicroop( + thisPC.microPC(), curMacroop); + } else { + staticInst = curMacroop->fetchMicroop(thisPC.microPC()); + } if (staticInst->isLastMicroop()) { curMacroop = NULL; pcOffset = 0; diff --git a/src/cpu/o3/iew_impl.hh b/src/cpu/o3/iew_impl.hh index 3f3761ff32..03f73c798f 100644 --- a/src/cpu/o3/iew_impl.hh +++ b/src/cpu/o3/iew_impl.hh @@ -1241,12 +1241,33 @@ DefaultIEW::executeInsts() // Loads will mark themselves as executed, and their writeback // event adds the instruction to the queue to commit fault = ldstQueue.executeLoad(inst); + + if (inst->isTranslationDelayed() && + fault == NoFault) { + // A hw page table walk is currently going on; the + // instruction must be deferred. + DPRINTF(IEW, "Execute: Delayed translation, deferring " + "load.\n"); + instQueue.deferMemInst(inst); + continue; + } + if (inst->isDataPrefetch() || inst->isInstPrefetch()) { fault = NoFault; } } else if (inst->isStore()) { fault = ldstQueue.executeStore(inst); + if (inst->isTranslationDelayed() && + fault == NoFault) { + // A hw page table walk is currently going on; the + // instruction must be deferred. + DPRINTF(IEW, "Execute: Delayed translation, deferring " + "store.\n"); + instQueue.deferMemInst(inst); + continue; + } + // If the store had a fault then it may not have a mem req if (fault != NoFault || inst->readPredicate() == false || !inst->isStoreConditional()) { diff --git a/src/cpu/o3/inst_queue.hh b/src/cpu/o3/inst_queue.hh index be936e2045..64df357438 100644 --- a/src/cpu/o3/inst_queue.hh +++ b/src/cpu/o3/inst_queue.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2011 ARM Limited + * All rights reserved. + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * * Copyright (c) 2004-2006 The Regents of The University of Michigan * All rights reserved. * @@ -180,6 +192,11 @@ class InstructionQueue */ DynInstPtr getInstToExecute(); + /** Returns a memory instruction that was referred due to a delayed DTB + * translation if it is now ready to execute. + */ + DynInstPtr getDeferredMemInstToExecute(); + /** * Records the instruction as the producer of a register without * adding it to the rest of the IQ. @@ -223,6 +240,12 @@ class InstructionQueue /** Completes a memory operation. */ void completeMemInst(DynInstPtr &completed_inst); + /** + * Defers a memory instruction when its DTB translation incurs a hw + * page table walk. + */ + void deferMemInst(DynInstPtr &deferred_inst); + /** Indicates an ordering violation between a store and a load. */ void violation(DynInstPtr &store, DynInstPtr &faulting_load); @@ -284,6 +307,11 @@ class InstructionQueue /** List of instructions that are ready to be executed. */ std::list instsToExecute; + /** List of instructions waiting for their DTB translation to + * complete (hw page table walk in progress). + */ + std::list deferredMemInsts; + /** * Struct for comparing entries to be added to the priority queue. * This gives reverse ordering to the instructions in terms of diff --git a/src/cpu/o3/inst_queue_impl.hh b/src/cpu/o3/inst_queue_impl.hh index 91cb2f0c82..aa21a0edc8 100644 --- a/src/cpu/o3/inst_queue_impl.hh +++ b/src/cpu/o3/inst_queue_impl.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2011 ARM Limited + * All rights reserved. + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * * Copyright (c) 2004-2006 The Regents of The University of Michigan * All rights reserved. * @@ -397,6 +409,7 @@ InstructionQueue::resetState() } nonSpecInsts.clear(); listOrder.clear(); + deferredMemInsts.clear(); } template @@ -733,6 +746,15 @@ InstructionQueue::scheduleReadyInsts() IssueStruct *i2e_info = issueToExecuteQueue->access(0); + DynInstPtr deferred_mem_inst; + int total_deferred_mem_issued = 0; + while (total_deferred_mem_issued < totalWidth && + (deferred_mem_inst = getDeferredMemInstToExecute()) != 0) { + issueToExecuteQueue->access(0)->size++; + instsToExecute.push_back(deferred_mem_inst); + total_deferred_mem_issued++; + } + // Have iterator to head of the list // While I haven't exceeded bandwidth or reached the end of the list, // Try to get a FU that can do what this op needs. @@ -745,7 +767,7 @@ InstructionQueue::scheduleReadyInsts() ListOrderIt order_end_it = listOrder.end(); int total_issued = 0; - while (total_issued < totalWidth && + while (total_issued < (totalWidth - total_deferred_mem_issued) && iewStage->canIssue() && order_it != order_end_it) { OpClass op_class = (*order_it).queueType; @@ -858,7 +880,7 @@ InstructionQueue::scheduleReadyInsts() iqInstsIssued+= total_issued; // If we issued any instructions, tell the CPU we had activity. - if (total_issued) { + if (total_issued || total_deferred_mem_issued) { cpu->activityThisCycle(); } else { DPRINTF(IQ, "Not able to schedule any instructions.\n"); @@ -1021,6 +1043,11 @@ void InstructionQueue::rescheduleMemInst(DynInstPtr &resched_inst) { DPRINTF(IQ, "Rescheduling mem inst [sn:%lli]\n", resched_inst->seqNum); + + // Reset DTB translation state + resched_inst->translationStarted = false; + resched_inst->translationCompleted = false; + resched_inst->clearCanIssue(); memDepUnit[resched_inst->threadNumber].reschedule(resched_inst); } @@ -1049,6 +1076,28 @@ InstructionQueue::completeMemInst(DynInstPtr &completed_inst) count[tid]--; } +template +void +InstructionQueue::deferMemInst(DynInstPtr &deferred_inst) +{ + deferredMemInsts.push_back(deferred_inst); +} + +template +typename Impl::DynInstPtr +InstructionQueue::getDeferredMemInstToExecute() +{ + for (ListIt it = deferredMemInsts.begin(); it != deferredMemInsts.end(); + ++it) { + if ((*it)->translationCompleted) { + DynInstPtr ret = *it; + deferredMemInsts.erase(it); + return ret; + } + } + return NULL; +} + template void InstructionQueue::violation(DynInstPtr &store, diff --git a/src/cpu/o3/lsq_unit_impl.hh b/src/cpu/o3/lsq_unit_impl.hh index dd3604ffe2..b5d3379356 100644 --- a/src/cpu/o3/lsq_unit_impl.hh +++ b/src/cpu/o3/lsq_unit_impl.hh @@ -445,12 +445,16 @@ LSQUnit::executeLoad(DynInstPtr &inst) Fault load_fault = NoFault; DPRINTF(LSQUnit, "Executing load PC %s, [sn:%lli]\n", - inst->pcState(),inst->seqNum); + inst->pcState(), inst->seqNum); assert(!inst->isSquashed()); load_fault = inst->initiateAcc(); + if (inst->isTranslationDelayed() && + load_fault == NoFault) + return load_fault; + // If the instruction faulted or predicated false, then we need to send it // along to commit without the instruction completing. if (load_fault != NoFault || inst->readPredicate() == false) { @@ -532,6 +536,10 @@ LSQUnit::executeStore(DynInstPtr &store_inst) Fault store_fault = store_inst->initiateAcc(); + if (store_inst->isTranslationDelayed() && + store_fault == NoFault) + return store_fault; + if (store_inst->readPredicate() == false) store_inst->forwardOldRegs(); diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index 453699f841..ab1ff91e8b 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -752,6 +752,7 @@ TimingSimpleCPU::sendFetch(Fault fault, RequestPtr req, ThreadContext *tc) } else { delete req; // fetch fault: advance directly to next instruction (fault handler) + _status = Running; advanceInst(fault); } @@ -805,12 +806,11 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt) if (curStaticInst && curStaticInst->isMemRef()) { // load or store: just send to dcache Fault fault = curStaticInst->initiateAcc(this, traceData); - if (_status != Running) { - // instruction will complete in dcache response callback - assert(_status == DcacheWaitResponse || - _status == DcacheRetry || DTBWaitResponse); - assert(fault == NoFault); - } else { + + // If we're not running now the instruction will complete in a dcache + // response callback or the instruction faulted and has started an + // ifetch + if (_status == Running) { if (fault != NoFault && traceData) { // If there was a fault, we shouldn't trace this instruction. delete traceData; diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh index 2b0c8942a3..a7a3eb7c3c 100644 --- a/src/cpu/simple/timing.hh +++ b/src/cpu/simple/timing.hh @@ -107,6 +107,13 @@ class TimingSimpleCPU : public BaseSimpleCPU : cpu(_cpu) {} + void + markDelayed() + { + assert(cpu->_status == Running); + cpu->_status = ITBWaitResponse; + } + void finish(Fault fault, RequestPtr req, ThreadContext *tc, BaseTLB::Mode mode) diff --git a/src/cpu/translation.hh b/src/cpu/translation.hh index 7db7c381aa..60953540fa 100644 --- a/src/cpu/translation.hh +++ b/src/cpu/translation.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2011 ARM Limited + * All rights reserved. + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * * Copyright (c) 2002-2005 The Regents of The University of Michigan * Copyright (c) 2009 The University of Edinburgh * All rights reserved. @@ -53,6 +65,7 @@ class WholeTranslationState Fault faults[2]; public: + bool delay; bool isSplit; RequestPtr mainReq; RequestPtr sreqLow; @@ -67,8 +80,8 @@ class WholeTranslationState */ WholeTranslationState(RequestPtr _req, uint8_t *_data, uint64_t *_res, BaseTLB::Mode _mode) - : outstanding(1), isSplit(false), mainReq(_req), sreqLow(NULL), - sreqHigh(NULL), data(_data), res(_res), mode(_mode) + : outstanding(1), delay(false), isSplit(false), mainReq(_req), + sreqLow(NULL), sreqHigh(NULL), data(_data), res(_res), mode(_mode) { faults[0] = faults[1] = NoFault; assert(mode == BaseTLB::Read || mode == BaseTLB::Write); @@ -82,8 +95,9 @@ class WholeTranslationState WholeTranslationState(RequestPtr _req, RequestPtr _sreqLow, RequestPtr _sreqHigh, uint8_t *_data, uint64_t *_res, BaseTLB::Mode _mode) - : outstanding(2), isSplit(true), mainReq(_req), sreqLow(_sreqLow), - sreqHigh(_sreqHigh), data(_data), res(_res), mode(_mode) + : outstanding(2), delay(false), isSplit(true), mainReq(_req), + sreqLow(_sreqLow), sreqHigh(_sreqHigh), data(_data), res(_res), + mode(_mode) { faults[0] = faults[1] = NoFault; assert(mode == BaseTLB::Read || mode == BaseTLB::Write); @@ -220,6 +234,16 @@ class DataTranslation : public BaseTLB::Translation { } + /** + * Signal the translation state that the translation has been delayed due + * to a hw page table walk. Split requests are transparently handled. + */ + void + markDelayed() + { + state->delay = true; + } + /** * Finish this part of the translation and indicate that the whole * translation is complete if the state says so. diff --git a/src/dev/SConscript b/src/dev/SConscript index 7cdea7961f..5243da683c 100644 --- a/src/dev/SConscript +++ b/src/dev/SConscript @@ -69,6 +69,7 @@ if env['FULL_SYSTEM']: Source('pcidev.cc') Source('pktfifo.cc') Source('platform.cc') + Source('ps2.cc') Source('simple_disk.cc') Source('sinic.cc') Source('terminal.cc') diff --git a/src/dev/arm/RealView.py b/src/dev/arm/RealView.py index cdc06e4ef7..ef3f68a884 100644 --- a/src/dev/arm/RealView.py +++ b/src/dev/arm/RealView.py @@ -52,6 +52,14 @@ class AmbaDevice(BasicPioDevice): abstract = True amba_id = Param.UInt32("ID of AMBA device for kernel detection") +class AmbaIntDevice(AmbaDevice): + type = 'AmbaIntDevice' + abstract = True + gic = Param.Gic(Parent.any, "Gic to use for interrupting") + int_num = Param.UInt32("Interrupt number that connects to GIC") + int_delay = Param.Latency("100ns", + "Time between action and interrupt generation by device") + class AmbaDmaDevice(DmaDevice): type = 'AmbaDmaDevice' abstract = True @@ -94,16 +102,17 @@ class Sp804(AmbaDevice): clock1 = Param.Clock('1MHz', "Clock speed of the input") amba_id = 0x00141804 -class Pl050(AmbaDevice): +class Pl050(AmbaIntDevice): type = 'Pl050' - gic = Param.Gic(Parent.any, "Gic to use for interrupting") - int_num = Param.UInt32("Interrupt number that connects to GIC") - int_delay = Param.Latency("100ns", "Time between action and interrupt generation by UART") + vnc = Param.VncServer(Parent.any, "Vnc server for remote frame buffer display") + is_mouse = Param.Bool(False, "Is this interface a mouse, if not a keyboard") + int_delay = '1us' amba_id = 0x00141050 class Pl111(AmbaDmaDevice): type = 'Pl111' clock = Param.Clock('24MHz', "Clock speed of the input") + vnc = Param.VncServer(Parent.any, "Vnc server for remote frame buffer display") amba_id = 0x00141111 class RealView(Platform): @@ -121,7 +130,7 @@ class RealViewPBX(RealView): timer1 = Sp804(int_num0=37, int_num1=37, pio_addr=0x10012000) clcd = Pl111(pio_addr=0x10020000, int_num=55) kmi0 = Pl050(pio_addr=0x10006000, int_num=52) - kmi1 = Pl050(pio_addr=0x10007000, int_num=53) + kmi1 = Pl050(pio_addr=0x10007000, int_num=53, is_mouse=True) l2x0_fake = IsaFake(pio_addr=0x1f002000, pio_size=0xfff) flash_fake = IsaFake(pio_addr=0x40000000, pio_size=0x4000000) @@ -140,7 +149,7 @@ class RealViewPBX(RealView): aaci_fake = AmbaFake(pio_addr=0x10004000) mmc_fake = AmbaFake(pio_addr=0x10005000) rtc_fake = AmbaFake(pio_addr=0x10017000, amba_id=0x41031) - + cf0_fake = IsaFake(pio_addr=0x18000000, pio_size=0xfff) # Attach I/O devices that are on chip @@ -175,6 +184,7 @@ class RealViewPBX(RealView): self.mmc_fake.pio = bus.port self.rtc_fake.pio = bus.port self.flash_fake.pio = bus.port + self.cf0_fake.pio = bus.port # Reference for memory map and interrupt number # RealView Emulation Baseboard User Guide (ARM DUI 0143B) @@ -187,7 +197,7 @@ class RealViewEB(RealView): timer1 = Sp804(int_num0=37, int_num1=37, pio_addr=0x10012000) clcd = Pl111(pio_addr=0x10020000, int_num=23) kmi0 = Pl050(pio_addr=0x10006000, int_num=20) - kmi1 = Pl050(pio_addr=0x10007000, int_num=21) + kmi1 = Pl050(pio_addr=0x10007000, int_num=21, is_mouse=True) l2x0_fake = IsaFake(pio_addr=0x1f002000, pio_size=0xfff, warn_access="1") dmac_fake = AmbaFake(pio_addr=0x10030000) diff --git a/src/dev/arm/amba_device.cc b/src/dev/arm/amba_device.cc index e5d53d6a38..37eb77ae1b 100644 --- a/src/dev/arm/amba_device.cc +++ b/src/dev/arm/amba_device.cc @@ -47,11 +47,19 @@ #include "mem/packet_access.hh" const uint64_t AmbaVendor = ULL(0xb105f00d00000000); + AmbaDevice::AmbaDevice(const Params *p) : BasicPioDevice(p), ambaId(AmbaVendor | p->amba_id) { } +AmbaIntDevice::AmbaIntDevice(const Params *p) + : AmbaDevice(p), intNum(p->int_num), gic(p->gic), intDelay(p->int_delay) +{ +} + + + AmbaDmaDevice::AmbaDmaDevice(const Params *p) : DmaDevice(p), ambaId(AmbaVendor | p->amba_id), pioAddr(p->pio_addr), pioSize(0), diff --git a/src/dev/arm/amba_device.hh b/src/dev/arm/amba_device.hh index 1782fb003f..297a78f827 100644 --- a/src/dev/arm/amba_device.hh +++ b/src/dev/arm/amba_device.hh @@ -55,6 +55,7 @@ #include "mem/packet.hh" #include "mem/packet_access.hh" #include "params/AmbaDevice.hh" +#include "params/AmbaIntDevice.hh" #include "params/AmbaDmaDevice.hh" namespace AmbaDev { @@ -81,6 +82,18 @@ class AmbaDevice : public BasicPioDevice AmbaDevice(const Params *p); }; +class AmbaIntDevice : public AmbaDevice +{ + protected: + int intNum; + Gic *gic; + Tick intDelay; + + public: + typedef AmbaIntDeviceParams Params; + AmbaIntDevice(const Params *p); +}; + class AmbaDmaDevice : public DmaDevice { protected: diff --git a/src/dev/arm/kmi.cc b/src/dev/arm/kmi.cc index 6cd61fd090..adf1439b3b 100644 --- a/src/dev/arm/kmi.cc +++ b/src/dev/arm/kmi.cc @@ -37,21 +37,31 @@ * (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: William Wang + * Authors: Ali Saidi + * William Wang */ #include "base/trace.hh" +#include "base/vnc/vncserver.hh" #include "dev/arm/amba_device.hh" #include "dev/arm/kmi.hh" +#include "dev/ps2.hh" #include "mem/packet.hh" #include "mem/packet_access.hh" Pl050::Pl050(const Params *p) - : AmbaDevice(p), control(0x00), status(0x43), kmidata(0x00), clkdiv(0x00), - intreg(0x00), intNum(p->int_num), gic(p->gic), intDelay(p->int_delay), - intEvent(this) + : AmbaIntDevice(p), control(0), status(0x43), clkdiv(0), interrupts(0), + rawInterrupts(0), ackNext(false), shiftDown(false), vnc(p->vnc), + driverInitialized(false), intEvent(this) { pioSize = 0xfff; + + if (vnc) { + if (!p->is_mouse) + vnc->setKeyboard(this); + else + vnc->setMouse(this); + } } Tick @@ -62,28 +72,39 @@ Pl050::read(PacketPtr pkt) Addr daddr = pkt->getAddr() - pioAddr; pkt->allocate(); - DPRINTF(Pl050, " read register %#x size=%d\n", daddr, pkt->getSize()); - // use a temporary data since the KMI registers are read/written with - // different size operations - // uint32_t data = 0; switch (daddr) { case kmiCr: + DPRINTF(Pl050, "Read Commmand: %#x\n", (uint32_t)control); data = control; break; case kmiStat: + if (rxQueue.empty()) + status.rxfull = 0; + else + status.rxfull = 1; + + DPRINTF(Pl050, "Read Status: %#x\n", (uint32_t)status); data = status; break; case kmiData: - data = kmidata; + if (rxQueue.empty()) { + data = 0; + } else { + data = rxQueue.front(); + rxQueue.pop_front(); + } + DPRINTF(Pl050, "Read Data: %#x\n", (uint32_t)data); + updateIntStatus(); break; case kmiClkDiv: data = clkdiv; break; case kmiISR: - data = intreg; + data = interrupts; + DPRINTF(Pl050, "Read Interrupts: %#x\n", (uint32_t)interrupts); break; default: if (AmbaDev::readId(pkt, ambaId, pioAddr)) { @@ -123,47 +144,22 @@ Pl050::write(PacketPtr pkt) Addr daddr = pkt->getAddr() - pioAddr; - DPRINTF(Pl050, " write register %#x value %#x size=%d\n", daddr, - pkt->get(), pkt->getSize()); - - // use a temporary data since the KMI registers are read/written with - // different size operations - // - uint32_t data = 0; - - switch (pkt->getSize()) { - case 1: - data = pkt->get(); - break; - case 2: - data = pkt->get(); - break; - case 4: - data = pkt->get(); - break; - default: - panic("KMI write size too big?\n"); - break; - } + assert(pkt->getSize() == sizeof(uint8_t)); switch (daddr) { case kmiCr: - control = data; - break; - case kmiStat: - panic("Tried to write PL050 register(read only) at offset %#x\n", - daddr); + DPRINTF(Pl050, "Write Commmand: %#x\n", (uint32_t)pkt->get()); + control = pkt->get(); + updateIntStatus(); break; case kmiData: - kmidata = data; + DPRINTF(Pl050, "Write Data: %#x\n", (uint32_t)pkt->get()); + processCommand(pkt->get()); + updateIntStatus(); break; case kmiClkDiv: - clkdiv = data; - break; - case kmiISR: - panic("Tried to write PL050 register(read only) at offset %#x\n", - daddr); + clkdiv = pkt->get(); break; default: warn("Tried to write PL050 at offset %#x that doesn't exist\n", daddr); @@ -173,15 +169,199 @@ Pl050::write(PacketPtr pkt) return pioDelay; } +void +Pl050::processCommand(uint8_t byte) +{ + using namespace Ps2; + + if (ackNext) { + ackNext--; + rxQueue.push_back(Ack); + updateIntStatus(); + return; + } + + switch (byte) { + case Ps2Reset: + rxQueue.push_back(Ack); + rxQueue.push_back(SelfTestPass); + break; + case SetResolution: + case SetRate: + case SetStatusLed: + case SetScaling1_1: + case SetScaling1_2: + rxQueue.push_back(Ack); + ackNext = 1; + break; + case ReadId: + rxQueue.push_back(Ack); + if (params()->is_mouse) + rxQueue.push_back(MouseId); + else + rxQueue.push_back(KeyboardId); + break; + case TpReadId: + if (!params()->is_mouse) + break; + // We're not a trackpoint device, this should make the probe go away + rxQueue.push_back(Ack); + rxQueue.push_back(0); + rxQueue.push_back(0); + // fall through + case Disable: + case Enable: + rxQueue.push_back(Ack); + break; + case StatusRequest: + rxQueue.push_back(Ack); + rxQueue.push_back(0); + rxQueue.push_back(2); // default resolution + rxQueue.push_back(100); // default sample rate + break; + case TouchKitId: + ackNext = 2; + rxQueue.push_back(Ack); + rxQueue.push_back(TouchKitId); + rxQueue.push_back(1); + rxQueue.push_back('A'); + + driverInitialized = true; + break; + default: + panic("Unknown byte received: %d\n", byte); + } + + updateIntStatus(); +} + + +void +Pl050::updateIntStatus() +{ + if (!rxQueue.empty()) + rawInterrupts.rx = 1; + else + rawInterrupts.rx = 0; + + interrupts.tx = rawInterrupts.tx & control.txint_enable; + interrupts.rx = rawInterrupts.rx & control.rxint_enable; + + DPRINTF(Pl050, "rawInterupts=%#x control=%#x interrupts=%#x\n", + (uint32_t)rawInterrupts, (uint32_t)control, (uint32_t)interrupts); + + if (interrupts && !intEvent.scheduled()) + schedule(intEvent, curTick() + intDelay); +} + void Pl050::generateInterrupt() { - if (intreg.rxintr || intreg.txintr) { + + if (interrupts) { gic->sendInt(intNum); - DPRINTF(Pl050, " -- Generated\n"); + DPRINTF(Pl050, "Generated interrupt\n"); } } +void +Pl050::mouseAt(uint16_t x, uint16_t y, uint8_t buttons) +{ + using namespace Ps2; + + // If the driver hasn't initialized the device yet, no need to try and send + // it anything. Similarly we can get vnc mouse events orders of maginture + // faster than m5 can process them. Only queue up two sets mouse movements + // and don't add more until those are processed. + if (!driverInitialized || rxQueue.size() > 10) + return; + + // We shouldn't be here unless a vnc server called us in which case + // we should have a pointer to it + assert(vnc); + + // Convert screen coordinates to touchpad coordinates + uint16_t _x = (2047.0/vnc->videoWidth()) * x; + uint16_t _y = (2047.0/vnc->videoHeight()) * y; + + rxQueue.push_back(buttons); + rxQueue.push_back(_x >> 7); + rxQueue.push_back(_x & 0x7f); + rxQueue.push_back(_y >> 7); + rxQueue.push_back(_y & 0x7f); + + updateIntStatus(); +} + + +void +Pl050::keyPress(uint32_t key, bool down) +{ + using namespace Ps2; + + std::list keys; + + // convert the X11 keysym into ps2 codes + keySymToPs2(key, down, shiftDown, keys); + + // Insert into our queue of charecters + rxQueue.splice(rxQueue.end(), keys); + updateIntStatus(); +} + +void +Pl050::serialize(std::ostream &os) +{ + uint8_t ctrlreg = control; + SERIALIZE_SCALAR(ctrlreg); + + uint8_t stsreg = status; + SERIALIZE_SCALAR(stsreg); + SERIALIZE_SCALAR(clkdiv); + + uint8_t ints = interrupts; + SERIALIZE_SCALAR(ints); + + uint8_t raw_ints = rawInterrupts; + SERIALIZE_SCALAR(raw_ints); + + SERIALIZE_SCALAR(ackNext); + SERIALIZE_SCALAR(shiftDown); + SERIALIZE_SCALAR(driverInitialized); + + arrayParamOut(os, "rxQueue", rxQueue); +} + +void +Pl050::unserialize(Checkpoint *cp, const std::string §ion) +{ + uint8_t ctrlreg; + UNSERIALIZE_SCALAR(ctrlreg); + control = ctrlreg; + + uint8_t stsreg; + UNSERIALIZE_SCALAR(stsreg); + status = stsreg; + + UNSERIALIZE_SCALAR(clkdiv); + + uint8_t ints; + UNSERIALIZE_SCALAR(ints); + interrupts = ints; + + uint8_t raw_ints; + UNSERIALIZE_SCALAR(raw_ints); + rawInterrupts = raw_ints; + + UNSERIALIZE_SCALAR(ackNext); + UNSERIALIZE_SCALAR(shiftDown); + UNSERIALIZE_SCALAR(driverInitialized); + + arrayParamIn(cp, section, "rxQueue", rxQueue); +} + + + Pl050 * Pl050Params::create() { diff --git a/src/dev/arm/kmi.hh b/src/dev/arm/kmi.hh index c96dd55a97..1e25f89748 100644 --- a/src/dev/arm/kmi.hh +++ b/src/dev/arm/kmi.hh @@ -48,13 +48,16 @@ #ifndef __DEV_ARM_PL050_HH__ #define __DEV_ARM_PL050_HH__ +#include + #include "base/range.hh" -#include "dev/io_device.hh" +#include "base/vnc/vncserver.hh" +#include "dev/arm/amba_device.hh" #include "params/Pl050.hh" class Gic; -class Pl050 : public AmbaDevice +class Pl050 : public AmbaIntDevice, public VncKeyboard, public VncMouse { protected: static const int kmiCr = 0x000; @@ -63,34 +66,68 @@ class Pl050 : public AmbaDevice static const int kmiClkDiv = 0x00C; static const int kmiISR = 0x010; - // control register - uint8_t control; + BitUnion8(ControlReg) + Bitfield<0> force_clock_low; + Bitfield<1> force_data_low; + Bitfield<2> enable; + Bitfield<3> txint_enable; + Bitfield<4> rxint_enable; + Bitfield<5> type; + EndBitUnion(ControlReg) - // status register - uint8_t status; + /** control register + */ + ControlReg control; - // received data (read) or data to be transmitted (write) - uint8_t kmidata; + /** KMI status register */ + BitUnion8(StatusReg) + Bitfield<0> data_in; + Bitfield<1> clk_in; + Bitfield<2> rxparity; + Bitfield<3> rxbusy; + Bitfield<4> rxfull; + Bitfield<5> txbusy; + Bitfield<6> txempty; + EndBitUnion(StatusReg) - // clock divisor register + StatusReg status; + + /** clock divisor register + * This register is just kept around to satisfy reads after driver does + * writes. The divsor does nothing, as we're not actually signaling ps2 + * serial commands to anything. + */ uint8_t clkdiv; - BitUnion8(IntReg) - Bitfield<0> txintr; - Bitfield<1> rxintr; - EndBitUnion(IntReg) + BitUnion8(InterruptReg) + Bitfield<0> rx; + Bitfield<1> tx; + EndBitUnion(InterruptReg) - /** interrupt mask register. */ - IntReg intreg; + /** interrupt status register. */ + InterruptReg interrupts; - /** Interrupt number to generate */ - int intNum; + /** raw interrupt register (unmasked) */ + InterruptReg rawInterrupts; - /** Gic to use for interrupting */ - Gic *gic; + /** If the controller should ignore the next data byte and acknowledge it. + * The driver is attempting to setup some feature we don't care about + */ + int ackNext; - /** Delay before interrupting */ - Tick intDelay; + /** is the shift key currently down */ + bool shiftDown; + + /** The vnc server we're connected to (if any) */ + VncServer *vnc; + + /** If the linux driver has initialized the device yet and thus can we send + * mouse data */ + bool driverInitialized; + + /** Update the status of the interrupt registers and schedule an interrupt + * if required */ + void updateIntStatus(); /** Function to generate interrupt */ void generateInterrupt(); @@ -98,6 +135,15 @@ class Pl050 : public AmbaDevice /** Wrapper to create an event out of the thing */ EventWrapper intEvent; + /** Receive queue. This list contains all the pending commands that + * need to be sent to the driver + */ + std::list rxQueue; + + /** Handle a command sent to the kmi and respond appropriately + */ + void processCommand(uint8_t byte); + public: typedef Pl050Params Params; const Params * @@ -111,12 +157,11 @@ class Pl050 : public AmbaDevice virtual Tick read(PacketPtr pkt); virtual Tick write(PacketPtr pkt); - /** - * Return if we have an interrupt pending - * @return interrupt status - * @todo fix me when implementation improves - */ - virtual bool intStatus() { return false; } + virtual void mouseAt(uint16_t x, uint16_t y, uint8_t buttons); + virtual void keyPress(uint32_t key, bool down); + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); }; -#endif +#endif // __DEV_ARM_PL050_HH__ diff --git a/src/dev/arm/pl111.cc b/src/dev/arm/pl111.cc index e597bf2724..e884d9b58f 100644 --- a/src/dev/arm/pl111.cc +++ b/src/dev/arm/pl111.cc @@ -35,9 +35,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: William Wang + * Ali Saidi */ +#include "base/bitmap.hh" +#include "base/output.hh" #include "base/trace.hh" +#include "base/vnc/vncserver.hh" #include "dev/arm/amba_device.hh" #include "dev/arm/gic.hh" #include "dev/arm/pl111.hh" @@ -50,20 +54,27 @@ using namespace AmbaDev; Pl111::Pl111(const Params *p) : AmbaDmaDevice(p), lcdTiming0(0), lcdTiming1(0), lcdTiming2(0), lcdTiming3(0), lcdUpbase(0), lcdLpbase(0), lcdControl(0), lcdImsc(0), - lcdRis(0), lcdMis(0), lcdIcr(0), lcdUpcurr(0), lcdLpcurr(0), + lcdRis(0), lcdMis(0), clcdCrsrCtrl(0), clcdCrsrConfig(0), clcdCrsrPalette0(0), clcdCrsrPalette1(0), clcdCrsrXY(0), clcdCrsrClip(0), clcdCrsrImsc(0), clcdCrsrIcr(0), clcdCrsrRis(0), clcdCrsrMis(0), clock(p->clock), - height(0), width(0), startTime(0), startAddr(0), maxAddr(0), curAddr(0), + vncserver(p->vnc), bmp(NULL), width(LcdMaxWidth), height(LcdMaxHeight), + bytesPerPixel(4), startTime(0), startAddr(0), maxAddr(0), curAddr(0), waterMark(0), dmaPendingNum(0), readEvent(this), fillFifoEvent(this), dmaDoneEvent(maxOutstandingDma, this), intEvent(this) { pioSize = 0xFFFF; + pic = simout.create("framebuffer.bmp", true); + + dmaBuffer = new uint8_t[LcdMaxWidth * LcdMaxHeight * sizeof(uint32_t)]; + memset(lcdPalette, 0, sizeof(lcdPalette)); memset(cursorImage, 0, sizeof(cursorImage)); memset(dmaBuffer, 0, sizeof(dmaBuffer)); - memset(frameBuffer, 0, sizeof(frameBuffer)); + + if (vncserver) + vncserver->setFramebufferAddr(dmaBuffer); } // read registers and frame buffer @@ -75,111 +86,105 @@ Pl111::read(PacketPtr pkt) uint32_t data = 0; - if ((pkt->getAddr()& 0xffff0000) == pioAddr) { + assert(pkt->getAddr() >= pioAddr && + pkt->getAddr() < pioAddr + pioSize); - assert(pkt->getAddr() >= pioAddr && - pkt->getAddr() < pioAddr + pioSize); + Addr daddr = pkt->getAddr() - pioAddr; + pkt->allocate(); - Addr daddr = pkt->getAddr()&0xFFFF; - pkt->allocate(); + DPRINTF(PL111, " read register %#x size=%d\n", daddr, pkt->getSize()); - DPRINTF(PL111, " read register %#x size=%d\n", daddr, pkt->getSize()); - - switch (daddr) { - case LcdTiming0: - data = lcdTiming0; + switch (daddr) { + case LcdTiming0: + data = lcdTiming0; + break; + case LcdTiming1: + data = lcdTiming1; + break; + case LcdTiming2: + data = lcdTiming2; + break; + case LcdTiming3: + data = lcdTiming3; + break; + case LcdUpBase: + data = lcdUpbase; + break; + case LcdLpBase: + data = lcdLpbase; + break; + case LcdControl: + data = lcdControl; + break; + case LcdImsc: + data = lcdImsc; + break; + case LcdRis: + data = lcdRis; + break; + case LcdMis: + data = lcdMis; + break; + case LcdIcr: + panic("LCD register at offset %#x is Write-Only\n", daddr); + break; + case LcdUpCurr: + data = curAddr; + break; + case LcdLpCurr: + data = curAddr; + break; + case ClcdCrsrCtrl: + data = clcdCrsrCtrl; + break; + case ClcdCrsrConfig: + data = clcdCrsrConfig; + break; + case ClcdCrsrPalette0: + data = clcdCrsrPalette0; + break; + case ClcdCrsrPalette1: + data = clcdCrsrPalette1; + break; + case ClcdCrsrXY: + data = clcdCrsrXY; + break; + case ClcdCrsrClip: + data = clcdCrsrClip; + break; + case ClcdCrsrImsc: + data = clcdCrsrImsc; + break; + case ClcdCrsrIcr: + panic("CLCD register at offset %#x is Write-Only\n", daddr); + break; + case ClcdCrsrRis: + data = clcdCrsrRis; + break; + case ClcdCrsrMis: + data = clcdCrsrMis; + break; + default: + if (AmbaDev::readId(pkt, AMBA_ID, pioAddr)) { + // Hack for variable size accesses + data = pkt->get(); break; - case LcdTiming1: - data = lcdTiming1; + } else if (daddr >= CrsrImage && daddr <= 0xBFC) { + // CURSOR IMAGE + int index; + index = (daddr - CrsrImage) >> 2; + data= cursorImage[index]; break; - case LcdTiming2: - data = lcdTiming2; + } else if (daddr >= LcdPalette && daddr <= 0x3FC) { + // LCD Palette + int index; + index = (daddr - LcdPalette) >> 2; + data = lcdPalette[index]; break; - case LcdTiming3: - data = lcdTiming3; - break; - case LcdUpBase: - data = lcdUpbase; - break; - case LcdLpBase: - data = lcdLpbase; - break; - case LcdControl: - data = lcdControl; - break; - case LcdImsc: - warn("LCD interrupt set/clear function not supported\n"); - data = lcdImsc; - break; - case LcdRis: - warn("LCD Raw interrupt status function not supported\n"); - data = lcdRis; - break; - case LcdMis: - warn("LCD Masked interrupt status function not supported\n"); - data = lcdMis; - break; - case LcdIcr: - panic("LCD register at offset %#x is Write-Only\n", daddr); - break; - case LcdUpCurr: - data = lcdUpcurr; - break; - case LcdLpCurr: - data = lcdLpcurr; - break; - case ClcdCrsrCtrl: - data = clcdCrsrCtrl; - break; - case ClcdCrsrConfig: - data = clcdCrsrConfig; - break; - case ClcdCrsrPalette0: - data = clcdCrsrPalette0; - break; - case ClcdCrsrPalette1: - data = clcdCrsrPalette1; - break; - case ClcdCrsrXY: - data = clcdCrsrXY; - break; - case ClcdCrsrClip: - data = clcdCrsrClip; - break; - case ClcdCrsrImsc: - data = clcdCrsrImsc; - break; - case ClcdCrsrIcr: - panic("CLCD register at offset %#x is Write-Only\n", daddr); - break; - case ClcdCrsrRis: - data = clcdCrsrRis; - break; - case ClcdCrsrMis: - data = clcdCrsrMis; - break; - default: - if (AmbaDev::readId(pkt, AMBA_ID, pioAddr)) { - // Hack for variable size accesses - data = pkt->get(); - break; - } else if (daddr >= CrsrImage && daddr <= 0xBFC) { - // CURSOR IMAGE - int index; - index = (daddr - CrsrImage) >> 2; - data= cursorImage[index]; - break; - } else if (daddr >= LcdPalette && daddr <= 0x3FC) { - // LCD Palette - int index; - index = (daddr - LcdPalette) >> 2; - data = lcdPalette[index]; - break; - } else { - panic("Tried to read CLCD register at offset %#x that \ + } else { + panic("Tried to read CLCD register at offset %#x that \ doesn't exist\n", daddr); - break; - } + break; } } @@ -226,119 +231,133 @@ Pl111::write(PacketPtr pkt) break; } - if ((pkt->getAddr()& 0xffff0000) == pioAddr) { + assert(pkt->getAddr() >= pioAddr && + pkt->getAddr() < pioAddr + pioSize); - assert(pkt->getAddr() >= pioAddr && - pkt->getAddr() < pioAddr + pioSize); + Addr daddr = pkt->getAddr() - pioAddr; - Addr daddr = pkt->getAddr() - pioAddr; + DPRINTF(PL111, " write register %#x value %#x size=%d\n", daddr, + pkt->get(), pkt->getSize()); - DPRINTF(PL111, " write register %#x value %#x size=%d\n", daddr, - pkt->get(), pkt->getSize()); + switch (daddr) { + case LcdTiming0: + lcdTiming0 = data; + // width = 16 * (PPL+1) + width = (lcdTiming0.ppl + 1) << 4; + break; + case LcdTiming1: + lcdTiming1 = data; + // height = LPP + 1 + height = (lcdTiming1.lpp) + 1; + break; + case LcdTiming2: + lcdTiming2 = data; + break; + case LcdTiming3: + lcdTiming3 = data; + break; + case LcdUpBase: + lcdUpbase = data; + DPRINTF(PL111, "####### Upper panel base set to: %#x #######\n", lcdUpbase); + break; + case LcdLpBase: + warn("LCD dual screen mode not supported\n"); + lcdLpbase = data; + DPRINTF(PL111, "###### Lower panel base set to: %#x #######\n", lcdLpbase); + break; + case LcdControl: + int old_lcdpwr; + old_lcdpwr = lcdControl.lcdpwr; + lcdControl = data; - switch (daddr) { - case LcdTiming0: - lcdTiming0 = data; - // width = 16 * (PPL+1) - width = (lcdTiming0.ppl + 1) << 4; + DPRINTF(PL111, "LCD power is:%d\n", lcdControl.lcdpwr); + + // LCD power enable + if (lcdControl.lcdpwr && !old_lcdpwr) { + updateVideoParams(); + DPRINTF(PL111, " lcd size: height %d width %d\n", height, width); + waterMark = lcdControl.watermark ? 8 : 4; + startDma(); + } + break; + case LcdImsc: + lcdImsc = data; + if (lcdImsc.vcomp) + panic("Interrupting on vcomp not supported\n"); + + lcdMis = lcdImsc & lcdRis; + + if (!lcdMis) + gic->clearInt(intNum); + + break; + case LcdRis: + panic("LCD register at offset %#x is Read-Only\n", daddr); + break; + case LcdMis: + panic("LCD register at offset %#x is Read-Only\n", daddr); + break; + case LcdIcr: + lcdRis = lcdRis & ~data; + lcdMis = lcdImsc & lcdRis; + + if (!lcdMis) + gic->clearInt(intNum); + + break; + case LcdUpCurr: + panic("LCD register at offset %#x is Read-Only\n", daddr); + break; + case LcdLpCurr: + panic("LCD register at offset %#x is Read-Only\n", daddr); + break; + case ClcdCrsrCtrl: + clcdCrsrCtrl = data; + break; + case ClcdCrsrConfig: + clcdCrsrConfig = data; + break; + case ClcdCrsrPalette0: + clcdCrsrPalette0 = data; + break; + case ClcdCrsrPalette1: + clcdCrsrPalette1 = data; + break; + case ClcdCrsrXY: + clcdCrsrXY = data; + break; + case ClcdCrsrClip: + clcdCrsrClip = data; + break; + case ClcdCrsrImsc: + clcdCrsrImsc = data; + break; + case ClcdCrsrIcr: + clcdCrsrIcr = data; + break; + case ClcdCrsrRis: + panic("CLCD register at offset %#x is Read-Only\n", daddr); + break; + case ClcdCrsrMis: + panic("CLCD register at offset %#x is Read-Only\n", daddr); + break; + default: + if (daddr >= CrsrImage && daddr <= 0xBFC) { + // CURSOR IMAGE + int index; + index = (daddr - CrsrImage) >> 2; + cursorImage[index] = data; break; - case LcdTiming1: - lcdTiming1 = data; - // height = LPP + 1 - height = (lcdTiming1.lpp) + 1; + } else if (daddr >= LcdPalette && daddr <= 0x3FC) { + // LCD Palette + int index; + index = (daddr - LcdPalette) >> 2; + lcdPalette[index] = data; break; - case LcdTiming2: - lcdTiming2 = data; - break; - case LcdTiming3: - lcdTiming3 = data; - break; - case LcdUpBase: - lcdUpbase = data; - break; - case LcdLpBase: - warn("LCD dual screen mode not supported\n"); - lcdLpbase = data; - break; - case LcdControl: - int old_lcdpwr; - old_lcdpwr = lcdControl.lcdpwr; - lcdControl = data; - // LCD power enable - if (lcdControl.lcdpwr&&!old_lcdpwr) { - DPRINTF(PL111, " lcd size: height %d width %d\n", height, width); - waterMark = lcdControl.watermark ? 8 : 4; - readFramebuffer(); - } - break; - case LcdImsc: - warn("LCD interrupt mask set/clear not supported\n"); - lcdImsc = data; - break; - case LcdRis: - warn("LCD register at offset %#x is Read-Only\n", daddr); - break; - case LcdMis: - warn("LCD register at offset %#x is Read-Only\n", daddr); - break; - case LcdIcr: - warn("LCD interrupt clear not supported\n"); - lcdIcr = data; - break; - case LcdUpCurr: - warn("LCD register at offset %#x is Read-Only\n", daddr); - break; - case LcdLpCurr: - warn("LCD register at offset %#x is Read-Only\n", daddr); - break; - case ClcdCrsrCtrl: - clcdCrsrCtrl = data; - break; - case ClcdCrsrConfig: - clcdCrsrConfig = data; - break; - case ClcdCrsrPalette0: - clcdCrsrPalette0 = data; - break; - case ClcdCrsrPalette1: - clcdCrsrPalette1 = data; - break; - case ClcdCrsrXY: - clcdCrsrXY = data; - break; - case ClcdCrsrClip: - clcdCrsrClip = data; - break; - case ClcdCrsrImsc: - clcdCrsrImsc = data; - break; - case ClcdCrsrIcr: - clcdCrsrIcr = data; - break; - case ClcdCrsrRis: - warn("CLCD register at offset %#x is Read-Only\n", daddr); - break; - case ClcdCrsrMis: - warn("CLCD register at offset %#x is Read-Only\n", daddr); - break; - default: - if (daddr >= CrsrImage && daddr <= 0xBFC) { - // CURSOR IMAGE - int index; - index = (daddr - CrsrImage) >> 2; - cursorImage[index] = data; - break; - } else if (daddr >= LcdPalette && daddr <= 0x3FC) { - // LCD Palette - int index; - index = (daddr - LcdPalette) >> 2; - lcdPalette[index] = data; - break; - } else { - panic("Tried to write PL111 register at offset %#x that \ + } else { + panic("Tried to write PL111 register at offset %#x that \ doesn't exist\n", daddr); - break; - } + break; } } @@ -346,18 +365,76 @@ Pl111::write(PacketPtr pkt) return pioDelay; } +void +Pl111::updateVideoParams() +{ + if (lcdControl.lcdbpp == bpp24) { + bytesPerPixel = 4; + } else if (lcdControl.lcdbpp == bpp16m565) { + bytesPerPixel = 2; + } + + if (vncserver) { + if (lcdControl.lcdbpp == bpp24 && lcdControl.bgr) + vncserver->setFrameBufferParams(VideoConvert::bgr8888, width, + height); + else if (lcdControl.lcdbpp == bpp24 && !lcdControl.bgr) + vncserver->setFrameBufferParams(VideoConvert::rgb8888, width, + height); + else if (lcdControl.lcdbpp == bpp16m565 && lcdControl.bgr) + vncserver->setFrameBufferParams(VideoConvert::bgr565, width, + height); + else if (lcdControl.lcdbpp == bpp16m565 && !lcdControl.bgr) + vncserver->setFrameBufferParams(VideoConvert::rgb565, width, + height); + else + panic("Unimplemented video mode\n"); + } + + if (bmp) + delete bmp; + + if (lcdControl.lcdbpp == bpp24 && lcdControl.bgr) + bmp = new Bitmap(VideoConvert::bgr8888, width, height, dmaBuffer); + else if (lcdControl.lcdbpp == bpp24 && !lcdControl.bgr) + bmp = new Bitmap(VideoConvert::rgb8888, width, height, dmaBuffer); + else if (lcdControl.lcdbpp == bpp16m565 && lcdControl.bgr) + bmp = new Bitmap(VideoConvert::bgr565, width, height, dmaBuffer); + else if (lcdControl.lcdbpp == bpp16m565 && !lcdControl.bgr) + bmp = new Bitmap(VideoConvert::rgb565, width, height, dmaBuffer); + else + panic("Unimplemented video mode\n"); +} + +void +Pl111::startDma() +{ + if (dmaPendingNum != 0 || readEvent.scheduled()) + return; + readFramebuffer(); +} + void Pl111::readFramebuffer() { // initialization for dma read from frame buffer to dma buffer - uint32_t length = height*width; - if (startAddr != lcdUpbase) { + uint32_t length = height * width; + if (startAddr != lcdUpbase) startAddr = lcdUpbase; - } + + // Updating base address, interrupt if we're supposed to + lcdRis.baseaddr = 1; + if (!intEvent.scheduled()) + schedule(intEvent, nextCycle()); + curAddr = 0; startTime = curTick(); - maxAddr = static_cast(length*sizeof(uint32_t)); - dmaPendingNum =0 ; + + maxAddr = static_cast(length * bytesPerPixel); + + DPRINTF(PL111, " lcd frame buffer size of %d bytes \n", maxAddr); + + dmaPendingNum = 0; fillFifo(); } @@ -369,11 +446,16 @@ Pl111::fillFifo() // concurrent dma reads need different dma done events // due to assertion in scheduling state ++dmaPendingNum; - DPRINTF(PL111, " ++ DMA pending number %d read addr %#x\n", - dmaPendingNum, curAddr); + assert(!dmaDoneEvent[dmaPendingNum-1].scheduled()); - dmaRead(curAddr + startAddr, dmaSize, &dmaDoneEvent[dmaPendingNum-1], - curAddr + dmaBuffer); + + // We use a uncachable request here because the requests from the CPU + // will be uncacheable as well. If we have uncacheable and cacheable + // requests in the memory system for the same address it won't be + // pleased + dmaPort->dmaAction(MemCmd::ReadReq, curAddr + startAddr, dmaSize, + &dmaDoneEvent[dmaPendingNum-1], curAddr + dmaBuffer, 0, + Request::UNCACHEABLE); curAddr += dmaSize; } } @@ -381,27 +463,34 @@ Pl111::fillFifo() void Pl111::dmaDone() { - Tick maxFrameTime = lcdTiming2.cpl*height*clock; + Tick maxFrameTime = lcdTiming2.cpl * height * clock; --dmaPendingNum; - DPRINTF(PL111, " -- DMA pending number %d\n", dmaPendingNum); - if (maxAddr == curAddr && !dmaPendingNum) { - if ((curTick() - startTime) > maxFrameTime) + if ((curTick() - startTime) > maxFrameTime) { warn("CLCD controller buffer underrun, took %d cycles when should" " have taken %d\n", curTick() - startTime, maxFrameTime); + lcdRis.underflow = 1; + if (!intEvent.scheduled()) + schedule(intEvent, nextCycle()); + } - // double buffering so the vnc server doesn't see a tear in the screen - memcpy(frameBuffer, dmaBuffer, maxAddr); assert(!readEvent.scheduled()); + if (vncserver) + vncserver->setDirty(); DPRINTF(PL111, "-- write out frame buffer into bmp\n"); - writeBMP(frameBuffer); + + assert(bmp); + pic->seekp(0); + bmp->write(pic); DPRINTF(PL111, "-- schedule next dma read event at %d tick \n", maxFrameTime + curTick()); - schedule(readEvent, nextCycle(startTime + maxFrameTime)); + + if (lcdControl.lcden) + schedule(readEvent, nextCycle(startTime + maxFrameTime)); } if (dmaPendingNum > (maxOutstandingDma - waterMark)) @@ -409,9 +498,9 @@ Pl111::dmaDone() if (!fillFifoEvent.scheduled()) schedule(fillFifoEvent, nextCycle()); - } + Tick Pl111::nextCycle() { @@ -431,33 +520,6 @@ Pl111::nextCycle(Tick beginTick) return nextTick; } -// write out the frame buffer into a bitmap file -void -Pl111::writeBMP(uint32_t* frameBuffer) -{ - fstream pic; - - // write out bmp head - std::string filename = "./m5out/frameBuffer.bmp"; - pic.open(filename.c_str(), ios::out|ios::binary); - Bitmap bm(pic, height, width); - - DPRINTF(PL111, "-- write out data into bmp\n"); - - // write out frame buffer data - for (int i = height -1; i >= 0; --i) { - for (int j = 0; j< width; ++j) { - uint32_t pixel = frameBuffer[i*width + j]; - pic.write(reinterpret_cast(&pixel), - sizeof(uint32_t)); - DPRINTF(PL111, " write pixel data %#x at addr %#x\n", - pixel, i*width + j); - } - } - - pic.close(); -} - void Pl111::serialize(std::ostream &os) { @@ -490,9 +552,6 @@ Pl111::serialize(std::ostream &os) uint8_t lcdMis_serial = lcdMis; SERIALIZE_SCALAR(lcdMis_serial); - uint8_t lcdIcr_serial = lcdIcr; - SERIALIZE_SCALAR(lcdIcr_serial); - SERIALIZE_ARRAY(lcdPalette, LcdPaletteSize); SERIALIZE_ARRAY(cursorImage, CrsrImageSize); @@ -518,9 +577,9 @@ Pl111::serialize(std::ostream &os) SERIALIZE_SCALAR(clock); SERIALIZE_SCALAR(height); SERIALIZE_SCALAR(width); + SERIALIZE_SCALAR(bytesPerPixel); - SERIALIZE_ARRAY(dmaBuffer, height*width); - SERIALIZE_ARRAY(frameBuffer, height*width); + SERIALIZE_ARRAY(dmaBuffer, height * width); SERIALIZE_SCALAR(startTime); SERIALIZE_SCALAR(startAddr); SERIALIZE_SCALAR(maxAddr); @@ -569,10 +628,6 @@ Pl111::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(lcdMis_serial); lcdMis = lcdMis_serial; - uint8_t lcdIcr_serial; - UNSERIALIZE_SCALAR(lcdIcr_serial); - lcdIcr = lcdIcr_serial; - UNSERIALIZE_ARRAY(lcdPalette, LcdPaletteSize); UNSERIALIZE_ARRAY(cursorImage, CrsrImageSize); @@ -602,25 +657,29 @@ Pl111::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(clock); UNSERIALIZE_SCALAR(height); UNSERIALIZE_SCALAR(width); + UNSERIALIZE_SCALAR(bytesPerPixel); - UNSERIALIZE_ARRAY(dmaBuffer, height*width); - UNSERIALIZE_ARRAY(frameBuffer, height*width); + UNSERIALIZE_ARRAY(dmaBuffer, height * width); UNSERIALIZE_SCALAR(startTime); UNSERIALIZE_SCALAR(startAddr); UNSERIALIZE_SCALAR(maxAddr); UNSERIALIZE_SCALAR(curAddr); UNSERIALIZE_SCALAR(waterMark); UNSERIALIZE_SCALAR(dmaPendingNum); + + updateVideoParams(); + if (vncserver) + vncserver->setDirty(); } void Pl111::generateInterrupt() { DPRINTF(PL111, "Generate Interrupt: lcdImsc=0x%x lcdRis=0x%x lcdMis=0x%x\n", - lcdImsc, lcdRis, lcdMis); + (uint32_t)lcdImsc, (uint32_t)lcdRis, (uint32_t)lcdMis); lcdMis = lcdImsc & lcdRis; - if (lcdMis.ffufie || lcdMis.nbupie || lcdMis.vtcpie || lcdMis.ahmeie) { + if (lcdMis.underflow || lcdMis.baseaddr || lcdMis.vcomp || lcdMis.ahbmaster) { gic->sendInt(intNum); DPRINTF(PL111, " -- Generated\n"); } @@ -639,15 +698,4 @@ Pl111Params::create() return new Pl111(this); } -// bitmap class ctor -Bitmap::Bitmap(std::fstream& bmp, uint16_t h, uint16_t w) -{ - Magic magic = {{'B','M'}}; - Header header = {sizeof(Color)*w*h , 0, 0, 54}; - Info info = {sizeof(Info), w, h, 1, sizeof(Color)*8, 0, - ( sizeof(Color) *(w*h) ), 1, 1, 0, 0}; - bmp.write(reinterpret_cast(&magic), sizeof(magic)); - bmp.write(reinterpret_cast(&header), sizeof(header)); - bmp.write(reinterpret_cast(&info), sizeof(info)); -} diff --git a/src/dev/arm/pl111.hh b/src/dev/arm/pl111.hh index 4e75af4e84..f36dc68103 100644 --- a/src/dev/arm/pl111.hh +++ b/src/dev/arm/pl111.hh @@ -35,6 +35,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: William Wang + * Ali Saidi */ @@ -55,6 +56,8 @@ using namespace std; class Gic; +class VncServer; +class Bitmap; class Pl111: public AmbaDmaDevice { @@ -96,58 +99,69 @@ class Pl111: public AmbaDmaDevice static const int dmaSize = 8; // 64 bits static const int maxOutstandingDma = 16; // 16 deep FIFO of 64 bits + enum LcdMode { + bpp1 = 0, + bpp2, + bpp4, + bpp8, + bpp16, + bpp24, + bpp16m565, + bpp12 + }; + BitUnion8(InterruptReg) - Bitfield<1> ffufie; - Bitfield<2> nbupie; - Bitfield<3> vtcpie; - Bitfield<4> ahmeie; + Bitfield<1> underflow; + Bitfield<2> baseaddr; + Bitfield<3> vcomp; + Bitfield<4> ahbmaster; EndBitUnion(InterruptReg) BitUnion32(TimingReg0) - Bitfield<7,2> ppl; - Bitfield<15,8> hsw; - Bitfield<23,16> hfp; - Bitfield<31,24> hbp; + Bitfield<7,2> ppl; + Bitfield<15,8> hsw; + Bitfield<23,16> hfp; + Bitfield<31,24> hbp; EndBitUnion(TimingReg0) BitUnion32(TimingReg1) - Bitfield<9,0> lpp; - Bitfield<15,10> vsw; - Bitfield<23,16> vfp; - Bitfield<31,24> vbp; + Bitfield<9,0> lpp; + Bitfield<15,10> vsw; + Bitfield<23,16> vfp; + Bitfield<31,24> vbp; EndBitUnion(TimingReg1) BitUnion32(TimingReg2) - Bitfield<4,0> pcdlo; - Bitfield<5> clksel; - Bitfield<10,6> acb; - Bitfield<11> avs; - Bitfield<12> ihs; - Bitfield<13> ipc; - Bitfield<14> ioe; - Bitfield<25,16> cpl; - Bitfield<26> bcd; - Bitfield<31,27> pcdhi; + Bitfield<4,0> pcdlo; + Bitfield<5> clksel; + Bitfield<10,6> acb; + Bitfield<11> avs; + Bitfield<12> ihs; + Bitfield<13> ipc; + Bitfield<14> ioe; + Bitfield<25,16> cpl; + Bitfield<26> bcd; + Bitfield<31,27> pcdhi; EndBitUnion(TimingReg2) BitUnion32(TimingReg3) - Bitfield<6,0> led; - Bitfield<16> lee; + Bitfield<6,0> led; + Bitfield<16> lee; EndBitUnion(TimingReg3) BitUnion32(ControlReg) - Bitfield<0> lcden; - Bitfield<3,1> lcdbpp; - Bitfield<4> lcdbw; - Bitfield<5> lcdtft; - Bitfield<6> lcdmono8; - Bitfield<7> lcddual; - Bitfield<8> bgr; - Bitfield<9> bebo; - Bitfield<10> bepo; - Bitfield<11> lcdpwr; - Bitfield<13,12> lcdvcomp; - Bitfield<16> watermark; + Bitfield<0> lcden; + Bitfield<3,1> lcdbpp; + Bitfield<4> lcdbw; + Bitfield<5> lcdtft; + Bitfield<6> lcdmono8; + Bitfield<7> lcddual; + Bitfield<8> bgr; + Bitfield<9> bebo; + Bitfield<10> bepo; + Bitfield<11> lcdpwr; + Bitfield<13,12> lcdvcomp; + Bitfield<16> watermark; EndBitUnion(ControlReg) /** Horizontal axis panel control register */ @@ -180,15 +194,6 @@ class Pl111: public AmbaDmaDevice /** Masked interrupt status register */ InterruptReg lcdMis; - /** Interrupt clear register */ - InterruptReg lcdIcr; - - /** Upper panel current address value register - ro */ - int lcdUpcurr; - - /** Lower panel current address value register - ro */ - int lcdLpcurr; - /** 256x16-bit color palette registers * 256 palette entries organized as 128 locations of two entries per word */ int lcdPalette[LcdPaletteSize]; @@ -228,17 +233,26 @@ class Pl111: public AmbaDmaDevice /** Clock speed */ Tick clock; - /** Frame buffer height - lines per panel */ - uint16_t height; + /** VNC server */ + VncServer *vncserver; + + /** Helper to write out bitmaps */ + Bitmap *bmp; + + /** Picture of what the current frame buffer looks like */ + std::ostream *pic; /** Frame buffer width - pixels per line */ uint16_t width; - /** CLCDC supports up to 1024x768 */ - uint8_t dmaBuffer[LcdMaxWidth * LcdMaxHeight * sizeof(uint32_t)]; + /** Frame buffer height - lines per panel */ + uint16_t height; - /** Double buffering */ - uint32_t frameBuffer[LcdMaxWidth * LcdMaxHeight]; + /** Bytes per pixel */ + uint8_t bytesPerPixel; + + /** CLCDC supports up to 1024x768 */ + uint8_t *dmaBuffer; /** Start time for frame buffer dma read */ Tick startTime; @@ -258,12 +272,12 @@ class Pl111: public AmbaDmaDevice /** Number of pending dma reads */ int dmaPendingNum; + /** Send updated parameters to the vnc server */ + void updateVideoParams(); + /** DMA framebuffer read */ void readFramebuffer(); - /** Write framebuffer to a bmp file */ - void writeBMP(uint32_t*); - /** Generate dma framebuffer read event */ void generateReadEvent(); @@ -273,6 +287,9 @@ class Pl111: public AmbaDmaDevice /** fillFIFO event */ void fillFifo(); + /** start the dmas off after power is enabled */ + void startDma(); + /** DMA done event */ void dmaDone(); @@ -289,7 +306,7 @@ class Pl111: public AmbaDmaDevice /** DMA done event */ vector > dmaDoneEvent; - /** Wrapper to create an event out of the thing */ + /** Wrapper to create an event out of the interrupt */ EventWrapper intEvent; public: @@ -312,57 +329,6 @@ class Pl111: public AmbaDmaDevice * @param range_list range list to populate with ranges */ void addressRanges(AddrRangeList &range_list); - - /** - * Return if we have an interrupt pending - * @return interrupt status - * @todo fix me when implementation improves - */ - virtual bool intStatus() { return false; } -}; - -// write frame buffer into a bitmap picture -class Bitmap -{ - public: - Bitmap(std::fstream& bmp, uint16_t h, uint16_t w); - - private: - struct Magic - { - unsigned char magic_number[2]; - } magic; - - struct Header - { - uint32_t size; - uint16_t reserved1; - uint16_t reserved2; - uint32_t offset; - } header; - - struct Info - { - uint32_t Size; - uint32_t Width; - uint32_t Height; - uint16_t Planes; - uint16_t BitCount; - uint32_t Compression; - uint32_t SizeImage; - uint32_t XPelsPerMeter; - uint32_t YPelsPerMeter; - uint32_t ClrUsed; - uint32_t ClrImportant; - } info; - - struct Color - { - unsigned char b; - unsigned char g; - unsigned char r; - unsigned char a; - } color; }; #endif diff --git a/src/dev/arm/rv_ctrl.cc b/src/dev/arm/rv_ctrl.cc index c0ba4c7aa1..b1bbc065b4 100644 --- a/src/dev/arm/rv_ctrl.cc +++ b/src/dev/arm/rv_ctrl.cc @@ -68,6 +68,27 @@ RealViewCtrl::read(PacketPtr pkt) case Flash: pkt->set(0); break; + case Clcd: + pkt->set(0x00001F00); + break; + case Osc0: + pkt->set(0x00012C5C); + break; + case Osc1: + pkt->set(0x00002CC0); + break; + case Osc2: + pkt->set(0x00002C75); + break; + case Osc3: + pkt->set(0x00020211); + break; + case Osc4: + pkt->set(0x00002C75); + break; + case Lock: + pkt->set(sysLock); + break; default: panic("Tried to read RealView I/O at offset %#x that doesn't exist\n", daddr); break; @@ -85,6 +106,15 @@ RealViewCtrl::write(PacketPtr pkt) Addr daddr = pkt->getAddr() - pioAddr; switch (daddr) { case Flash: + case Clcd: + case Osc0: + case Osc1: + case Osc2: + case Osc3: + case Osc4: + break; + case Lock: + sysLock.lockVal = pkt->get(); break; default: panic("Tried to write RVIO at offset %#x that doesn't exist\n", daddr); diff --git a/src/dev/arm/rv_ctrl.hh b/src/dev/arm/rv_ctrl.hh index 00a19d7158..ceed5ef2f4 100644 --- a/src/dev/arm/rv_ctrl.hh +++ b/src/dev/arm/rv_ctrl.hh @@ -40,6 +40,7 @@ #ifndef __DEV_ARM_RV_HH__ #define __DEV_ARM_RV_HH__ +#include "base/bitunion.hh" #include "base/range.hh" #include "dev/io_device.hh" #include "params/RealViewCtrl.hh" @@ -86,6 +87,14 @@ class RealViewCtrl : public BasicPioDevice TestOsc4 = 0xD0 }; + // system lock value + BitUnion32(SysLockReg) + Bitfield<15,0> lockVal; + Bitfield<16> locked; + EndBitUnion(SysLockReg) + + SysLockReg sysLock; + public: typedef RealViewCtrlParams Params; const Params * @@ -120,4 +129,3 @@ class RealViewCtrl : public BasicPioDevice #endif // __DEV_ARM_RV_HH__ - diff --git a/src/dev/arm/timer_sp804.cc b/src/dev/arm/timer_sp804.cc index 04668d2685..e6d2657ea9 100644 --- a/src/dev/arm/timer_sp804.cc +++ b/src/dev/arm/timer_sp804.cc @@ -178,11 +178,11 @@ Sp804::Timer::restartCounter(uint32_t val) if (!control.timerEnable) return; - Tick time = clock << power(16, control.timerPrescale); + Tick time = clock * power(16, control.timerPrescale); if (control.timerSize) - time *= bits(val,15,0); - else time *= val; + else + time *= bits(val,15,0); if (zeroEvent.scheduled()) { DPRINTF(Timer, "-- Event was already schedule, de-scheduling\n"); diff --git a/src/dev/ps2.cc b/src/dev/ps2.cc new file mode 100644 index 0000000000..fe90ce6bc3 --- /dev/null +++ b/src/dev/ps2.cc @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2011 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * 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: Ali Saidi + */ + +#include +#include "x11keysym/keysym.h" + +#include "base/misc.hh" +#include "dev/ps2.hh" + + +namespace Ps2 { + +/** Table to convert simple key symbols (0x00XX) into ps2 bytes. Lower byte + * is the scan code to send and upper byte is if a modifier is required to + * generate it. The table generates us keyboard codes, (e.g. the guest is + * supposed to recognize the keyboard as en_US). A new table would be required + * for another locale. + */ + +static const uint16_t keySymToPs2Byte[128] = { +// 0 / 8 1 / 9 2 / A 3 / B 4 / C 5 / D 6 / E 7 / F + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x00-0x07 + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x08-0x0f + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x10-0x17 + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x18-0x1f + 0x0029, 0x0116, 0x0152, 0x0126, 0x0125, 0x012e, 0x013d, 0x0052, // 0x20-0x27 + 0x0146, 0x0145, 0x013e, 0x0155, 0x0041, 0x004e, 0x0049, 0x004a, // 0x28-0x2f + 0x0045, 0x0016, 0x001e, 0x0026, 0x0025, 0x002e, 0x0036, 0x003d, // 0x30-0x37 + 0x003e, 0x0046, 0x014c, 0x004c, 0x0141, 0x0055, 0x0149, 0x014a, // 0x38-0x3f + 0x011e, 0x011c, 0x0132, 0x0121, 0x0123, 0x0124, 0x012b, 0x0134, // 0x40-0x47 + 0x0133, 0x0143, 0x013b, 0x0142, 0x014b, 0x013a, 0x0131, 0x0144, // 0x48-0x4f + 0x014d, 0x0115, 0x012d, 0x011b, 0x012c, 0x013c, 0x012a, 0x011d, // 0x50-0x57 + 0x0122, 0x0135, 0x011a, 0x0054, 0x005d, 0x005b, 0x0136, 0x014e, // 0x58-0x5f + 0x000e, 0x001c, 0x0032, 0x0021, 0x0023, 0x0024, 0x002b, 0x0034, // 0x60-0x67 + 0x0033, 0x0043, 0x003b, 0x0042, 0x004b, 0x003a, 0x0031, 0x0044, // 0x68-0x6f + 0x004d, 0x0015, 0x002d, 0x001b, 0x002c, 0x003c, 0x002a, 0x001d, // 0x70-0x77 + 0x0022, 0x0035, 0x001a, 0x0154, 0x015d, 0x015b, 0x010e, 0x0000 // 0x78-0x7f +}; + +const uint8_t ShiftKey = 0x12; +const uint8_t BreakKey = 0xf0; +const uint8_t ExtendedKey = 0xe0; +const uint32_t UpperKeys = 0xff00; + +void +keySymToPs2(uint32_t key, bool down, bool &cur_shift, + std::list &keys) +{ + if (key <= XK_asciitilde) { + uint16_t tmp = keySymToPs2Byte[key]; + uint8_t code = tmp & 0xff; + bool shift = tmp >> 8; + + if (down) { + if (!cur_shift && shift) { + keys.push_back(ShiftKey); + cur_shift = true; + } + keys.push_back(code); + } else { + if (cur_shift && !shift) { + keys.push_back(BreakKey); + keys.push_back(ShiftKey); + cur_shift = false; + } + keys.push_back(BreakKey); + keys.push_back(code); + } + } else { + if ((key & UpperKeys) == UpperKeys) { + bool extended = false; + switch (key) { + case XK_BackSpace: + keys.push_back(0x66); + break; + case XK_Tab: + keys.push_back(0x0d); + break; + case XK_Return: + keys.push_back(0x5a); + break; + case XK_Escape: + keys.push_back(0x76); + break; + case XK_Delete: + extended = true; + keys.push_back(0x71); + break; + case XK_Home: + extended = true; + keys.push_back(0x6c); + break; + case XK_Left: + extended = true; + keys.push_back(0x6b); + break; + case XK_Right: + extended = true; + keys.push_back(0x74); + break; + case XK_Down: + extended = true; + keys.push_back(0x72); + break; + case XK_Up: + extended = true; + keys.push_back(0x75); + break; + case XK_Page_Up: + extended = true; + keys.push_back(0x7d); + break; + case XK_Page_Down: + extended = true; + keys.push_back(0x7a); + break; + case XK_End: + extended = true; + keys.push_back(0x69); + break; + case XK_Shift_L: + keys.push_back(0x12); + if (down) + cur_shift = true; + else + cur_shift = false; + break; + case XK_Shift_R: + keys.push_back(0x59); + if (down) + cur_shift = true; + else + cur_shift = false; + break; + case XK_Control_L: + keys.push_back(0x14); + break; + case XK_Control_R: + extended = true; + keys.push_back(0x14); + break; + default: + warn("Unknown extended key %#x\n", key); + return; + } + + if (extended) { + if (down) { + keys.push_front(ExtendedKey); + } else { + keys.push_front(BreakKey); + keys.push_front(ExtendedKey); + } + } else { + if (!down) + keys.push_front(BreakKey); + } + } // upper keys + } // extended keys + return; +} + +} /* namespace Ps2 */ + diff --git a/src/dev/ps2.hh b/src/dev/ps2.hh new file mode 100644 index 0000000000..73f3f9cd8c --- /dev/null +++ b/src/dev/ps2.hh @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2011 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * 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: Ali Saidi + */ + +#ifndef __DEV_PS2_HH__ +#define __DEV_PS2_HH__ + +#include + +#include "base/bitunion.hh" + +/** @file misc functions and constants required to interface with or emulate ps2 + * devices + */ + +namespace Ps2 { +enum { + Ps2Reset = 0xff, + SelfTestPass = 0xAA, + SetStatusLed = 0xed, + SetResolution = 0xe8, + StatusRequest = 0xe9, + SetScaling1_2 = 0xe7, + SetScaling1_1 = 0xe6, + ReadId = 0xf2, + TpReadId = 0xe1, + Ack = 0xfa, + SetRate = 0xf3, + Enable = 0xf4, + Disable = 0xf6, + KeyboardId = 0xab, + TouchKitId = 0x0a, + MouseId = 0x00, +}; + +/** A bitfield that represents the first byte of a mouse movement packet + */ +BitUnion8(Ps2MouseMovement) + Bitfield<0> leftButton; + Bitfield<1> rightButton; + Bitfield<2> middleButton; + Bitfield<3> one; + Bitfield<4> xSign; + Bitfield<5> ySign; + Bitfield<6> xOverflow; + Bitfield<7> yOverflow; +EndBitUnion(Ps2MouseMovement) + +/** Convert an x11 key symbol into a set of ps2 charecters. + * @param key x11 key symbol + * @param down if the key is being pressed or released + * @param cur_shift if device has already sent a shift + * @param keys list of keys command to send to emulate the x11 key symbol + */ +void keySymToPs2(uint32_t key, bool down, bool &cur_shift, + std::list &keys); + +} /* namespace Ps2 */ +#endif // __DEV_PS2_HH__ diff --git a/src/mem/protocol/MESI_CMP_directory-L1cache.sm b/src/mem/protocol/MESI_CMP_directory-L1cache.sm index 8744a71225..4442cee412 100644 --- a/src/mem/protocol/MESI_CMP_directory-L1cache.sm +++ b/src/mem/protocol/MESI_CMP_directory-L1cache.sm @@ -287,20 +287,21 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") if (in_msg.Type == CacheRequestType:IFETCH) { // ** INSTRUCTION ACCESS *** - // Check to see if it is in the OTHER L1 - Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress); - if (is_valid(L1Dcache_entry)) { - // The block is in the wrong L1, put the request on the queue to the shared L2 - trigger(Event:L1_Replacement, in_msg.LineAddress, - L1Dcache_entry, L1_TBEs[in_msg.LineAddress]); - } - Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress); if (is_valid(L1Icache_entry)) { // The tag matches for the L1, so the L1 asks the L2 for it. trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress, L1Icache_entry, L1_TBEs[in_msg.LineAddress]); } else { + + // Check to see if it is in the OTHER L1 + Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress); + if (is_valid(L1Dcache_entry)) { + // The block is in the wrong L1, put the request on the queue to the shared L2 + trigger(Event:L1_Replacement, in_msg.LineAddress, + L1Dcache_entry, L1_TBEs[in_msg.LineAddress]); + } + if (L1IcacheMemory.cacheAvail(in_msg.LineAddress)) { // L1 does't have the line, but we have space for it in the L1 so let's see if the L2 has it trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress, @@ -313,21 +314,23 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") } } } else { - // *** DATA ACCESS *** - // Check to see if it is in the OTHER L1 - Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress); - if (is_valid(L1Icache_entry)) { - // The block is in the wrong L1, put the request on the queue to the shared L2 - trigger(Event:L1_Replacement, in_msg.LineAddress, - L1Icache_entry, L1_TBEs[in_msg.LineAddress]); - } + // *** DATA ACCESS *** Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress); if (is_valid(L1Dcache_entry)) { // The tag matches for the L1, so the L1 ask the L2 for it trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress, L1Dcache_entry, L1_TBEs[in_msg.LineAddress]); } else { + + // Check to see if it is in the OTHER L1 + Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress); + if (is_valid(L1Icache_entry)) { + // The block is in the wrong L1, put the request on the queue to the shared L2 + trigger(Event:L1_Replacement, in_msg.LineAddress, + L1Icache_entry, L1_TBEs[in_msg.LineAddress]); + } + if (L1DcacheMemory.cacheAvail(in_msg.LineAddress)) { // L1 does't have the line, but we have space for it in the L1 let's see if the L2 has it trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress, diff --git a/src/mem/protocol/MOESI_CMP_directory-L1cache.sm b/src/mem/protocol/MOESI_CMP_directory-L1cache.sm index 4082f23c9f..e590c952ad 100644 --- a/src/mem/protocol/MOESI_CMP_directory-L1cache.sm +++ b/src/mem/protocol/MOESI_CMP_directory-L1cache.sm @@ -44,7 +44,6 @@ machine(L1Cache, "Directory protocol") // From this node's L1 cache TO the network // a local L1 -> this L2 bank, currently ordered with directory forwarded requests MessageBuffer requestFromL1Cache, network="To", virtual_network="0", ordered="false"; - MessageBuffer foo, network="To", virtual_network="1", ordered="false"; // a local L1 -> this L2 bank MessageBuffer responseFromL1Cache, network="To", virtual_network="2", ordered="false"; // MessageBuffer writebackFromL1Cache, network="To", virtual_network="3", ordered="false"; @@ -53,7 +52,6 @@ machine(L1Cache, "Directory protocol") // To this node's L1 cache FROM the network // a L2 bank -> this L1 MessageBuffer requestToL1Cache, network="From", virtual_network="0", ordered="false"; - MessageBuffer goo, network="From", virtual_network="1", ordered="false"; // a L2 bank -> this L1 MessageBuffer responseToL1Cache, network="From", virtual_network="2", ordered="false"; @@ -229,7 +227,6 @@ machine(L1Cache, "Directory protocol") out_port(requestNetwork_out, RequestMsg, requestFromL1Cache); out_port(responseNetwork_out, ResponseMsg, responseFromL1Cache); out_port(triggerQueue_out, TriggerMsg, triggerQueue); - out_port(foo_out, ResponseMsg, foo); // ** IN_PORTS ** @@ -242,15 +239,6 @@ machine(L1Cache, "Directory protocol") } } - - in_port(goo_in, RequestMsg, goo) { - if (goo_in.isReady()) { - peek(goo_in, RequestMsg) { - assert(false); - } - } - } - // Trigger Queue in_port(triggerQueue_in, TriggerMsg, triggerQueue) { if (triggerQueue_in.isReady()) { @@ -338,14 +326,6 @@ machine(L1Cache, "Directory protocol") if (in_msg.Type == CacheRequestType:IFETCH) { // ** INSTRUCTION ACCESS *** - Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress); - // Check to see if it is in the OTHER L1 - if (is_valid(L1Dcache_entry)) { - // The block is in the wrong L1, put the request on the queue to the shared L2 - trigger(Event:L1_Replacement, in_msg.LineAddress, L1Dcache_entry, - TBEs[in_msg.LineAddress]); - } - Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress); if (is_valid(L1Icache_entry)) { // The tag matches for the L1, so the L1 asks the L2 for it. @@ -353,6 +333,14 @@ machine(L1Cache, "Directory protocol") in_msg.LineAddress, L1Icache_entry, TBEs[in_msg.LineAddress]); } else { + + Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress); + // Check to see if it is in the OTHER L1 + if (is_valid(L1Dcache_entry)) { + // The block is in the wrong L1, put the request on the queue to the shared L2 + trigger(Event:L1_Replacement, in_msg.LineAddress, L1Dcache_entry, + TBEs[in_msg.LineAddress]); + } if (L1IcacheMemory.cacheAvail(in_msg.LineAddress)) { // L1 does't have the line, but we have space for it in the L1 so let's see if the L2 has it trigger(mandatory_request_type_to_event(in_msg.Type), @@ -369,14 +357,6 @@ machine(L1Cache, "Directory protocol") } else { // *** DATA ACCESS *** - Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress); - // Check to see if it is in the OTHER L1 - if (is_valid(L1Icache_entry)) { - // The block is in the wrong L1, put the request on the queue to the shared L2 - trigger(Event:L1_Replacement, in_msg.LineAddress, - L1Icache_entry, TBEs[in_msg.LineAddress]); - } - Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress); if (is_valid(L1Dcache_entry)) { // The tag matches for the L1, so the L1 ask the L2 for it @@ -384,6 +364,14 @@ machine(L1Cache, "Directory protocol") in_msg.LineAddress, L1Dcache_entry, TBEs[in_msg.LineAddress]); } else { + + Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress); + // Check to see if it is in the OTHER L1 + if (is_valid(L1Icache_entry)) { + // The block is in the wrong L1, put the request on the queue to the shared L2 + trigger(Event:L1_Replacement, in_msg.LineAddress, + L1Icache_entry, TBEs[in_msg.LineAddress]); + } if (L1DcacheMemory.cacheAvail(in_msg.LineAddress)) { // L1 does't have the line, but we have space for it in the L1 let's see if the L2 has it trigger(mandatory_request_type_to_event(in_msg.Type), @@ -411,6 +399,7 @@ machine(L1Cache, "Directory protocol") out_msg.Address := address; out_msg.Type := CoherenceRequestType:GETS; out_msg.Requestor := machineID; + out_msg.RequestorMachine := MachineType:L1Cache; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, l2_select_low_bit, l2_select_num_bits)); out_msg.MessageSize := MessageSizeType:Request_Control; @@ -455,6 +444,7 @@ machine(L1Cache, "Directory protocol") out_msg.Address := address; out_msg.Type := CoherenceRequestType:PUTO; out_msg.Requestor := machineID; + out_msg.RequestorMachine := MachineType:L1Cache; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, l2_select_low_bit, l2_select_num_bits)); out_msg.MessageSize := MessageSizeType:Writeback_Control; @@ -467,6 +457,7 @@ machine(L1Cache, "Directory protocol") out_msg.Address := address; out_msg.Type := CoherenceRequestType:PUTS; out_msg.Requestor := machineID; + out_msg.RequestorMachine := MachineType:L1Cache; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, l2_select_low_bit, l2_select_num_bits)); out_msg.MessageSize := MessageSizeType:Writeback_Control; @@ -481,6 +472,7 @@ machine(L1Cache, "Directory protocol") out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; out_msg.Sender := machineID; + out_msg.SenderMachine := MachineType:L1Cache; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, l2_select_low_bit, l2_select_num_bits)); out_msg.DataBlk := cache_entry.DataBlk; @@ -496,6 +488,7 @@ machine(L1Cache, "Directory protocol") out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; out_msg.Sender := machineID; + out_msg.SenderMachine := MachineType:L1Cache; out_msg.Destination.add(in_msg.Requestor); out_msg.DataBlk := cache_entry.DataBlk; // out_msg.Dirty := cache_entry.Dirty; @@ -514,6 +507,7 @@ machine(L1Cache, "Directory protocol") out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; out_msg.Sender := machineID; + out_msg.SenderMachine := MachineType:L1Cache; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, l2_select_low_bit, l2_select_num_bits)); out_msg.DataBlk := cache_entry.DataBlk; @@ -592,6 +586,7 @@ machine(L1Cache, "Directory protocol") out_msg.Address := address; out_msg.Type := CoherenceResponseType:UNBLOCK; out_msg.Sender := machineID; + out_msg.SenderMachine := MachineType:L1Cache; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, l2_select_low_bit, l2_select_num_bits)); out_msg.MessageSize := MessageSizeType:Unblock_Control; @@ -690,6 +685,7 @@ machine(L1Cache, "Directory protocol") out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; out_msg.Sender := machineID; + out_msg.SenderMachine := MachineType:L1Cache; out_msg.Destination.add(in_msg.Requestor); out_msg.DataBlk := tbe.DataBlk; // out_msg.Dirty := tbe.Dirty; @@ -703,6 +699,7 @@ machine(L1Cache, "Directory protocol") out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; out_msg.Sender := machineID; + out_msg.SenderMachine := MachineType:L1Cache; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, l2_select_low_bit, l2_select_num_bits)); out_msg.DataBlk := tbe.DataBlk; @@ -723,6 +720,7 @@ machine(L1Cache, "Directory protocol") out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE; out_msg.Sender := machineID; + out_msg.SenderMachine := MachineType:L1Cache; out_msg.Destination.add(in_msg.Requestor); out_msg.DataBlk := tbe.DataBlk; out_msg.Dirty := tbe.Dirty; @@ -735,6 +733,7 @@ machine(L1Cache, "Directory protocol") out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE; out_msg.Sender := machineID; + out_msg.SenderMachine := MachineType:L1Cache; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, l2_select_low_bit, l2_select_num_bits)); out_msg.DataBlk := tbe.DataBlk; diff --git a/src/mem/protocol/MOESI_CMP_token-L1cache.sm b/src/mem/protocol/MOESI_CMP_token-L1cache.sm index 00e9404c9b..226f213744 100644 --- a/src/mem/protocol/MOESI_CMP_token-L1cache.sm +++ b/src/mem/protocol/MOESI_CMP_token-L1cache.sm @@ -647,20 +647,21 @@ machine(L1Cache, "Token protocol") if (in_msg.Type == CacheRequestType:IFETCH) { // ** INSTRUCTION ACCESS *** - // Check to see if it is in the OTHER L1 - Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress); - if (is_valid(L1Dcache_entry)) { - // The block is in the wrong L1, try to write it to the L2 - trigger(Event:L1_Replacement, in_msg.LineAddress, - L1Dcache_entry, tbe); - } - Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress); if (is_valid(L1Icache_entry)) { // The tag matches for the L1, so the L1 fetches the line. We know it can't be in the L2 due to exclusion trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress, L1Icache_entry, tbe); } else { + + // Check to see if it is in the OTHER L1 + Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress); + if (is_valid(L1Dcache_entry)) { + // The block is in the wrong L1, try to write it to the L2 + trigger(Event:L1_Replacement, in_msg.LineAddress, + L1Dcache_entry, tbe); + } + if (L1IcacheMemory.cacheAvail(in_msg.LineAddress)) { // L1 does't have the line, but we have space for it in the L1 trigger(mandatory_request_type_to_event(in_msg.Type), @@ -676,21 +677,21 @@ machine(L1Cache, "Token protocol") } else { // *** DATA ACCESS *** - // Check to see if it is in the OTHER L1 - Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress); - - if (is_valid(L1Icache_entry)) { - // The block is in the wrong L1, try to write it to the L2 - trigger(Event:L1_Replacement, in_msg.LineAddress, - L1Icache_entry, tbe); - } - Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress); if (is_valid(L1Dcache_entry)) { // The tag matches for the L1, so the L1 fetches the line. We know it can't be in the L2 due to exclusion trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress, L1Dcache_entry, tbe); } else { + + // Check to see if it is in the OTHER L1 + Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress); + if (is_valid(L1Icache_entry)) { + // The block is in the wrong L1, try to write it to the L2 + trigger(Event:L1_Replacement, in_msg.LineAddress, + L1Icache_entry, tbe); + } + if (L1DcacheMemory.cacheAvail(in_msg.LineAddress)) { // L1 does't have the line, but we have space for it in the L1 trigger(mandatory_request_type_to_event(in_msg.Type), diff --git a/src/mem/protocol/MOESI_hammer-cache.sm b/src/mem/protocol/MOESI_hammer-cache.sm index 26598f5418..f9d5ffcab2 100644 --- a/src/mem/protocol/MOESI_hammer-cache.sm +++ b/src/mem/protocol/MOESI_hammer-cache.sm @@ -377,26 +377,26 @@ machine(L1Cache, "AMD Hammer-like protocol") if (in_msg.Type == CacheRequestType:IFETCH) { // ** INSTRUCTION ACCESS *** - // Check to see if it is in the OTHER L1 - Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress); - if (is_valid(L1Dcache_entry)) { - // The block is in the wrong L1, try to write it to the L2 - if (L2cacheMemory.cacheAvail(in_msg.LineAddress)) { - trigger(Event:L1_to_L2, in_msg.LineAddress, L1Dcache_entry, tbe); - } else { - trigger(Event:L2_Replacement, - L2cacheMemory.cacheProbe(in_msg.LineAddress), - getL2CacheEntry(L2cacheMemory.cacheProbe(in_msg.LineAddress)), - TBEs[L2cacheMemory.cacheProbe(in_msg.LineAddress)]); - } - } - Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress); if (is_valid(L1Icache_entry)) { // The tag matches for the L1, so the L1 fetches the line. We know it can't be in the L2 due to exclusion trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress, L1Icache_entry, tbe); } else { + // Check to see if it is in the OTHER L1 + Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress); + if (is_valid(L1Dcache_entry)) { + // The block is in the wrong L1, try to write it to the L2 + if (L2cacheMemory.cacheAvail(in_msg.LineAddress)) { + trigger(Event:L1_to_L2, in_msg.LineAddress, L1Dcache_entry, tbe); + } else { + trigger(Event:L2_Replacement, + L2cacheMemory.cacheProbe(in_msg.LineAddress), + getL2CacheEntry(L2cacheMemory.cacheProbe(in_msg.LineAddress)), + TBEs[L2cacheMemory.cacheProbe(in_msg.LineAddress)]); + } + } + if (L1IcacheMemory.cacheAvail(in_msg.LineAddress)) { // L1 does't have the line, but we have space for it in the L1 @@ -430,26 +430,27 @@ machine(L1Cache, "AMD Hammer-like protocol") } else { // *** DATA ACCESS *** - // Check to see if it is in the OTHER L1 - Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress); - if (is_valid(L1Icache_entry)) { - // The block is in the wrong L1, try to write it to the L2 - if (L2cacheMemory.cacheAvail(in_msg.LineAddress)) { - trigger(Event:L1_to_L2, in_msg.LineAddress, L1Icache_entry, tbe); - } else { - trigger(Event:L2_Replacement, - L2cacheMemory.cacheProbe(in_msg.LineAddress), - getL2CacheEntry(L2cacheMemory.cacheProbe(in_msg.LineAddress)), - TBEs[L2cacheMemory.cacheProbe(in_msg.LineAddress)]); - } - } - Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress); if (is_valid(L1Dcache_entry)) { // The tag matches for the L1, so the L1 fetches the line. We know it can't be in the L2 due to exclusion trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress, L1Dcache_entry, tbe); } else { + + // Check to see if it is in the OTHER L1 + Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress); + if (is_valid(L1Icache_entry)) { + // The block is in the wrong L1, try to write it to the L2 + if (L2cacheMemory.cacheAvail(in_msg.LineAddress)) { + trigger(Event:L1_to_L2, in_msg.LineAddress, L1Icache_entry, tbe); + } else { + trigger(Event:L2_Replacement, + L2cacheMemory.cacheProbe(in_msg.LineAddress), + getL2CacheEntry(L2cacheMemory.cacheProbe(in_msg.LineAddress)), + TBEs[L2cacheMemory.cacheProbe(in_msg.LineAddress)]); + } + } + if (L1DcacheMemory.cacheAvail(in_msg.LineAddress)) { // L1 does't have the line, but we have space for it in the L1 Entry L2cache_entry := getL2CacheEntry(in_msg.LineAddress); diff --git a/src/mem/ruby/buffers/MessageBuffer.cc b/src/mem/ruby/buffers/MessageBuffer.cc index f6b79c5803..2255950053 100644 --- a/src/mem/ruby/buffers/MessageBuffer.cc +++ b/src/mem/ruby/buffers/MessageBuffer.cc @@ -58,6 +58,8 @@ MessageBuffer::MessageBuffer(const string &name) m_name = name; m_stall_msg_map.clear(); + m_input_link_id = 0; + m_vnet_id = 0; } int @@ -228,6 +230,7 @@ MessageBuffer::enqueue(MsgPtr message, Time delta) // Schedule the wakeup if (m_consumer_ptr != NULL) { g_eventQueue_ptr->scheduleEventAbsolute(m_consumer_ptr, arrival_time); + m_consumer_ptr->storeEventInfo(m_vnet_id); } else { panic("No consumer: %s name: %s\n", *this, m_name); } diff --git a/src/mem/ruby/buffers/MessageBuffer.hh b/src/mem/ruby/buffers/MessageBuffer.hh index 62cc656701..88df5b788e 100644 --- a/src/mem/ruby/buffers/MessageBuffer.hh +++ b/src/mem/ruby/buffers/MessageBuffer.hh @@ -142,6 +142,9 @@ class MessageBuffer void printStats(std::ostream& out); void clearStats() { m_not_avail_count = 0; m_msg_counter = 0; } + void setIncomingLink(int link_id) { m_input_link_id = link_id; } + void setVnet(int net) { m_vnet_id = net; } + private: //added by SS int m_recycle_latency; @@ -184,6 +187,9 @@ class MessageBuffer bool m_ordering_set; bool m_randomization; Time m_last_arrival_time; + + int m_input_link_id; + int m_vnet_id; }; inline std::ostream& diff --git a/src/mem/ruby/common/Consumer.hh b/src/mem/ruby/common/Consumer.hh index c1f8bc42e6..a119abb390 100644 --- a/src/mem/ruby/common/Consumer.hh +++ b/src/mem/ruby/common/Consumer.hh @@ -67,6 +67,7 @@ class Consumer virtual void wakeup() = 0; virtual void print(std::ostream& out) const = 0; + virtual void storeEventInfo(int info) {} const Time& getLastScheduledWakeup() const diff --git a/src/mem/ruby/network/simple/PerfectSwitch.cc b/src/mem/ruby/network/simple/PerfectSwitch.cc index 7229c724f0..5c461c63fe 100644 --- a/src/mem/ruby/network/simple/PerfectSwitch.cc +++ b/src/mem/ruby/network/simple/PerfectSwitch.cc @@ -54,6 +54,11 @@ PerfectSwitch::PerfectSwitch(SwitchID sid, SimpleNetwork* network_ptr) m_round_robin_start = 0; m_network_ptr = network_ptr; m_wakeups_wo_switch = 0; + + for(int i = 0;i < m_virtual_networks;++i) + { + m_pending_message_count.push_back(0); + } } void @@ -62,12 +67,15 @@ PerfectSwitch::addInPort(const vector& in) assert(in.size() == m_virtual_networks); NodeID port = m_in.size(); m_in.push_back(in); + for (int j = 0; j < m_virtual_networks; j++) { m_in[port][j]->setConsumer(this); string desc = csprintf("[Queue from port %s %s %s to PerfectSwitch]", NodeIDToString(m_switch_id), NodeIDToString(port), NodeIDToString(j)); m_in[port][j]->setDescription(desc); + m_in[port][j]->setIncomingLink(port); + m_in[port][j]->setVnet(j); } } @@ -154,160 +162,169 @@ PerfectSwitch::wakeup() m_round_robin_start = 0; } - // for all input ports, use round robin scheduling - for (int counter = 0; counter < m_in.size(); counter++) { - // Round robin scheduling - incoming++; - if (incoming >= m_in.size()) { - incoming = 0; - } - - // temporary vectors to store the routing results - vector output_links; - vector output_link_destinations; - - // Is there a message waiting? - while (m_in[incoming][vnet]->isReady()) { - DPRINTF(RubyNetwork, "incoming: %d\n", incoming); - - // Peek at message - msg_ptr = m_in[incoming][vnet]->peekMsgPtr(); - net_msg_ptr = safe_cast(msg_ptr.get()); - DPRINTF(RubyNetwork, "Message: %s\n", (*net_msg_ptr)); - - output_links.clear(); - output_link_destinations.clear(); - NetDest msg_dsts = - net_msg_ptr->getInternalDestination(); - - // Unfortunately, the token-protocol sends some - // zero-destination messages, so this assert isn't valid - // assert(msg_dsts.count() > 0); - - assert(m_link_order.size() == m_routing_table.size()); - assert(m_link_order.size() == m_out.size()); - - if (m_network_ptr->getAdaptiveRouting()) { - if (m_network_ptr->isVNetOrdered(vnet)) { - // Don't adaptively route - for (int out = 0; out < m_out.size(); out++) { - m_link_order[out].m_link = out; - m_link_order[out].m_value = 0; - } - } else { - // Find how clogged each link is - for (int out = 0; out < m_out.size(); out++) { - int out_queue_length = 0; - for (int v = 0; v < m_virtual_networks; v++) { - out_queue_length += m_out[out][v]->getSize(); - } - int value = - (out_queue_length << 8) | (random() & 0xff); - m_link_order[out].m_link = out; - m_link_order[out].m_value = value; - } - - // Look at the most empty link first - sort(m_link_order.begin(), m_link_order.end()); - } + if(m_pending_message_count[vnet] > 0) { + // for all input ports, use round robin scheduling + for (int counter = 0; counter < m_in.size(); counter++) { + // Round robin scheduling + incoming++; + if (incoming >= m_in.size()) { + incoming = 0; } - for (int i = 0; i < m_routing_table.size(); i++) { - // pick the next link to look at - int link = m_link_order[i].m_link; - NetDest dst = m_routing_table[link]; - DPRINTF(RubyNetwork, "dst: %s\n", dst); + // temporary vectors to store the routing results + vector output_links; + vector output_link_destinations; - if (!msg_dsts.intersectionIsNotEmpty(dst)) - continue; + // Is there a message waiting? + while (m_in[incoming][vnet]->isReady()) { + DPRINTF(RubyNetwork, "incoming: %d\n", incoming); - // Remember what link we're using - output_links.push_back(link); - - // Need to remember which destinations need this - // message in another vector. This Set is the - // intersection of the routing_table entry and the - // current destination set. The intersection must - // not be empty, since we are inside "if" - output_link_destinations.push_back(msg_dsts.AND(dst)); - - // Next, we update the msg_destination not to - // include those nodes that were already handled - // by this link - msg_dsts.removeNetDest(dst); - } - - assert(msg_dsts.count() == 0); - //assert(output_links.size() > 0); - - // Check for resources - for all outgoing queues - bool enough = true; - for (int i = 0; i < output_links.size(); i++) { - int outgoing = output_links[i]; - if (!m_out[outgoing][vnet]->areNSlotsAvailable(1)) - enough = false; - DPRINTF(RubyNetwork, "Checking if node is blocked\n" - "outgoing: %d, vnet: %d, enough: %d\n", - outgoing, vnet, enough); - } - - // There were not enough resources - if (!enough) { - g_eventQueue_ptr->scheduleEvent(this, 1); - DPRINTF(RubyNetwork, "Can't deliver message since a node " - "is blocked\n" - "Message: %s\n", (*net_msg_ptr)); - break; // go to next incoming port - } - - MsgPtr unmodified_msg_ptr; - - if (output_links.size() > 1) { - // If we are sending this message down more than - // one link (size>1), we need to make a copy of - // the message so each branch can have a different - // internal destination we need to create an - // unmodified MsgPtr because the MessageBuffer - // enqueue func will modify the message - - // This magic line creates a private copy of the - // message - unmodified_msg_ptr = msg_ptr->clone(); - } - - // Enqueue it - for all outgoing queues - for (int i=0; i 0) { - // create a private copy of the unmodified - // message - msg_ptr = unmodified_msg_ptr->clone(); - } - - // Change the internal destination set of the - // message so it knows which destinations this - // link is responsible for. + // Peek at message + msg_ptr = m_in[incoming][vnet]->peekMsgPtr(); net_msg_ptr = safe_cast(msg_ptr.get()); - net_msg_ptr->getInternalDestination() = - output_link_destinations[i]; + DPRINTF(RubyNetwork, "Message: %s\n", (*net_msg_ptr)); - // Enqeue msg - DPRINTF(RubyNetwork, "Switch: %d enqueuing net msg from " - "inport[%d][%d] to outport [%d][%d] time: %lld.\n", - m_switch_id, incoming, vnet, outgoing, vnet, - g_eventQueue_ptr->getTime()); + output_links.clear(); + output_link_destinations.clear(); + NetDest msg_dsts = + net_msg_ptr->getInternalDestination(); - m_out[outgoing][vnet]->enqueue(msg_ptr); + // Unfortunately, the token-protocol sends some + // zero-destination messages, so this assert isn't valid + // assert(msg_dsts.count() > 0); + + assert(m_link_order.size() == m_routing_table.size()); + assert(m_link_order.size() == m_out.size()); + + if (m_network_ptr->getAdaptiveRouting()) { + if (m_network_ptr->isVNetOrdered(vnet)) { + // Don't adaptively route + for (int out = 0; out < m_out.size(); out++) { + m_link_order[out].m_link = out; + m_link_order[out].m_value = 0; + } + } else { + // Find how clogged each link is + for (int out = 0; out < m_out.size(); out++) { + int out_queue_length = 0; + for (int v = 0; v < m_virtual_networks; v++) { + out_queue_length += m_out[out][v]->getSize(); + } + int value = + (out_queue_length << 8) | (random() & 0xff); + m_link_order[out].m_link = out; + m_link_order[out].m_value = value; + } + + // Look at the most empty link first + sort(m_link_order.begin(), m_link_order.end()); + } + } + + for (int i = 0; i < m_routing_table.size(); i++) { + // pick the next link to look at + int link = m_link_order[i].m_link; + NetDest dst = m_routing_table[link]; + DPRINTF(RubyNetwork, "dst: %s\n", dst); + + if (!msg_dsts.intersectionIsNotEmpty(dst)) + continue; + + // Remember what link we're using + output_links.push_back(link); + + // Need to remember which destinations need this + // message in another vector. This Set is the + // intersection of the routing_table entry and the + // current destination set. The intersection must + // not be empty, since we are inside "if" + output_link_destinations.push_back(msg_dsts.AND(dst)); + + // Next, we update the msg_destination not to + // include those nodes that were already handled + // by this link + msg_dsts.removeNetDest(dst); + } + + assert(msg_dsts.count() == 0); + //assert(output_links.size() > 0); + + // Check for resources - for all outgoing queues + bool enough = true; + for (int i = 0; i < output_links.size(); i++) { + int outgoing = output_links[i]; + if (!m_out[outgoing][vnet]->areNSlotsAvailable(1)) + enough = false; + DPRINTF(RubyNetwork, "Checking if node is blocked\n" + "outgoing: %d, vnet: %d, enough: %d\n", + outgoing, vnet, enough); + } + + // There were not enough resources + if (!enough) { + g_eventQueue_ptr->scheduleEvent(this, 1); + DPRINTF(RubyNetwork, "Can't deliver message since a node " + "is blocked\n" + "Message: %s\n", (*net_msg_ptr)); + break; // go to next incoming port + } + + MsgPtr unmodified_msg_ptr; + + if (output_links.size() > 1) { + // If we are sending this message down more than + // one link (size>1), we need to make a copy of + // the message so each branch can have a different + // internal destination we need to create an + // unmodified MsgPtr because the MessageBuffer + // enqueue func will modify the message + + // This magic line creates a private copy of the + // message + unmodified_msg_ptr = msg_ptr->clone(); + } + + // Enqueue it - for all outgoing queues + for (int i=0; i 0) { + // create a private copy of the unmodified + // message + msg_ptr = unmodified_msg_ptr->clone(); + } + + // Change the internal destination set of the + // message so it knows which destinations this + // link is responsible for. + net_msg_ptr = safe_cast(msg_ptr.get()); + net_msg_ptr->getInternalDestination() = + output_link_destinations[i]; + + // Enqeue msg + DPRINTF(RubyNetwork, "Switch: %d enqueuing net msg from " + "inport[%d][%d] to outport [%d][%d] time: %lld.\n", + m_switch_id, incoming, vnet, outgoing, vnet, + g_eventQueue_ptr->getTime()); + + m_out[outgoing][vnet]->enqueue(msg_ptr); + } + + // Dequeue msg + m_in[incoming][vnet]->pop(); + m_pending_message_count[vnet]--; } - - // Dequeue msg - m_in[incoming][vnet]->pop(); } } } } +void +PerfectSwitch::storeEventInfo(int info) +{ + m_pending_message_count[info]++; +} + void PerfectSwitch::printStats(std::ostream& out) const { diff --git a/src/mem/ruby/network/simple/PerfectSwitch.hh b/src/mem/ruby/network/simple/PerfectSwitch.hh index a7e577df01..cd0219fd9f 100644 --- a/src/mem/ruby/network/simple/PerfectSwitch.hh +++ b/src/mem/ruby/network/simple/PerfectSwitch.hh @@ -69,6 +69,7 @@ class PerfectSwitch : public Consumer int getOutLinks() const { return m_out.size(); } void wakeup(); + void storeEventInfo(int info); void printStats(std::ostream& out) const; void clearStats(); @@ -92,6 +93,7 @@ class PerfectSwitch : public Consumer int m_round_robin_start; int m_wakeups_wo_switch; SimpleNetwork* m_network_ptr; + std::vector m_pending_message_count; }; inline std::ostream& diff --git a/src/mem/ruby/slicc_interface/Message.hh b/src/mem/ruby/slicc_interface/Message.hh index ff94fdd409..7fcfabe9ca 100644 --- a/src/mem/ruby/slicc_interface/Message.hh +++ b/src/mem/ruby/slicc_interface/Message.hh @@ -57,6 +57,8 @@ class Message : public RefCounted virtual Message* clone() const = 0; virtual void print(std::ostream& out) const = 0; + virtual void setIncomingLink(int) {} + virtual void setVnet(int) {} void setDelayedCycles(const int& cycles) { m_DelayedCycles = cycles; } const int& getDelayedCycles() const {return m_DelayedCycles;} diff --git a/src/mem/ruby/slicc_interface/NetworkMessage.hh b/src/mem/ruby/slicc_interface/NetworkMessage.hh index 082481e054..a8f9c625b3 100644 --- a/src/mem/ruby/slicc_interface/NetworkMessage.hh +++ b/src/mem/ruby/slicc_interface/NetworkMessage.hh @@ -82,9 +82,16 @@ class NetworkMessage : public Message virtual void print(std::ostream& out) const = 0; + int getIncomingLink() const { return incoming_link; } + void setIncomingLink(int link) { incoming_link = link; } + int getVnet() const { return vnet; } + void setVnet(int net) { vnet = net; } + private: NetDest m_internal_dest; bool m_internal_dest_valid; + int incoming_link; + int vnet; }; inline std::ostream& diff --git a/src/python/m5/main.py b/src/python/m5/main.py index cd139ccb39..23a012166a 100644 --- a/src/python/m5/main.py +++ b/src/python/m5/main.py @@ -61,8 +61,6 @@ add_option('-C', "--copyright", action="store_true", default=False, help="Show full copyright information") add_option('-R', "--readme", action="store_true", default=False, help="Show the readme") -add_option('-N', "--release-notes", action="store_true", default=False, - help="Show the release notes") # Options for configuring the base simulator add_option('-d', "--outdir", metavar="DIR", default="m5out", @@ -207,13 +205,6 @@ def main(): print info.README print - if options.release_notes: - done = True - print 'Release Notes:' - print - print info.RELEASE_NOTES - print - if options.trace_help: done = True check_tracing() diff --git a/src/sim/root.cc b/src/sim/root.cc index 1dc9b60586..d51fcbda60 100644 --- a/src/sim/root.cc +++ b/src/sim/root.cc @@ -108,7 +108,18 @@ Root::Root(RootParams *p) : SimObject(p), _enabled(false), assert(_root == NULL); _root = this; lastTime.setTimer(); - timeSyncEnable(p->time_sync_enable); +} + +void +Root::initState() +{ + timeSyncEnable(params()->time_sync_enable); +} + +void +Root::loadState(Checkpoint *cp) +{ + timeSyncEnable(params()->time_sync_enable); } Root * diff --git a/src/sim/root.hh b/src/sim/root.hh index 2beced9d4a..76a508c194 100644 --- a/src/sim/root.hh +++ b/src/sim/root.hh @@ -95,7 +95,22 @@ class Root : public SimObject /// Set the threshold for time remaining to spin wait. void timeSyncSpinThreshold(Time newThreshold); - Root(RootParams *p); + typedef RootParams Params; + const Params * + params() const + { + return dynamic_cast(_params); + } + + Root(Params *p); + + /** Schedule the timesync event at loadState() so that curTick is correct + */ + void loadState(Checkpoint *cp); + + /** Schedule the timesync event at initState() when not unserializing + */ + void initState(); }; #endif // __SIM_ROOT_HH__ diff --git a/src/sim/serialize.cc b/src/sim/serialize.cc index d28f335beb..44fe7b2e7f 100644 --- a/src/sim/serialize.cc +++ b/src/sim/serialize.cc @@ -201,6 +201,23 @@ arrayParamOut(ostream &os, const string &name, const vector ¶m) os << "\n"; } +template +void +arrayParamOut(ostream &os, const string &name, const list ¶m) +{ + typename list::const_iterator it = param.begin(); + + os << name << "="; + if (param.size() > 0) + showParam(os, *it); + it++; + while (it != param.end()) { + os << " "; + showParam(os, *it); + it++; + } + os << "\n"; +} template void @@ -326,6 +343,37 @@ arrayParamIn(Checkpoint *cp, const string §ion, } } +template +void +arrayParamIn(Checkpoint *cp, const string §ion, + const string &name, list ¶m) +{ + string str; + if (!cp->find(section, name, str)) { + fatal("Can't unserialize '%s:%s'\n", section, name); + } + param.clear(); + + vector tokens; + tokenize(tokens, str, ' '); + + for (vector::size_type i = 0; i < tokens.size(); i++) { + T scalar_value = 0; + if (!parseParam(tokens[i], scalar_value)) { + string err("could not parse \""); + + err += str; + err += "\""; + + fatal(err); + } + + // assign parsed value to vector + param.push_back(scalar_value); + } +} + + void objParamIn(Checkpoint *cp, const string §ion, const string &name, SimObject * ¶m) @@ -356,7 +404,13 @@ arrayParamOut(ostream &os, const string &name, \ const vector ¶m); \ template void \ arrayParamIn(Checkpoint *cp, const string §ion, \ - const string &name, vector ¶m); + const string &name, vector ¶m); \ +template void \ +arrayParamOut(ostream &os, const string &name, \ + const list ¶m); \ +template void \ +arrayParamIn(Checkpoint *cp, const string §ion, \ + const string &name, list ¶m); INSTANTIATE_PARAM_TEMPLATES(char) INSTANTIATE_PARAM_TEMPLATES(signed char) diff --git a/src/sim/serialize.hh b/src/sim/serialize.hh index 5ea632ea4b..6be8ce3b6e 100644 --- a/src/sim/serialize.hh +++ b/src/sim/serialize.hh @@ -69,6 +69,10 @@ template void arrayParamOut(std::ostream &os, const std::string &name, const std::vector ¶m); +template +void arrayParamOut(std::ostream &os, const std::string &name, + const std::list ¶m); + template void arrayParamIn(Checkpoint *cp, const std::string §ion, const std::string &name, T *param, unsigned size); @@ -77,6 +81,10 @@ template void arrayParamIn(Checkpoint *cp, const std::string §ion, const std::string &name, std::vector ¶m); +template +void arrayParamIn(Checkpoint *cp, const std::string §ion, + const std::string &name, std::list ¶m); + void objParamIn(Checkpoint *cp, const std::string §ion, const std::string &name, SimObject * ¶m); diff --git a/src/sim/tlb.hh b/src/sim/tlb.hh index 1512bc0fae..253f120720 100644 --- a/src/sim/tlb.hh +++ b/src/sim/tlb.hh @@ -1,4 +1,16 @@ /* + * Copyright (c) 2011 ARM Limited + * All rights reserved. + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * * Copyright (c) 2006 The Regents of The University of Michigan * All rights reserved. * @@ -64,6 +76,12 @@ class BaseTLB : public SimObject virtual ~Translation() {} + /** + * Signal that the translation has been delayed due to a hw page table + * walk. + */ + virtual void markDelayed() = 0; + /* * The memory for this object may be dynamically allocated, and it may * be responsible for cleaning itself up which will happen in this diff --git a/system/alpha/console/Makefile b/system/alpha/console/Makefile new file mode 100644 index 0000000000..9fea133a2f --- /dev/null +++ b/system/alpha/console/Makefile @@ -0,0 +1,60 @@ +# Copyright (c) 2005 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: Nathan L. Binkert +# Ali G. Saidi + +# Point to the M5 diretory so we can get some headers +M5?=../../.. + +### If we are not compiling on an alpha, we must use cross tools ### +ifneq ($(shell uname -m), alpha) +CROSS_COMPILE?=alpha-unknown-linux-gnu- +endif +CC=$(CROSS_COMPILE)gcc +AS=$(CROSS_COMPILE)as +LD=$(CROSS_COMPILE)ld + +DBMENTRY= fffffc0000010000 +CFLAGS=-I . -I ../h -I$(M5)/src/dev/alpha -I$(M5)/util/m5/ -fno-builtin -Wa,-m21164 +OBJS=dbmentry.o printf.o paljtokern.o paljtoslave.o console.o m5op.o + +all: console + +m5op.o: $(M5)/util/m5/m5op_alpha.S + $(CC) $(CFLAGS) -nostdinc -o $@ -c $< + +%.o: %.S + $(CC) $(CFLAGS) -nostdinc -o $@ -c $< + +%.o: %.c + $(CC) -g3 $(CFLAGS) -o $@ -c $< + +console: $(OBJS) + $(LD) -o console -N -Ttext $(DBMENTRY) -non_shared $(OBJS) -lc + +clean: + rm -f *.o console diff --git a/system/alpha/console/console.c b/system/alpha/console/console.c new file mode 100644 index 0000000000..f57ce054f0 --- /dev/null +++ b/system/alpha/console/console.c @@ -0,0 +1,1074 @@ +/* + * Copyright (c) 2003-2004 The Regents of The University of Michigan + * Copyright (c) 1993 The Hewlett-Packard Development Company + * 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. + */ + +/* ****************************************** + * M5 Console + * ******************************************/ + +#include +#include + +#define CONSOLE +#include "access.h" +#include "cserve.h" +#include "rpb.h" + +#define CONS_INT_TX 0x01 /* interrupt enable / state bits */ +#define CONS_INT_RX 0x02 + +#define PAGE_SIZE (8192) + +#define KSTACK_REGION_VA 0x20040000 + +#define KSEG 0xfffffc0000000000 +#define K1BASE 0xfffffc8000000000 +#define KSEG_TO_PHYS(x) (((ulong)x) & ~KSEG) + +#define ROUNDUP8(x) ((ulong)(((ulong)x)+7) & ~7) +#define ROUNDUP128(x) ((ulong)(((ulong)x) + 127) & ~127) +#define ROUNDUP8K(x) ((ulong)(((ulong)(x)) + 8191) & ~8191) + +#define FIRST(x) ((((ulong)(x)) >> 33) & 0x3ff) +#define SECOND(x) ((((ulong)(x)) >> 23) & 0x3ff) +#define THIRD(x) ((((ulong)(x)) >> 13) & 0x3ff) +#define THIRD_XXX(x) ((((ulong)(x)) >> 13) & 0xfff) +#define PFN(x) ((((ulong)(x) & ~KSEG) >> 13)) + +/* Kernel write | kernel read | valid */ +#define KPTE(x) ((ulong)((((ulong)(x)) << 32) | 0x1101)) + +#define HWRPB_PAGES 16 + +#define NUM_KERNEL_THIRD (4) + +#define printf_lock(args...) \ + do { \ + SpinLock(&theLock); \ + printf(args); \ + SpinUnlock(&theLock); \ + } while (0) + + +void unixBoot(int argc, char **argv); +void JToKern(char *bootadr, ulong rpb_percpu, ulong free_pfn, ulong k_argc, + char **k_argv, char **envp); +void JToPal(ulong bootadr); +void SlaveLoop(int cpu); + +volatile struct AlphaAccess *m5AlphaAccess; +struct AlphaAccess m5Conf; + +ulong theLock; + +extern void SpinLock(ulong *lock); +#define SpinUnlock(_x) *(_x) = 0; + +struct _kernel_params { + char *bootadr; + ulong rpb_percpu; + ulong free_pfn; + ulong argc; + ulong argv; + ulong envp; /* NULL */ +}; + +extern consoleCallback[]; +extern consoleFixup[]; +long CallBackDispatcher(); +long CallBackFixup(); + +/* + * m5 console output + */ + +void +InitConsole() +{ +} + +char +GetChar() +{ + return m5AlphaAccess->inputChar; +} + +void +PutChar(char c) +{ + m5AlphaAccess->outputChar = c; +} + +int +passArgs(int argc) +{ + return 0; +} + +int +main(int argc, char **argv) +{ + int x, i; + uint *k1ptr, *ksegptr; + + InitConsole(); + printf_lock("M5 console: m5AlphaAccess @ 0x%x\n", m5AlphaAccess); + + /* + * get configuration from backdoor + */ + m5Conf.last_offset = m5AlphaAccess->last_offset; + printf_lock("Got Configuration %d\n", m5Conf.last_offset); + + m5Conf.last_offset = m5AlphaAccess->last_offset; + m5Conf.version = m5AlphaAccess->version; + m5Conf.numCPUs = m5AlphaAccess->numCPUs; + m5Conf.intrClockFrequency = m5AlphaAccess->intrClockFrequency; + m5Conf.cpuClock = m5AlphaAccess->cpuClock; + m5Conf.mem_size = m5AlphaAccess->mem_size; + m5Conf.kernStart = m5AlphaAccess->kernStart; + m5Conf.kernEnd = m5AlphaAccess->kernEnd; + m5Conf.entryPoint = m5AlphaAccess->entryPoint; + m5Conf.diskUnit = m5AlphaAccess->diskUnit; + m5Conf.diskCount = m5AlphaAccess->diskCount; + m5Conf.diskPAddr = m5AlphaAccess->diskPAddr; + m5Conf.diskBlock = m5AlphaAccess->diskBlock; + m5Conf.diskOperation = m5AlphaAccess->diskOperation; + m5Conf.outputChar = m5AlphaAccess->outputChar; + m5Conf.inputChar = m5AlphaAccess->inputChar; + + if (m5Conf.version != ALPHA_ACCESS_VERSION) { + panic("Console version mismatch. Console expects %d. has %d \n", + ALPHA_ACCESS_VERSION, m5Conf.version); + } + + /* + * setup arguments to kernel + */ + unixBoot(argc, argv); + + panic("unix failed to boot\n"); + return 1; +} + +/* + * BOOTING + */ +struct rpb m5_rpb = { + NULL, /* 000: physical self-reference */ + ((long)'H') | (((long)'W') << 8) | (((long)'R') << 16) | + ((long)'P' << 24) | (((long)'B') << 32), /* 008: contains "HWRPB" */ + 6, /* 010: HWRPB version number */ + /* the byte count is wrong, but who needs it? - lance */ + 0, /* 018: bytes in RPB perCPU CTB CRB MEDSC */ + 0, /* 020: primary cpu id */ + PAGE_SIZE, /* 028: page size in bytes */ + 43, /* 030: number of phys addr bits */ + 127, /* 038: max valid ASN */ + {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1'}, + /* 040: system serial num: 10 ascii chars */ + 0, /* OVERRIDDEN */ + (1<<10), /* 058: system variation */ + 'c'|('o'<<8)|('o'<<16)|('l'<< 24), /* 060: system revision */ + 1024*4096, /* 068: scaled interval clock intr freq */ + 0, /* 070: cycle counter frequency */ + 0x200000000, /* 078: virtual page table base */ + 0, /* 080: reserved */ + 0, /* 088: offset to translation buffer hint */ + 1, /* 090: number of processor slots OVERRIDDEN*/ + sizeof(struct rpb_percpu), /* 098: per-cpu slot size. OVERRIDDEN */ + 0, /* 0A0: offset to per_cpu slots */ + 1, /* 0A8: number of CTBs */ + sizeof(struct ctb_tt), + 0, /* 0B8: offset to CTB (cons term block) */ + 0, /* 0C0: offset to CRB (cons routine block) */ + 0, /* 0C8: offset to memory descriptor table */ + 0, /* 0D0: offset to config data block */ + 0, /* 0D8: offset to FRU table */ + 0, /* 0E0: virt addr of save term routine */ + 0, /* 0E8: proc value for save term routine */ + 0, /* 0F0: virt addr of restore term routine */ + 0, /* 0F8: proc value for restore term routine */ + 0, /* 100: virt addr of CPU restart routine */ + 0, /* 108: proc value for CPU restart routine */ + 0, /* 110: used to determine presence of kdebug */ + 0, /* 118: reserved for hardware */ +/* the checksum is wrong, but who needs it? - lance */ + 0, /* 120: checksum of prior entries in rpb */ + 0, /* 128: receive ready bitmask */ + 0, /* 130: transmit ready bitmask */ + 0, /* 138: Dynamic System Recog. offset */ +}; + +ulong m5_tbb[] = { 0x1e1e1e1e1e1e1e1e, 0x1e1e1e1e1e1e1e1e, + 0x1e1e1e1e1e1e1e1e, 0x1e1e1e1e1e1e1e1e, + 0x1e1e1e1e1e1e1e1e, 0x1e1e1e1e1e1e1e1e, + 0x1e1e1e1e1e1e1e1e, 0x1e1e1e1e1e1e1e1e }; + +struct rpb_percpu m5_rpb_percpu = { + {0,0,0,0,0,0,1,{0,0},{0,0,0,0,0,0,0,0}}, /* 000: boot/restart HWPCB */ + (STATE_PA | STATE_PP | STATE_CV | + STATE_PV | STATE_PMV | STATE_PL), /* 080: per-cpu state bits */ + 0xc000, /* 088: palcode memory length */ + 0x2000, /* 090: palcode scratch length */ + 0x4000, /* 098: paddr of pal mem space */ + 0x2000, /* 0A0: paddr of pal scratch space */ + (2 << 16) | (5 << 8) | 1, /* 0A8: PALcode rev required */ + 11 | (2L << 32), /* 0B0: processor type */ + 7, /* 0B8: processor variation */ + 'M'|('5'<<8)|('A'<<16)|('0'<<24), /* 0C0: processor revision */ + {'M','5','/','A','l','p','h','a','0','0','0','0','0','0','0','0'}, + /* 0C8: proc serial num: 10 chars */ + 0, /* 0D8: phys addr of logout area */ + 0, /* 0E0: len in bytes of logout area */ + 0, /* 0E8: halt pcb base */ + 0, /* 0F0: halt pc */ + 0, /* 0F8: halt ps */ + 0, /* 100: halt arg list (R25) */ + 0, /* 108: halt return address (R26) */ + 0, /* 110: halt procedure value (R27) */ + 0, /* 118: reason for halt */ + 0, /* 120: for software */ + {0}, /* 128: inter-console comm buffer */ + {1,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0}, /* 1D0: PALcode revs available */ + 0 /* 250: reserved for arch use */ +/* the dump stack grows from the end of the rpb page not to reach here */ +}; + +struct _m5_rpb_mdt { + long rpb_checksum; /* 000: checksum of entire mem desc table */ + long rpb_impaddr; /* 008: PA of implementation dep info */ + long rpb_numcl; /* 010: number of clusters */ + struct rpb_cluster rpb_cluster[3]; /* first instance of a cluster */ +}; + +struct _m5_rpb_mdt m5_rpb_mdt = { + 0, /* 000: checksum of entire mem desc table */ + 0, /* 008: PA of implementation dep info */ + 0, /* 010: number of clusters */ + {{ 0, /* 000: starting PFN of this cluster */ + 0, /* 008: count of PFNs in this cluster */ + 0, /* 010: count of tested PFNs in cluster */ + 0, /* 018: va of bitmap */ + 0, /* 020: pa of bitmap */ + 0, /* 028: checksum of bitmap */ + 1 /* 030: usage of cluster */ + }, + { 0, /* 000: starting PFN of this cluster */ + 0, /* 008: count of PFNs in this cluster */ + 0, /* 010: count of tested PFNs in cluster */ + 0, /* 018: va of bitmap */ + 0, /* 020: pa of bitmap */ + 0, /* 028: checksum of bitmap */ + 0 /* 030: usage of cluster */ + }, + { 0, /* 000: starting PFN of this cluster */ + 0, /* 008: count of PFNs in this cluster */ + 0, /* 010: count of tested PFNs in cluster */ + 0, /* 018: va of bitmap */ + 0, /* 020: pa of bitmap */ + 0, /* 028: checksum of bitmap */ + 0 /* 030: usage of cluster */ + }} +}; + +/* constants for slotinfo bus_type subfield */ +#define SLOTINFO_TC 0 +#define SLOTINFO_ISA 1 +#define SLOTINFO_EISA 2 +#define SLOTINFO_PCI 3 + +struct rpb_ctb m5_rpb_ctb = { + CONS_DZ, /* 000: console type */ + 0, /* 008: console unit */ + 0, /* 010: reserved */ + 0 /* 018: byte length of device dep portion */ +}; + +/* we don't do any fixup (aka relocate the console) - we hope */ +struct rpb_crb m5_rpb_crb = { + 0, /* va of call-back dispatch rtn */ + 0, /* pa of call-back dispatch rtn */ + 0, /* va of call-back fixup rtn */ + 0, /* pa of call-back fixup rtn */ + 0, /* number of entries in phys/virt map */ + 0 /* Number of pages to be mapped */ +}; + +struct _rpb_name { + ulong length; + char name[16]; +}; + +extern struct _rpb_name m5_name; + +struct rpb_dsr m5_rpb_dsr = { + 0, + 0, + 0, +}; + +struct _rpb_name m5_name = { + 16, + {'U','M','I','C','H',' ','M','5','/','A','L','P','H','A',' ',0}, +}; + +/* + * M5 has one LURT entry: + * 1050 is for workstations + * 1100 is servers (and is needed for CXX) + */ +long m5_lurt[10] = { 9, 12, -1, -1, -1, -1, -1, -1, 1100, 1100 }; + +ulong unix_boot_mem; +ulong bootadr; + +char **kargv; +int kargc; +ulong free_pfn; +struct rpb_percpu *rpb_percpu; + +char * +unix_boot_alloc(int pages) +{ + char *ret = (char *)unix_boot_mem; + unix_boot_mem += (pages * PAGE_SIZE); + return ret; +} + +ulong *first = 0; +ulong *third_rpb = 0; +ulong *reservedFixup = 0; + +int strcpy(char *dst, char *src); + +struct rpb *rpb; +extern ulong _end; + +void +unixBoot(int argc, char **argv) +{ + ulong *second, *third_kernel, ptr, *tbb, size, *percpu_logout; + unsigned char *mdt_bitmap; + long *lp1, *lp2, sum; + int i, cl; + ulong kern_first_page; + ulong mem_size = m5Conf.mem_size; + + ulong mem_pages = mem_size / PAGE_SIZE, cons_pages; + ulong mdt_bitmap_pages = mem_pages / (PAGE_SIZE*8); + + ulong kernel_bytes, ksp, kernel_end, *unix_kernel_stack, bss, + ksp_bottom, ksp_top; + struct rpb_ctb *rpb_ctb; + struct ctb_tt *ctb_tt; + struct rpb_dsr *rpb_dsr; + struct rpb_crb *rpb_crb; + struct _m5_rpb_mdt *rpb_mdt; + int *rpb_lurt; + char *rpb_name; + ulong nextPtr; + + printf_lock("memsize %x pages %x \n", mem_size, mem_pages); + + /* Allocate: + * two pages for the HWRPB + * five page table pages: + * 1: First level page table + * 1: Second level page table + * 1: Third level page table for HWRPB + * 2: Third level page table for kernel (for up to 16MB) + * set up the page tables + * load the kernel at the physical address 0x230000 + * build the HWRPB + * set up memory descriptor table to give up the + * physical memory between the end of the page + * tables and the start of the kernel + * enable kseg addressing + * jump to the kernel + */ + + unix_boot_mem = ROUNDUP8K(&_end); + + printf_lock("First free page after ROM 0x%x\n", unix_boot_mem); + + rpb = (struct rpb *)unix_boot_alloc(HWRPB_PAGES); + + mdt_bitmap = (unsigned char *)unix_boot_alloc(mdt_bitmap_pages); + first = (ulong *)unix_boot_alloc(1); + second = (ulong *)unix_boot_alloc(1); + third_rpb = (ulong *)unix_boot_alloc(1); + reservedFixup = (ulong*) unix_boot_alloc(1); + third_kernel = (ulong *)unix_boot_alloc(NUM_KERNEL_THIRD); + percpu_logout = (ulong*)unix_boot_alloc(1); + + cons_pages = KSEG_TO_PHYS(unix_boot_mem) / PAGE_SIZE; + + /* Set up the page tables */ + bzero((char *)first, PAGE_SIZE); + bzero((char *)second, PAGE_SIZE); + bzero((char *)reservedFixup, PAGE_SIZE); + bzero((char *)third_rpb, HWRPB_PAGES * PAGE_SIZE); + bzero((char *)third_kernel, PAGE_SIZE * NUM_KERNEL_THIRD); + + first[0] = KPTE(PFN(second)); + first[1] = KPTE(PFN(first)); /* Region 3 */ + + /* Region 0 */ + second[SECOND(0x10000000)] = KPTE(PFN(third_rpb)); + + for (i = 0; i < NUM_KERNEL_THIRD; i++) { + /* Region 1 */ + second[SECOND(0x20000000) + i] = KPTE(PFN(third_kernel) + i); + } + + /* Region 2 */ + second[SECOND(0x40000000)] = KPTE(PFN(second)); + + + /* For some obscure reason, Dec Unix's database read + * from /etc/sysconfigtab is written to this fixed + * mapped memory location. Go figure, since it is + * not initialized by the console. Maybe it is + * to look at the database from the console + * after a boot/crash. + * + * Black magic to estimate the max size. SEGVs on overflow + * bugnion + */ + +#define DATABASE_BASE 0x20000000 +#define DATABASE_END 0x20020000 + + ulong *dbPage = (ulong*)unix_boot_alloc(1); + bzero(dbPage, PAGE_SIZE); + second[SECOND(DATABASE_BASE)] = KPTE(PFN(dbPage)); + for (i = DATABASE_BASE; i < DATABASE_END ; i += PAGE_SIZE) { + ulong *db = (ulong*)unix_boot_alloc(1); + dbPage[THIRD(i)] = KPTE(PFN(db)); + } + + /* Region 0 */ + /* Map the HWRPB */ + for (i = 0; i < HWRPB_PAGES; i++) + third_rpb[i] = KPTE(PFN(rpb) + i); + + /* Map the MDT bitmap table */ + for (i = 0; i < mdt_bitmap_pages; i++) { + third_rpb[HWRPB_PAGES + i] = KPTE(PFN(mdt_bitmap) + i); + } + + /* Protect the PAL pages */ + for (i = 1; i < PFN(first); i++) + third_rpb[HWRPB_PAGES + mdt_bitmap_pages + i] = KPTE(i); + + /* Set up third_kernel after it's loaded, when we know where it is */ + kern_first_page = (KSEG_TO_PHYS(m5Conf.kernStart)/PAGE_SIZE); + kernel_end = ROUNDUP8K(m5Conf.kernEnd); + bootadr = m5Conf.entryPoint; + + printf_lock("HWRPB 0x%x l1pt 0x%x l2pt 0x%x l3pt_rpb 0x%x l3pt_kernel 0x%x" + " l2reserv 0x%x\n", + rpb, first, second, third_rpb, third_kernel, reservedFixup); + if (kernel_end - m5Conf.kernStart > (0x800000*NUM_KERNEL_THIRD)) { + printf_lock("Kernel is more than 8MB 0x%x - 0x%x = 0x%x\n", + kernel_end, m5Conf.kernStart, + kernel_end - m5Conf.kernStart ); + panic("kernel too big\n"); + } + printf_lock("kstart = 0x%x, kend = 0x%x, kentry = 0x%x, numCPUs = 0x%x\n", m5Conf.kernStart, m5Conf.kernEnd, m5Conf.entryPoint, m5Conf.numCPUs); + ksp_bottom = (ulong)unix_boot_alloc(1); + ksp_top = ksp_bottom + PAGE_SIZE; + ptr = (ulong) ksp_bottom; + bzero((char *)ptr, PAGE_SIZE); + dbPage[THIRD(KSTACK_REGION_VA)] = 0; /* Stack Guard Page */ + dbPage[THIRD(KSTACK_REGION_VA + PAGE_SIZE)] = KPTE(PFN(ptr)); /* Kernel Stack Page */ + dbPage[THIRD(KSTACK_REGION_VA + 2*PAGE_SIZE)] = 0; /* Stack Guard Page */ + + /* put argv into the bottom of the stack - argv starts at 1 because + * the command thatr got us here (i.e. "unixboot) is in argv[0]. + */ + ksp = ksp_top - 8; /* Back up one longword */ + ksp -= argc * sizeof(char *); /* Make room for argv */ + kargv = (char **) ksp; + for (i = 1; i < argc; i++) { /* Copy arguments to stack */ + ksp -= ((strlen(argv[i]) + 1) + 7) & ~0x7; + kargv[i-1] = (char *) ksp; + strcpy(kargv[i - 1], argv[i]); + } + kargc = i - 1; + kargv[kargc] = NULL; /* just to be sure; doesn't seem to be used */ + ksp -= sizeof(char *); /* point above last arg for no real reason */ + + free_pfn = PFN(kernel_end); + + bcopy((char *)&m5_rpb, (char *)rpb, sizeof(struct rpb)); + + rpb->rpb_selfref = (struct rpb *) KSEG_TO_PHYS(rpb); + rpb->rpb_string = 0x0000004250525748; + + tbb = (ulong *) (((char *) rpb) + ROUNDUP8(sizeof(struct rpb))); + rpb->rpb_trans_off = (ulong)tbb - (ulong)rpb; + bcopy((char *)m5_tbb, (char *)tbb, sizeof(m5_tbb)); + + /* + * rpb_counter. Use to determine timeouts in OS. + * XXX must be patched after a checkpoint restore (I guess) + */ + + printf_lock("CPU Clock at %d MHz IntrClockFrequency=%d \n", + m5Conf.cpuClock, m5Conf.intrClockFrequency); + rpb->rpb_counter = m5Conf.cpuClock * 1000 * 1000; + + /* + * By definition, the rpb_clock is scaled by 4096 (in hz) + */ + rpb->rpb_clock = m5Conf.intrClockFrequency * 4096; + + /* + * Per CPU Slots. Multiprocessor support. + */ + int percpu_size = ROUNDUP128(sizeof(struct rpb_percpu)); + + printf_lock("Booting with %d processor(s) \n", m5Conf.numCPUs); + + rpb->rpb_numprocs = m5Conf.numCPUs; + rpb->rpb_slotsize = percpu_size; + rpb_percpu = (struct rpb_percpu *) + ROUNDUP128(((ulong)tbb) + (sizeof(m5_tbb))); + + rpb->rpb_percpu_off = (ulong)rpb_percpu - (ulong)rpb; + + for (i = 0; i < m5Conf.numCPUs; i++) { + struct rpb_percpu *thisCPU = (struct rpb_percpu*) + ((ulong)rpb_percpu + percpu_size * i); + + bzero((char *)thisCPU, percpu_size); + bcopy((char *)&m5_rpb_percpu, (char *)thisCPU, + sizeof(struct rpb_percpu)); + + thisCPU->rpb_pcb.rpb_ksp = (KSTACK_REGION_VA + 2*PAGE_SIZE - (ksp_top - ksp)); + thisCPU->rpb_pcb.rpb_ptbr = PFN(first); + + thisCPU->rpb_logout = KSEG_TO_PHYS(percpu_logout); + thisCPU->rpb_logout_len = PAGE_SIZE; + + printf_lock("KSP: 0x%x PTBR 0x%x\n", + thisCPU->rpb_pcb.rpb_ksp, thisCPU->rpb_pcb.rpb_ptbr); + } + + nextPtr = (ulong)rpb_percpu + percpu_size * m5Conf.numCPUs; + + /* + * Console Terminal Block + */ + rpb_ctb = (struct rpb_ctb *) nextPtr; + ctb_tt = (struct ctb_tt*) rpb_ctb; + + rpb->rpb_ctb_off = ((ulong)rpb_ctb) - (ulong)rpb; + rpb->rpb_ctb_size = sizeof(struct rpb_ctb); + + bzero((char *)rpb_ctb, sizeof(struct ctb_tt)); + + rpb_ctb->rpb_type = CONS_DZ; + rpb_ctb->rpb_length = sizeof(ctb_tt) - sizeof(rpb_ctb); + + /* + * uart initizliation + */ + ctb_tt->ctb_tintr_vec = 0x6c0; /* matches tlaser pal code */ + ctb_tt->ctb_rintr_vec = 0x680; /* matches tlaser pal code */ + ctb_tt->ctb_term_type = CTB_GRAPHICS; + + rpb_crb = (struct rpb_crb *) (((ulong)rpb_ctb) + sizeof(struct ctb_tt)); + rpb->rpb_crb_off = ((ulong)rpb_crb) - (ulong)rpb; + + bzero((char *)rpb_crb, sizeof(struct rpb_crb)); + + /* + * console callback stuff (m5) + */ + rpb_crb->rpb_num = 1; + rpb_crb->rpb_mapped_pages = HWRPB_PAGES; + rpb_crb->rpb_map[0].rpb_virt = 0x10000000; + rpb_crb->rpb_map[0].rpb_phys = KSEG_TO_PHYS(((ulong)rpb) & ~0x1fff); + rpb_crb->rpb_map[0].rpb_pgcount = HWRPB_PAGES; + + printf_lock("Console Callback at 0x%x, fixup at 0x%x, crb offset: 0x%x\n", + rpb_crb->rpb_va_disp, rpb_crb->rpb_va_fixup, rpb->rpb_crb_off); + + rpb_mdt = (struct _m5_rpb_mdt *)((ulong)rpb_crb + sizeof(struct rpb_crb)); + rpb->rpb_mdt_off = (ulong)rpb_mdt - (ulong)rpb; + bcopy((char *)&m5_rpb_mdt, (char *)rpb_mdt, sizeof(struct _m5_rpb_mdt)); + + + cl = 0; + rpb_mdt->rpb_cluster[cl].rpb_pfncount = kern_first_page; + cl++; + + rpb_mdt->rpb_cluster[cl].rpb_pfn = kern_first_page; + rpb_mdt->rpb_cluster[cl].rpb_pfncount = mem_pages - kern_first_page; + rpb_mdt->rpb_cluster[cl].rpb_pfntested = + rpb_mdt->rpb_cluster[cl].rpb_pfncount; + rpb_mdt->rpb_cluster[cl].rpb_pa = KSEG_TO_PHYS(mdt_bitmap); + rpb_mdt->rpb_cluster[cl].rpb_va = 0x10000000 + HWRPB_PAGES * PAGE_SIZE; + cl++; + + rpb_mdt->rpb_numcl = cl; + + for (i = 0; i < cl; i++) + printf_lock("Memory cluster %d [%d - %d]\n", i, + rpb_mdt->rpb_cluster[i].rpb_pfn, + rpb_mdt->rpb_cluster[i].rpb_pfncount); + + /* Checksum the rpb for good luck */ + sum = 0; + lp1 = (long *)&rpb_mdt->rpb_impaddr; + lp2 = (long *)&rpb_mdt->rpb_cluster[cl]; + while (lp1 < lp2) sum += *lp1++; + rpb_mdt->rpb_checksum = sum; + + /* XXX should checksum the cluster descriptors */ + bzero((char *)mdt_bitmap, mdt_bitmap_pages * PAGE_SIZE); + for (i = 0; i < mem_pages/8; i++) + ((unsigned char *)mdt_bitmap)[i] = 0xff; + + printf_lock("Initalizing mdt_bitmap addr 0x%x mem_pages %x \n", + (long)mdt_bitmap,(long)mem_pages); + + m5_rpb.rpb_config_off = 0; + m5_rpb.rpb_fru_off = 0; + + rpb_dsr = (struct rpb_dsr *)((ulong)rpb_mdt + sizeof(struct _m5_rpb_mdt)); + rpb->rpb_dsr_off = (ulong)rpb_dsr - (ulong)rpb; + bzero((char *)rpb_dsr, sizeof(struct rpb_dsr)); + rpb_dsr->rpb_smm = 1578; /* Official XXM SMM number as per SRM */ + rpb_dsr->rpb_smm = 1089; /* Official Alcor SMM number as per SRM */ + + rpb_lurt = (int *) ROUNDUP8((ulong)rpb_dsr + sizeof(struct rpb_dsr)); + rpb_dsr->rpb_lurt_off = ((ulong) rpb_lurt) - (ulong) rpb_dsr; + bcopy((char *)m5_lurt, (char *)rpb_lurt, sizeof(m5_lurt)); + + rpb_name = (char *) ROUNDUP8(((ulong)rpb_lurt) + sizeof(m5_lurt)); + rpb_dsr->rpb_sysname_off = ((ulong) rpb_name) - (ulong) rpb_dsr; +#define THENAME " M5/Alpha " + sum = sizeof(THENAME); + bcopy(THENAME, rpb_name, sum); + *(ulong *)rpb_name = sizeof(THENAME); /* put in length field */ + + /* calculate size of rpb */ + rpb->rpb_size = ((ulong) &rpb_name[sum]) - (ulong)rpb; + + if (rpb->rpb_size > PAGE_SIZE * HWRPB_PAGES) { + panic("HWRPB_PAGES=%d too small for HWRPB !!! \n"); + } + + ulong *rpbptr = (ulong*)((char*)rpb_dsr + sizeof(struct rpb_dsr)); + rpb_crb->rpb_pa_disp = KSEG_TO_PHYS(rpbptr); + rpb_crb->rpb_va_disp = 0x10000000 + + (((ulong)rpbptr - (ulong)rpb) & (0x2000 * HWRPB_PAGES - 1)); + printf_lock("ConsoleDispatch at virt %x phys %x val %x\n", + rpb_crb->rpb_va_disp, rpb_crb->rpb_pa_disp, consoleCallback); + *rpbptr++ = 0; + *rpbptr++ = (ulong) consoleCallback; + rpb_crb->rpb_pa_fixup = KSEG_TO_PHYS(rpbptr); + rpb_crb->rpb_va_fixup = 0x10000000 + + (((ulong)rpbptr - (ulong)rpb) & (0x2000 * HWRPB_PAGES - 1)); + *rpbptr++ = 0; + + *rpbptr++ = (ulong) consoleFixup; + + /* Checksum the rpb for good luck */ + sum = 0; + lp1 = (long *)rpb; + lp2 = &rpb->rpb_checksum; + while (lp1 < lp2) + sum += *lp1++; + *lp2 = sum; + + /* + * MP bootstrap + */ + for (i = 1; i < m5Conf.numCPUs; i++) { + ulong stack = (ulong)unix_boot_alloc(1); + printf_lock("Bootstraping CPU %d with sp=0x%x\n", i, stack); + m5AlphaAccess->cpuStack[i] = stack; + } + + /* + * Make sure that we are not stepping on the kernel + */ + if ((ulong)unix_boot_mem >= (ulong)m5Conf.kernStart) { + panic("CONSOLE: too much memory. Smashing kernel\n"); + } else { + printf_lock("unix_boot_mem ends at %x \n", unix_boot_mem); + } + + JToKern((char *)bootadr, (ulong)rpb_percpu, free_pfn, kargc, kargv, NULL); +} + + +void +JToKern(char *bootadr, ulong rpb_percpu, ulong free_pfn, ulong k_argc, + char **k_argv, char **envp) +{ + extern ulong palJToKern[]; + + struct _kernel_params *kernel_params = (struct _kernel_params *) KSEG; + int i; + + printf_lock("k_argc = %d ", k_argc); + for (i = 0; i < k_argc; i++) { + printf_lock("'%s' ", k_argv[i]); + } + printf_lock("\n"); + + kernel_params->bootadr = bootadr; + kernel_params->rpb_percpu = KSEG_TO_PHYS(rpb_percpu); + kernel_params->free_pfn = free_pfn; + kernel_params->argc = k_argc; + kernel_params->argv = (ulong)k_argv; + kernel_params->envp = (ulong)envp; + printf_lock("jumping to kernel at 0x%x, (PCBB 0x%x pfn %d)\n", + bootadr, rpb_percpu, free_pfn); + JToPal(KSEG_TO_PHYS(palJToKern)); + printf_lock("returned from JToPal. Looping\n"); + while (1) + continue; +} + +void +JToPal(ulong bootadr) +{ + cServe(bootadr, 0, CSERVE_K_JTOPAL); + + /* + * Make sure that floating point is enabled incase + * it was disabled by the user program. + */ + wrfen(1); +} + +int +strcpy(char *dst, char *src) +{ + int i = 0; + while (*src) { + *dst++ = *src++; + i++; + } + return i; +} + +/* + * Console I/O + * + */ + +int numOpenDevices = 11; +struct { + char name[128]; +} deviceState[32]; + +#define BOOTDEVICE_NAME "SCSI 1 0 0 1 100 0" + +void +DeviceOperation(long op, long channel, long count, long address, long block) +{ + long pAddr; + + if (strcmp(deviceState[channel].name, BOOTDEVICE_NAME )) { + panic("DeviceRead: only implemented for root disk \n"); + } + pAddr = KSEG_TO_PHYS(address); + if (pAddr + count > m5Conf.mem_size) { + panic("DeviceRead: request out of range \n"); + } + + m5AlphaAccess->diskCount = count; + m5AlphaAccess->diskPAddr = pAddr; + m5AlphaAccess->diskBlock = block; + m5AlphaAccess->diskOperation = op; /* launch */ +} + +/* + * M5 Console callbacks + * + */ + +/* AXP manual 2-31 */ +#define CONSCB_GETC 0x1 +#define CONSCB_PUTS 0x2 +#define CONSCB_RESET_TERM 0x3 +#define CONSCB_SET_TERM_INT 0x4 +#define CONSCB_SET_TERM_CTL 0x5 +#define CONSCB_PROCESS_KEY 0x6 +#define CONSCB_OPEN_CONSOLE 0x7 +#define CONSCB_CLOSE_CONSOLE 0x8 + +#define CONSCB_OPEN 0x10 +#define CONSCB_CLOSE 0x11 +#define CONSCB_READ 0x13 + +#define CONSCB_GETENV 0x22 + +/* AXP manual 2-26 */ +#define ENV_AUTO_ACTION 0X01 +#define ENV_BOOT_DEV 0X02 +#define ENV_BOOTDEF_DEV 0X03 +#define ENV_BOOTED_DEV 0X04 +#define ENV_BOOT_FILE 0X05 +#define ENV_BOOTED_FILE 0X06 +#define ENV_BOOT_OSFLAGS 0X07 +#define ENV_BOOTED_OSFLAGS 0X08 +#define ENV_BOOT_RESET 0X09 +#define ENV_DUMP_DEV 0X0A +#define ENV_ENABLE_AUDIT 0X0B +#define ENV_LICENSE 0X0C +#define ENV_CHAR_SET 0X0D +#define ENV_LANGUAGE 0X0E +#define ENV_TTY_DEV 0X0F +#define ENV_SCSIID 0X42 +#define ENV_SCSIFAST 0X43 +#define ENV_COM1_BAUD 0X44 +#define ENV_COM1_MODEM 0X45 +#define ENV_COM1_FLOW 0X46 +#define ENV_COM1_MISC 0X47 +#define ENV_COM2_BAUD 0X48 +#define ENV_COM2_MODEM 0X49 +#define ENV_COM2_FLOW 0X4A +#define ENV_COM2_MISC 0X4B +#define ENV_PASSWORD 0X4C +#define ENV_SECURE 0X4D +#define ENV_LOGFAIL 0X4E +#define ENV_SRM2DEV_ID 0X4F + +#define MAX_ENVLEN 32 + +char env_auto_action[MAX_ENVLEN] = "BOOT"; +char env_boot_dev[MAX_ENVLEN] = ""; +char env_bootdef_dev[MAX_ENVLEN] = ""; +char env_booted_dev[MAX_ENVLEN] = BOOTDEVICE_NAME; +char env_boot_file[MAX_ENVLEN] = ""; +char env_booted_file[MAX_ENVLEN] = ""; +char env_boot_osflags[MAX_ENVLEN] = ""; +char env_booted_osflags[MAX_ENVLEN] = ""; +char env_boot_reset[MAX_ENVLEN] = ""; +char env_dump_dev[MAX_ENVLEN] = ""; +char env_enable_audit[MAX_ENVLEN] = ""; +char env_license[MAX_ENVLEN] = ""; +char env_char_set[MAX_ENVLEN] = ""; +char env_language[MAX_ENVLEN] = ""; +char env_tty_dev[MAX_ENVLEN] = "0"; +char env_scsiid[MAX_ENVLEN] = ""; +char env_scsifast[MAX_ENVLEN] = ""; +char env_com1_baud[MAX_ENVLEN] = ""; +char env_com1_modem[MAX_ENVLEN] = ""; +char env_com1_flow[MAX_ENVLEN] = ""; +char env_com1_misc[MAX_ENVLEN] = ""; +char env_com2_baud[MAX_ENVLEN] = ""; +char env_com2_modem[MAX_ENVLEN] = ""; +char env_com2_flow[MAX_ENVLEN] = ""; +char env_com2_misc[MAX_ENVLEN] = ""; +char env_password[MAX_ENVLEN] = ""; +char env_secure[MAX_ENVLEN] = ""; +char env_logfail[MAX_ENVLEN] = ""; +char env_srm2dev_id[MAX_ENVLEN] = ""; + +#define MAX_ENV_INDEX 100 +char *envptr[MAX_ENV_INDEX] = { + 0, /* 0x00 */ + env_auto_action, /* 0x01 */ + env_boot_dev, /* 0x02 */ + env_bootdef_dev, /* 0x03 */ + env_booted_dev, /* 0x04 */ + env_boot_file, /* 0x05 */ + env_booted_file, /* 0x06 */ + env_boot_osflags, /* 0x07 */ + env_booted_osflags, /* 0x08 */ + env_boot_reset, /* 0x09 */ + env_dump_dev, /* 0x0A */ + env_enable_audit, /* 0x0B */ + env_license, /* 0x0C */ + env_char_set, /* 0x0D */ + (char *)&env_language, /* 0x0E */ + env_tty_dev, /* 0x0F */ + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x10 - 0x1F */ + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x20 - 0x2F */ + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x30 - 0x3F */ + 0, /* 0x40 */ + 0, /* 0x41 */ + env_scsiid, /* 0x42 */ + env_scsifast, /* 0x43 */ + env_com1_baud, /* 0x44 */ + env_com1_modem, /* 0x45 */ + env_com1_flow, /* 0x46 */ + env_com1_misc, /* 0x47 */ + env_com2_baud, /* 0x48 */ + env_com2_modem, /* 0x49 */ + env_com2_flow, /* 0x4A */ + env_com2_misc, /* 0x4B */ + env_password, /* 0x4C */ + env_secure, /* 0x4D */ + env_logfail, /* 0x4E */ + env_srm2dev_id, /* 0x4F */ + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x50 - 0x5F */ + 0, /* 0x60 */ + 0, /* 0x61 */ + 0, /* 0x62 */ + 0, /* 0x63 */ +}; + +long +CallBackDispatcher(long a0, long a1, long a2, long a3, long a4) +{ + long i; + switch (a0) { + case CONSCB_GETC: + return GetChar(); + + case CONSCB_PUTS: + for (i = 0; i < a3; i++) + PutChar(*((char *)a2 + i)); + return a3; + + case CONSCB_GETENV: + if (a1 >= 0 && a1 < MAX_ENV_INDEX && envptr[a1] != 0 && *envptr[a1]) { + i = strcpy((char*)a2, envptr[a1]); + } else { + strcpy((char*)a2, ""); + i = (long)0xc000000000000000; + if (a1 >= 0 && a1 < MAX_ENV_INDEX) + printf_lock("GETENV unsupported option %d (0x%x)\n", a1, a1); + else + printf_lock("GETENV unsupported option %s\n", a1); + } + + if (i > a3) + panic("CONSCB_GETENV overwrote buffer\n"); + return i; + + case CONSCB_OPEN: + bcopy((char*)a1, deviceState[numOpenDevices].name, a2); + deviceState[numOpenDevices].name[a2] = '\0'; + printf_lock("CONSOLE OPEN : %s --> success \n", + deviceState[numOpenDevices].name); + return numOpenDevices++; + + case CONSCB_READ: + DeviceOperation(a0, a1, a2, a3, a4); + break; + + case CONSCB_CLOSE: + break; + + case CONSCB_OPEN_CONSOLE: + printf_lock("CONSOLE OPEN\n"); + return 0; /* success */ + break; /* not reached */ + + case CONSCB_CLOSE_CONSOLE: + printf_lock("CONSOLE CLOSE\n"); + return 0; /* success */ + break; /* not reached */ + + default: + panic("CallBackDispatcher(%x,%x,%x,%x,%x)\n", a0, a1, a2, a3, a4); + } + + return 0; +} + +long +CallBackFixup(int a0, int a1, int a2) +{ + long temp; + /* + * Linux uses r8 for the current pointer (pointer to data + * structure contating info about currently running process). It + * is set when the kernel starts and is expected to remain + * there... Problem is that the unlike the kernel, the console + * does not prevent the assembler from using r8. So here is a work + * around. So far this has only been a problem in CallBackFixup() + * but any other call back functions couldd cause a problem at + * some point + */ + + /* save off the current pointer to a temp variable */ + asm("bis $8, $31, %0" : "=r" (temp)); + + /* call original code */ + printf_lock("CallbackFixup %x %x, t7=%x\n", a0, a1, temp); + + /* restore the current pointer */ + asm("bis %0, $31, $8" : : "r" (temp) : "$8"); + + return 0; +} + +void +SlaveCmd(int cpu, struct rpb_percpu *my_rpb) +{ + extern ulong palJToSlave[]; + + printf_lock("Slave CPU %d console command %s", cpu, + my_rpb->rpb_iccb.iccb_rxbuf); + + my_rpb->rpb_state |= STATE_BIP; + my_rpb->rpb_state &= ~STATE_RC; + + printf_lock("SlaveCmd: restart %x %x vptb %x my_rpb %x my_rpb_phys %x\n", + rpb->rpb_restart, rpb->rpb_restart_pv, rpb->rpb_vptb, my_rpb, + KSEG_TO_PHYS(my_rpb)); + + cServe(KSEG_TO_PHYS(palJToSlave), (ulong)rpb->rpb_restart, + CSERVE_K_JTOPAL, rpb->rpb_restart_pv, rpb->rpb_vptb, + KSEG_TO_PHYS(my_rpb)); + + panic("SlaveCmd returned \n"); +} + +void +SlaveLoop(int cpu) +{ + int size = ROUNDUP128(sizeof(struct rpb_percpu)); + struct rpb_percpu *my_rpb = (struct rpb_percpu*) + ((ulong)rpb_percpu + size * cpu); + + if (cpu == 0) { + panic("CPU 0 entering slaveLoop. Reenetering the console. HOSED\n"); + } else { + printf_lock("Entering slaveloop for cpu %d my_rpb=%x\n", cpu, my_rpb); + } + + // swap the processors context to the one in the + // rpb_percpu struct very carefully (i.e. no stack usage) + // so that linux knows which processor ends up in __smp_callin + // and we don't trash any data is the process + SlaveSpin(cpu, my_rpb, &my_rpb->rpb_iccb.iccb_rxlen); +} diff --git a/system/alpha/console/dbmentry.S b/system/alpha/console/dbmentry.S new file mode 100644 index 0000000000..56a2c1950b --- /dev/null +++ b/system/alpha/console/dbmentry.S @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2003-2004 The Regents of The University of Michigan + * Copyright (c) 1993 The Hewlett-Packard Development Company + * 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. + */ + +/* + * Debug Monitor Entry code + */ +#include "fromHudsonOsf.h" + + .extern myAlphaAccess + .text + +/* return address and padding to octaword align */ +#define STARTFRM 16 + + .globl _start + .ent _start, 0 +_start: +_entry: + br t0, 2f # get the current PC +2: ldgp gp, 0(t0) # init gp + +/* Processor 0 start stack frame is begining of physical memory (0) + Other processors spin here waiting to get their stacks from + Processor 0, then they can progress as normal. +*/ + call_pal PAL_WHAMI_ENTRY + beq v0, cpuz + ldq t3, m5AlphaAccess + addq t3,0x70,t3 # *** If offset in console alpha access struct changes + # This must be changed as well! + bis zero,8,t4 + mulq t4,v0,t4 + addq t3,t4,t3 + ldah a0, 3(zero) # load arg0 with 65536*3 +cpuwait: .long 0x6000002 # jsr quiesceNs + ldq t4, 0(t3) + beq t4, cpuwait + bis t4,t4,sp + + +cpuz: bis sp,sp,s0 /* save sp */ + +slave: lda v0,(8*1024)(sp) /* end of page */ + + subq zero, 1, t0 + sll t0, 42, t0 + bis t0, v0, sp + + lda sp, -STARTFRM(sp) # Create a stack frame + stq ra, 0(sp) # Place return address on the stack + + .mask 0x84000000, -8 + .frame sp, STARTFRM, ra + +/* + * Enable the Floating Point Unit + */ + lda a0, 1(zero) + call_pal PAL_WRFEN_ENTRY + +/* + * Every good C program has a main() + */ + +/* If stack pointer was 0, then this is CPU0*/ + beq s0,master + + call_pal PAL_WHAMI_ENTRY + bis v0,v0,a0 + jsr ra, SlaveLoop +master: + jsr ra, main + + + +/* + * The Debug Monitor should never return. + * However, just incase... + */ + ldgp gp, 0(ra) + bsr zero, _exit + +.end _start + + + + .globl _exit + .ent _exit, 0 +_exit: + + ldq ra, 0(sp) # restore return address + lda sp, STARTFRM(sp) # prune back the stack + ret zero, (ra) # Back from whence we came +.end _exit + + .globl cServe + .ent cServe 2 +cServe: + .option O1 + .frame sp, 0, ra + call_pal PAL_CSERVE_ENTRY + ret zero, (ra) + .end cServe + + .globl wrfen + .ent wrfen 2 +wrfen: + .option O1 + .frame sp, 0, ra + call_pal PAL_WRFEN_ENTRY + ret zero, (ra) + .end wrfen + .globl consoleCallback + .ent consoleCallback 2 +consoleCallback: + br t0, 2f # get the current PC +2: ldgp gp, 0(t0) # init gp + lda sp,-64(sp) + stq ra,0(sp) + jsr CallBackDispatcher + ldq ra,0(sp) + lda sp,64(sp) + ret zero,(ra) + .end consoleCallback + + + .globl consoleFixup + .ent consoleFixup 2 +consoleFixup: + br t0, 2f # get the current PC +2: ldgp gp, 0(t0) # init gp + lda sp,-64(sp) + stq ra,0(sp) + jsr CallBackFixup + ldq ra,0(sp) + lda sp,64(sp) + ret zero,(ra) + .end consoleFixup + + + + .globl SpinLock + .ent SpinLock 2 +SpinLock: +1: + ldq_l a1,0(a0) # interlock complete lock state + subl ra,3,v0 # get calling addr[31:0] + 1 + blbs a1,2f # branch if lock is busy + stq_c v0,0(a0) # attempt to acquire lock + beq v0,2f # branch if lost atomicity + mb # ensure memory coherence + ret zero,(ra) # return to caller (v0 is 1) +2: + br zero,1b + .end SpinLock + + .globl loadContext + .ent loadContext 2 +loadContext: + .option O1 + .frame sp, 0, ra + call_pal PAL_SWPCTX_ENTRY + ret zero, (ra) + .end loadContext + + + .globl SlaveSpin # Very carefully spin wait + .ent SlaveSpin 2 # and swap context without +SlaveSpin: # using any stack space + .option O1 + .frame sp, 0, ra + mov a0, t0 # cpu number + mov a1, t1 # cpu rpb pointer (virtual) + mov a2, t2 # what to spin on + ldah a0, 3(zero) # load arg0 with 65536 +test: .long 0x6000002 # jsr quiesceNs # wait 65us*3 + ldl t3, 0(t2) + beq t3, test + zapnot t1,0x1f,a0 # make rpb physical + call_pal PAL_SWPCTX_ENTRY # switch to pcb + mov t0, a0 # setup args for SlaveCmd + mov t1, a1 + jsr SlaveCmd # call SlaveCmd + ret zero, (ra) # Should never be reached + .end SlaveSpin + + diff --git a/system/alpha/console/paljtokern.S b/system/alpha/console/paljtokern.S new file mode 100644 index 0000000000..dfaf325331 --- /dev/null +++ b/system/alpha/console/paljtokern.S @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2003-2004 The Regents of The University of Michigan + * Copyright (c) 1993 The Hewlett-Packard Development Company + * 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. + */ + +#include "dc21164FromGasSources.h" // DECchip 21164 specific definitions +#include "ev5_defs.h" +#include "fromHudsonOsf.h" // OSF/1 specific definitions +#include "fromHudsonMacros.h" // Global macro definitions + +/* Jump to kernel + * args: + * Kernel address - a0 + * PCBB - a1 + * First free PFN - a3? + * + * Enable kseg addressing in ICSR + * Enable kseg addressing in MCSR + * Set VTBR -- Set to 1GB as per SRM, or maybe 8GB?? + * Set PCBB -- pass pointer in arg + * Set PTBR -- get it out of PCB + * Set KSP -- get it out of PCB + * + * Jump to kernel address + * + * Kernel args- + * s0 first free PFN + * s1 ptbr + * s2 argc 0 + * s3 argv NULL + * s5 osf_param (sysconfigtab) NULL + */ + + .global palJToKern + .text 3 +palJToKern: + ALIGN_BRANCH + + ldq_p a0, 0(zero) + ldq_p a1, 8(zero) + ldq_p a3, 16(zero) + + /* Point the Vptbr at 8GB */ + lda t0, 0x1(zero) + sll t0, 33, t0 + + mtpr t0, mVptBr // Load Mbox copy + mtpr t0, iVptBr // Load Ibox copy + STALL // don't dual issue the load with mtpr -pb + + /* Turn on superpage mapping in the mbox and icsr */ + lda t0, (2< + STALL // don't dual issue the load with mtpr -pb + mtpr t0, mcsr // Set the super page mode enable bit + STALL // don't dual issue the load with mtpr -pb + + lda t0, 0(zero) + mtpr t0, dtbAsn + mtpr t0, itbAsn + + LDLI (t1,0x20000000) + STALL // don't dual issue the load with mtpr -pb + mfpr t0, icsr // Enable superpage mapping + STALL // don't dual issue the load with mtpr -pb + bis t0, t1, t0 + mtpr t0, icsr + + STALL // Required stall to update chip ... + STALL + STALL + STALL + STALL + + ldq_p s0, PCB_Q_PTBR(a1) + sll s0, VA_S_OFF, s0 // Shift PTBR into position + STALL // don't dual issue the load with mtpr -pb + mtpr s0, ptPtbr // PHYSICAL MBOX INST -> MT PT20 IN 0,1 + STALL // don't dual issue the load with mtpr -pb + ldq_p sp, PCB_Q_KSP(a1) + + mtpr a0, excAddr // Load the dispatch address. + STALL // don't dual issue the load with mtpr -pb + bis a3, zero, a0 // first free PFN + ldq_p a1, PCB_Q_PTBR(a1) // ptbr + ldq_p a2, 24(zero) // argc + ldq_p a3, 32(zero) // argv + ldq_p a4, 40(zero) // environ + lda a5, 0(zero) // osf_param + STALL // don't dual issue the load with mtpr -pb + mtpr zero, dtbIa // Flush all D-stream TB entries + mtpr zero, itbIa // Flush all I-stream TB entries + br zero, 2f + + ALIGN_BLOCK + +2: NOP + mtpr zero, icFlush // Flush the icache. + NOP + NOP + + NOP // Required NOPs ... 1-10 + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + + NOP // Required NOPs ... 11-20 + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + + NOP // Required NOPs ... 21-30 + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + + NOP // Required NOPs ... 31-40 + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + + NOP // Required NOPs ... 41-44 + NOP + NOP + NOP + + hw_rei_stall // Dispatch to kernel diff --git a/system/alpha/console/paljtoslave.S b/system/alpha/console/paljtoslave.S new file mode 100644 index 0000000000..59cfb210d3 --- /dev/null +++ b/system/alpha/console/paljtoslave.S @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2003-2004 The Regents of The University of Michigan + * Copyright (c) 1993 The Hewlett-Packard Development Company + * 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. + */ + +#include "dc21164FromGasSources.h" // DECchip 21164 specific definitions +#include "ev5_defs.h" +#include "fromHudsonOsf.h" // OSF/1 specific definitions +#include "fromHudsonMacros.h" // Global macro definitions + +/* + * args: + * a0: here + * a1: boot location + * a2: CSERVE_J_KTOPAL + * a3: restrart_pv + * a4: vptb + * a5: my_rpb + * + * SRM Console Architecture III 3-26 + */ + + .global palJToSlave + .text 3 +palJToSlave: + + ALIGN_BRANCH + + bis a3, zero, pv + bis zero, zero, t11 + bis zero, zero, ra + + /* Point the Vptbr to a2 */ + + mtpr a4, mVptBr // Load Mbox copy + mtpr a4, iVptBr // Load Ibox copy + STALL // don't dual issue the load with mtpr -pb + + /* Turn on superpage mapping in the mbox and icsr */ + lda t0, (2< + STALL // don't dual issue the load with mtpr -pb + mtpr t0, mcsr // Set the super page mode enable bit + STALL // don't dual issue the load with mtpr -pb + + lda t0, 0(zero) + mtpr t0, dtbAsn + mtpr t0, itbAsn + + LDLI (t1,0x20000000) + STALL // don't dual issue the load with mtpr -pb + mfpr t0, icsr // Enable superpage mapping + STALL // don't dual issue the load with mtpr -pb + bis t0, t1, t0 + mtpr t0, icsr + + STALL // Required stall to update chip ... + STALL + STALL + STALL + STALL + + ldq_p s0, PCB_Q_PTBR(a5) + sll s0, VA_S_OFF, s0 // Shift PTBR into position + STALL // don't dual issue the load with mtpr -pb + mtpr s0, ptPtbr // PHYSICAL MBOX INST -> MT PT20 IN 0,1 + STALL // don't dual issue the load with mtpr -pb + ldq_p sp, PCB_Q_KSP(a5) + + mtpr zero, dtbIa // Flush all D-stream TB entries + mtpr zero, itbIa // Flush all I-stream TB entries + + mtpr a1, excAddr // Load the dispatch address. + + STALL // don't dual issue the load with mtpr -pb + STALL // don't dual issue the load with mtpr -pb + mtpr zero, dtbIa // Flush all D-stream TB entries + mtpr zero, itbIa // Flush all I-stream TB entries + br zero, 2f + + ALIGN_BLOCK + +2: NOP + mtpr zero, icFlush // Flush the icache. + NOP + NOP + + NOP // Required NOPs ... 1-10 + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + + NOP // Required NOPs ... 11-20 + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + + NOP // Required NOPs ... 21-30 + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + + NOP // Required NOPs ... 31-40 + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + + NOP // Required NOPs ... 41-44 + NOP + NOP + NOP + + hw_rei_stall // Dispatch to kernel + diff --git a/system/alpha/console/printf.c b/system/alpha/console/printf.c new file mode 100644 index 0000000000..3d8cb41084 --- /dev/null +++ b/system/alpha/console/printf.c @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2003-2004 The Regents of The University of Michigan + * Copyright (c) 1993 The Hewlett-Packard Development Company + * 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. + */ + +#include +#include +#include +#include "m5op.h" + +/* The string s is terminated by a '\0' */ +void +PutString(const char *s) +{ + while (*s) + PutChar(*s++); +} + +/* print c count times */ +void +PutRepChar(char c, int count) +{ + while (count--) + PutChar(c); +} + +/* put string reverse */ +void +PutStringReverse(const char *s, int index) +{ + while (index-- > 0) + PutChar(s[index]); +} + +/* + * prints value in radix, in a field width width, with fill + * character fill + * if radix is negative, print as signed quantity + * if width is negative, left justify + * if width is 0, use whatever is needed + * if fill is 0, use ' ' + */ +void +PutNumber(long value, int radix, int width, char fill) +{ + char buffer[40]; + uint bufferindex = 0; + ulong uvalue; + ushort digit; + ushort left = 0; + ushort negative = 0; + + if (fill == 0) + fill = ' '; + + if (width < 0) { + width = -width; + left = 1; + } + + if (width < 0 || width > 80) + width = 0; + + if (radix < 0) { + radix = -radix; + if (value < 0) { + negative = 1; + value = -value; + } + } + + switch (radix) { + case 8: + case 10: + case 16: + break; + + default: + PutString("****"); + return; + } + + uvalue = value; + + do { + if (radix != 16) { + digit = (ushort)(uvalue % radix); + uvalue /= radix; + } else { + digit = (ushort)(uvalue & 0xf); + uvalue = uvalue >> 4; + } + buffer[bufferindex] = digit + ((digit <= 9) ? '0' : ('A' - 10)); + bufferindex += 1; + } while (uvalue != 0); + + /* fill # ' ' and negative cannot happen at once */ + if (negative) { + buffer[bufferindex] = '-'; + bufferindex += 1; + } + + if ((uint)width <= bufferindex) { + PutStringReverse(buffer, bufferindex); + } else { + width -= bufferindex; + if (!left) + PutRepChar(fill, width); + PutStringReverse(buffer, bufferindex); + if (left) + PutRepChar(fill, width); + } +} + +ulong +power(long base, long n) +{ + ulong p; + + for (p = 1; n > 0; --n) + p = p * base; + return p; +} + +void +putFloat(double a, int fieldwidth, char fill) +{ + int i; + ulong b; + + /* + * Put out everything before the decimal place. + */ + PutNumber(((ulong) a), 10, fieldwidth, fill); + + /* + * Output the decimal place. + */ + PutChar('.' & 0x7f); + + /* + * Output the n digits after the decimal place. + */ + for (i = 1; i < 6; i++) { + b = (ulong)(power(10, i) * (double)(a - (ulong) a)); + PutChar((char)(b % 10) + '0'); + } +} + +const char * +FormatItem(const char *f, va_list *ap) +{ + char c; + int fieldwidth = 0; + int leftjust = 0; + int radix = 0; + char fill = ' '; + + if (*f == '0') + fill = '0'; + + while (c = *f++) { + if (c >= '0' && c <= '9') { + fieldwidth = (fieldwidth * 10) + (c - '0'); + } else { + switch (c) { + case '\000': + return(--f); + case '%': + PutChar('%'); + return(f); + case '-': + leftjust = 1; + break; + case 'c': { + char a = (char)va_arg(*ap, int); + + if (leftjust) + PutChar(a & 0x7f); + if (fieldwidth > 0) + PutRepChar(fill, fieldwidth - 1); + if (!leftjust) + PutChar(a & 0x7f); + return(f); + } + case 's': { + const char *a = va_arg(*ap, const char *); + + if (leftjust) + PutString((const char *) a); + if (fieldwidth > strlen((const char *) a)) + PutRepChar(fill, fieldwidth - strlen((const char *)a)); + if (!leftjust) + PutString((const char *) a); + return(f); + } + case 'd': + radix = -10; + break; + case 'u': + radix = 10; + break; + case 'x': + radix = 16; + break; + case 'X': + radix = 16; + break; + case 'o': + radix = 8; + break; + case 'f': { + double a = va_arg(*ap, double); + + putFloat(a, fieldwidth, fill); + return(f); + } + default: /* unknown switch! */ + radix = 3; + break; + } + } + + if (radix) + break; + } + + if (leftjust) + fieldwidth = -fieldwidth; + + long a = va_arg(*ap, long); + PutNumber(a, radix, fieldwidth, fill); + + return(f); +} + +int +printf(const char *f, ...) +{ + va_list ap; + + va_start(ap, f); + + while (*f) { + if (*f == '%') + f = FormatItem(f + 1, &ap); + else + PutChar(*f++); + } + + if (*(f - 1) == '\n') { + /* add a line-feed (SimOS console output goes to shell */ + PutChar('\r'); + } + + va_end(ap); /* clean up */ + return 0; +} + +void +panic(const char *f, ...) +{ + va_list ap; + + va_start(ap, f); + + printf("CONSOLE PANIC (looping): "); + while (*f) { + if (*f == '%') + f = FormatItem(f + 1, &ap); + else + PutChar(*f++); + } + + va_end(ap); /* clean up */ + m5_panic(); +} diff --git a/system/alpha/h/cserve.h b/system/alpha/h/cserve.h new file mode 100644 index 0000000000..5b0e0f61c6 --- /dev/null +++ b/system/alpha/h/cserve.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1993 The Hewlett-Packard Development Company + * 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. + */ + +#define __CSERVE_LOADED 1 + +/* + * Console Service (cserve) sub-function codes: + */ +#define CSERVE_K_LDQP 0x01 +#define CSERVE_K_STQP 0x02 +#define CSERVE_K_JTOPAL 0x09 +#define CSERVE_K_WR_INT 0x0A +#define CSERVE_K_RD_IMPURE 0x0B +#define CSERVE_K_PUTC 0x0F +#define CSERVE_K_WR_ICSR 0x10 +#define CSERVE_K_WR_ICCSR 0x10 /* for ev4 backwards compatibility */ +#define CSERVE_K_RD_ICSR 0x11 +#define CSERVE_K_RD_ICCSR 0x11 /* for ev4 backwards compatibility */ +#define CSERVE_K_RD_BCCTL 0x12 +#define CSERVE_K_RD_BCCFG 0x13 + +#define CSERVE_K_WR_BCACHE 0x16 + +#define CSERVE_K_RD_BCCFG_OFF 0x17 +#define CSERVE_K_JTOKERN 0x18 + + diff --git a/system/alpha/h/dc21164FromGasSources.h b/system/alpha/h/dc21164FromGasSources.h new file mode 100644 index 0000000000..038861d360 --- /dev/null +++ b/system/alpha/h/dc21164FromGasSources.h @@ -0,0 +1,886 @@ +/* + * Copyright (c) 1993 The Hewlett-Packard Development Company + * 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. + */ + +#ifndef DC21164FROMGASSOURCES_INCLUDED +#define DC21164FROMGASSOURCES_INCLUDED 1 + +/* +** +** INTERNAL PROCESSOR REGISTER DEFINITIONS +** +** The internal processor register definitions below are annotated +** with one of the following symbols: +** +** RW - The register may be read and written +** RO - The register may only be read +** WO - The register may only be written +** +** For RO and WO registers, all bits and fields within the register are +** also read-only or write-only. For RW registers, each bit or field +** within the register is annotated with one of the following: +** +** RW - The bit/field may be read and written +** RO - The bit/field may be read; writes are ignored +** WO - The bit/field may be written; reads return UNPREDICTABLE +** WZ - The bit/field may be written; reads return a zero value +** W0C - The bit/field may be read; write-zero-to-clear +** W1C - The bit/field may be read; write-one-to-clear +** WA - The bit/field may be read; write-anything-to-clear +** RC - The bit/field may be read, causing state to clear; +** writes are ignored +** +*/ + + +/* +** +** Ibox IPR Definitions: +** +*/ + +// replaced by ev5_defs.h #define isr 0x100 /* RO - Interrupt Summary */ +#define itbTag 0x101 /* WO - ITB Tag */ +#define itbPte 0x102 /* RW - ITB Page Table Entry */ +#define itbAsn 0x103 /* RW - ITB Address Space Number */ +#define itbPteTemp 0x104 /* RO - ITB Page Table Entry Temporary */ +#define itbIa 0x105 /* WO - ITB Invalidate All */ +#define itbIap 0x106 /* WO - ITB Invalidate All Process */ +#define itbIs 0x107 /* WO - ITB Invalidate Single */ +// replaced by ev5_defs.h #define sirr 0x108 /* RW - Software Interrupt Request */ +// replaced by ev5_defs.h #define astrr 0x109 /* RW - Async. System Trap Request */ +// replaced by ev5_defs.h #define aster 0x10A /* RW - Async. System Trap Enable */ +#define excAddr 0x10B /* RW - Exception Address */ +#define excSum 0x10C /* RW - Exception Summary */ +#define excMask 0x10D /* RO - Exception Mask */ +#define palBase 0x10E /* RW - PAL Base */ +#define ips 0x10F /* RW - Processor Status */ +// replaced by ev5_defs.h #define ipl 0x110 /* RW - Interrupt Priority Level */ +#define intId 0x111 /* RO - Interrupt ID */ +#define iFaultVaForm 0x112 /* RO - Formatted Faulting VA */ +#define iVptBr 0x113 /* RW - I-Stream Virtual Page Table Base */ +#define hwIntClr 0x115 /* WO - Hardware Interrupt Clear */ +#define slXmit 0x116 /* WO - Serial Line Transmit */ +#define slRcv 0x117 /* RO - Serial Line Receive */ +// replaced by ev5_defs.h #define icsr 0x118 /* RW - Ibox Control/Status */ +#define icFlush 0x119 /* WO - I-Cache Flush Control */ +#define flushIc 0x119 /* WO - I-Cache Flush Control (DC21064 Symbol) */ +#define icPerr 0x11A /* RW - I-Cache Parity Error Status */ +#define PmCtr 0x11C /* RW - Performance Counter */ + +/* +** +** Ibox Control/Status Register (ICSR) Bit Summary +** +** Extent Size Name Type Function +** ------ ---- ---- ---- ------------------------------------ +** <39> 1 TST RW,0 Assert Test Status +** <38> 1 ISTA RO I-Cache BIST Status +** <37> 1 DBS RW,1 Debug Port Select +** <36> 1 FBD RW,0 Force Bad I-Cache Data Parity +** <35> 1 FBT RW,0 Force Bad I-Cache Tag Parity +** <34> 1 FMS RW,0 Force I-Cache Miss +** <33> 1 SLE RW,0 Enable Serial Line Interrupts +** <32> 1 CRDE RW,0 Enable Correctable Error Interrupts +** <30> 1 SDE RW,0 Enable PAL Shadow Registers +** <29:28> 2 SPE RW,0 Enable I-Stream Super Page Mode +** <27> 1 HWE RW,0 Enable PALRES Instrs in Kernel Mode +** <26> 1 FPE RW,0 Enable Floating Point Instructions +** <25> 1 TMD RW,0 Disable Ibox Timeout Counter +** <24> 1 TMM RW,0 Timeout Counter Mode +** +*/ + +#define ICSR_V_TST 39 +#define ICSR_M_TST (1< 1 TMT WO,1 Serial line transmit data +** +*/ + +#define SLXMIT_V_TMT 7 +#define SLXMIT_M_TMT (1< 1 RCV RO Serial line receive data +** +*/ + +#define SLRCV_V_RCV 6 +#define SLRCV_M_RCV (1< 1 TMR W1C Timeout reset error +** <12> 1 TPE W1C Tag parity error +** <11> 1 DPE W1C Data parity error +** +*/ + +#define ICPERR_V_TMR 13 +#define ICPERR_M_TMR (1< 1 IOV WA Integer overflow +** <15> 1 INE WA Inexact result +** <14> 1 UNF WA Underflow +** <13> 1 FOV WA Overflow +** <12> 1 DZE WA Division by zero +** <11> 1 INV WA Invalid operation +** <10> 1 SWC WA Software completion +** +*/ + +#define EXC_V_IOV 16 +#define EXC_M_IOV (1< 1 SLC W1C Clear Serial Line interrupt +** <32> 1 CRDC W1C Clear Correctable Read Data interrupt +** <29> 1 PC2C W1C Clear Performance Counter 2 interrupt +** <28> 1 PC1C W1C Clear Performance Counter 1 interrupt +** <27> 1 PC0C W1C Clear Performance Counter 0 interrupt +** +*/ + +#define HWINT_V_SLC 33 +#define HWINT_M_SLC (1< 1 HLT RO External Halt interrupt +** <33> 1 SLI RO Serial Line interrupt +** <32> 1 CRD RO Correctable ECC errors +** <31> 1 MCK RO System Machine Check +** <30> 1 PFL RO Power Fail +** <29> 1 PC2 RO Performance Counter 2 interrupt +** <28> 1 PC1 RO Performance Counter 1 interrupt +** <27> 1 PC0 RO Performance Counter 0 interrupt +** <23> 1 I23 RO External Hardware interrupt +** <22> 1 I22 RO External Hardware interrupt +** <21> 1 I21 RO External Hardware interrupt +** <20> 1 I20 RO External Hardware interrupt +** <19> 1 ATR RO Async. System Trap request +** <18:4> 15 SIRR RO,0 Software Interrupt request +** <3:0> 4 ASTRR RO Async. System Trap request (USEK) +** +**/ + +#define ISR_V_HLT 34 +#define ISR_M_HLT (1< 6 OPCODE RO Opcode of faulting instruction +** <10:06> 5 RA RO Ra field of faulting instruction +** <5> 1 BAD_VA RO Bad virtual address +** <4> 1 DTB_MISS RO Reference resulted in DTB miss +** <3> 1 FOW RO Fault on write +** <2> 1 FOR RO Fault on read +** <1> 1 ACV RO Access violation +** <0> 1 WR RO Reference type +** +*/ + +#define MMSTAT_V_OPC 11 +#define MMSTAT_M_OPC (0x3F< 1 DBG1 RW,0 Mbox Debug Packet Select +** <4> 1 E_BE RW,0 Ebox Big Endian mode enable +** <3> 1 DBG0 RW,0 Debug Test Select +** <2:1> 2 SP RW,0 Superpage mode enable +** <0> 1 M_BE RW,0 Mbox Big Endian mode enable +** +*/ + +#define MCSR_V_DBG1 5 +#define MCSR_M_DBG1 (1< 1 TP1 RO Dcache bank 1 tag parity error +** <4> 1 TP0 RO Dcache bank 0 tag parity error +** <3> 1 DP1 RO Dcache bank 1 data parity error +** <2> 1 DP0 RO Dcache bank 0 data parity error +** <1> 1 LOCK W1C Locks/clears bits <5:2> +** <0> 1 SEO W1C Second Dcache parity error occurred +** +*/ + +#define DCPERR_V_TP1 5 +#define DCPERR_M_TP1 (1< 1 DOA RO Hardware Dcache Disable +** <3> 1 PERR_DIS RW,0 Disable Dcache Parity Error reporting +** <2> 1 BAD_DP RW,0 Force Dcache data bad parity +** <1> 1 FHIT RW,0 Force Dcache hit +** <0> 1 ENA RW,0 Software Dcache Enable +** +*/ + +#define DC_V_DOA 4 +#define DC_M_DOA (1< 1 WB RO,0 If set, pending WB request +** <6> 1 DREAD RO,0 If set, pending D-read request +** +*/ + +#define MAF_V_WB_PENDING 7 +#define MAF_M_WB_PENDING (1< 3 SET_EN RW,1 Set enable +** <12> 1 BLK_SIZE RW,1 Scache/Bcache block size select +** <11:08> 4 FB_DP RW,0 Force bad data parity +** <07:02> 6 TAG_STAT RW Tag status and parity +** <1> 1 FLUSH RW,0 If set, clear all tag valid bits +** <0> 1 FHIT RW,0 Force hits +** +*/ + +#define SC_V_SET_EN 13 +#define SC_M_SET_EN (7< 1 DIS_VIC_BUF WO,0 Disable Scache victim buffer +** <26> 1 DIS_BAF_BYP WO,0 Disable speculative Bcache reads +** <25> 1 DBG_MUX_SEL WO,0 Debug MUX select +** <24:19> 6 PM_MUX_SEL WO,0 Performance counter MUX select +** <18:17> 2 BC_WAVE WO,0 Number of cycles of wave pipelining +** <16> 1 TL_PIPE_LATCH WO,0 Pipe system control pins +** <15> 1 EI_DIS_ERR WO,1 Disable ECC (parity) error +** <14:13> 2 BC_BAD_DAT WO,0 Force bad data +** <12:08> 5 BC_TAG_STAT WO Bcache tag status and parity +** <7> 1 BC_FHIT WO,0 Bcache force hit +** <6> 1 EI_ECC WO,1 ECC or byte parity mode +** <5> 1 VTM_FIRST WO,1 Drive out victim block address first +** <4> 1 CORR_FILL_DAT WO,1 Correct fill data +** <3> 1 EI_CMD_GRP3 WO,0 Drive MB command to external pins +** <2> 1 EI_CMD_GRP2 WO,0 Drive LOCK & SET_DIRTY to ext. pins +** <1> 1 ALLOC_CYC WO,0 Allocate cycle for non-cached LDs. +** <0> 1 BC_ENA W0,0 Bcache enable +** +*/ +#define BC_V_DIS_SC_VIC_BUF 27 +#define BC_M_DIS_SC_VIC_BUF (1<>1) +/* +** +** Bcache Configuration Register (BC_CONFIG) Bit Summary +** +** Extent Size Name Type Function +** ------ ---- ---- ---- --------------------------------- +** <35:29> 7 RSVD WO Reserved - Must Be Zero +** <28:20> 9 WE_CTL WO,0 Bcache write enable control +** <19:19> 1 RSVD WO,0 Reserved - Must Be Zero +** <18:16> 3 WE_OFF WO,1 Bcache fill write enable pulse offset +** <15:15> 1 RSVD WO,0 Reserved - Must Be Zero +** <14:12> 3 RD_WR_SPC WO,7 Bcache private read/write spacing +** <11:08> 4 WR_SPD WO,4 Bcache write speed in CPU cycles +** <07:04> 4 RD_SPD WO,4 Bcache read speed in CPU cycles +** <03:03> 1 RSVD WO,0 Reserved - Must Be Zero +** <02:00> 3 SIZE WO,1 Bcache size +*/ +#define BC_V_WE_CTL 20 +#define BC_M_WE_CTL (0x1FF< = 1. +*/ + +#define p0 r8 /* ITB/DTB Miss Scratch */ +#define p1 r9 /* ITB/DTB Miss Scratch */ +#define p2 r10 /* ITB/DTB Miss Scratch */ +#define p3 r11 +// #define ps r11 /* Processor Status */ +#define p4 r12 /* Local Scratch */ +#define p5 r13 /* Local Scratch */ +#define p6 r14 /* Local Scratch */ +#define p7 r25 /* Local Scratch */ + +/* +** SRM Defined State Definitions: +*/ + +/* +** This table is an accounting of the DECchip 21164 storage used to +** implement the SRM defined state for OSF/1. +** +** IPR Name Internal Storage +** -------- ---------------- +** Processor Status ps, dtbCm, ipl, r11 +** Program Counter Ibox +** Interrupt Entry ptEntInt +** Arith Trap Entry ptEntArith +** MM Fault Entry ptEntMM +** Unaligned Access Entry ptEntUna +** Instruction Fault Entry ptEntIF +** Call System Entry ptEntSys +** User Stack Pointer ptUsp +** Kernel Stack Pointer ptKsp +** Kernel Global Pointer ptKgp +** System Value ptSysVal +** Page Table Base Register ptPtbr +** Virtual Page Table Base iVptBr, mVptBr +** Process Control Block Base ptPcbb +** Address Space Number itbAsn, dtbAsn +** Cycle Counter cc, ccCtl +** Float Point Enable icsr +** Lock Flag Cbox/System +** Unique PCB +** Who-Am-I ptWhami +*/ + +#define ptEntUna pt2 /* Unaligned Access Dispatch Entry */ +#define ptImpure pt3 /* Pointer To PAL Scratch Area */ +#define ptEntIF pt7 /* Instruction Fault Dispatch Entry */ +#define ptIntMask pt8 /* Interrupt Enable Mask */ +#define ptEntSys pt9 /* Call System Dispatch Entry */ +#define ptTrap pt11 +#define ptEntInt pt11 /* Hardware Interrupt Dispatch Entry */ +#define ptEntArith pt12 /* Arithmetic Trap Dispatch Entry */ +#if defined(KDEBUG) +#define ptEntDbg pt13 /* Kernel Debugger Dispatch Entry */ +#endif /* KDEBUG */ +#define ptMisc pt16 /* Miscellaneous Flags */ +#define ptWhami pt16 /* Who-Am-I Register Pt16<15:8> */ +#define ptMces pt16 /* Machine Check Error Summary Pt16<4:0> */ +#define ptSysVal pt17 /* Per-Processor System Value */ +#define ptUsp pt18 /* User Stack Pointer */ +#define ptKsp pt19 /* Kernel Stack Pointer */ +#define ptPtbr pt20 /* Page Table Base Register */ +#define ptEntMM pt21 /* MM Fault Dispatch Entry */ +#define ptKgp pt22 /* Kernel Global Pointer */ +#define ptPcbb pt23 /* Process Control Block Base */ + +/* +** +** Miscellaneous PAL State Flags (ptMisc) Bit Summary +** +** Extent Size Name Function +** ------ ---- ---- --------------------------------- +** <55:48> 8 SWAP Swap PALcode flag -- character 'S' +** <47:32> 16 MCHK Machine Check Error code +** <31:16> 16 SCB System Control Block vector +** <15:08> 8 WHAMI Who-Am-I identifier +** <04:00> 5 MCES Machine Check Error Summary bits +** +*/ + +#define PT16_V_MCES 0 +#define PT16_V_WHAMI 8 +#define PT16_V_SCB 16 +#define PT16_V_MCHK 32 +#define PT16_V_SWAP 48 + +#endif /* DC21164FROMGASSOURCES_INCLUDED */ diff --git a/system/alpha/h/ev5_alpha_defs.h b/system/alpha/h/ev5_alpha_defs.h new file mode 100644 index 0000000000..d0264a4ca9 --- /dev/null +++ b/system/alpha/h/ev5_alpha_defs.h @@ -0,0 +1,314 @@ +/* + * Copyright (c) 1993 The Hewlett-Packard Development Company + * 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. + */ + +#ifndef EV5_ALPHA_DEFS_INCLUDED +#define EV5_ALPHA_DEFS_INCLUDED 1 + +// from ev5_alpha_defs.mar from Lance's fetch directory +// Lower-caseified and $ signs removed ... pb Nov/95 + +// +// PS Layout - PS +// Loc Size name function +// ------ ------ ______ ----------------------------------- +// <31:29> 3 SA stack alignment +// <31:13> 24 RES Reserved MBZ +// <12:8> 5 IPL Priority level +// <7> 1 VMM Virtual Mach Monitor +// <6:5> 2 RES Reserved MBZ +// <4:3> 2 CM Current Mode +// <2> 1 IP Interrupt Pending +// <1:0> 2 SW Software bits +// + +#define ps_v_sw 0 +#define ps_m_sw (3< 32 PFN Page Frame Number +// <31:16> 16 SOFT Bits reserved for software use +// <15> 1 UWE User write enable +// <14> 1 SWE Super write enable +// <13> 1 EWE Exec write enable +// <12> 1 KWE Kernel write enable +// <11> 1 URE User read enable +// <10> 1 SRE Super read enable +// <9> 1 ERE Exec read enable +// <8> 1 KRE Kernel read enable +// <7:6> 2 RES Reserved SBZ +// <5> 1 HPF Huge Page Flag +// <4> 1 ASM Wild card address space number match +// <3> 1 FOE Fault On execute +// <2> 1 FOW Fault On Write +// <1> 1 FOR Fault On Read +// <0> 1 V valid bit +// + +#define pte_v_pfn 32 +#define pte_m_soft (0xFFFF0000) +#define pte_v_soft 16 +#define pte_m_uwe (0x8000) +#define pte_v_uwe 15 +#define pte_m_swe (0x4000) +#define pte_v_swe 14 +#define pte_m_ewe (0x2000) +#define pte_v_ewe 13 +#define pte_m_kwe (0x1000) +#define pte_v_kwe 12 +#define pte_m_ure (0x0800) +#define pte_v_ure 11 +#define pte_m_sre (0x0400) +#define pte_v_sre 10 +#define pte_m_ere (0x0200) +#define pte_v_ere 9 +#define pte_m_kre (0x0100) +#define pte_v_kre 8 +#define pte_m_hpf (0x0020) +#define pte_v_hpf 5 +#define pte_m_asm (0x0010) +#define pte_v_asm 4 +#define pte_m_foe (0x0008) +#define pte_v_foe 3 +#define pte_m_fow (0x0004) +#define pte_v_fow 2 +#define pte_m_for (0x0002) +#define pte_v_for 1 +#define pte_m_v (0x0001) +#define pte_v_v 0 + +// +// VA layout - symbol prefix VA_ +// +// Loc Size name function +// ------ ------ ------- ----------------------------------- +// <42:33> 10 SEG1 First seg table offset for mapping +// <32:23> 10 SEG2 Second seg table offset for mapping +// <22:13> 10 SEG3 Third seg table offset for mapping +// <12:0> 13 OFFSET Byte within page +// + +#define va_m_offset (0x000000001FFF) +#define va_v_offset 0 +#define va_m_seg3 (0x0000007FE000) +#define va_v_seg3 13 +#define va_m_seg2 (0x0001FF800000) +#define va_v_seg2 23 +#define va_m_seg1 (0x7FE00000000) +#define va_v_seg1 33 + +// +//PRIVILEGED CONTEXT BLOCK (PCB) +// +#define pcb_q_ksp 0 +#define pcb_q_esp 8 +#define pcb_q_ssp 16 +#define pcb_q_usp 24 +#define pcb_q_ptbr 32 +#define pcb_q_asn 40 +#define pcb_q_ast 48 +#define pcb_q_fen 56 +#define pcb_q_cc 64 +#define pcb_q_unq 72 +#define pcb_q_sct 80 + +#define pcb_v_asten 0 +#define pcb_m_asten (0x0f< ; Software completion +// exs_v_inv <1> ; Ivalid operation +// exs_v_dze <2> ; Div by zero +// exs_v_fov <3> ; Floating point overflow +// exs_v_unf <4> ; Floating point underflow +// exs_v_ine <5> ; Floating point inexact +// exs_v_iov <6> ; Floating convert to integer overflow +#define exs_v_swc 0 +#define exs_v_inv 1 +#define exs_v_dze 2 +#define exs_v_fov 3 +#define exs_v_unf 4 +#define exs_v_ine 5 +#define exs_v_iov 6 + +#define exs_m_swc (1< ; machine check in progress +// mces_v_sce <1> ; system correctable error +// mces_v_pce <2> ; processor correctable error +// mces_v_dpc <3> ; disable reporting of processor correctable errors +// mces_v_dsc <4> ; disable reporting of system correctable errors +#define mces_v_mchk 0 +#define mces_v_sce 1 +#define mces_v_pce 2 +#define mces_v_dpc 3 +#define mces_v_dsc 4 + +#define mces_m_mchk (1< = 1, dc_fhit = 0, dc_bad_parity = 0 +#define mcsr_v_big_endian 0 +#define mcsr_v_sp0 1 +#define mcsr_v_sp1 2 +#define mcsr_v_mbox_sel 3 +#define mcsr_v_e_big_endian 4 +#define mcsr_v_dbg_packet_sel 5 +#define dc_mode_v_dc_ena 0 +#define dc_mode_v_dc_fhit 1 +#define dc_mode_v_dc_bad_parity 2 +#define dc_mode_v_dc_perr_dis 3 +#define dc_mode_v_dc_doa 4 +#define maf_mode_v_maf_nomerge 0 +#define maf_mode_v_wb_flush_always 1 +#define maf_mode_v_wb_nomerge 2 +#define maf_mode_v_io_nomerge 3 +#define maf_mode_v_wb_cnt_disable 4 +#define maf_mode_v_maf_arb_disable 5 +#define maf_mode_v_dread_pending 6 +#define maf_mode_v_wb_pending 7 +// mbox and dcache registers, continued. +#define mm_stat_v_wr 0 +#define mm_stat_v_acv 1 +#define mm_stat_v_for 2 +#define mm_stat_v_fow 3 +#define mm_stat_v_dtb_miss 4 +#define mm_stat_v_bad_va 5 +#define mm_stat_s_ra 5 +#define mm_stat_v_ra 6 +#define mm_stat_s_opcode 6 +#define mm_stat_v_opcode 11 +#define mvptbr_s_vptb 31 +#define mvptbr_v_vptb 33 +#define va_form_s_va 30 +#define va_form_v_va 3 +#define va_form_s_vptb 31 +#define va_form_v_vptb 33 +#define va_form_nt_s_va 19 +#define va_form_nt_v_va 3 +//.endm + +#endif diff --git a/system/alpha/h/ev5_impure.h b/system/alpha/h/ev5_impure.h new file mode 100644 index 0000000000..88634a7ef0 --- /dev/null +++ b/system/alpha/h/ev5_impure.h @@ -0,0 +1,420 @@ +/* + * Copyright (c) 1993 The Hewlett-Packard Development Company + * 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. + */ + +#ifndef EV5_IMPURE_INCLUDED +#define EV5_IMPURE_INCLUDED + +// This uses the Hudson file format from "impure.h" but with the fields from +// the distrubuted palcode "ev5_impure.sdl" .. pboyle Nov/95 + +// file: impure.sdl +// +// PAL impure scratch area and logout area data structure definitions for +// Alpha firmware. +// +// +// module $pal_impure; +// +// Edit Date Who Description +// ---- --------- --- --------------------- +// 1 7-Jul-93 JEM Initial Entry +// 2 18-nov-93 JEM Add shadow bc_ctl and pmctr_ctl to impure area +// Delete mvptbr +// Calculate pal$logout from end of impure area +// 3 6-dec-93 JEM Add pmctr_ctl bitfield definitions +// 4 3-feb-94 JEM Remove f31,r31 from impure area; Remove bc_ctl, +// pmctr_ctl; add ic_perr_stat, pmctr, dc_perr_stat, +// sc_stat, sc_addr, sc_ctl, bc_tag_addr, ei_stat, +// ei_addr, fill_syn, ld_lock +// 5 19-feb-94 JEM add gpr constants, and add f31,r31 back in to be +// consistent with ev4 +// add cns$ipr_offset +// 6 18-apr-94 JEM Add shadow bc_ctl and pmctr_ctl to impure area again. +// 7 18-jul-94 JEM Add bc_config shadow. Add mchk$sys_base constant +// to mchk logout frame +// +// +// constant REVISION equals 7 prefix IMPURE$; // Revision number of this file +//orig + +/* +** Macros for saving/restoring data to/from the PAL impure scratch +** area. +** +** The console save state area is larger than the addressibility +** of the HW_LD/ST instructions (10-bit signed byte displacement), +** so some adjustments to the base offsets, as well as the offsets +** within each base region, are necessary. +** +** The console save state area is divided into two segments; the +** CPU-specific segment and the platform-specific segment. The +** state that is saved in the CPU-specific segment includes GPRs, +** FPRs, IPRs, halt code, MCHK flag, etc. All other state is saved +** in the platform-specific segment. +** +** The impure pointer will need to be adjusted by a different offset +** value for each region within a given segment. The SAVE and RESTORE +** macros will auto-magically adjust the offsets accordingly. +** +*/ +//#define SEXT10(X) (((X) & 0x200) ? ((X) | 0xfffffffffffffc00) : (X)) +#define SEXT10(X) ((X) & 0x3ff) +//#define SEXT10(X) (((X) << 55) >> 55) + +#define SAVE_GPR(reg,offset,base) \ + stq_p reg, (SEXT10(offset-0x200))(base) + +#define RESTORE_GPR(reg,offset,base) \ + ldq_p reg, (SEXT10(offset-0x200))(base) + + +#define SAVE_FPR(reg,offset,base) \ + stt reg, (SEXT10(offset-0x200))(base) + +#define RESTORE_FPR(reg,offset,base) \ + ldt reg, (SEXT10(offset-0x200))(base) + +#define SAVE_IPR(reg,offset,base) \ + mfpr v0, reg; \ + stq_p v0, (SEXT10(offset-CNS_Q_IPR))(base) + +#define RESTORE_IPR(reg,offset,base) \ + ldq_p v0, (SEXT10(offset-CNS_Q_IPR))(base); \ + mtpr v0, reg + +#define SAVE_SHADOW(reg,offset,base) \ + stq_p reg, (SEXT10(offset-CNS_Q_IPR))(base) + +#define RESTORE_SHADOW(reg,offset,base)\ + ldq_p reg, (SEXT10(offset-CNS_Q_IPR))(base) + +/* Structure of the processor-specific impure area */ + +/* aggregate impure struct prefix "" tag ""; + * cns$flag quadword; + * cns$hlt quadword; + */ + +/* Define base for debug monitor compatibility */ +#define CNS_Q_BASE 0x000 +#define CNS_Q_FLAG 0x100 +#define CNS_Q_HALT 0x108 + + +/* constant ( + * cns$r0,cns$r1,cns$r2,cns$r3,cns$r4,cns$r5,cns$r6,cns$r7, + * cns$r8,cns$r9,cns$r10,cns$r11,cns$r12,cns$r13,cns$r14,cns$r15, + * cns$r16,cns$r17,cns$r18,cns$r19,cns$r20,cns$r21,cns$r22,cns$r23, + * cns$r24,cns$r25,cns$r26,cns$r27,cns$r28,cns$r29,cns$r30,cns$r31 + * ) equals . increment 8 prefix "" tag ""; + * cns$gpr quadword dimension 32; + */ + +/* Offset to base of saved GPR area - 32 quadword */ +#define CNS_Q_GPR 0x110 +#define cns_gpr CNS_Q_GPR + +/* constant ( + * cns$f0,cns$f1,cns$f2,cns$f3,cns$f4,cns$f5,cns$f6,cns$f7, + * cns$f8,cns$f9,cns$f10,cns$f11,cns$f12,cns$f13,cns$f14,cns$f15, + * cns$f16,cns$f17,cns$f18,cns$f19,cns$f20,cns$f21,cns$f22,cns$f23, + * cns$f24,cns$f25,cns$f26,cns$f27,cns$f28,cns$f29,cns$f30,cns$f31 + * ) equals . increment 8 prefix "" tag ""; + * cns$fpr quadword dimension 32; + */ + +/* Offset to base of saved FPR area - 32 quadwords */ +#define CNS_Q_FPR 0x210 + +/* #t=.; + * cns$mchkflag quadword; + */ +#define CNS_Q_MCHK 0x310 + +/* constant cns$pt_offset equals .; + * constant ( + * cns$pt0,cns$pt1,cns$pt2,cns$pt3,cns$pt4,cns$pt5,cns$pt6, + * cns$pt7,cns$pt8,cns$pt9,cns$pt10,cns$pt11,cns$pt12,cns$pt13, + * cns$pt14,cns$pt15,cns$pt16,cns$pt17,cns$pt18,cns$pt19,cns$pt20, + * cns$pt21,cns$pt22,cns$pt23 + * ) equals . increment 8 prefix "" tag ""; + * cns$pt quadword dimension 24; + */ +/* Offset to base of saved PALtemp area - 25 quadwords */ +#define CNS_Q_PT 0x318 + +/* cns$shadow8 quadword; + * cns$shadow9 quadword; + * cns$shadow10 quadword; + * cns$shadow11 quadword; + * cns$shadow12 quadword; + * cns$shadow13 quadword; + * cns$shadow14 quadword; + * cns$shadow25 quadword; + */ +/* Offset to base of saved PALshadow area - 8 quadwords */ +#define CNS_Q_SHADOW 0x3D8 + +/* Offset to base of saved IPR area */ +#define CNS_Q_IPR 0x418 + +/* constant cns$ipr_offset equals .; */ +/* cns$exc_addr quadword; */ +#define CNS_Q_EXC_ADDR 0x418 +/* cns$pal_base quadword; */ +#define CNS_Q_PAL_BASE 0x420 +/* cns$mm_stat quadword; */ +#define CNS_Q_MM_STAT 0x428 +/* cns$va quadword; */ +#define CNS_Q_VA 0x430 +/* cns$icsr quadword; */ +#define CNS_Q_ICSR 0x438 +/* cns$ipl quadword; */ +#define CNS_Q_IPL 0x440 +/* cns$ps quadword; // Ibox current mode */ +#define CNS_Q_IPS 0x448 +/* cns$itb_asn quadword; */ +#define CNS_Q_ITB_ASN 0x450 +/* cns$aster quadword; */ +#define CNS_Q_ASTER 0x458 +/* cns$astrr quadword; */ +#define CNS_Q_ASTRR 0x460 +/* cns$isr quadword; */ +#define CNS_Q_ISR 0x468 +/* cns$ivptbr quadword; */ +#define CNS_Q_IVPTBR 0x470 +/* cns$mcsr quadword; */ +#define CNS_Q_MCSR 0x478 +/* cns$dc_mode quadword; */ +#define CNS_Q_DC_MODE 0x480 +/* cns$maf_mode quadword; */ +#define CNS_Q_MAF_MODE 0x488 +/* cns$sirr quadword; */ +#define CNS_Q_SIRR 0x490 +/* cns$fpcsr quadword; */ +#define CNS_Q_FPCSR 0x498 +/* cns$icperr_stat quadword; */ +#define CNS_Q_ICPERR_STAT 0x4A0 +/* cns$pmctr quadword; */ +#define CNS_Q_PM_CTR 0x4A8 +/* cns$exc_sum quadword; */ +#define CNS_Q_EXC_SUM 0x4B0 +/* cns$exc_mask quadword; */ +#define CNS_Q_EXC_MASK 0x4B8 +/* cns$intid quadword; */ +#define CNS_Q_INT_ID 0x4C0 +/* cns$dcperr_stat quadword; */ +#define CNS_Q_DCPERR_STAT 0x4C8 +/* cns$sc_stat quadword; */ +#define CNS_Q_SC_STAT 0x4D0 +/* cns$sc_addr quadword; */ +#define CNS_Q_SC_ADDR 0x4D8 +/* cns$sc_ctl quadword; */ +#define CNS_Q_SC_CTL 0x4E0 +/* cns$bc_tag_addr quadword; */ +#define CNS_Q_BC_TAG_ADDR 0x4E8 +/* cns$ei_stat quadword; */ +#define CNS_Q_EI_STAT 0x4F0 +/* cns$ei_addr quadword; */ +#define CNS_Q_EI_ADDR 0x4F8 +/* cns$fill_syn quadword; */ +#define CNS_Q_FILL_SYN 0x500 +/* cns$ld_lock quadword; */ +#define CNS_Q_LD_LOCK 0x508 +/* cns$bc_ctl quadword; // shadow of on chip bc_ctl */ +#define CNS_Q_BC_CTL 0x510 +/* cns$pmctr_ctl quadword; // saved frequency select info for performance monitor counter */ +#define CNS_Q_PM_CTL 0x518 +/* cns$bc_config quadword; // shadow of on chip bc_config */ +#define CNS_Q_BC_CFG 0x520 + +/* constant cns$size equals .; + * + * constant pal$impure_common_size equals (%x0200 +7) & %xfff8; + * constant pal$impure_specific_size equals (.+7) & %xfff8; + * constant cns$mchksize equals (.+7-#t) & %xfff8; + * constant pal$logout_area equals pal$impure_specific_size ; + * end impure; +*/ + +/* This next set of stuff came from the old code ..pb */ +#define CNS_Q_SROM_REV 0x528 +#define CNS_Q_PROC_ID 0x530 +#define CNS_Q_MEM_SIZE 0x538 +#define CNS_Q_CYCLE_CNT 0x540 +#define CNS_Q_SIGNATURE 0x548 +#define CNS_Q_PROC_MASK 0x550 +#define CNS_Q_SYSCTX 0x558 + + + +#define MACHINE_CHECK_CRD_BASE 0 +#define MACHINE_CHECK_SIZE ((CNS_Q_SYSCTX + 7 - CNS_Q_MCHK) & 0xfff8) + + + +/* + * aggregate EV5PMCTRCTL_BITS structure fill prefix PMCTR_CTL$; + * SPROCESS bitfield length 1 ; + * FILL_0 bitfield length 3 fill tag $$; + * FRQ2 bitfield length 2 ; + * FRQ1 bitfield length 2 ; + * FRQ0 bitfield length 2 ; + * CTL2 bitfield length 2 ; + * CTL1 bitfield length 2 ; + * CTL0 bitfield length 2 ; + * FILL_1 bitfield length 16 fill tag $$; + * FILL_2 bitfield length 32 fill tag $$; + * end EV5PMCTRCTL_BITS; + * + * end_module $pal_impure; + * + * module $pal_logout; + * + * // + * // Start definition of Corrected Error Frame + * // + */ + +/* + * aggregate crd_logout struct prefix "" tag ""; + */ + +#define pal_logout_area 0x600 +#define mchk_crd_base 0 + +/* mchk$crd_flag quadword; */ +#define mchk_crd_flag 0 +/* mchk$crd_offsets quadword; */ +#define mchk_crd_offsets 8 +/* + * // Pal-specific information */ +#define mchk_crd_mchk_code 0x10 +/* mchk$crd_mchk_code quadword; + * + * // CPU-specific information + * constant mchk$crd_cpu_base equals . ; + * mchk$crd_ei_addr quadword; */ +#define mchk_crd_ei_addr 0x18 +/* mchk$crd_fill_syn quadword; */ +#define mchk_crd_fill_syn 0x20 +/* mchk$crd_ei_stat quadword; */ +#define mchk_crd_ei_stat 0x28 +/* mchk$crd_isr quadword; */ +#define mchk_crd_isr 0x30 + +/* + * Hacked up constants for the turbolaser build. Hope + * this is moreless correct + */ + +#define mchk_crd_whami 0x38 +#define mchk_crd_tldev 0x40 +#define mchk_crd_tlber 0x48 +#define mchk_crd_tlesr0 0x50 +#define mchk_crd_tlesr1 0x58 +#define mchk_crd_tlesr2 0x60 +#define mchk_crd_tlesr3 0x68 +#define mchk_crd_rsvd 0x70 + + +/* + * mchk area seems different for tlaser + */ + +#define mchk_crd_size 0x80 +#define mchk_mchk_base (mchk_crd_size) + +#define mchk_tlber 0x0 +#define mchk_tlepaerr 0x8 +#define mchk_tlepderr 0x10 +#define mchk_tlepmerr 0x18 + + +/* + * // System-specific information + * constant mchk$crd_sys_base equals . ; + * constant mchk$crd_size equals (.+7) & %xfff8; + * + * end crd_logout; + * // + * // Start definition of Machine check logout Frame + * // + * aggregate logout struct prefix "" tag ""; + * mchk$flag quadword; */ +/* mchk$offsets quadword; */ +/* + * // Pal-specific information + * mchk$mchk_code quadword; */ +/* + + * mchk$pt quadword dimension 24; + * + * // CPU-specific information + * constant mchk$cpu_base equals . ; + * mchk$exc_addr quadword; + * mchk$exc_sum quadword; + * mchk$exc_mask quadword; + * mchk$pal_base quadword; + * mchk$isr quadword; + * mchk$icsr quadword; + * mchk$ic_perr_stat quadword; + * mchk$dc_perr_stat quadword; + * mchk$va quadword; + * mchk$mm_stat quadword; + * mchk$sc_addr quadword; + * mchk$sc_stat quadword; + * mchk$bc_tag_addr quadword; + * mchk$ei_addr quadword; + * mchk$fill_syn quadword; + * mchk$ei_stat quadword; + * mchk$ld_lock quadword; + * + * // System-specific information + * + * constant mchk$sys_base equals . ; + * mchk$sys_ipr1 quadword ; // Holder for system-specific stuff + * + * constant mchk$size equals (.+7) & %xfff8; + * + * + * constant mchk$crd_base equals 0 ; + * constant mchk$mchk_base equals mchk$crd_size ; + * + * + * end logout; + * + * end_module $pal_logout; +*/ + +/* + * this is lingering in the old ladbx code but looks like it was from + * ev4 days. This was 0x160 in the old days..pb + */ +#define LAF_K_SIZE MACHINE_CHECK_SIZE +#endif diff --git a/system/alpha/h/ev5_osfalpha_defs.h b/system/alpha/h/ev5_osfalpha_defs.h new file mode 100644 index 0000000000..bb98503b41 --- /dev/null +++ b/system/alpha/h/ev5_osfalpha_defs.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 1993 The Hewlett-Packard Development Company + * 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. + */ + +#ifndef EV5_OSFALPHA_DEFS_INCLUDED +#define EV5_OSFALPHA_DEFS_INCLUDED 1 + +// from ev5_osfalpha_defs.mar from Lance's fetch directory +// lowercaseified and $ changed to _ and reformatting for gas...pb Nov/95 + +// +// PS Layout - PS +// Loc Size name function +// ------ ------ ----- ----------------------------------- +// <0:2> 3 IPL Prio level +// <3> 1 CM Current Mode +// + +#define osfps_v_mode 3 +#define osfps_m_mode (1< 32 PFN Page Frame Number +// <31:16> 16 SOFT Bits reserved for software use +// <15:14> 2 +// <13> 1 UWE User write enable +// <12> 1 KWE Kernel write enable +// <11:10> 2 +// <9> 1 URE User read enable +// <8> 1 KRE Kernel read enable +// <7:6> 2 RES Reserved SBZ +// <5> 1 HPF Huge Page Flag +// <4> 1 ASM Wild card address space number match +// <3> 1 FOE Fault On execute +// <2> 1 FOW Fault On Write +// <1> 1 FOR Fault On Read +// <0> 1 V valid bit +// + +#define osfpte_v_pfn 32 +#define osfpte_m_soft (0xFFFF0000) +#define osfpte_v_soft 16 +#define osfpte_m_uwe (0x2000) +#define osfpte_v_uwe 13 +#define osfpte_m_kwe (0x1000) +#define osfpte_v_kwe 12 +#define osfpte_m_ure (0x0200) +#define osfpte_v_ure 9 +#define osfpte_m_kre (0x0100) +#define osfpte_v_kre 8 +#define osfpte_m_hpf (0x0020) +#define osfpte_v_hpf 5 +#define osfpte_m_asm (0x0010) +#define osfpte_v_asm 4 +#define osfpte_m_foe (0x0008) +#define osfpte_v_foe 3 +#define osfpte_m_fow (0x0004) +#define osfpte_v_fow 2 +#define osfpte_m_for (0x0002) +#define osfpte_v_for 1 +#define osfpte_m_v (0x0001) +#define osfpte_v_v 0 + +#define osfpte_m_ksegbits (osfpte_m_kre | osfpte_m_kwe | osfpte_m_v | osfpte_m_asm) +#define osfpte_m_prot (osfpte_m_ure+osfpte_m_uwe | osfpte_m_kre | osfpte_m_kwe) + +// +// VA layout - symbol prefix VA_ +// +// Loc Size name function +// ------ ------ ------- ----------------------------------- +// <42:33> 10 SEG1 First seg table offset for mapping +// <32:23> 10 SEG2 Second seg table offset for mapping +// <22:13> 10 SEG3 Third seg table offset for mapping +// <12:0> 13 OFFSET Byte within page +// + +#define osfva_m_offset (0x000000001FFF) +#define osfva_v_offset 0 +#define osfva_m_seg3 (0x0000007FE000) +#define osfva_v_seg3 13 +#define osfva_m_seg2 (0x0001FF800000) +#define osfva_v_seg2 23 +#define osfva_m_seg1 (0x7FE00000000) +#define osfva_v_seg1 33 + +#define osfpcb_q_ksp (0x0000) +#define osfpcb_q_usp (0x0008) +#define osfpcb_q_Usp (0x0008) +#define osfpcb_q_mmptr (0x0010) +#define osfpcb_q_Mmptr (0x0010) +#define osfpcb_l_cc (0x0018) +#define osfpcb_l_asn (0x001C) +#define osfpcb_q_unique (0x0020) +#define osfpcb_q_fen (0x0028) +#define osfpcb_v_pme 62 + +#define osfsf_ps (0x00) +#define osfsf_pc (0x08) +#define osfsf_gp (0x10) +#define osfsf_a0 (0x18) +#define osfsf_a1 (0x20) +#define osfsf_a2 (0x28) +#define osfsf_c_size (0x30) + +#endif diff --git a/system/alpha/h/ev5_paldef.h b/system/alpha/h/ev5_paldef.h new file mode 100644 index 0000000000..49cea5faab --- /dev/null +++ b/system/alpha/h/ev5_paldef.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 1993 The Hewlett-Packard Development Company + * 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. + */ + +#ifndef EV5_PALDEF_INCLUDED +#define EV5_PALDEF_INCLUDED 1 + +// from ev5_paldef.mar from Lance's fetch directory...pb Nov/95 +// some entries have been superceeded by the more recent evt_defs.h + +// These are lower-caseified and have the $ signs (unnecessarily we +// now discover) removed. + +// Note that at the bottom of this file is the version of ev5_defs.mar +// which is more recent than the top part of the file and contains +// overlapping information...pb Nov/95 + +#define hlt_c_reset 0 +#define hlt_c_hw_halt 1 +#define hlt_c_ksp_inval 2 +#define hlt_c_scbb_inval 3 +#define hlt_c_ptbr_inval 4 +#define hlt_c_sw_halt 5 +#define hlt_c_dbl_mchk 6 +#define hlt_c_mchk_from_pal 7 +#define hlt_c_start 32 +#define hlt_c_callback 33 +#define hlt_c_mpstart 34 +#define hlt_c_lfu_start 35 + +#define mchk_c_tperr (64<<1) +#define mchk_c_tcperr (65<<1) +#define mchk_c_herr (66<<1) +#define mchk_c_ecc_c (67<<1) +#define mchk_c_ecc_nc (68<<1) +#define mchk_c_unknown (69<<1) +#define mchk_c_cacksoft (70<<1) +#define mchk_c_bugcheck (71<<1) +#define mchk_c_os_bugcheck (72<<1) +#define mchk_c_dcperr (73<<1) +#define mchk_c_icperr (74<<1) +#define mchk_c_retryable_ird (75<<1) +#define mchk_c_proc_hrd_error (76<<1) +#define mchk_c_scperr (77<<1) +#define mchk_c_bcperr (78<<1) +//; mchk codes above 255 reserved for platform specific errors + + +#define mchk_c_read_nxm (256<<1) +#define mchk_c_sys_hrd_error (257<<1) +#define mchk_c_sys_ecc (258<<1) + +#define page_seg_size_bits 10 +#define page_offset_size_bits 13 +#define page_size_bytes 8192 +#define va_size_bits 43 +#define pa_size_bits 45 + +// replaced by ev5_defs.h #define pt0 (0x140) +// replaced by ev5_defs.h #define pt1 (0x141) +// replaced by ev5_defs.h #define pt2 (0x142) +#define pt_entuna (0x142) +// replaced by ev5_defs.h #define pt3 (0x143) +#define pt_impure (0x143) +// replaced by ev5_defs.h #define pt4 (0x144) +// replaced by ev5_defs.h #define pt5 (0x145) +// replaced by ev5_defs.h #define pt6 (0x146) +// replaced by ev5_defs.h #define pt7 (0x147) +#define pt_entif (0x147) +// replaced by ev5_defs.h #define pt8 (0x148) +#define pt_intmask (0x148) +// replaced by ev5_defs.h #define pt9 (0x149) +#define pt_entsys (0x149) +#define pt_ps (0x149) +// replaced by ev5_defs.h #define pt10 (0x14a) +// replaced by ev5_defs.h #define pt11 (0x14b) +#define pt_trap (0x14b) +#define pt_entint (0x14b) +// replaced by ev5_defs.h #define pt12 (0x14c) +#define pt_entarith (0x14c) +// replaced by ev5_defs.h #define pt13 (0x14d) +#define pt_sys0 (0x14d) +// replaced by ev5_defs.h #define pt14 (0x14e) +#define pt_sys1 (0x14e) +// replaced by ev5_defs.h #define pt15 (0x14f) +#define pt_sys2 (0x14f) +// replaced by ev5_defs.h #define pt16 (0x150) +#define pt_whami (0x150) +#define pt_mces (0x150) +#define pt_misc (0x150) +// replaced by ev5_defs.h #define pt17 (0x151) +#define pt_scc (0x151) +#define pt_sysval (0x151) +// replaced by ev5_defs.h #define pt18 (0x152) +#define pt_prbr (0x152) +#define pt_usp (0x152) +// replaced by ev5_defs.h #define pt19 (0x153) +#define pt_ksp (0x153) +// replaced by ev5_defs.h #define pt20 (0x154) +#define pt_ptbr (0x154) +// replaced by ev5_defs.h #define pt21 (0x155) +#define pt_vptbr (0x155) +#define pt_entmm (0x155) +// replaced by ev5_defs.h #define pt22 (0x156) +#define pt_scbb (0x156) +#define pt_kgp (0x156) +// replaced by ev5_defs.h #define pt23 (0x157) +#define pt_pcbb (0x157) + + +#define pt_misc_v_switch 48 +#define pt_misc_v_cm 56 + +#define mmcsr_c_tnv 0 +#define mmcsr_c_acv 1 +#define mmcsr_c_for 2 +#define mmcsr_c_foe 3 +#define mmcsr_c_fow 4 + +#define mm_stat_m_opcode (0x3F) +#define mm_stat_m_ra (0x1F) +#define evx_opc_sync (0x18) +#define EVX_OPC_SYNC (0x18) +#define evx_opc_hw_ld (0x1B) + +#define osf_a0_bpt (0x0) +#define osf_a0_bugchk (0x1) +#define osf_a0_gentrap (0x2) +#define osf_a0_fen (0x3) +#define osf_a0_opdec (0x4) + +#define ipl_machine_check 31 +#define ipl_powerfail 30 +#define ipl_perf_count 29 +#define ipl_clock 22 +#define ipl_interprocessor 22 + +#endif diff --git a/system/alpha/h/fromHudsonMacros.h b/system/alpha/h/fromHudsonMacros.h new file mode 100644 index 0000000000..68f8999c05 --- /dev/null +++ b/system/alpha/h/fromHudsonMacros.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 1993-1994 The Hewlett-Packard Development Company + * 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. + */ + +#ifndef HUDSON_MACROS_LOADED +#define HUDSON_MACROS_LOADED 1 + +#define STALL \ + mfpr r31, pt0 + +#define NOP \ + bis $31, $31, $31 + +/* +** Align code on an 8K byte page boundary. +*/ + +#define ALIGN_PAGE \ + .align 13 + +/* +** Align code on a 32 byte block boundary. +*/ + +#define ALIGN_BLOCK \ + .align 5 + +/* +** Align code on a quadword boundary. +*/ + +#define ALIGN_BRANCH \ + .align 3 + +/* +** Hardware vectors go in .text 0 sub-segment. +*/ + +#define HDW_VECTOR(offset) \ + . = offset + +/* +** Privileged CALL_PAL functions are in .text 1 sub-segment. +*/ + +#define CALL_PAL_PRIV(vector) \ + . = (PAL_CALL_PAL_PRIV_ENTRY+(vector<<6)) + +/* +** Unprivileged CALL_PAL functions are in .text 1 sub-segment, +** the privileged bit is removed from these vectors. +*/ + +#define CALL_PAL_UNPRIV(vector) \ + . = (PAL_CALL_PAL_UNPRIV_ENTRY+((vector&0x3F)<<6)) + +/* +** Implements a load "immediate" longword function +*/ +#define LDLI(reg,val) \ + ldah reg, ((val+0x8000) >> 16)(zero); \ + lda reg, (val&0xffff)(reg) + +#endif diff --git a/system/alpha/h/fromHudsonOsf.h b/system/alpha/h/fromHudsonOsf.h new file mode 100644 index 0000000000..e1dfc8171d --- /dev/null +++ b/system/alpha/h/fromHudsonOsf.h @@ -0,0 +1,483 @@ +/* + * Copyright (c) 1993-1994 The Hewlett-Packard Development Company + * 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. + */ + +#ifndef FROMHUDSONOSF_INCLUDED +#define FROMHUDSONOSF_INCLUDED 1 + +#define __OSF_LOADED 1 +/* +** Seg0 and Seg1 Virtual Address (VA) Format +** +** Loc Size Name Function +** ----- ---- ---- --------------------------------- +** <42:33> 10 SEG1 First level page table offset +** <32:23> 10 SEG2 Second level page table offset +** <22:13> 10 SEG3 Third level page table offset +** <12:00> 13 OFFSET Byte within page offset +*/ + +#define VA_V_SEG1 33 +#define VA_M_SEG1 (0x3FF< 32 PFN Page Frame Number +** <31:16> 16 SW Reserved for software +** <15:14> 2 RSV0 Reserved for hardware SBZ +** <13> 1 UWE User Write Enable +** <12> 1 KWE Kernel Write Enable +** <11:10> 2 RSV1 Reserved for hardware SBZ +** <9> 1 URE User Read Enable +** <8> 1 KRE Kernel Read Enable +** <7> 1 RSV2 Reserved for hardware SBZ +** <6:5> 2 GH Granularity Hint +** <4> 1 ASM Address Space Match +** <3> 1 FOE Fault On Execute +** <2> 1 FOW Fault On Write +** <1> 1 FOR Fault On Read +** <0> 1 V Valid +*/ + +#define PTE_V_PFN 32 +#define PTE_M_PFN 0xFFFFFFFF00000000 +#define PTE_V_SW 16 +#define PTE_M_SW 0x00000000FFFF0000 +#define PTE_V_UWE 13 +#define PTE_M_UWE (1< 1 CM Current Mode +** <2:0> 3 IPL Interrupt Priority Level +**/ + +#define PS_V_CM 3 +#define PS_M_CM (1< 1 MIP Machine check in progress +** <1> 1 SCE System correctable error in progress +** <2> 1 PCE Processor correctable error in progress +** <3> 1 DPC Disable PCE error reporting +** <4> 1 DSC Disable SCE error reporting +*/ + +#define MCES_V_MIP 0 +#define MCES_M_MIP (1< 8 ID Who-Am-I identifier +** <15:8> 1 SWAP Swap PALcode flag - character 'S' +*/ + +#define WHAMI_V_SWAP 8 +#define WHAMI_M_SWAP (1<rpb_ctb_off))) + +#define CRB_SETUP \ + ((struct rpb_crb *) ((long)hwrpb_addr + (long)(hwrpb_addr->rpb_crb_off))) + +/* + * The "Dynamic System Recognition" portion of the HWRPB. + * It is used to obtain the platform specific data need to allow + * the platform define the platform name, the platform SMM and LURT + * data for software licensing + */ +struct rpb_dsr { + long rpb_smm; /* SMM nubber used by LMF */ + ulong rpb_lurt_off; /* offset to LURT table */ + ulong rpb_sysname_off; /* offset to sysname char count */ + int lurt[10]; /* XXM has one LURT entry */ +}; diff --git a/system/alpha/h/tlaser.h b/system/alpha/h/tlaser.h new file mode 100644 index 0000000000..283d61be3c --- /dev/null +++ b/system/alpha/h/tlaser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 1990 Hewlett-Packard Development Company + * 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. + */ + +#define tlsb_tlber 0x40 +#define tlsb_tldev 0x00 +#define tlsb_tlesr0 0x680 +#define tlsb_tlesr1 0x6C0 +#define tlsb_tlesr2 0x700 +#define tlsb_tlesr3 0x740 diff --git a/system/alpha/palcode/Makefile b/system/alpha/palcode/Makefile new file mode 100644 index 0000000000..2f1eded33f --- /dev/null +++ b/system/alpha/palcode/Makefile @@ -0,0 +1,92 @@ +# Copyright (c) 2003, 2004 +# The Regents of The University of Michigan +# All Rights Reserved +# +# This code is part of the M5 simulator. +# +# Permission is granted to use, copy, create derivative works and +# redistribute this software and such derivative works for any purpose, +# so long as the copyright notice above, this grant of permission, and +# the disclaimer below appear in all copies made; and so long as the +# name of The University of Michigan is not used in any advertising or +# publicity pertaining to the use or distribution of this software +# without specific, written prior authorization. +# +# THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE +# UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND WITHOUT +# WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER EXPRESS OR +# IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE REGENTS OF +# THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE FOR ANY DAMAGES, +# INCLUDING DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +# DAMAGES, WITH RESPECT TO ANY CLAIM ARISING OUT OF OR IN CONNECTION +# WITH THE USE OF THE SOFTWARE, EVEN IF IT HAS BEEN OR IS HEREAFTER +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +# +# Authors: Nathan L. Binkert +# Ali G. Saidi + +# Makefile for palcode +# Works on alpha-linux and builds elf executable + +### If we are not compiling on an alpha, we must use cross tools ### +ifneq ($(shell uname -m), alpha) +CROSS_COMPILE?=alpha-unknown-linux-gnu- +endif +CC=$(CROSS_COMPILE)gcc +AS=$(CROSS_COMPILE)as +LD=$(CROSS_COMPILE)ld + +CFLAGS=-I . -I ../h -nostdinc -nostdinc++ -Wa,-m21164 +LDFLAGS=-Ttext 0x4000 + +TLOBJS = osfpal.o platform_tlaser.o +TLOBJS_COPY = osfpal_cache_copy.o platform_tlaser.o +TLOBJS_COPY_UNALIGNED = osfpal_cache_copy_unaligned.o platform_tlaser.o +TSOBJS = osfpal.o platform_tsunami.o +TSBOBJS = osfpal.o platform_bigtsunami.o +TSOBJS_COPY = osfpal_cache_copy.o platform_tsunami.o +TSOBJS_COPY_UNALIGNED = osfpal_cache_copy_unaligned.o platform_bigtsunami.o + +all: tlaser tsunami tsunami_b64 + +all_copy: tlaser tlaser_copy tsunami tsunami_b64 tsunami_copy + +osfpal.o: osfpal.S + $(CC) $(CFLAGS) -o $@ -c $< + +osfpal_cache_copy.o: osfpal.S + $(CC) $(CFLAGS) -DCACHE_COPY -o $@ -c $< + +osfpal_cache_copy_unaligned.o: osfpal.S + $(CC) $(CFLAGS) -DCACHE_COPY -DCACHE_COPY_UNALIGNED -o $@ -c $< + +platform_tlaser.o: platform.S + $(CC) $(CFLAGS) -DTLASER -o $@ -c $< + +platform_tsunami.o: platform.S + $(CC) $(CFLAGS) -DTSUNAMI -o $@ -c $< + +platform_bigtsunami.o: platform.S + $(CC) $(CFLAGS) -DBIG_TSUNAMI -o $@ -c $< + +tlaser: $(TLOBJS) + $(LD) $(LDFLAGS) -o tl_osfpal $(TLOBJS) + +tlaser_copy: $(TLOBJS_COPY) $(TLOBJS_COPY_UNALIGNED) + $(LD) $(LDFLAGS) -o tl_osfpal_cache $(TLOBJS_COPY) + $(LD) $(LDFLAGS) -o tl_osfpal_unalign $(TLOBJS_COPY_UNALIGNED) + +tsunami: $(TSOBJS) + $(LD) $(LDFLAGS) -o ts_osfpal $(TSOBJS) + +tsunami_b64: $(TSBOBJS) + $(LD) $(LDFLAGS) -o tsb_osfpal $(TSBOBJS) + +tsunami_copy: $(TSOBJS_COPY) $(TSOBJS_COPY_UNALIGNED) + $(LD) $(LDFLAGS) -o ts_osfpal_cache $(TSOBJS_COPY) + $(LD) $(LDFLAGS) -o ts_osfpal_unalign $(TSOBJS_COPY_UNALIGNED) + +clean: + rm -f *.o tl_osfpal tl_osfpal_cache tl_osfpal_unalign ts_osfpal \ + ts_osfpal_cache ts_osfpal_unalign tsb_osfpal diff --git a/system/alpha/palcode/osfpal.S b/system/alpha/palcode/osfpal.S new file mode 100644 index 0000000000..3ec4d40118 --- /dev/null +++ b/system/alpha/palcode/osfpal.S @@ -0,0 +1,4202 @@ +/* + * Copyright (c) 2003-2006 The Regents of The University of Michigan + * Copyright (c) 1992-1995 Hewlett-Packard Development Company + * 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: Ali G. Saidi + * Nathan L. Binkert + */ + +// modified to use the Hudson style "impure.h" instead of ev5_impure.sdl +// since we don't have a mechanism to expand the data structures.... pb Nov/95 +#include "ev5_defs.h" +#include "ev5_impure.h" +#include "ev5_alpha_defs.h" +#include "ev5_paldef.h" +#include "ev5_osfalpha_defs.h" +#include "fromHudsonMacros.h" +#include "fromHudsonOsf.h" +#include "dc21164FromGasSources.h" + +#define DEBUGSTORE(c) nop + +#define DEBUG_EXC_ADDR()\ + bsr r25, put_exc_addr; \ + DEBUGSTORE(13) ; \ + DEBUGSTORE(10) + +// This is the fix for the user-mode super page references causing the +// machine to crash. +#define hw_rei_spe hw_rei + +#define vmaj 1 +#define vmin 18 +#define vms_pal 1 +#define osf_pal 2 +#define pal_type osf_pal +#define osfpal_version_l ((pal_type<<16) | (vmaj<<8) | (vmin<<0)) + + +/////////////////////////// +// PALtemp register usage +/////////////////////////// + +// The EV5 Ibox holds 24 PALtemp registers. This maps the OSF PAL usage +// for these PALtemps: +// +// pt0 local scratch +// pt1 local scratch +// pt2 entUna pt_entUna +// pt3 CPU specific impure area pointer pt_impure +// pt4 memory management temp +// pt5 memory management temp +// pt6 memory management temp +// pt7 entIF pt_entIF +// pt8 intmask pt_intmask +// pt9 entSys pt_entSys +// pt10 +// pt11 entInt pt_entInt +// pt12 entArith pt_entArith +// pt13 reserved for system specific PAL +// pt14 reserved for system specific PAL +// pt15 reserved for system specific PAL +// pt16 MISC: scratch ! WHAMI<7:0> ! 0 0 0 MCES<4:0> pt_misc, pt_whami, +// pt_mces +// pt17 sysval pt_sysval +// pt18 usp pt_usp +// pt19 ksp pt_ksp +// pt20 PTBR pt_ptbr +// pt21 entMM pt_entMM +// pt22 kgp pt_kgp +// pt23 PCBB pt_pcbb +// +// + + +///////////////////////////// +// PALshadow register usage +///////////////////////////// + +// +// EV5 shadows R8-R14 and R25 when in PALmode and ICSR = 1. +// This maps the OSF PAL usage of R8 - R14 and R25: +// +// r8 ITBmiss/DTBmiss scratch +// r9 ITBmiss/DTBmiss scratch +// r10 ITBmiss/DTBmiss scratch +// r11 PS +// r12 local scratch +// r13 local scratch +// r14 local scratch +// r25 local scratch +// + + + +// .sbttl "PALcode configuration options" + +// There are a number of options that may be assembled into this version of +// PALcode. They should be adjusted in a prefix assembly file (i.e. do not edit +// the following). The options that can be adjusted cause the resultant PALcode +// to reflect the desired target system. + +// multiprocessor support can be enabled for a max of n processors by +// setting the following to the number of processors on the system. +// Note that this is really the max cpuid. + +#define max_cpuid 1 +#ifndef max_cpuid +#define max_cpuid 8 +#endif + +#define osf_svmin 1 +#define osfpal_version_h ((max_cpuid<<16) | (osf_svmin<<0)) + +// +// RESET - Reset Trap Entry Point +// +// RESET - offset 0000 +// Entry: +// Vectored into via hardware trap on reset, or branched to +// on swppal. +// +// r0 = whami +// r1 = pal_base +// r2 = base of scratch area +// r3 = halt code +// +// +// Function: +// +// + + .text 0 + . = 0x0000 + .globl _start + .globl Pal_Base +_start: +Pal_Base: + HDW_VECTOR(PAL_RESET_ENTRY) +Trap_Reset: + nop + /* + * store into r1 + */ + br r1,sys_reset + + // Specify PAL version info as a constant + // at a known location (reset + 8). + + .long osfpal_version_l // ! ! + .long osfpal_version_h // ! + .long 0 + .long 0 +pal_impure_start: + .quad 0 +pal_debug_ptr: + .quad 0 // reserved for debug pointer ; 20 + + +// +// IACCVIO - Istream Access Violation Trap Entry Point +// +// IACCVIO - offset 0080 +// Entry: +// Vectored into via hardware trap on Istream access violation or sign check error on PC. +// +// Function: +// Build stack frame +// a0 <- Faulting VA +// a1 <- MMCSR (1 for ACV) +// a2 <- -1 (for ifetch fault) +// vector via entMM +// + + HDW_VECTOR(PAL_IACCVIO_ENTRY) +Trap_Iaccvio: + DEBUGSTORE(0x42) + sll r11, 63-osfps_v_mode, r25 // Shift mode up to MS bit + mtpr r31, ev5__ps // Set Ibox current mode to kernel + + bis r11, r31, r12 // Save PS + bge r25, TRAP_IACCVIO_10_ // no stack swap needed if cm=kern + + + mtpr r31, ev5__dtb_cm // Set Mbox current mode to kernel - + // no virt ref for next 2 cycles + mtpr r30, pt_usp // save user stack + + bis r31, r31, r12 // Set new PS + mfpr r30, pt_ksp + +TRAP_IACCVIO_10_: + lda sp, 0-osfsf_c_size(sp)// allocate stack space + mfpr r14, exc_addr // get pc + + stq r16, osfsf_a0(sp) // save regs + bic r14, 3, r16 // pass pc/va as a0 + + stq r17, osfsf_a1(sp) // a1 + or r31, mmcsr_c_acv, r17 // pass mm_csr as a1 + + stq r18, osfsf_a2(sp) // a2 + mfpr r13, pt_entmm // get entry point + + stq r11, osfsf_ps(sp) // save old ps + bis r12, r31, r11 // update ps + + stq r16, osfsf_pc(sp) // save pc + stq r29, osfsf_gp(sp) // save gp + + mtpr r13, exc_addr // load exc_addr with entMM + // 1 cycle to hw_rei + mfpr r29, pt_kgp // get the kgp + + subq r31, 1, r18 // pass flag of istream, as a2 + hw_rei_spe + + +// +// INTERRUPT - Interrupt Trap Entry Point +// +// INTERRUPT - offset 0100 +// Entry: +// Vectored into via trap on hardware interrupt +// +// Function: +// check for halt interrupt +// check for passive release (current ipl geq requestor) +// if necessary, switch to kernel mode push stack frame, +// update ps (including current mode and ipl copies), sp, and gp +// pass the interrupt info to the system module +// +// + HDW_VECTOR(PAL_INTERRUPT_ENTRY) +Trap_Interrupt: + mfpr r13, ev5__intid // Fetch level of interruptor + mfpr r25, ev5__isr // Fetch interrupt summary register + + srl r25, isr_v_hlt, r9 // Get HLT bit + mfpr r14, ev5__ipl + + mtpr r31, ev5__dtb_cm // Set Mbox current mode to kern + blbs r9, sys_halt_interrupt // halt_interrupt if HLT bit set + + cmple r13, r14, r8 // R8 = 1 if intid .less than or eql. ipl + bne r8, sys_passive_release // Passive release is current rupt is lt or eq ipl + + and r11, osfps_m_mode, r10 // get mode bit + beq r10, TRAP_INTERRUPT_10_ // Skip stack swap in kernel + + mtpr r30, pt_usp // save user stack + mfpr r30, pt_ksp // get kern stack + +TRAP_INTERRUPT_10_: + lda sp, (0-osfsf_c_size)(sp)// allocate stack space + mfpr r14, exc_addr // get pc + + stq r11, osfsf_ps(sp) // save ps + stq r14, osfsf_pc(sp) // save pc + + stq r29, osfsf_gp(sp) // push gp + stq r16, osfsf_a0(sp) // a0 + +// pvc_violate 354 // ps is cleared anyway, if store to stack faults. + mtpr r31, ev5__ps // Set Ibox current mode to kernel + stq r17, osfsf_a1(sp) // a1 + + stq r18, osfsf_a2(sp) // a2 + subq r13, 0x11, r12 // Start to translate from EV5IPL->OSFIPL + + srl r12, 1, r8 // 1d, 1e: ipl 6. 1f: ipl 7. + subq r13, 0x1d, r9 // Check for 1d, 1e, 1f + + cmovge r9, r8, r12 // if .ge. 1d, then take shifted value + bis r12, r31, r11 // set new ps + + mfpr r12, pt_intmask + and r11, osfps_m_ipl, r14 // Isolate just new ipl (not really needed, since all non-ipl bits zeroed already) + + /* + * Lance had space problems. We don't. + */ + extbl r12, r14, r14 // Translate new OSFIPL->EV5IPL + mfpr r29, pt_kgp // update gp + mtpr r14, ev5__ipl // load the new IPL into Ibox + br r31, sys_interrupt // Go handle interrupt + + + +// +// ITBMISS - Istream TBmiss Trap Entry Point +// +// ITBMISS - offset 0180 +// Entry: +// Vectored into via hardware trap on Istream translation buffer miss. +// +// Function: +// Do a virtual fetch of the PTE, and fill the ITB if the PTE is valid. +// Can trap into DTBMISS_DOUBLE. +// This routine can use the PALshadow registers r8, r9, and r10 +// +// + + HDW_VECTOR(PAL_ITB_MISS_ENTRY) +Trap_Itbmiss: + // Real MM mapping + nop + mfpr r8, ev5__ifault_va_form // Get virtual address of PTE. + + nop + mfpr r10, exc_addr // Get PC of faulting instruction in case of DTBmiss. + +pal_itb_ldq: + ld_vpte r8, 0(r8) // Get PTE, traps to DTBMISS_DOUBLE in case of TBmiss + mtpr r10, exc_addr // Restore exc_address if there was a trap. + + mfpr r31, ev5__va // Unlock VA in case there was a double miss + nop + + and r8, osfpte_m_foe, r25 // Look for FOE set. + blbc r8, invalid_ipte_handler // PTE not valid. + + nop + bne r25, foe_ipte_handler // FOE is set + + nop + mtpr r8, ev5__itb_pte // Ibox remembers the VA, load the PTE into the ITB. + + hw_rei_stall // + + +// +// DTBMISS_SINGLE - Dstream Single TBmiss Trap Entry Point +// +// DTBMISS_SINGLE - offset 0200 +// Entry: +// Vectored into via hardware trap on Dstream single translation +// buffer miss. +// +// Function: +// Do a virtual fetch of the PTE, and fill the DTB if the PTE is valid. +// Can trap into DTBMISS_DOUBLE. +// This routine can use the PALshadow registers r8, r9, and r10 +// + + HDW_VECTOR(PAL_DTB_MISS_ENTRY) +Trap_Dtbmiss_Single: + mfpr r8, ev5__va_form // Get virtual address of PTE - 1 cycle delay. E0. + mfpr r10, exc_addr // Get PC of faulting instruction in case of error. E1. + +// DEBUGSTORE(0x45) +// DEBUG_EXC_ADDR() + // Real MM mapping + mfpr r9, ev5__mm_stat // Get read/write bit. E0. + mtpr r10, pt6 // Stash exc_addr away + +pal_dtb_ldq: + ld_vpte r8, 0(r8) // Get PTE, traps to DTBMISS_DOUBLE in case of TBmiss + nop // Pad MF VA + + mfpr r10, ev5__va // Get original faulting VA for TB load. E0. + nop + + mtpr r8, ev5__dtb_pte // Write DTB PTE part. E0. + blbc r8, invalid_dpte_handler // Handle invalid PTE + + mtpr r10, ev5__dtb_tag // Write DTB TAG part, completes DTB load. No virt ref for 3 cycles. + mfpr r10, pt6 + + // Following 2 instructions take 2 cycles + mtpr r10, exc_addr // Return linkage in case we trapped. E1. + mfpr r31, pt0 // Pad the write to dtb_tag + + hw_rei // Done, return + + +// +// DTBMISS_DOUBLE - Dstream Double TBmiss Trap Entry Point +// +// +// DTBMISS_DOUBLE - offset 0280 +// Entry: +// Vectored into via hardware trap on Double TBmiss from single +// miss flows. +// +// r8 - faulting VA +// r9 - original MMstat +// r10 - original exc_addr (both itb,dtb miss) +// pt6 - original exc_addr (dtb miss flow only) +// VA IPR - locked with original faulting VA +// +// Function: +// Get PTE, if valid load TB and return. +// If not valid then take TNV/ACV exception. +// +// pt4 and pt5 are reserved for this flow. +// +// +// + + HDW_VECTOR(PAL_DOUBLE_MISS_ENTRY) +Trap_Dtbmiss_double: + mtpr r8, pt4 // save r8 to do exc_addr check + mfpr r8, exc_addr + blbc r8, Trap_Dtbmiss_Single //if not in palmode, should be in the single routine, dummy! + mfpr r8, pt4 // restore r8 + nop + mtpr r22, pt5 // Get some scratch space. E1. + // Due to virtual scheme, we can skip the first lookup and go + // right to fetch of level 2 PTE + sll r8, (64-((2*page_seg_size_bits)+page_offset_size_bits)), r22 // Clean off upper bits of VA + mtpr r21, pt4 // Get some scratch space. E1. + + srl r22, 61-page_seg_size_bits, r22 // Get Va*8 + mfpr r21, pt_ptbr // Get physical address of the page table. + + nop + addq r21, r22, r21 // Index into page table for level 2 PTE. + + sll r8, (64-((1*page_seg_size_bits)+page_offset_size_bits)), r22 // Clean off upper bits of VA + ldq_p r21, 0(r21) // Get level 2 PTE (addr<2:0> ignored) + + srl r22, 61-page_seg_size_bits, r22 // Get Va*8 + blbc r21, double_pte_inv // Check for Invalid PTE. + + srl r21, 32, r21 // extract PFN from PTE + sll r21, page_offset_size_bits, r21 // get PFN * 2^13 for add to *8 + + addq r21, r22, r21 // Index into page table for level 3 PTE. + nop + + ldq_p r21, 0(r21) // Get level 3 PTE (addr<2:0> ignored) + blbc r21, double_pte_inv // Check for invalid PTE. + + mtpr r21, ev5__dtb_pte // Write the PTE. E0. + mfpr r22, pt5 // Restore scratch register + + mtpr r8, ev5__dtb_tag // Write the TAG. E0. No virtual references in subsequent 3 cycles. + mfpr r21, pt4 // Restore scratch register + + nop // Pad write to tag. + nop + + nop // Pad write to tag. + nop + + hw_rei + + + +// +// UNALIGN -- Dstream unalign trap +// +// UNALIGN - offset 0300 +// Entry: +// Vectored into via hardware trap on unaligned Dstream reference. +// +// Function: +// Build stack frame +// a0 <- Faulting VA +// a1 <- Opcode +// a2 <- src/dst register number +// vector via entUna +// + + HDW_VECTOR(PAL_UNALIGN_ENTRY) +Trap_Unalign: +/* DEBUGSTORE(0x47)*/ + sll r11, 63-osfps_v_mode, r25 // Shift mode up to MS bit + mtpr r31, ev5__ps // Set Ibox current mode to kernel + + mfpr r8, ev5__mm_stat // Get mmstat --ok to use r8, no tbmiss + mfpr r14, exc_addr // get pc + + srl r8, mm_stat_v_ra, r13 // Shift Ra field to ls bits + blbs r14, pal_pal_bug_check // Bugcheck if unaligned in PAL + + blbs r8, UNALIGN_NO_DISMISS // lsb only set on store or fetch_m + // not set, must be a load + and r13, 0x1F, r8 // isolate ra + + cmpeq r8, 0x1F, r8 // check for r31/F31 + bne r8, dfault_fetch_ldr31_err // if its a load to r31 or f31 -- dismiss the fault + +UNALIGN_NO_DISMISS: + bis r11, r31, r12 // Save PS + bge r25, UNALIGN_NO_DISMISS_10_ // no stack swap needed if cm=kern + + + mtpr r31, ev5__dtb_cm // Set Mbox current mode to kernel - + // no virt ref for next 2 cycles + mtpr r30, pt_usp // save user stack + + bis r31, r31, r12 // Set new PS + mfpr r30, pt_ksp + +UNALIGN_NO_DISMISS_10_: + mfpr r25, ev5__va // Unlock VA + lda sp, 0-osfsf_c_size(sp)// allocate stack space + + mtpr r25, pt0 // Stash VA + stq r18, osfsf_a2(sp) // a2 + + stq r11, osfsf_ps(sp) // save old ps + srl r13, mm_stat_v_opcode-mm_stat_v_ra, r25// Isolate opcode + + stq r29, osfsf_gp(sp) // save gp + addq r14, 4, r14 // inc PC past the ld/st + + stq r17, osfsf_a1(sp) // a1 + and r25, mm_stat_m_opcode, r17// Clean opocde for a1 + + stq r16, osfsf_a0(sp) // save regs + mfpr r16, pt0 // a0 <- va/unlock + + stq r14, osfsf_pc(sp) // save pc + mfpr r25, pt_entuna // get entry point + + + bis r12, r31, r11 // update ps + br r31, unalign_trap_cont + + +// +// DFAULT - Dstream Fault Trap Entry Point +// +// DFAULT - offset 0380 +// Entry: +// Vectored into via hardware trap on dstream fault or sign check +// error on DVA. +// +// Function: +// Ignore faults on FETCH/FETCH_M +// Check for DFAULT in PAL +// Build stack frame +// a0 <- Faulting VA +// a1 <- MMCSR (1 for ACV, 2 for FOR, 4 for FOW) +// a2 <- R/W +// vector via entMM +// +// + HDW_VECTOR(PAL_D_FAULT_ENTRY) +Trap_Dfault: +// DEBUGSTORE(0x48) + sll r11, 63-osfps_v_mode, r25 // Shift mode up to MS bit + mtpr r31, ev5__ps // Set Ibox current mode to kernel + + mfpr r13, ev5__mm_stat // Get mmstat + mfpr r8, exc_addr // get pc, preserve r14 + + srl r13, mm_stat_v_opcode, r9 // Shift opcode field to ls bits + blbs r8, dfault_in_pal + + bis r8, r31, r14 // move exc_addr to correct place + bis r11, r31, r12 // Save PS + + mtpr r31, ev5__dtb_cm // Set Mbox current mode to kernel - + // no virt ref for next 2 cycles + and r9, mm_stat_m_opcode, r9 // Clean all but opcode + + cmpeq r9, evx_opc_sync, r9 // Is the opcode fetch/fetchm? + bne r9, dfault_fetch_ldr31_err // Yes, dismiss the fault + + //dismiss exception if load to r31/f31 + blbs r13, dfault_no_dismiss // mm_stat<0> set on store or fetchm + + // not a store or fetch, must be a load + srl r13, mm_stat_v_ra, r9 // Shift rnum to low bits + + and r9, 0x1F, r9 // isolate rnum + nop + + cmpeq r9, 0x1F, r9 // Is the rnum r31 or f31? + bne r9, dfault_fetch_ldr31_err // Yes, dismiss the fault + +dfault_no_dismiss: + and r13, 0xf, r13 // Clean extra bits in mm_stat + bge r25, dfault_trap_cont // no stack swap needed if cm=kern + + + mtpr r30, pt_usp // save user stack + bis r31, r31, r12 // Set new PS + + mfpr r30, pt_ksp + br r31, dfault_trap_cont + + +// +// MCHK - Machine Check Trap Entry Point +// +// MCHK - offset 0400 +// Entry: +// Vectored into via hardware trap on machine check. +// +// Function: +// +// + + HDW_VECTOR(PAL_MCHK_ENTRY) +Trap_Mchk: + DEBUGSTORE(0x49) + mtpr r31, ic_flush_ctl // Flush the Icache + br r31, sys_machine_check + + +// +// OPCDEC - Illegal Opcode Trap Entry Point +// +// OPCDEC - offset 0480 +// Entry: +// Vectored into via hardware trap on illegal opcode. +// +// Build stack frame +// a0 <- code +// a1 <- unpred +// a2 <- unpred +// vector via entIF +// +// + + HDW_VECTOR(PAL_OPCDEC_ENTRY) +Trap_Opcdec: + DEBUGSTORE(0x4a) +//simos DEBUG_EXC_ADDR() + sll r11, 63-osfps_v_mode, r25 // Shift mode up to MS bit + mtpr r31, ev5__ps // Set Ibox current mode to kernel + + mfpr r14, exc_addr // get pc + blbs r14, pal_pal_bug_check // check opcdec in palmode + + bis r11, r31, r12 // Save PS + bge r25, TRAP_OPCDEC_10_ // no stack swap needed if cm=kern + + + mtpr r31, ev5__dtb_cm // Set Mbox current mode to kernel - + // no virt ref for next 2 cycles + mtpr r30, pt_usp // save user stack + + bis r31, r31, r12 // Set new PS + mfpr r30, pt_ksp + +TRAP_OPCDEC_10_: + lda sp, 0-osfsf_c_size(sp)// allocate stack space + addq r14, 4, r14 // inc pc + + stq r16, osfsf_a0(sp) // save regs + bis r31, osf_a0_opdec, r16 // set a0 + + stq r11, osfsf_ps(sp) // save old ps + mfpr r13, pt_entif // get entry point + + stq r18, osfsf_a2(sp) // a2 + stq r17, osfsf_a1(sp) // a1 + + stq r29, osfsf_gp(sp) // save gp + stq r14, osfsf_pc(sp) // save pc + + bis r12, r31, r11 // update ps + mtpr r13, exc_addr // load exc_addr with entIF + // 1 cycle to hw_rei, E1 + + mfpr r29, pt_kgp // get the kgp, E1 + + hw_rei_spe // done, E1 + + +// +// ARITH - Arithmetic Exception Trap Entry Point +// +// ARITH - offset 0500 +// Entry: +// Vectored into via hardware trap on arithmetic excpetion. +// +// Function: +// Build stack frame +// a0 <- exc_sum +// a1 <- exc_mask +// a2 <- unpred +// vector via entArith +// +// + HDW_VECTOR(PAL_ARITH_ENTRY) +Trap_Arith: + DEBUGSTORE(0x4b) + and r11, osfps_m_mode, r12 // get mode bit + mfpr r31, ev5__va // unlock mbox + + bis r11, r31, r25 // save ps + mfpr r14, exc_addr // get pc + + nop + blbs r14, pal_pal_bug_check // arith trap from PAL + + mtpr r31, ev5__dtb_cm // Set Mbox current mode to kernel - + // no virt ref for next 2 cycles + beq r12, TRAP_ARITH_10_ // if zero we are in kern now + + bis r31, r31, r25 // set the new ps + mtpr r30, pt_usp // save user stack + + nop + mfpr r30, pt_ksp // get kern stack + +TRAP_ARITH_10_: lda sp, 0-osfsf_c_size(sp) // allocate stack space + mtpr r31, ev5__ps // Set Ibox current mode to kernel + + nop // Pad current mode write and stq + mfpr r13, ev5__exc_sum // get the exc_sum + + mfpr r12, pt_entarith + stq r14, osfsf_pc(sp) // save pc + + stq r17, osfsf_a1(sp) + mfpr r17, ev5__exc_mask // Get exception register mask IPR - no mtpr exc_sum in next cycle + + stq r11, osfsf_ps(sp) // save ps + bis r25, r31, r11 // set new ps + + stq r16, osfsf_a0(sp) // save regs + srl r13, exc_sum_v_swc, r16 // shift data to correct position + + stq r18, osfsf_a2(sp) +// pvc_violate 354 // ok, but make sure reads of exc_mask/sum are not in same trap shadow + mtpr r31, ev5__exc_sum // Unlock exc_sum and exc_mask + + stq r29, osfsf_gp(sp) + mtpr r12, exc_addr // Set new PC - 1 bubble to hw_rei - E1 + + mfpr r29, pt_kgp // get the kern gp - E1 + hw_rei_spe // done - E1 + + +// +// FEN - Illegal Floating Point Operation Trap Entry Point +// +// FEN - offset 0580 +// Entry: +// Vectored into via hardware trap on illegal FP op. +// +// Function: +// Build stack frame +// a0 <- code +// a1 <- unpred +// a2 <- unpred +// vector via entIF +// +// + + HDW_VECTOR(PAL_FEN_ENTRY) +Trap_Fen: + sll r11, 63-osfps_v_mode, r25 // Shift mode up to MS bit + mtpr r31, ev5__ps // Set Ibox current mode to kernel + + mfpr r14, exc_addr // get pc + blbs r14, pal_pal_bug_check // check opcdec in palmode + + mfpr r13, ev5__icsr + nop + + bis r11, r31, r12 // Save PS + bge r25, TRAP_FEN_10_ // no stack swap needed if cm=kern + + mtpr r31, ev5__dtb_cm // Set Mbox current mode to kernel - + // no virt ref for next 2 cycles + mtpr r30, pt_usp // save user stack + + bis r31, r31, r12 // Set new PS + mfpr r30, pt_ksp + +TRAP_FEN_10_: + lda sp, 0-osfsf_c_size(sp)// allocate stack space + srl r13, icsr_v_fpe, r25 // Shift FP enable to bit 0 + + + stq r16, osfsf_a0(sp) // save regs + mfpr r13, pt_entif // get entry point + + stq r18, osfsf_a2(sp) // a2 + stq r11, osfsf_ps(sp) // save old ps + + stq r29, osfsf_gp(sp) // save gp + bis r12, r31, r11 // set new ps + + stq r17, osfsf_a1(sp) // a1 + blbs r25,fen_to_opcdec // If FP is enabled, this is really OPCDEC. + + bis r31, osf_a0_fen, r16 // set a0 + stq r14, osfsf_pc(sp) // save pc + + mtpr r13, exc_addr // load exc_addr with entIF + // 1 cycle to hw_rei -E1 + + mfpr r29, pt_kgp // get the kgp -E1 + + hw_rei_spe // done -E1 + +// FEN trap was taken, but the fault is really opcdec. + ALIGN_BRANCH +fen_to_opcdec: + addq r14, 4, r14 // save PC+4 + bis r31, osf_a0_opdec, r16 // set a0 + + stq r14, osfsf_pc(sp) // save pc + mtpr r13, exc_addr // load exc_addr with entIF + // 1 cycle to hw_rei + + mfpr r29, pt_kgp // get the kgp + hw_rei_spe // done + + + +////////////////////////////////////////////////////////////////////////////// +// Misc handlers - Start area for misc code. +////////////////////////////////////////////////////////////////////////////// + +// +// dfault_trap_cont +// A dfault trap has been taken. The sp has been updated if necessary. +// Push a stack frame a vector via entMM. +// +// Current state: +// r12 - new PS +// r13 - MMstat +// VA - locked +// +// + ALIGN_BLOCK +dfault_trap_cont: + lda sp, 0-osfsf_c_size(sp)// allocate stack space + mfpr r25, ev5__va // Fetch VA/unlock + + stq r18, osfsf_a2(sp) // a2 + and r13, 1, r18 // Clean r/w bit for a2 + + stq r16, osfsf_a0(sp) // save regs + bis r25, r31, r16 // a0 <- va + + stq r17, osfsf_a1(sp) // a1 + srl r13, 1, r17 // shift fault bits to right position + + stq r11, osfsf_ps(sp) // save old ps + bis r12, r31, r11 // update ps + + stq r14, osfsf_pc(sp) // save pc + mfpr r25, pt_entmm // get entry point + + stq r29, osfsf_gp(sp) // save gp + cmovlbs r17, 1, r17 // a2. acv overrides fox. + + mtpr r25, exc_addr // load exc_addr with entMM + // 1 cycle to hw_rei + mfpr r29, pt_kgp // get the kgp + + hw_rei_spe // done + +// +//unalign_trap_cont +// An unalign trap has been taken. Just need to finish up a few things. +// +// Current state: +// r25 - entUna +// r13 - shifted MMstat +// +// + ALIGN_BLOCK +unalign_trap_cont: + mtpr r25, exc_addr // load exc_addr with entUna + // 1 cycle to hw_rei + + + mfpr r29, pt_kgp // get the kgp + and r13, mm_stat_m_ra, r18 // Clean Ra for a2 + + hw_rei_spe // done + + + +// +// dfault_in_pal +// Dfault trap was taken, exc_addr points to a PAL PC. +// r9 - mmstat right justified +// r8 - exception address +// +// These are the cases: +// opcode was STQ -- from a stack builder, KSP not valid halt +// r14 - original exc_addr +// r11 - original PS +// opcode was STL_C -- rti or retsys clear lock_flag by stack write, +// KSP not valid halt +// r11 - original PS +// r14 - original exc_addr +// opcode was LDQ -- retsys or rti stack read, KSP not valid halt +// r11 - original PS +// r14 - original exc_addr +// opcode was HW_LD -- itbmiss or dtbmiss, bugcheck due to fault on page tables +// r10 - original exc_addr +// r11 - original PS +// +// +// + ALIGN_BLOCK +dfault_in_pal: + DEBUGSTORE(0x50) + bic r8, 3, r8 // Clean PC + mfpr r9, pal_base + + mfpr r31, va // unlock VA + + // if not real_mm, should never get here from miss flows + + subq r9, r8, r8 // pal_base - offset + + lda r9, pal_itb_ldq-pal_base(r8) + nop + + beq r9, dfault_do_bugcheck + lda r9, pal_dtb_ldq-pal_base(r8) + + beq r9, dfault_do_bugcheck + +// +// KSP invalid halt case -- +ksp_inval_halt: + DEBUGSTORE(76) + bic r11, osfps_m_mode, r11 // set ps to kernel mode + mtpr r0, pt0 + + mtpr r31, dtb_cm // Make sure that the CM IPRs are all kernel mode + mtpr r31, ips + + mtpr r14, exc_addr // Set PC to instruction that caused trouble + bsr r0, pal_update_pcb // update the pcb + + lda r0, hlt_c_ksp_inval(r31) // set halt code to hw halt + br r31, sys_enter_console // enter the console + + ALIGN_BRANCH +dfault_do_bugcheck: + bis r10, r31, r14 // bugcheck expects exc_addr in r14 + br r31, pal_pal_bug_check + + +// +// dfault_fetch_ldr31_err - ignore faults on fetch(m) and loads to r31/f31 +// On entry - +// r14 - exc_addr +// VA is locked +// +// + ALIGN_BLOCK +dfault_fetch_ldr31_err: + mtpr r11, ev5__dtb_cm + mtpr r11, ev5__ps // Make sure ps hasn't changed + + mfpr r31, va // unlock the mbox + addq r14, 4, r14 // inc the pc to skip the fetch + + mtpr r14, exc_addr // give ibox new PC + mfpr r31, pt0 // pad exc_addr write + + hw_rei + + + + ALIGN_BLOCK +// +// sys_from_kern +// callsys from kernel mode - OS bugcheck machine check +// +// +sys_from_kern: + mfpr r14, exc_addr // PC points to call_pal + subq r14, 4, r14 + + lda r25, mchk_c_os_bugcheck(r31) // fetch mchk code + br r31, pal_pal_mchk + + +// Continuation of long call_pal flows +// +// wrent_tbl +// Table to write *int in paltemps. +// 4 instructions/entry +// r16 has new value +// +// + ALIGN_BLOCK +wrent_tbl: +//orig pvc_jsr wrent, dest=1 + nop + mtpr r16, pt_entint + + mfpr r31, pt0 // Pad for mt->mf paltemp rule + hw_rei + + +//orig pvc_jsr wrent, dest=1 + nop + mtpr r16, pt_entarith + + mfpr r31, pt0 // Pad for mt->mf paltemp rule + hw_rei + + +//orig pvc_jsr wrent, dest=1 + nop + mtpr r16, pt_entmm + + mfpr r31, pt0 // Pad for mt->mf paltemp rule + hw_rei + + +//orig pvc_jsr wrent, dest=1 + nop + mtpr r16, pt_entif + + mfpr r31, pt0 // Pad for mt->mf paltemp rule + hw_rei + + +//orig pvc_jsr wrent, dest=1 + nop + mtpr r16, pt_entuna + + mfpr r31, pt0 // Pad for mt->mf paltemp rule + hw_rei + + +//orig pvc_jsr wrent, dest=1 + nop + mtpr r16, pt_entsys + + mfpr r31, pt0 // Pad for mt->mf paltemp rule + hw_rei + + ALIGN_BLOCK +// +// tbi_tbl +// Table to do tbi instructions +// 4 instructions per entry +// +tbi_tbl: + // -2 tbia +//orig pvc_jsr tbi, dest=1 + mtpr r31, ev5__dtb_ia // Flush DTB + mtpr r31, ev5__itb_ia // Flush ITB + + hw_rei_stall + + nop // Pad table + + // -1 tbiap +//orig pvc_jsr tbi, dest=1 + mtpr r31, ev5__dtb_iap // Flush DTB + mtpr r31, ev5__itb_iap // Flush ITB + + hw_rei_stall + + nop // Pad table + + + // 0 unused +//orig pvc_jsr tbi, dest=1 + hw_rei // Pad table + nop + nop + nop + + + // 1 tbisi +//orig pvc_jsr tbi, dest=1 + + nop + nop + mtpr r17, ev5__itb_is // Flush ITB + hw_rei_stall + + // 2 tbisd +//orig pvc_jsr tbi, dest=1 + mtpr r17, ev5__dtb_is // Flush DTB. + nop + + nop + hw_rei_stall + + + // 3 tbis +//orig pvc_jsr tbi, dest=1 + mtpr r17, ev5__dtb_is // Flush DTB + br r31, tbi_finish + ALIGN_BRANCH +tbi_finish: + mtpr r17, ev5__itb_is // Flush ITB + hw_rei_stall + + + + ALIGN_BLOCK +// +// bpt_bchk_common: +// Finish up the bpt/bchk instructions +// +bpt_bchk_common: + stq r18, osfsf_a2(sp) // a2 + mfpr r13, pt_entif // get entry point + + stq r12, osfsf_ps(sp) // save old ps + stq r14, osfsf_pc(sp) // save pc + + stq r29, osfsf_gp(sp) // save gp + mtpr r13, exc_addr // load exc_addr with entIF + // 1 cycle to hw_rei + + mfpr r29, pt_kgp // get the kgp + + + hw_rei_spe // done + + + ALIGN_BLOCK +// +// rti_to_user +// Finish up the rti instruction +// +rti_to_user: + mtpr r11, ev5__dtb_cm // set Mbox current mode - no virt ref for 2 cycles + mtpr r11, ev5__ps // set Ibox current mode - 2 bubble to hw_rei + + mtpr r31, ev5__ipl // set the ipl. No hw_rei for 2 cycles + mtpr r25, pt_ksp // save off incase RTI to user + + mfpr r30, pt_usp + hw_rei_spe // and back + + + ALIGN_BLOCK +// +// rti_to_kern +// Finish up the rti instruction +// +rti_to_kern: + and r12, osfps_m_ipl, r11 // clean ps + mfpr r12, pt_intmask // get int mask + + extbl r12, r11, r12 // get mask for this ipl + mtpr r25, pt_ksp // save off incase RTI to user + + mtpr r12, ev5__ipl // set the new ipl. + or r25, r31, sp // sp + +// pvc_violate 217 // possible hidden mt->mf ipl not a problem in callpals + hw_rei + + ALIGN_BLOCK +// +// swpctx_cont +// Finish up the swpctx instruction +// + +swpctx_cont: + + bic r25, r24, r25 // clean icsr + sll r12, icsr_v_fpe, r12 // shift new fen to pos + + ldq_p r14, osfpcb_q_mmptr(r16)// get new mmptr + srl r22, osfpcb_v_pme, r22 // get pme down to bit 0 + + or r25, r12, r25 // icsr with new fen + srl r23, 32, r24 // move asn to low asn pos + + and r22, 1, r22 + sll r24, itb_asn_v_asn, r12 + + sll r22, icsr_v_pmp, r22 + nop + + or r25, r22, r25 // icsr with new pme + + sll r24, dtb_asn_v_asn, r24 + + subl r23, r13, r13 // gen new cc offset + mtpr r12, itb_asn // no hw_rei_stall in 0,1,2,3,4 + + mtpr r24, dtb_asn // Load up new ASN + mtpr r25, icsr // write the icsr + + sll r14, page_offset_size_bits, r14 // Move PTBR into internal position. + ldq_p r25, osfpcb_q_usp(r16) // get new usp + + insll r13, 4, r13 // >> 32 +// pvc_violate 379 // ldq_p can't trap except replay. only problem if mf same ipr in same shadow + mtpr r14, pt_ptbr // load the new ptbr + + mtpr r13, cc // set new offset + ldq_p r30, osfpcb_q_ksp(r16) // get new ksp + +// pvc_violate 379 // ldq_p can't trap except replay. only problem if mf same ipr in same shadow + mtpr r25, pt_usp // save usp + +no_pm_change_10_: hw_rei_stall // back we go + + ALIGN_BLOCK +// +// swppal_cont - finish up the swppal call_pal +// + +swppal_cont: + mfpr r2, pt_misc // get misc bits + sll r0, pt_misc_v_switch, r0 // get the "I've switched" bit + or r2, r0, r2 // set the bit + mtpr r31, ev5__alt_mode // ensure alt_mode set to 0 (kernel) + mtpr r2, pt_misc // update the chip + + or r3, r31, r4 + mfpr r3, pt_impure // pass pointer to the impure area in r3 +//orig fix_impure_ipr r3 // adjust impure pointer for ipr read +//orig restore_reg1 bc_ctl, r1, r3, ipr=1 // pass cns_bc_ctl in r1 +//orig restore_reg1 bc_config, r2, r3, ipr=1 // pass cns_bc_config in r2 +//orig unfix_impure_ipr r3 // restore impure pointer + lda r3, CNS_Q_IPR(r3) + RESTORE_SHADOW(r1,CNS_Q_BC_CTL,r3); + RESTORE_SHADOW(r1,CNS_Q_BC_CFG,r3); + lda r3, -CNS_Q_IPR(r3) + + or r31, r31, r0 // set status to success +// pvc_violate 1007 + jmp r31, (r4) // and call our friend, it's her problem now + + +swppal_fail: + addq r0, 1, r0 // set unknown pal or not loaded + hw_rei // and return + + +// .sbttl "Memory management" + + ALIGN_BLOCK +// +//foe_ipte_handler +// IFOE detected on level 3 pte, sort out FOE vs ACV +// +// on entry: +// with +// R8 = pte +// R10 = pc +// +// Function +// Determine TNV vs ACV vs FOE. Build stack and dispatch +// Will not be here if TNV. +// + +foe_ipte_handler: + sll r11, 63-osfps_v_mode, r25 // Shift mode up to MS bit + mtpr r31, ev5__ps // Set Ibox current mode to kernel + + bis r11, r31, r12 // Save PS for stack write + bge r25, foe_ipte_handler_10_ // no stack swap needed if cm=kern + + + mtpr r31, ev5__dtb_cm // Set Mbox current mode to kernel - + // no virt ref for next 2 cycles + mtpr r30, pt_usp // save user stack + + bis r31, r31, r11 // Set new PS + mfpr r30, pt_ksp + + srl r8, osfpte_v_ure-osfpte_v_kre, r8 // move pte user bits to kern + nop + +foe_ipte_handler_10_: srl r8, osfpte_v_kre, r25 // get kre to <0> + lda sp, 0-osfsf_c_size(sp)// allocate stack space + + or r10, r31, r14 // Save pc/va in case TBmiss or fault on stack + mfpr r13, pt_entmm // get entry point + + stq r16, osfsf_a0(sp) // a0 + or r14, r31, r16 // pass pc/va as a0 + + stq r17, osfsf_a1(sp) // a1 + nop + + stq r18, osfsf_a2(sp) // a2 + lda r17, mmcsr_c_acv(r31) // assume ACV + + stq r16, osfsf_pc(sp) // save pc + cmovlbs r25, mmcsr_c_foe, r17 // otherwise FOE + + stq r12, osfsf_ps(sp) // save ps + subq r31, 1, r18 // pass flag of istream as a2 + + stq r29, osfsf_gp(sp) + mtpr r13, exc_addr // set vector address + + mfpr r29, pt_kgp // load kgp + hw_rei_spe // out to exec + + ALIGN_BLOCK +// +//invalid_ipte_handler +// TNV detected on level 3 pte, sort out TNV vs ACV +// +// on entry: +// with +// R8 = pte +// R10 = pc +// +// Function +// Determine TNV vs ACV. Build stack and dispatch. +// + +invalid_ipte_handler: + sll r11, 63-osfps_v_mode, r25 // Shift mode up to MS bit + mtpr r31, ev5__ps // Set Ibox current mode to kernel + + bis r11, r31, r12 // Save PS for stack write + bge r25, invalid_ipte_handler_10_ // no stack swap needed if cm=kern + + + mtpr r31, ev5__dtb_cm // Set Mbox current mode to kernel - + // no virt ref for next 2 cycles + mtpr r30, pt_usp // save user stack + + bis r31, r31, r11 // Set new PS + mfpr r30, pt_ksp + + srl r8, osfpte_v_ure-osfpte_v_kre, r8 // move pte user bits to kern + nop + +invalid_ipte_handler_10_: srl r8, osfpte_v_kre, r25 // get kre to <0> + lda sp, 0-osfsf_c_size(sp)// allocate stack space + + or r10, r31, r14 // Save pc/va in case TBmiss on stack + mfpr r13, pt_entmm // get entry point + + stq r16, osfsf_a0(sp) // a0 + or r14, r31, r16 // pass pc/va as a0 + + stq r17, osfsf_a1(sp) // a1 + nop + + stq r18, osfsf_a2(sp) // a2 + and r25, 1, r17 // Isolate kre + + stq r16, osfsf_pc(sp) // save pc + xor r17, 1, r17 // map to acv/tnv as a1 + + stq r12, osfsf_ps(sp) // save ps + subq r31, 1, r18 // pass flag of istream as a2 + + stq r29, osfsf_gp(sp) + mtpr r13, exc_addr // set vector address + + mfpr r29, pt_kgp // load kgp + hw_rei_spe // out to exec + + + + + ALIGN_BLOCK +// +//invalid_dpte_handler +// INVALID detected on level 3 pte, sort out TNV vs ACV +// +// on entry: +// with +// R10 = va +// R8 = pte +// R9 = mm_stat +// PT6 = pc +// +// Function +// Determine TNV vs ACV. Build stack and dispatch +// + + +invalid_dpte_handler: + mfpr r12, pt6 + blbs r12, tnv_in_pal // Special handler if original faulting reference was in PALmode + + bis r12, r31, r14 // save PC in case of tbmiss or fault + srl r9, mm_stat_v_opcode, r25 // shift opc to <0> + + mtpr r11, pt0 // Save PS for stack write + and r25, mm_stat_m_opcode, r25 // isolate opcode + + cmpeq r25, evx_opc_sync, r25 // is it FETCH/FETCH_M? + blbs r25, nmiss_fetch_ldr31_err // yes + + //dismiss exception if load to r31/f31 + blbs r9, invalid_dpte_no_dismiss // mm_stat<0> set on store or fetchm + + // not a store or fetch, must be a load + srl r9, mm_stat_v_ra, r25 // Shift rnum to low bits + + and r25, 0x1F, r25 // isolate rnum + nop + + cmpeq r25, 0x1F, r25 // Is the rnum r31 or f31? + bne r25, nmiss_fetch_ldr31_err // Yes, dismiss the fault + +invalid_dpte_no_dismiss: + sll r11, 63-osfps_v_mode, r25 // Shift mode up to MS bit + mtpr r31, ev5__ps // Set Ibox current mode to kernel + + mtpr r31, ev5__dtb_cm // Set Mbox current mode to kernel - + // no virt ref for next 2 cycles + bge r25, invalid_dpte_no_dismiss_10_ // no stack swap needed if cm=kern + + srl r8, osfpte_v_ure-osfpte_v_kre, r8 // move pte user bits to kern + mtpr r30, pt_usp // save user stack + + bis r31, r31, r11 // Set new PS + mfpr r30, pt_ksp + +invalid_dpte_no_dismiss_10_: srl r8, osfpte_v_kre, r12 // get kre to <0> + lda sp, 0-osfsf_c_size(sp)// allocate stack space + + or r10, r31, r25 // Save va in case TBmiss on stack + and r9, 1, r13 // save r/w flag + + stq r16, osfsf_a0(sp) // a0 + or r25, r31, r16 // pass va as a0 + + stq r17, osfsf_a1(sp) // a1 + or r31, mmcsr_c_acv, r17 // assume acv + + srl r12, osfpte_v_kwe-osfpte_v_kre, r25 // get write enable to <0> + stq r29, osfsf_gp(sp) + + stq r18, osfsf_a2(sp) // a2 + cmovlbs r13, r25, r12 // if write access move acv based on write enable + + or r13, r31, r18 // pass flag of dstream access and read vs write + mfpr r25, pt0 // get ps + + stq r14, osfsf_pc(sp) // save pc + mfpr r13, pt_entmm // get entry point + + stq r25, osfsf_ps(sp) // save ps + mtpr r13, exc_addr // set vector address + + mfpr r29, pt_kgp // load kgp + cmovlbs r12, mmcsr_c_tnv, r17 // make p2 be tnv if access ok else acv + + hw_rei_spe // out to exec + +// +// +// We come here if we are erring on a dtb_miss, and the instr is a +// fetch, fetch_m, of load to r31/f31. +// The PC is incremented, and we return to the program. +// essentially ignoring the instruction and error. +// +// + ALIGN_BLOCK +nmiss_fetch_ldr31_err: + mfpr r12, pt6 + addq r12, 4, r12 // bump pc to pc+4 + + mtpr r12, exc_addr // and set entry point + mfpr r31, pt0 // pad exc_addr write + + hw_rei // + + ALIGN_BLOCK +// +// double_pte_inv +// We had a single tbmiss which turned into a double tbmiss which found +// an invalid PTE. Return to single miss with a fake pte, and the invalid +// single miss flow will report the error. +// +// on entry: +// r21 PTE +// r22 available +// VA IPR locked with original fault VA +// pt4 saved r21 +// pt5 saved r22 +// pt6 original exc_addr +// +// on return to tbmiss flow: +// r8 fake PTE +// +// +// +double_pte_inv: + srl r21, osfpte_v_kre, r21 // get the kre bit to <0> + mfpr r22, exc_addr // get the pc + + lda r22, 4(r22) // inc the pc + lda r8, osfpte_m_prot(r31) // make a fake pte with xre and xwe set + + cmovlbc r21, r31, r8 // set to all 0 for acv if pte is 0 + mtpr r22, exc_addr // set for rei + + mfpr r21, pt4 // restore regs + mfpr r22, pt5 // restore regs + + hw_rei // back to tb miss + + ALIGN_BLOCK +// +//tnv_in_pal +// The only places in pal that ld or store are the +// stack builders, rti or retsys. Any of these mean we +// need to take a ksp not valid halt. +// +// +tnv_in_pal: + + + br r31, ksp_inval_halt + + +// .sbttl "Icache flush routines" + + ALIGN_BLOCK +// +// Common Icache flush routine. +// +// +// +pal_ic_flush: + nop + mtpr r31, ev5__ic_flush_ctl // Icache flush - E1 + nop + nop + +// Now, do 44 NOPs. 3RFB prefetches (24) + IC buffer,IB,slot,issue (20) + nop + nop + nop + nop + + nop + nop + nop + nop + + nop + nop // 10 + + nop + nop + nop + nop + + nop + nop + nop + nop + + nop + nop // 20 + + nop + nop + nop + nop + + nop + nop + nop + nop + + nop + nop // 30 + nop + nop + nop + nop + + nop + nop + nop + nop + + nop + nop // 40 + + nop + nop + +one_cycle_and_hw_rei: + nop + nop + + hw_rei_stall + + ALIGN_BLOCK +// +//osfpal_calpal_opcdec +// Here for all opcdec CALL_PALs +// +// Build stack frame +// a0 <- code +// a1 <- unpred +// a2 <- unpred +// vector via entIF +// +// + +osfpal_calpal_opcdec: + sll r11, 63-osfps_v_mode, r25 // Shift mode up to MS bit + mtpr r31, ev5__ps // Set Ibox current mode to kernel + + mfpr r14, exc_addr // get pc + nop + + bis r11, r31, r12 // Save PS for stack write + bge r25, osfpal_calpal_opcdec_10_ // no stack swap needed if cm=kern + + + mtpr r31, ev5__dtb_cm // Set Mbox current mode to kernel - + // no virt ref for next 2 cycles + mtpr r30, pt_usp // save user stack + + bis r31, r31, r11 // Set new PS + mfpr r30, pt_ksp + +osfpal_calpal_opcdec_10_: + lda sp, 0-osfsf_c_size(sp)// allocate stack space + nop + + stq r16, osfsf_a0(sp) // save regs + bis r31, osf_a0_opdec, r16 // set a0 + + stq r18, osfsf_a2(sp) // a2 + mfpr r13, pt_entif // get entry point + + stq r12, osfsf_ps(sp) // save old ps + stq r17, osfsf_a1(sp) // a1 + + stq r14, osfsf_pc(sp) // save pc + nop + + stq r29, osfsf_gp(sp) // save gp + mtpr r13, exc_addr // load exc_addr with entIF + // 1 cycle to hw_rei + + mfpr r29, pt_kgp // get the kgp + + + hw_rei_spe // done + + + + + +// +//pal_update_pcb +// Update the PCB with the current SP, AST, and CC info +// +// r0 - return linkage +// + ALIGN_BLOCK + +pal_update_pcb: + mfpr r12, pt_pcbb // get pcbb + and r11, osfps_m_mode, r25 // get mode + beq r25, pal_update_pcb_10_ // in kern? no need to update user sp + mtpr r30, pt_usp // save user stack + stq_p r30, osfpcb_q_usp(r12) // store usp + br r31, pal_update_pcb_20_ // join common +pal_update_pcb_10_: stq_p r30, osfpcb_q_ksp(r12) // store ksp +pal_update_pcb_20_: rpcc r13 // get cyccounter + srl r13, 32, r14 // move offset + addl r13, r14, r14 // merge for new time + stl_p r14, osfpcb_l_cc(r12) // save time + +//orig pvc_jsr updpcb, bsr=1, dest=1 + ret r31, (r0) + + +// +// pal_save_state +// +// Function +// All chip state saved, all PT's, SR's FR's, IPR's +// +// +// Regs' on entry... +// +// R0 = halt code +// pt0 = r0 +// R1 = pointer to impure +// pt4 = r1 +// R3 = return addr +// pt5 = r3 +// +// register usage: +// r0 = halt_code +// r1 = addr of impure area +// r3 = return_address +// r4 = scratch +// +// + + ALIGN_BLOCK + .globl pal_save_state +pal_save_state: +// +// +// start of implementation independent save routine +// +// the impure area is larger than the addressibility of hw_ld and hw_st +// therefore, we need to play some games: The impure area +// is informally divided into the "machine independent" part and the +// "machine dependent" part. The state that will be saved in the +// "machine independent" part are gpr's, fpr's, hlt, flag, mchkflag (use (un)fix_impure_gpr macros). +// All others will be in the "machine dependent" part (use (un)fix_impure_ipr macros). +// The impure pointer will need to be adjusted by a different offset for each. The store/restore_reg +// macros will automagically adjust the offset correctly. +// + +// The distributed code is commented out and followed by corresponding SRC code. +// Beware: SAVE_IPR and RESTORE_IPR blow away r0(v0) + +//orig fix_impure_gpr r1 // adjust impure area pointer for stores to "gpr" part of impure area + lda r1, 0x200(r1) // Point to center of CPU segment +//orig store_reg1 flag, r31, r1, ipr=1 // clear dump area flag + SAVE_GPR(r31,CNS_Q_FLAG,r1) // Clear the valid flag +//orig store_reg1 hlt, r0, r1, ipr=1 + SAVE_GPR(r0,CNS_Q_HALT,r1) // Save the halt code + + mfpr r0, pt0 // get r0 back //orig +//orig store_reg1 0, r0, r1 // save r0 + SAVE_GPR(r0,CNS_Q_GPR+0x00,r1) // Save r0 + + mfpr r0, pt4 // get r1 back //orig +//orig store_reg1 1, r0, r1 // save r1 + SAVE_GPR(r0,CNS_Q_GPR+0x08,r1) // Save r1 + +//orig store_reg 2 // save r2 + SAVE_GPR(r2,CNS_Q_GPR+0x10,r1) // Save r2 + + mfpr r0, pt5 // get r3 back //orig +//orig store_reg1 3, r0, r1 // save r3 + SAVE_GPR(r0,CNS_Q_GPR+0x18,r1) // Save r3 + + // reason code has been saved + // r0 has been saved + // r1 has been saved + // r2 has been saved + // r3 has been saved + // pt0, pt4, pt5 have been lost + + // + // Get out of shadow mode + // + + mfpr r2, icsr // Get icsr + ldah r0, (1<<(icsr_v_sde-16))(r31) + bic r2, r0, r0 // ICSR with SDE clear + mtpr r0, icsr // Turn off SDE + + mfpr r31, pt0 // SDE bubble cycle 1 + mfpr r31, pt0 // SDE bubble cycle 2 + mfpr r31, pt0 // SDE bubble cycle 3 + nop + + + // save integer regs R4-r31 + SAVE_GPR(r4,CNS_Q_GPR+0x20,r1) + SAVE_GPR(r5,CNS_Q_GPR+0x28,r1) + SAVE_GPR(r6,CNS_Q_GPR+0x30,r1) + SAVE_GPR(r7,CNS_Q_GPR+0x38,r1) + SAVE_GPR(r8,CNS_Q_GPR+0x40,r1) + SAVE_GPR(r9,CNS_Q_GPR+0x48,r1) + SAVE_GPR(r10,CNS_Q_GPR+0x50,r1) + SAVE_GPR(r11,CNS_Q_GPR+0x58,r1) + SAVE_GPR(r12,CNS_Q_GPR+0x60,r1) + SAVE_GPR(r13,CNS_Q_GPR+0x68,r1) + SAVE_GPR(r14,CNS_Q_GPR+0x70,r1) + SAVE_GPR(r15,CNS_Q_GPR+0x78,r1) + SAVE_GPR(r16,CNS_Q_GPR+0x80,r1) + SAVE_GPR(r17,CNS_Q_GPR+0x88,r1) + SAVE_GPR(r18,CNS_Q_GPR+0x90,r1) + SAVE_GPR(r19,CNS_Q_GPR+0x98,r1) + SAVE_GPR(r20,CNS_Q_GPR+0xA0,r1) + SAVE_GPR(r21,CNS_Q_GPR+0xA8,r1) + SAVE_GPR(r22,CNS_Q_GPR+0xB0,r1) + SAVE_GPR(r23,CNS_Q_GPR+0xB8,r1) + SAVE_GPR(r24,CNS_Q_GPR+0xC0,r1) + SAVE_GPR(r25,CNS_Q_GPR+0xC8,r1) + SAVE_GPR(r26,CNS_Q_GPR+0xD0,r1) + SAVE_GPR(r27,CNS_Q_GPR+0xD8,r1) + SAVE_GPR(r28,CNS_Q_GPR+0xE0,r1) + SAVE_GPR(r29,CNS_Q_GPR+0xE8,r1) + SAVE_GPR(r30,CNS_Q_GPR+0xF0,r1) + SAVE_GPR(r31,CNS_Q_GPR+0xF8,r1) + + // save all paltemp regs except pt0 + +//orig unfix_impure_gpr r1 // adjust impure area pointer for gpr stores +//orig fix_impure_ipr r1 // adjust impure area pointer for pt stores + + lda r1, -0x200(r1) // Restore the impure base address. + lda r1, CNS_Q_IPR(r1) // Point to the base of IPR area. + SAVE_IPR(pt0,CNS_Q_PT+0x00,r1) // the osf code didn't save/restore palTemp 0 ?? pboyle + SAVE_IPR(pt1,CNS_Q_PT+0x08,r1) + SAVE_IPR(pt2,CNS_Q_PT+0x10,r1) + SAVE_IPR(pt3,CNS_Q_PT+0x18,r1) + SAVE_IPR(pt4,CNS_Q_PT+0x20,r1) + SAVE_IPR(pt5,CNS_Q_PT+0x28,r1) + SAVE_IPR(pt6,CNS_Q_PT+0x30,r1) + SAVE_IPR(pt7,CNS_Q_PT+0x38,r1) + SAVE_IPR(pt8,CNS_Q_PT+0x40,r1) + SAVE_IPR(pt9,CNS_Q_PT+0x48,r1) + SAVE_IPR(pt10,CNS_Q_PT+0x50,r1) + SAVE_IPR(pt11,CNS_Q_PT+0x58,r1) + SAVE_IPR(pt12,CNS_Q_PT+0x60,r1) + SAVE_IPR(pt13,CNS_Q_PT+0x68,r1) + SAVE_IPR(pt14,CNS_Q_PT+0x70,r1) + SAVE_IPR(pt15,CNS_Q_PT+0x78,r1) + SAVE_IPR(pt16,CNS_Q_PT+0x80,r1) + SAVE_IPR(pt17,CNS_Q_PT+0x88,r1) + SAVE_IPR(pt18,CNS_Q_PT+0x90,r1) + SAVE_IPR(pt19,CNS_Q_PT+0x98,r1) + SAVE_IPR(pt20,CNS_Q_PT+0xA0,r1) + SAVE_IPR(pt21,CNS_Q_PT+0xA8,r1) + SAVE_IPR(pt22,CNS_Q_PT+0xB0,r1) + SAVE_IPR(pt23,CNS_Q_PT+0xB8,r1) + + // Restore shadow mode + mfpr r31, pt0 // pad write to icsr out of shadow of store (trap does not abort write) + mfpr r31, pt0 + mtpr r2, icsr // Restore original ICSR + + mfpr r31, pt0 // SDE bubble cycle 1 + mfpr r31, pt0 // SDE bubble cycle 2 + mfpr r31, pt0 // SDE bubble cycle 3 + nop + + // save all integer shadow regs + SAVE_SHADOW( r8,CNS_Q_SHADOW+0x00,r1) // also called p0...p7 in the Hudson code + SAVE_SHADOW( r9,CNS_Q_SHADOW+0x08,r1) + SAVE_SHADOW(r10,CNS_Q_SHADOW+0x10,r1) + SAVE_SHADOW(r11,CNS_Q_SHADOW+0x18,r1) + SAVE_SHADOW(r12,CNS_Q_SHADOW+0x20,r1) + SAVE_SHADOW(r13,CNS_Q_SHADOW+0x28,r1) + SAVE_SHADOW(r14,CNS_Q_SHADOW+0x30,r1) + SAVE_SHADOW(r25,CNS_Q_SHADOW+0x38,r1) + + SAVE_IPR(excAddr,CNS_Q_EXC_ADDR,r1) + SAVE_IPR(palBase,CNS_Q_PAL_BASE,r1) + SAVE_IPR(mmStat,CNS_Q_MM_STAT,r1) + SAVE_IPR(va,CNS_Q_VA,r1) + SAVE_IPR(icsr,CNS_Q_ICSR,r1) + SAVE_IPR(ipl,CNS_Q_IPL,r1) + SAVE_IPR(ips,CNS_Q_IPS,r1) + SAVE_IPR(itbAsn,CNS_Q_ITB_ASN,r1) + SAVE_IPR(aster,CNS_Q_ASTER,r1) + SAVE_IPR(astrr,CNS_Q_ASTRR,r1) + SAVE_IPR(sirr,CNS_Q_SIRR,r1) + SAVE_IPR(isr,CNS_Q_ISR,r1) + SAVE_IPR(iVptBr,CNS_Q_IVPTBR,r1) + SAVE_IPR(mcsr,CNS_Q_MCSR,r1) + SAVE_IPR(dcMode,CNS_Q_DC_MODE,r1) + +//orig pvc_violate 379 // mf maf_mode after a store ok (pvc doesn't distinguish ld from st) +//orig store_reg maf_mode, ipr=1 // save ipr -- no mbox instructions for +//orig // PVC violation applies only to +pvc$osf35$379: // loads. HW_ST ok here, so ignore + SAVE_IPR(mafMode,CNS_Q_MAF_MODE,r1) // MBOX INST->MF MAF_MODE IN 0,1,2 + + + //the following iprs are informational only -- will not be restored + + SAVE_IPR(icPerr,CNS_Q_ICPERR_STAT,r1) + SAVE_IPR(PmCtr,CNS_Q_PM_CTR,r1) + SAVE_IPR(intId,CNS_Q_INT_ID,r1) + SAVE_IPR(excSum,CNS_Q_EXC_SUM,r1) + SAVE_IPR(excMask,CNS_Q_EXC_MASK,r1) + ldah r14, 0xFFF0(zero) + zap r14, 0xE0, r14 // Get base address of CBOX IPRs + NOP // Pad mfpr dcPerr out of shadow of + NOP // last store + NOP + SAVE_IPR(dcPerr,CNS_Q_DCPERR_STAT,r1) + + // read cbox ipr state + + mb + ldq_p r2, scCtl(r14) + ldq_p r13, ldLock(r14) + ldq_p r4, scAddr(r14) + ldq_p r5, eiAddr(r14) + ldq_p r6, bcTagAddr(r14) + ldq_p r7, fillSyn(r14) + bis r5, r4, zero // Make sure all loads complete before + bis r7, r6, zero // reading registers that unlock them. + ldq_p r8, scStat(r14) // Unlocks scAddr. + ldq_p r9, eiStat(r14) // Unlocks eiAddr, bcTagAddr, fillSyn. + ldq_p zero, eiStat(r14) // Make sure it is really unlocked. + mb + + // save cbox ipr state + SAVE_SHADOW(r2,CNS_Q_SC_CTL,r1); + SAVE_SHADOW(r13,CNS_Q_LD_LOCK,r1); + SAVE_SHADOW(r4,CNS_Q_SC_ADDR,r1); + SAVE_SHADOW(r5,CNS_Q_EI_ADDR,r1); + SAVE_SHADOW(r6,CNS_Q_BC_TAG_ADDR,r1); + SAVE_SHADOW(r7,CNS_Q_FILL_SYN,r1); + SAVE_SHADOW(r8,CNS_Q_SC_STAT,r1); + SAVE_SHADOW(r9,CNS_Q_EI_STAT,r1); + //bc_config? sl_rcv? + +// restore impure base +//orig unfix_impure_ipr r1 + lda r1, -CNS_Q_IPR(r1) + +// save all floating regs + mfpr r0, icsr // get icsr + or r31, 1, r2 // get a one + sll r2, icsr_v_fpe, r2 // Shift it into ICSR position + or r2, r0, r0 // set FEN on + mtpr r0, icsr // write to icsr, enabling FEN + +// map the save area virtually + mtpr r31, dtbIa // Clear all DTB entries + srl r1, va_s_off, r0 // Clean off byte-within-page offset + sll r0, pte_v_pfn, r0 // Shift to form PFN + lda r0, pte_m_prot(r0) // Set all read/write enable bits + mtpr r0, dtbPte // Load the PTE and set valid + mtpr r1, dtbTag // Write the PTE and tag into the DTB + + +// map the next page too - in case the impure area crosses a page boundary + lda r4, (1< and ICSR + mtpr r0, icsr // Update the chip + + mfpr r31, pt0 // FPE bubble cycle 1 //orig + mfpr r31, pt0 // FPE bubble cycle 2 //orig + mfpr r31, pt0 // FPE bubble cycle 3 //orig + +//orig fix_impure_ipr r1 +//orig restore_reg1 fpcsr, f0, r1, fpcsr=1 +//orig mt_fpcr f0 +//orig +//orig unfix_impure_ipr r1 +//orig fix_impure_gpr r1 // adjust impure pointer offset for gpr access + lda r1, 200(r1) // Point to base of IPR area again + RESTORE_FPR(f0,CNS_Q_FPCSR,r1) // can it reach?? pb + mt_fpcr f0 // original + + lda r1, 0x200(r1) // point to center of CPU segment + +// restore all floating regs + RESTORE_FPR(f0,CNS_Q_FPR+0x00,r1) + RESTORE_FPR(f1,CNS_Q_FPR+0x08,r1) + RESTORE_FPR(f2,CNS_Q_FPR+0x10,r1) + RESTORE_FPR(f3,CNS_Q_FPR+0x18,r1) + RESTORE_FPR(f4,CNS_Q_FPR+0x20,r1) + RESTORE_FPR(f5,CNS_Q_FPR+0x28,r1) + RESTORE_FPR(f6,CNS_Q_FPR+0x30,r1) + RESTORE_FPR(f7,CNS_Q_FPR+0x38,r1) + RESTORE_FPR(f8,CNS_Q_FPR+0x40,r1) + RESTORE_FPR(f9,CNS_Q_FPR+0x48,r1) + RESTORE_FPR(f10,CNS_Q_FPR+0x50,r1) + RESTORE_FPR(f11,CNS_Q_FPR+0x58,r1) + RESTORE_FPR(f12,CNS_Q_FPR+0x60,r1) + RESTORE_FPR(f13,CNS_Q_FPR+0x68,r1) + RESTORE_FPR(f14,CNS_Q_FPR+0x70,r1) + RESTORE_FPR(f15,CNS_Q_FPR+0x78,r1) + RESTORE_FPR(f16,CNS_Q_FPR+0x80,r1) + RESTORE_FPR(f17,CNS_Q_FPR+0x88,r1) + RESTORE_FPR(f18,CNS_Q_FPR+0x90,r1) + RESTORE_FPR(f19,CNS_Q_FPR+0x98,r1) + RESTORE_FPR(f20,CNS_Q_FPR+0xA0,r1) + RESTORE_FPR(f21,CNS_Q_FPR+0xA8,r1) + RESTORE_FPR(f22,CNS_Q_FPR+0xB0,r1) + RESTORE_FPR(f23,CNS_Q_FPR+0xB8,r1) + RESTORE_FPR(f24,CNS_Q_FPR+0xC0,r1) + RESTORE_FPR(f25,CNS_Q_FPR+0xC8,r1) + RESTORE_FPR(f26,CNS_Q_FPR+0xD0,r1) + RESTORE_FPR(f27,CNS_Q_FPR+0xD8,r1) + RESTORE_FPR(f28,CNS_Q_FPR+0xE0,r1) + RESTORE_FPR(f29,CNS_Q_FPR+0xE8,r1) + RESTORE_FPR(f30,CNS_Q_FPR+0xF0,r1) + RESTORE_FPR(f31,CNS_Q_FPR+0xF8,r1) + +// switch impure pointer from gpr to ipr area -- +//orig unfix_impure_gpr r1 +//orig fix_impure_ipr r1 + lda r1, -0x200(r1) // Restore base address of impure area. + lda r1, CNS_Q_IPR(r1) // Point to base of IPR area. + +// restore all pal regs + RESTORE_IPR(pt0,CNS_Q_PT+0x00,r1) // the osf code didn't save/restore palTemp 0 ?? pboyle + RESTORE_IPR(pt1,CNS_Q_PT+0x08,r1) + RESTORE_IPR(pt2,CNS_Q_PT+0x10,r1) + RESTORE_IPR(pt3,CNS_Q_PT+0x18,r1) + RESTORE_IPR(pt4,CNS_Q_PT+0x20,r1) + RESTORE_IPR(pt5,CNS_Q_PT+0x28,r1) + RESTORE_IPR(pt6,CNS_Q_PT+0x30,r1) + RESTORE_IPR(pt7,CNS_Q_PT+0x38,r1) + RESTORE_IPR(pt8,CNS_Q_PT+0x40,r1) + RESTORE_IPR(pt9,CNS_Q_PT+0x48,r1) + RESTORE_IPR(pt10,CNS_Q_PT+0x50,r1) + RESTORE_IPR(pt11,CNS_Q_PT+0x58,r1) + RESTORE_IPR(pt12,CNS_Q_PT+0x60,r1) + RESTORE_IPR(pt13,CNS_Q_PT+0x68,r1) + RESTORE_IPR(pt14,CNS_Q_PT+0x70,r1) + RESTORE_IPR(pt15,CNS_Q_PT+0x78,r1) + RESTORE_IPR(pt16,CNS_Q_PT+0x80,r1) + RESTORE_IPR(pt17,CNS_Q_PT+0x88,r1) + RESTORE_IPR(pt18,CNS_Q_PT+0x90,r1) + RESTORE_IPR(pt19,CNS_Q_PT+0x98,r1) + RESTORE_IPR(pt20,CNS_Q_PT+0xA0,r1) + RESTORE_IPR(pt21,CNS_Q_PT+0xA8,r1) + RESTORE_IPR(pt22,CNS_Q_PT+0xB0,r1) + RESTORE_IPR(pt23,CNS_Q_PT+0xB8,r1) + + +//orig restore_reg exc_addr, ipr=1 // restore ipr +//orig restore_reg pal_base, ipr=1 // restore ipr +//orig restore_reg ipl, ipr=1 // restore ipr +//orig restore_reg ps, ipr=1 // restore ipr +//orig mtpr r0, dtb_cm // set current mode in mbox too +//orig restore_reg itb_asn, ipr=1 +//orig srl r0, itb_asn_v_asn, r0 +//orig sll r0, dtb_asn_v_asn, r0 +//orig mtpr r0, dtb_asn // set ASN in Mbox too +//orig restore_reg ivptbr, ipr=1 +//orig mtpr r0, mvptbr // use ivptbr value to restore mvptbr +//orig restore_reg mcsr, ipr=1 +//orig restore_reg aster, ipr=1 +//orig restore_reg astrr, ipr=1 +//orig restore_reg sirr, ipr=1 +//orig restore_reg maf_mode, ipr=1 // no mbox instruction for 3 cycles +//orig mfpr r31, pt0 // (may issue with mt maf_mode) +//orig mfpr r31, pt0 // bubble cycle 1 +//orig mfpr r31, pt0 // bubble cycle 2 +//orig mfpr r31, pt0 // bubble cycle 3 +//orig mfpr r31, pt0 // (may issue with following ld) + + // r0 gets the value of RESTORE_IPR in the macro and this code uses this side effect (gag) + RESTORE_IPR(excAddr,CNS_Q_EXC_ADDR,r1) + RESTORE_IPR(palBase,CNS_Q_PAL_BASE,r1) + RESTORE_IPR(ipl,CNS_Q_IPL,r1) + RESTORE_IPR(ips,CNS_Q_IPS,r1) + mtpr r0, dtbCm // Set Mbox current mode too. + RESTORE_IPR(itbAsn,CNS_Q_ITB_ASN,r1) + srl r0, 4, r0 + sll r0, 57, r0 + mtpr r0, dtbAsn // Set Mbox ASN too + RESTORE_IPR(iVptBr,CNS_Q_IVPTBR,r1) + mtpr r0, mVptBr // Set Mbox VptBr too + RESTORE_IPR(mcsr,CNS_Q_MCSR,r1) + RESTORE_IPR(aster,CNS_Q_ASTER,r1) + RESTORE_IPR(astrr,CNS_Q_ASTRR,r1) + RESTORE_IPR(sirr,CNS_Q_SIRR,r1) + RESTORE_IPR(mafMode,CNS_Q_MAF_MODE,r1) + STALL + STALL + STALL + STALL + STALL + + + // restore all integer shadow regs + RESTORE_SHADOW( r8,CNS_Q_SHADOW+0x00,r1) // also called p0...p7 in the Hudson code + RESTORE_SHADOW( r9,CNS_Q_SHADOW+0x08,r1) + RESTORE_SHADOW(r10,CNS_Q_SHADOW+0x10,r1) + RESTORE_SHADOW(r11,CNS_Q_SHADOW+0x18,r1) + RESTORE_SHADOW(r12,CNS_Q_SHADOW+0x20,r1) + RESTORE_SHADOW(r13,CNS_Q_SHADOW+0x28,r1) + RESTORE_SHADOW(r14,CNS_Q_SHADOW+0x30,r1) + RESTORE_SHADOW(r25,CNS_Q_SHADOW+0x38,r1) + RESTORE_IPR(dcMode,CNS_Q_DC_MODE,r1) + + // + // Get out of shadow mode + // + + mfpr r31, pt0 // pad last load to icsr write (in case of replay, icsr will be written anyway) + mfpr r31, pt0 // "" + mfpr r0, icsr // Get icsr + ldah r2, (1<<(ICSR_V_SDE-16))(r31) // Get a one in SHADOW_ENABLE bit location + bic r0, r2, r2 // ICSR with SDE clear + mtpr r2, icsr // Turn off SDE - no palshadow rd/wr for 3 bubble cycles + + mfpr r31, pt0 // SDE bubble cycle 1 + mfpr r31, pt0 // SDE bubble cycle 2 + mfpr r31, pt0 // SDE bubble cycle 3 + nop + +// switch impure pointer from ipr to gpr area -- +//orig unfix_impure_ipr r1 +//orig fix_impure_gpr r1 + +// Restore GPRs (r0, r2 are restored later, r1 and r3 are trashed) ... + + lda r1, -CNS_Q_IPR(r1) // Restore base address of impure area + lda r1, 0x200(r1) // Point to center of CPU segment + + // restore all integer regs + RESTORE_GPR(r4,CNS_Q_GPR+0x20,r1) + RESTORE_GPR(r5,CNS_Q_GPR+0x28,r1) + RESTORE_GPR(r6,CNS_Q_GPR+0x30,r1) + RESTORE_GPR(r7,CNS_Q_GPR+0x38,r1) + RESTORE_GPR(r8,CNS_Q_GPR+0x40,r1) + RESTORE_GPR(r9,CNS_Q_GPR+0x48,r1) + RESTORE_GPR(r10,CNS_Q_GPR+0x50,r1) + RESTORE_GPR(r11,CNS_Q_GPR+0x58,r1) + RESTORE_GPR(r12,CNS_Q_GPR+0x60,r1) + RESTORE_GPR(r13,CNS_Q_GPR+0x68,r1) + RESTORE_GPR(r14,CNS_Q_GPR+0x70,r1) + RESTORE_GPR(r15,CNS_Q_GPR+0x78,r1) + RESTORE_GPR(r16,CNS_Q_GPR+0x80,r1) + RESTORE_GPR(r17,CNS_Q_GPR+0x88,r1) + RESTORE_GPR(r18,CNS_Q_GPR+0x90,r1) + RESTORE_GPR(r19,CNS_Q_GPR+0x98,r1) + RESTORE_GPR(r20,CNS_Q_GPR+0xA0,r1) + RESTORE_GPR(r21,CNS_Q_GPR+0xA8,r1) + RESTORE_GPR(r22,CNS_Q_GPR+0xB0,r1) + RESTORE_GPR(r23,CNS_Q_GPR+0xB8,r1) + RESTORE_GPR(r24,CNS_Q_GPR+0xC0,r1) + RESTORE_GPR(r25,CNS_Q_GPR+0xC8,r1) + RESTORE_GPR(r26,CNS_Q_GPR+0xD0,r1) + RESTORE_GPR(r27,CNS_Q_GPR+0xD8,r1) + RESTORE_GPR(r28,CNS_Q_GPR+0xE0,r1) + RESTORE_GPR(r29,CNS_Q_GPR+0xE8,r1) + RESTORE_GPR(r30,CNS_Q_GPR+0xF0,r1) + RESTORE_GPR(r31,CNS_Q_GPR+0xF8,r1) + +//orig // switch impure pointer from gpr to ipr area -- +//orig unfix_impure_gpr r1 +//orig fix_impure_ipr r1 +//orig restore_reg icsr, ipr=1 // restore original icsr- 4 bubbles to hw_rei + + lda t0, -0x200(t0) // Restore base address of impure area. + lda t0, CNS_Q_IPR(t0) // Point to base of IPR area again. + RESTORE_IPR(icsr,CNS_Q_ICSR,r1) + +//orig // and back again -- +//orig unfix_impure_ipr r1 +//orig fix_impure_gpr r1 +//orig store_reg1 flag, r31, r1, ipr=1 // clear dump area valid flag +//orig mb + + lda t0, -CNS_Q_IPR(t0) // Back to base of impure area again, + lda t0, 0x200(t0) // and back to center of CPU segment + SAVE_GPR(r31,CNS_Q_FLAG,r1) // Clear the dump area valid flag + mb + +//orig // and back we go +//orig// restore_reg 3 +//orig restore_reg 2 +//orig// restore_reg 1 +//orig restore_reg 0 +//orig // restore impure area base +//orig unfix_impure_gpr r1 + + RESTORE_GPR(r2,CNS_Q_GPR+0x10,r1) + RESTORE_GPR(r0,CNS_Q_GPR+0x00,r1) + lda r1, -0x200(r1) // Restore impure base address + + mfpr r31, pt0 // stall for ldq_p above //orig + + mtpr r31, dtb_ia // clear the tb //orig + mtpr r31, itb_ia // clear the itb //orig + +//orig pvc_jsr rststa, bsr=1, dest=1 + ret r31, (r3) // back we go //orig + + +// +// pal_pal_bug_check -- code has found a bugcheck situation. +// Set things up and join common machine check flow. +// +// Input: +// r14 - exc_addr +// +// On exit: +// pt0 - saved r0 +// pt1 - saved r1 +// pt4 - saved r4 +// pt5 - saved r5 +// pt6 - saved r6 +// pt10 - saved exc_addr +// pt_misc<47:32> - mchk code +// pt_misc<31:16> - scb vector +// r14 - base of Cbox IPRs in IO space +// MCES is set +// + + ALIGN_BLOCK + .globl pal_pal_bug_check_from_int +pal_pal_bug_check_from_int: + DEBUGSTORE(0x79) +//simos DEBUG_EXC_ADDR() + DEBUGSTORE(0x20) +//simos bsr r25, put_hex + lda r25, mchk_c_bugcheck(r31) + addq r25, 1, r25 // set flag indicating we came from interrupt and stack is already pushed + br r31, pal_pal_mchk + nop + +pal_pal_bug_check: + lda r25, mchk_c_bugcheck(r31) + +pal_pal_mchk: + sll r25, 32, r25 // Move mchk code to position + + mtpr r14, pt10 // Stash exc_addr + mtpr r14, exc_addr + + mfpr r12, pt_misc // Get MCES and scratch + zap r12, 0x3c, r12 + + or r12, r25, r12 // Combine mchk code + lda r25, scb_v_procmchk(r31) // Get SCB vector + + sll r25, 16, r25 // Move SCBv to position + or r12, r25, r25 // Combine SCBv + + mtpr r0, pt0 // Stash for scratch + bis r25, mces_m_mchk, r25 // Set MCES bit + + mtpr r25, pt_misc // Save mchk code!scbv!whami!mces + ldah r14, 0xfff0(r31) + + mtpr r1, pt1 // Stash for scratch + zap r14, 0xE0, r14 // Get Cbox IPR base + + mtpr r4, pt4 + mtpr r5, pt5 + + mtpr r6, pt6 + blbs r12, sys_double_machine_check // MCHK halt if double machine check + + br r31, sys_mchk_collect_iprs // Join common machine check flow + + + +// align_to_call_pal_section +// Align to address of first call_pal entry point - 2000 + +// +// HALT - PALcode for HALT instruction +// +// Entry: +// Vectored into via hardware PALcode instruction dispatch. +// +// Function: +// GO to console code +// +// + + .text 1 +// . = 0x2000 + CALL_PAL_PRIV(PAL_HALT_ENTRY) +call_pal_halt: + mfpr r31, pt0 // Pad exc_addr read + mfpr r31, pt0 + + mfpr r12, exc_addr // get PC + subq r12, 4, r12 // Point to the HALT + + mtpr r12, exc_addr + mtpr r0, pt0 + +//orig pvc_jsr updpcb, bsr=1 + bsr r0, pal_update_pcb // update the pcb + lda r0, hlt_c_sw_halt(r31) // set halt code to sw halt + br r31, sys_enter_console // enter the console + +// +// CFLUSH - PALcode for CFLUSH instruction +// +// Entry: +// Vectored into via hardware PALcode instruction dispatch. +// +// R16 - contains the PFN of the page to be flushed +// +// Function: +// Flush all Dstream caches of 1 entire page +// The CFLUSH routine is in the system specific module. +// +// + + CALL_PAL_PRIV(PAL_CFLUSH_ENTRY) +Call_Pal_Cflush: + br r31, sys_cflush + +// +// DRAINA - PALcode for DRAINA instruction +// +// Entry: +// Vectored into via hardware PALcode instruction dispatch. +// Implicit TRAPB performed by hardware. +// +// Function: +// Stall instruction issue until all prior instructions are guaranteed to +// complete without incurring aborts. For the EV5 implementation, this +// means waiting until all pending DREADS are returned. +// +// + + CALL_PAL_PRIV(PAL_DRAINA_ENTRY) +Call_Pal_Draina: + ldah r14, 0x100(r31) // Init counter. Value? + nop + +DRAINA_LOOP: + subq r14, 1, r14 // Decrement counter + mfpr r13, ev5__maf_mode // Fetch status bit + + srl r13, maf_mode_v_dread_pending, r13 + ble r14, DRAINA_LOOP_TOO_LONG + + nop + blbs r13, DRAINA_LOOP // Wait until all DREADS clear + + hw_rei + +DRAINA_LOOP_TOO_LONG: + br r31, call_pal_halt + +// CALL_PAL OPCDECs + + CALL_PAL_PRIV(0x0003) +CallPal_OpcDec03: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x0004) +CallPal_OpcDec04: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x0005) +CallPal_OpcDec05: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x0006) +CallPal_OpcDec06: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x0007) +CallPal_OpcDec07: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x0008) +CallPal_OpcDec08: + br r31, osfpal_calpal_opcdec + +// +// CSERVE - PALcode for CSERVE instruction +// +// Entry: +// Vectored into via hardware PALcode instruction dispatch. +// +// Function: +// Various functions for private use of console software +// +// option selector in r0 +// arguments in r16.... +// The CSERVE routine is in the system specific module. +// +// + + CALL_PAL_PRIV(PAL_CSERVE_ENTRY) +Call_Pal_Cserve: + br r31, sys_cserve + +// +// swppal - PALcode for swppal instruction +// +// Entry: +// Vectored into via hardware PALcode instruction dispatch. +// Vectored into via hardware PALcode instruction dispatch. +// R16 contains the new PAL identifier +// R17:R21 contain implementation-specific entry parameters +// +// R0 receives status: +// 0 success (PAL was switched) +// 1 unknown PAL variant +// 2 known PAL variant, but PAL not loaded +// +// +// Function: +// Swap control to another PAL. +// + + CALL_PAL_PRIV(PAL_SWPPAL_ENTRY) +Call_Pal_Swppal: + cmpule r16, 255, r0 // see if a kibble was passed + cmoveq r16, r16, r0 // if r16=0 then a valid address (ECO 59) + + or r16, r31, r3 // set r3 incase this is a address + blbc r0, swppal_cont // nope, try it as an address + + cmpeq r16, 2, r0 // is it our friend OSF? + blbc r0, swppal_fail // nope, don't know this fellow + + br r2, CALL_PAL_SWPPAL_10_ // tis our buddy OSF + +// .global osfpal_hw_entry_reset +// .weak osfpal_hw_entry_reset +// .long +//orig halt // don't know how to get the address here - kludge ok, load pal at 0 + .long 0 // ?? hack upon hack...pb + +CALL_PAL_SWPPAL_10_: ldl_p r3, 0(r2) // fetch target addr +// ble r3, swppal_fail ; if OSF not linked in say not loaded. + mfpr r2, pal_base // fetch pal base + + addq r2, r3, r3 // add pal base + lda r2, 0x3FFF(r31) // get pal base checker mask + + and r3, r2, r2 // any funky bits set? + cmpeq r2, 0, r0 // + + blbc r0, swppal_fail // return unknown if bad bit set. + br r31, swppal_cont + +// .sbttl "CALL_PAL OPCDECs" + + CALL_PAL_PRIV(0x000B) +CallPal_OpcDec0B: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x000C) +CallPal_OpcDec0C: + br r31, osfpal_calpal_opcdec + +// +// wripir - PALcode for wripir instruction +// +// Entry: +// Vectored into via hardware PALcode instruction dispatch. +// r16 = processor number to interrupt +// +// Function: +// IPIR <- R16 +// Handled in system-specific code +// +// Exit: +// interprocessor interrupt is recorded on the target processor +// and is initiated when the proper enabling conditions are present. +// + + CALL_PAL_PRIV(PAL_WRIPIR_ENTRY) +Call_Pal_Wrpir: + br r31, sys_wripir + +// .sbttl "CALL_PAL OPCDECs" + + CALL_PAL_PRIV(0x000E) +CallPal_OpcDec0E: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x000F) +CallPal_OpcDec0F: + br r31, osfpal_calpal_opcdec + +// +// rdmces - PALcode for rdmces instruction +// +// Entry: +// Vectored into via hardware PALcode instruction dispatch. +// +// Function: +// R0 <- ZEXT(MCES) +// + + CALL_PAL_PRIV(PAL_RDMCES_ENTRY) +Call_Pal_Rdmces: + mfpr r0, pt_mces // Read from PALtemp + and r0, mces_m_all, r0 // Clear other bits + + hw_rei + +// +// wrmces - PALcode for wrmces instruction +// +// Entry: +// Vectored into via hardware PALcode instruction dispatch. +// +// Function: +// If {R16<0> EQ 1} then MCES<0> <- 0 (MCHK) +// If {R16<1> EQ 1} then MCES<1> <- 0 (SCE) +// If {R16<2> EQ 1} then MCES<2> <- 0 (PCE) +// MCES<3> <- R16<3> (DPC) +// MCES<4> <- R16<4> (DSC) +// +// + + CALL_PAL_PRIV(PAL_WRMCES_ENTRY) +Call_Pal_Wrmces: + and r16, ((1<read restriction + + nop + hw_rei + + + +// CALL_PAL OPCDECs + + CALL_PAL_PRIV(0x0012) +CallPal_OpcDec12: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x0013) +CallPal_OpcDec13: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x0014) +CallPal_OpcDec14: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x0015) +CallPal_OpcDec15: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x0016) +CallPal_OpcDec16: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x0017) +CallPal_OpcDec17: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x0018) +CallPal_OpcDec18: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x0019) +CallPal_OpcDec19: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x001A) +CallPal_OpcDec1A: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x001B) +CallPal_OpcDec1B: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x001C) +CallPal_OpcDec1C: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x001D) +CallPal_OpcDec1D: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x001E) +CallPal_OpcDec1E: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x001F) +CallPal_OpcDec1F: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x0020) +CallPal_OpcDec20: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x0021) +CallPal_OpcDec21: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x0022) +CallPal_OpcDec22: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x0023) +CallPal_OpcDec23: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x0024) +CallPal_OpcDec24: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x0025) +CallPal_OpcDec25: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x0026) +CallPal_OpcDec26: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x0027) +CallPal_OpcDec27: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x0028) +CallPal_OpcDec28: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x0029) +CallPal_OpcDec29: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x002A) +CallPal_OpcDec2A: + br r31, osfpal_calpal_opcdec + +// +// wrfen - PALcode for wrfen instruction +// +// Entry: +// Vectored into via hardware PALcode instruction dispatch. +// +// Function: +// a0<0> -> ICSR +// Store new FEN in PCB +// Final value of t0 (r1), t8..t10 (r22..r24) and a0 (r16) +// are UNPREDICTABLE +// +// Issue: What about pending FP loads when FEN goes from on->off???? +// + + CALL_PAL_PRIV(PAL_WRFEN_ENTRY) +Call_Pal_Wrfen: + or r31, 1, r13 // Get a one + mfpr r1, ev5__icsr // Get current FPE + + sll r13, icsr_v_fpe, r13 // shift 1 to icsr spot, e0 + and r16, 1, r16 // clean new fen + + sll r16, icsr_v_fpe, r12 // shift new fen to correct bit position + bic r1, r13, r1 // zero icsr + + or r1, r12, r1 // Or new FEN into ICSR + mfpr r12, pt_pcbb // Get PCBB - E1 + + mtpr r1, ev5__icsr // write new ICSR. 3 Bubble cycles to HW_REI + stl_p r16, osfpcb_q_fen(r12) // Store FEN in PCB. + + mfpr r31, pt0 // Pad ICSR write. + mfpr r31, pt0 + + mfpr r31, pt0 +// pvc_violate 225 // cuz PVC can't distinguish which bits changed + hw_rei + + + CALL_PAL_PRIV(0x002C) +CallPal_OpcDec2C: + br r31, osfpal_calpal_opcdec + +// +// wrvptpr - PALcode for wrvptpr instruction +// +// Entry: +// Vectored into via hardware PALcode instruction dispatch. +// +// Function: +// vptptr <- a0 (r16) +// + + CALL_PAL_PRIV(PAL_WRVPTPTR_ENTRY) +Call_Pal_Wrvptptr: + mtpr r16, ev5__mvptbr // Load Mbox copy + mtpr r16, ev5__ivptbr // Load Ibox copy + nop // Pad IPR write + nop + hw_rei + + CALL_PAL_PRIV(0x002E) +CallPal_OpcDec2E: + br r31, osfpal_calpal_opcdec + + CALL_PAL_PRIV(0x002F) +CallPal_OpcDec2F: + br r31, osfpal_calpal_opcdec + + +// +// swpctx - PALcode for swpctx instruction +// +// Entry: +// hardware dispatch via callPal instruction +// R16 -> new pcb +// +// Function: +// dynamic state moved to old pcb +// new state loaded from new pcb +// pcbb pointer set +// old pcbb returned in R0 +// +// Note: need to add perf monitor stuff +// + + CALL_PAL_PRIV(PAL_SWPCTX_ENTRY) +Call_Pal_Swpctx: + rpcc r13 // get cyccounter + mfpr r0, pt_pcbb // get pcbb + + ldq_p r22, osfpcb_q_fen(r16) // get new fen/pme + ldq_p r23, osfpcb_l_cc(r16) // get new asn + + srl r13, 32, r25 // move offset + mfpr r24, pt_usp // get usp + + stq_p r30, osfpcb_q_ksp(r0) // store old ksp +// pvc_violate 379 // stq_p can't trap except replay. only problem if mf same ipr in same shadow. + mtpr r16, pt_pcbb // set new pcbb + + stq_p r24, osfpcb_q_usp(r0) // store usp + addl r13, r25, r25 // merge for new time + + stl_p r25, osfpcb_l_cc(r0) // save time + ldah r24, (1<<(icsr_v_fpe-16))(r31) + + and r22, 1, r12 // isolate fen + mfpr r25, icsr // get current icsr + + lda r24, (1< +// PS <- a0<2:0> (r16) +// +// t8 (r22) is scratch +// + + CALL_PAL_PRIV(PAL_SWPIPL_ENTRY) +Call_Pal_Swpipl: + and r16, osfps_m_ipl, r16 // clean New ipl + mfpr r22, pt_intmask // get int mask + + extbl r22, r16, r22 // get mask for this ipl + bis r11, r31, r0 // return old ipl + + bis r16, r31, r11 // set new ps + mtpr r22, ev5__ipl // set new mask + + mfpr r31, pt0 // pad ipl write + mfpr r31, pt0 // pad ipl write + + hw_rei // back + +// +// rdps - PALcode for rdps instruction +// +// Entry: +// Vectored into via hardware PALcode instruction dispatch. +// +// Function: +// v0 (r0) <- ps +// + + CALL_PAL_PRIV(PAL_RDPS_ENTRY) +Call_Pal_Rdps: + bis r11, r31, r0 // Fetch PALshadow PS + nop // Must be 2 cycles long + hw_rei + +// +// wrkgp - PALcode for wrkgp instruction +// +// Entry: +// Vectored into via hardware PALcode instruction dispatch. +// +// Function: +// kgp <- a0 (r16) +// + + CALL_PAL_PRIV(PAL_WRKGP_ENTRY) +Call_Pal_Wrkgp: + nop + mtpr r16, pt_kgp + nop // Pad for pt write->read restriction + nop + hw_rei + +// +// wrusp - PALcode for wrusp instruction +// +// Entry: +// Vectored into via hardware PALcode instruction dispatch. +// +// Function: +// usp <- a0 (r16) +// + + CALL_PAL_PRIV(PAL_WRUSP_ENTRY) +Call_Pal_Wrusp: + nop + mtpr r16, pt_usp + nop // Pad possible pt write->read restriction + nop + hw_rei + +// +// wrperfmon - PALcode for wrperfmon instruction +// +// Entry: +// Vectored into via hardware PALcode instruction dispatch. +// +// +// Function: +// Various control functions for the onchip performance counters +// +// option selector in r16 +// option argument in r17 +// returned status in r0 +// +// +// r16 = 0 Disable performance monitoring for one or more cpu's +// r17 = 0 disable no counters +// r17 = bitmask disable counters specified in bit mask (1=disable) +// +// r16 = 1 Enable performance monitoring for one or more cpu's +// r17 = 0 enable no counters +// r17 = bitmask enable counters specified in bit mask (1=enable) +// +// r16 = 2 Mux select for one or more cpu's +// r17 = Mux selection (cpu specific) +// <24:19> bc_ctl field (see spec) +// <31>,<7:4>,<3:0> pmctr ,, fields (see spec) +// +// r16 = 3 Options +// r17 = (cpu specific) +// <0> = 0 log all processes +// <0> = 1 log only selected processes +// <30,9,8> mode select - ku,kp,kk +// +// r16 = 4 Interrupt frequency select +// r17 = (cpu specific) indicates interrupt frequencies desired for each +// counter, with "zero interrupts" being an option +// frequency info in r17 bits as defined by PMCTR_CTL below +// +// r16 = 5 Read Counters +// r17 = na +// r0 = value (same format as ev5 pmctr) +// <0> = 0 Read failed +// <0> = 1 Read succeeded +// +// r16 = 6 Write Counters +// r17 = value (same format as ev5 pmctr; all counters written simultaneously) +// +// r16 = 7 Enable performance monitoring for one or more cpu's and reset counter to 0 +// r17 = 0 enable no counters +// r17 = bitmask enable & clear counters specified in bit mask (1=enable & clear) +// +//============================================================================= +//Assumptions: +//PMCTR_CTL: +// +// <15:14> CTL0 -- encoded frequency select and enable - CTR0 +// <13:12> CTL1 -- " - CTR1 +// <11:10> CTL2 -- " - CTR2 +// +// <9:8> FRQ0 -- frequency select for CTR0 (no enable info) +// <7:6> FRQ1 -- frequency select for CTR1 +// <5:4> FRQ2 -- frequency select for CTR2 +// +// <0> all vs. select processes (0=all,1=select) +// +// where +// FRQx<1:0> +// 0 1 disable interrupt +// 1 0 frequency = 65536 (16384 for ctr2) +// 1 1 frequency = 256 +// note: FRQx<1:0> = 00 will keep counters from ever being enabled. +// +//============================================================================= +// + CALL_PAL_PRIV(0x0039) +// unsupported in Hudson code .. pboyle Nov/95 +CALL_PAL_Wrperfmon: + // "real" performance monitoring code + cmpeq r16, 1, r0 // check for enable + bne r0, perfmon_en // br if requested to enable + + cmpeq r16, 2, r0 // check for mux ctl + bne r0, perfmon_muxctl // br if request to set mux controls + + cmpeq r16, 3, r0 // check for options + bne r0, perfmon_ctl // br if request to set options + + cmpeq r16, 4, r0 // check for interrupt frequency select + bne r0, perfmon_freq // br if request to change frequency select + + cmpeq r16, 5, r0 // check for counter read request + bne r0, perfmon_rd // br if request to read counters + + cmpeq r16, 6, r0 // check for counter write request + bne r0, perfmon_wr // br if request to write counters + + cmpeq r16, 7, r0 // check for counter clear/enable request + bne r0, perfmon_enclr // br if request to clear/enable counters + + beq r16, perfmon_dis // br if requested to disable (r16=0) + br r31, perfmon_unknown // br if unknown request + +// +// rdusp - PALcode for rdusp instruction +// +// Entry: +// Vectored into via hardware PALcode instruction dispatch. +// +// Function: +// v0 (r0) <- usp +// + + CALL_PAL_PRIV(PAL_RDUSP_ENTRY) +Call_Pal_Rdusp: + nop + mfpr r0, pt_usp + hw_rei + + + CALL_PAL_PRIV(0x003B) +CallPal_OpcDec3B: + br r31, osfpal_calpal_opcdec + +// +// whami - PALcode for whami instruction +// +// Entry: +// Vectored into via hardware PALcode instruction dispatch. +// +// Function: +// v0 (r0) <- whami +// + CALL_PAL_PRIV(PAL_WHAMI_ENTRY) +Call_Pal_Whami: + nop + mfpr r0, pt_whami // Get Whami + extbl r0, 1, r0 // Isolate just whami bits + hw_rei + +// +// retsys - PALcode for retsys instruction +// +// Entry: +// Vectored into via hardware PALcode instruction dispatch. +// 00(sp) contains return pc +// 08(sp) contains r29 +// +// Function: +// Return from system call. +// mode switched from kern to user. +// stacks swapped, ugp, upc restored. +// r23, r25 junked +// + + CALL_PAL_PRIV(PAL_RETSYS_ENTRY) +Call_Pal_Retsys: + lda r25, osfsf_c_size(sp) // pop stack + bis r25, r31, r14 // touch r25 & r14 to stall mf exc_addr + + mfpr r14, exc_addr // save exc_addr in case of fault + ldq r23, osfsf_pc(sp) // get pc + + ldq r29, osfsf_gp(sp) // get gp + stl_c r31, -4(sp) // clear lock_flag + + lda r11, 1<