/* * Copyright (c) 2010 Gabe Black * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer; * redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution; * neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Gabe Black */ #ifndef __ARCH_GENERIC_TYPES_HH__ #define __ARCH_GENERIC_TYPES_HH__ #include #include "base/trace.hh" #include "base/types.hh" #include "sim/serialize.hh" namespace GenericISA { // The guaranteed interface. class PCStateBase { protected: Addr _pc; Addr _npc; PCStateBase() {} PCStateBase(Addr val) { set(val); } public: /** * Returns the memory address the bytes of this instruction came from. * * @return Memory address of the current instruction's encoding. */ Addr instAddr() const { return _pc; } /** * Returns the memory address the bytes of the next instruction came from. * * @return Memory address of the next instruction's encoding. */ Addr nextInstAddr() const { return _npc; } /** * Returns the current micropc. * * @return The current micropc. */ MicroPC microPC() const { return 0; } /** * Force this PC to reflect a particular value, resetting all its other * fields around it. This is useful for in place (re)initialization. * * @param val The value to set the PC to. */ void set(Addr val); bool operator == (const PCStateBase &opc) const { return _pc == opc._pc && _npc == opc._npc; } void serialize(std::ostream &os) { SERIALIZE_SCALAR(_pc); SERIALIZE_SCALAR(_npc); } void unserialize(Checkpoint *cp, const std::string §ion) { UNSERIALIZE_SCALAR(_pc); UNSERIALIZE_SCALAR(_npc); } }; /* * Different flavors of PC state. Only ISA specific code should rely on * any particular type of PC state being available. All other code should * use the interface above. */ // The most basic type of PC. template class SimplePCState : public PCStateBase { protected: typedef PCStateBase Base; public: Addr pc() const { return _pc; } void pc(Addr val) { _pc = val; } Addr npc() const { return _npc; } void npc(Addr val) { _npc = val; } void set(Addr val) { pc(val); npc(val + sizeof(MachInst)); }; SimplePCState() {} SimplePCState(Addr val) { set(val); } bool branching() const { return this->npc() != this->pc() + sizeof(MachInst); } // Advance the PC. void advance() { _pc = _npc; _npc += sizeof(MachInst); } }; template std::ostream & operator<<(std::ostream & os, const SimplePCState &pc) { ccprintf(os, "(%#x=>%#x)", pc.pc(), pc.npc()); return os; } // A PC and microcode PC. template class UPCState : public SimplePCState { protected: typedef SimplePCState Base; MicroPC _upc; MicroPC _nupc; public: MicroPC upc() const { return _upc; } void upc(MicroPC val) { _upc = val; } MicroPC nupc() const { return _nupc; } void nupc(MicroPC val) { _nupc = val; } MicroPC microPC() const { return _upc; } void set(Addr val) { Base::set(val); upc(0); nupc(1); } UPCState() {} UPCState(Addr val) { set(val); } bool branching() const { return this->npc() != this->pc() + sizeof(MachInst) || this->nupc() != this->upc() + 1; } // Advance the upc within the instruction. void uAdvance() { _upc = _nupc; _nupc++; } // End the macroop by resetting the upc and advancing the regular pc. void uEnd() { this->advance(); _upc = 0; _nupc = 1; } bool operator == (const UPCState &opc) const { return Base::_pc == opc._pc && Base::_npc == opc._npc && _upc == opc._upc && _nupc == opc._nupc; } void serialize(std::ostream &os) { Base::serialize(os); SERIALIZE_SCALAR(_upc); SERIALIZE_SCALAR(_nupc); } void unserialize(Checkpoint *cp, const std::string §ion) { Base::unserialize(cp, section); UNSERIALIZE_SCALAR(_upc); UNSERIALIZE_SCALAR(_nupc); } }; template std::ostream & operator<<(std::ostream & os, const UPCState &pc) { ccprintf(os, "(%#x=>%#x).(%d=>%d)", pc.pc(), pc.npc(), pc.upc(), pc.npc()); return os; } // A PC with a delay slot. template class DelaySlotPCState : public SimplePCState { protected: typedef SimplePCState Base; Addr _nnpc; public: Addr nnpc() const { return _nnpc; } void nnpc(Addr val) { _nnpc = val; } void set(Addr val) { Base::set(val); nnpc(val + 2 * sizeof(MachInst)); } DelaySlotPCState() {} DelaySlotPCState(Addr val) { set(val); } bool branching() const { return !(this->nnpc() == this->npc() + sizeof(MachInst) && (this->npc() == this->pc() + sizeof(MachInst) || this->npc() == this->pc() + 2 * sizeof(MachInst))); } // Advance the PC. void advance() { Base::_pc = Base::_npc; Base::_npc = _nnpc; _nnpc += sizeof(MachInst); } bool operator == (const DelaySlotPCState &opc) const { return Base::_pc == opc._pc && Base::_npc == opc._npc && _nnpc == opc._nnpc; } void serialize(std::ostream &os) { Base::serialize(os); SERIALIZE_SCALAR(_nnpc); } void unserialize(Checkpoint *cp, const std::string §ion) { Base::unserialize(cp, section); UNSERIALIZE_SCALAR(_nnpc); } }; template std::ostream & operator<<(std::ostream & os, const DelaySlotPCState &pc) { ccprintf(os, "(%#x=>%#x=>%#x)", pc.pc(), pc.npc(), pc.nnpc()); return os; } // A PC with a delay slot and a microcode PC. template class DelaySlotUPCState : public DelaySlotPCState { protected: typedef DelaySlotPCState Base; MicroPC _upc; MicroPC _nupc; public: MicroPC upc() const { return _upc; } void upc(MicroPC val) { _upc = val; } MicroPC nupc() const { return _nupc; } void nupc(MicroPC val) { _nupc = val; } MicroPC microPC() const { return _upc; } void set(Addr val) { Base::set(val); upc(0); nupc(1); } DelaySlotUPCState() {} DelaySlotUPCState(Addr val) { set(val); } bool branching() const { return Base::branching() || this->nupc() != this->upc() + 1; } // Advance the upc within the instruction. void uAdvance() { _upc = _nupc; _nupc++; } // End the macroop by resetting the upc and advancing the regular pc. void uEnd() { this->advance(); _upc = 0; _nupc = 1; } bool operator == (const DelaySlotUPCState &opc) const { return Base::_pc == opc._pc && Base::_npc == opc._npc && Base::_nnpc == opc._nnpc && _upc == opc._upc && _nupc == opc._nupc; } void serialize(std::ostream &os) { Base::serialize(os); SERIALIZE_SCALAR(_upc); SERIALIZE_SCALAR(_nupc); } void unserialize(Checkpoint *cp, const std::string §ion) { Base::unserialize(cp, section); UNSERIALIZE_SCALAR(_upc); UNSERIALIZE_SCALAR(_nupc); } }; template std::ostream & operator<<(std::ostream & os, const DelaySlotUPCState &pc) { ccprintf(os, "(%#x=>%#x=>%#x).(%d=>%d)", pc.pc(), pc.npc(), pc.nnpc(), pc.upc(), pc.nupc()); return os; } } #endif