/* * Copyright (c) 2010, 2012-2013, 2017-2018 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) 2007-2008 The Florida State University * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer; * redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution; * neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __ARCH_ARM_PCSTATE_HH__ #define __ARCH_ARM_PCSTATE_HH__ #include "arch/generic/pcstate.hh" #include "base/bitunion.hh" #include "base/types.hh" #include "debug/Decoder.hh" namespace gem5 { namespace ArmISA { BitUnion8(ITSTATE) /* Note that the split (cond, mask) below is not as in ARM ARM. * But it is more convenient for simulation. The condition * is always the concatenation of the top 3 bits and the next bit, * which applies when one of the bottom 4 bits is set. * Refer to predecoder.cc for the use case. */ Bitfield<7, 4> cond; Bitfield<3, 0> mask; // Bitfields for moving to/from CPSR Bitfield<7, 2> top6; Bitfield<1, 0> bottom2; EndBitUnion(ITSTATE) class PCState : public GenericISA::UPCState<4> { protected: typedef GenericISA::UPCState<4> Base; enum FlagBits { ThumbBit = (1 << 0), JazelleBit = (1 << 1), AArch64Bit = (1 << 2) }; uint8_t flags = 0; uint8_t nextFlags = 0; uint8_t _itstate = 0; uint8_t _nextItstate = 0; uint8_t _size = 0; bool _illegalExec = false; // Software Step flags bool _debugStep = false; bool _stepped = false; public: void set(Addr val) { Base::set(val); npc(val + (thumb() ? 2 : 4)); } PCState(const PCState &other) : Base(other), flags(other.flags), nextFlags(other.nextFlags), _itstate(other._itstate), _nextItstate(other._nextItstate), _size(other._size), _illegalExec(other._illegalExec), _debugStep(other._debugStep), _stepped(other._stepped) {} PCState &operator=(const PCState &other) = default; PCState() {} explicit PCState(Addr val) { set(val); } PCStateBase *clone() const override { return new PCState(*this); } void update(const PCStateBase &other) override { Base::update(other); auto &pcstate = other.as(); flags = pcstate.flags; nextFlags = pcstate.nextFlags; _itstate = pcstate._itstate; _nextItstate = pcstate._nextItstate; _size = pcstate._size; _illegalExec = pcstate._illegalExec; _debugStep = pcstate._debugStep; _stepped = pcstate._stepped; } bool illegalExec() const { return _illegalExec; } void illegalExec(bool val) { _illegalExec = val; } bool debugStep() const { return _debugStep; } void debugStep(bool val) { _debugStep = val; } bool stepped() const { return _stepped; } void stepped(bool val) { _stepped = val; } bool thumb() const { return flags & ThumbBit; } void thumb(bool val) { if (val) flags |= ThumbBit; else flags &= ~ThumbBit; } bool nextThumb() const { return nextFlags & ThumbBit; } void nextThumb(bool val) { if (val) nextFlags |= ThumbBit; else nextFlags &= ~ThumbBit; } void size(uint8_t s) { _size = s; } uint8_t size() const { return _size; } bool branching() const override { return ((this->pc() + this->size()) != this->npc()); } bool jazelle() const { return flags & JazelleBit; } void jazelle(bool val) { if (val) flags |= JazelleBit; else flags &= ~JazelleBit; } bool nextJazelle() const { return nextFlags & JazelleBit; } void nextJazelle(bool val) { if (val) nextFlags |= JazelleBit; else nextFlags &= ~JazelleBit; } bool aarch64() const { return flags & AArch64Bit; } void aarch64(bool val) { if (val) flags |= AArch64Bit; else flags &= ~AArch64Bit; } bool nextAArch64() const { return nextFlags & AArch64Bit; } void nextAArch64(bool val) { if (val) nextFlags |= AArch64Bit; else nextFlags &= ~AArch64Bit; } uint8_t itstate() const { return _itstate; } void itstate(uint8_t value) { _itstate = value; } uint8_t nextItstate() const { return _nextItstate; } void nextItstate(uint8_t value) { _nextItstate = value; } void advance() override { Base::advance(); flags = nextFlags; npc(pc() + (thumb() ? 2 : 4)); if (_nextItstate) { _itstate = _nextItstate; _nextItstate = 0; } else if (_itstate) { ITSTATE it = _itstate; uint8_t cond_mask = it.mask; uint8_t thumb_cond = it.cond; DPRINTF(Decoder, "Advancing ITSTATE from %#x,%#x.\n", thumb_cond, cond_mask); cond_mask <<= 1; uint8_t new_bit = bits(cond_mask, 4); cond_mask &= mask(4); if (cond_mask == 0) thumb_cond = 0; else replaceBits(thumb_cond, 0, new_bit); DPRINTF(Decoder, "Advancing ITSTATE to %#x,%#x.\n", thumb_cond, cond_mask); it.mask = cond_mask; it.cond = thumb_cond; _itstate = it; } } void uEnd() { advance(); upc(0); nupc(1); } Addr instPC() const { return pc() + (thumb() ? 4 : 8); } void instNPC(Addr val) { // @todo: review this when AArch32/64 interprocessing is // supported if (aarch64()) npc(val); // AArch64 doesn't force PC alignment, a PC // Alignment Fault can be raised instead else npc(val &~ mask(nextThumb() ? 1 : 2)); } Addr instNPC() const { return npc(); } // Perform an interworking branch. void instIWNPC(Addr val) { bool thumbEE = (thumb() && jazelle()); Addr newPC = val; if (thumbEE) { if (bits(newPC, 0)) { newPC = newPC & ~mask(1); } // else we have a bad interworking address; do not call // panic() since the instruction could be executed // speculatively } else { if (bits(newPC, 0)) { nextThumb(true); newPC = newPC & ~mask(1); } else if (!bits(newPC, 1)) { nextThumb(false); } else { // This state is UNPREDICTABLE in the ARM architecture // The easy thing to do is just mask off the bit and // stay in the current mode, so we'll do that. newPC &= ~mask(2); } } npc(newPC); } // Perform an interworking branch in ARM mode, a regular branch // otherwise. void instAIWNPC(Addr val) { if (!thumb() && !jazelle()) instIWNPC(val); else instNPC(val); } bool equals(const PCStateBase &other) const override { auto &opc = other.as(); return Base::equals(other) && flags == opc.flags && nextFlags == opc.nextFlags && _itstate == opc._itstate && _nextItstate == opc._nextItstate && _illegalExec == opc._illegalExec && _debugStep == opc._debugStep && _stepped == opc._stepped; } void serialize(CheckpointOut &cp) const override { Base::serialize(cp); SERIALIZE_SCALAR(flags); SERIALIZE_SCALAR(_size); SERIALIZE_SCALAR(nextFlags); SERIALIZE_SCALAR(_itstate); SERIALIZE_SCALAR(_nextItstate); SERIALIZE_SCALAR(_illegalExec); SERIALIZE_SCALAR(_debugStep); SERIALIZE_SCALAR(_stepped); } void unserialize(CheckpointIn &cp) override { Base::unserialize(cp); UNSERIALIZE_SCALAR(flags); UNSERIALIZE_SCALAR(_size); UNSERIALIZE_SCALAR(nextFlags); UNSERIALIZE_SCALAR(_itstate); UNSERIALIZE_SCALAR(_nextItstate); UNSERIALIZE_SCALAR(_illegalExec); UNSERIALIZE_SCALAR(_debugStep); UNSERIALIZE_SCALAR(_stepped); } }; } // namespace ArmISA } // namespace gem5 #endif