From 396600de107220db8c2c8f3951eeb7062ac0e81c Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Tue, 25 Sep 2012 11:49:40 -0500 Subject: [PATCH] mem: Add a gasket that allows memory ranges to be re-mapped. For example if DRAM is at two locations and mirrored this patch allows the mirroring to occur. --- src/mem/AddrMapper.py | 70 ++++++++++ src/mem/SConscript | 2 + src/mem/addr_mapper.cc | 295 +++++++++++++++++++++++++++++++++++++++++ src/mem/addr_mapper.hh | 294 ++++++++++++++++++++++++++++++++++++++++ src/mem/packet.hh | 9 ++ 5 files changed, 670 insertions(+) create mode 100644 src/mem/AddrMapper.py create mode 100644 src/mem/addr_mapper.cc create mode 100644 src/mem/addr_mapper.hh diff --git a/src/mem/AddrMapper.py b/src/mem/AddrMapper.py new file mode 100644 index 000000000..2b999ee92 --- /dev/null +++ b/src/mem/AddrMapper.py @@ -0,0 +1,70 @@ +# Copyright (c) 2012 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: Andreas Hansson + +from m5.params import * +from MemObject import MemObject + +# An address mapper changes the packet addresses in going from the +# slave port side of the mapper to the master port side. When the +# slave port is queried for the address ranges, it also performs the +# necessary range updates. Note that snoop requests that travel from +# the master port (i.e. the memory side) to the slave port are +# currently not modified. +class AddrMapper(MemObject): + type = 'AddrMapper' + abstract = True + + # one port in each direction + master = MasterPort("Master port") + slave = SlavePort("Slave port") + + +# Range address mapper that maps a set of original ranges to a set of +# remapped ranges, where a specific range is of the same size +# (original and remapped), only with an offset. +class RangeAddrMapper(AddrMapper): + type = 'RangeAddrMapper' + + # These two vectors should be the exact same length and each range + # should be the exact same size. Each range in original_ranges is + # mapped to the corresponding element in the remapped_ranges. Note + # that the same range can occur multiple times in the remapped + # ranges for address aliasing. + original_ranges = VectorParam.AddrRange( + "Ranges of memory that should me remapped") + remapped_ranges = VectorParam.AddrRange( + "Ranges of memory that are being mapped to") diff --git a/src/mem/SConscript b/src/mem/SConscript index 1c43975df..9cf8b08d1 100644 --- a/src/mem/SConscript +++ b/src/mem/SConscript @@ -30,11 +30,13 @@ Import('*') +SimObject('AddrMapper.py') SimObject('Bridge.py') SimObject('Bus.py') SimObject('CommMonitor.py') SimObject('MemObject.py') +Source('addr_mapper.cc') Source('bridge.cc') Source('bus.cc') Source('coherent_bus.cc') diff --git a/src/mem/addr_mapper.cc b/src/mem/addr_mapper.cc new file mode 100644 index 000000000..53e8277cc --- /dev/null +++ b/src/mem/addr_mapper.cc @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2012 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: Andreas Hansson + */ + +#include "mem/addr_mapper.hh" + +AddrMapper::AddrMapper(const AddrMapperParams* p) + : MemObject(p), + masterPort(name() + "-master", *this), + slavePort(name() + "-slave", *this) +{ +} + +void +AddrMapper::init() +{ + if (!slavePort.isConnected() || !masterPort.isConnected()) + fatal("Address mapper is not connected on both sides.\n"); + + if ((slavePort.peerBlockSize() != masterPort.peerBlockSize()) && + slavePort.peerBlockSize() && masterPort.peerBlockSize()) + fatal("Slave port size %d, master port size %d \n " + "don't have the same block size... Not supported.\n", + slavePort.peerBlockSize(), masterPort.peerBlockSize()); +} + +MasterPort& +AddrMapper::getMasterPort(const std::string& if_name, int idx) +{ + if (if_name == "master") { + return masterPort; + } else { + return MemObject::getMasterPort(if_name, idx); + } +} + +SlavePort& +AddrMapper::getSlavePort(const std::string& if_name, int idx) +{ + if (if_name == "slave") { + return slavePort; + } else { + return MemObject::getSlavePort(if_name, idx); + } +} + +void +AddrMapper::recvFunctional(PacketPtr pkt) +{ + Addr orig_addr = pkt->getAddr(); + pkt->setAddr(remapAddr(orig_addr)); + masterPort.sendFunctional(pkt); + pkt->setAddr(orig_addr); +} + +void +AddrMapper::recvFunctionalSnoop(PacketPtr pkt) +{ + Addr orig_addr = pkt->getAddr(); + pkt->setAddr(remapAddr(orig_addr)); + slavePort.sendFunctionalSnoop(pkt); + pkt->setAddr(orig_addr); +} + +Tick +AddrMapper::recvAtomic(PacketPtr pkt) +{ + Addr orig_addr = pkt->getAddr(); + pkt->setAddr(remapAddr(orig_addr)); + Tick ret_tick = masterPort.sendAtomic(pkt); + pkt->setAddr(orig_addr); + return ret_tick; +} + +Tick +AddrMapper::recvAtomicSnoop(PacketPtr pkt) +{ + Addr orig_addr = pkt->getAddr(); + pkt->setAddr(remapAddr(orig_addr)); + Tick ret_tick = slavePort.sendAtomicSnoop(pkt); + pkt->setAddr(orig_addr); + return ret_tick; +} + +bool +AddrMapper::recvTimingReq(PacketPtr pkt) +{ + Addr orig_addr = pkt->getAddr(); + bool needsResponse = pkt->needsResponse(); + bool memInhibitAsserted = pkt->memInhibitAsserted(); + Packet::SenderState* senderState = pkt->senderState; + + if (needsResponse && !memInhibitAsserted) { + pkt->senderState = new AddrMapperSenderState(senderState, orig_addr); + } + + pkt->setAddr(remapAddr(orig_addr)); + + // Attempt to send the packet (always succeeds for inhibited + // packets) + bool successful = masterPort.sendTimingReq(pkt); + + // If not successful, restore the sender state + if (!successful && needsResponse) { + delete pkt->senderState; + pkt->senderState = senderState; + } + + return successful; +} + +bool +AddrMapper::recvTimingResp(PacketPtr pkt) +{ + AddrMapperSenderState* receivedState = + dynamic_cast(pkt->senderState); + + // Restore initial sender state + if (receivedState == NULL) + panic("AddrMapper %s got a response without sender state\n", + name()); + + Addr remapped_addr = pkt->getAddr(); + + // Restore the state and address + pkt->senderState = receivedState->origSenderState; + pkt->setAddr(receivedState->origAddr); + + // Attempt to send the packet + bool successful = slavePort.sendTimingResp(pkt); + + // If packet successfully sent, delete the sender state, otherwise + // restore state + if (successful) { + delete receivedState; + } else { + // Don't delete anything and let the packet look like we did + // not touch it + pkt->senderState = receivedState; + pkt->setAddr(remapped_addr); + } + return successful; +} + +void +AddrMapper::recvTimingSnoopReq(PacketPtr pkt) +{ + slavePort.sendTimingSnoopReq(pkt); +} + +bool +AddrMapper::recvTimingSnoopResp(PacketPtr pkt) +{ + return masterPort.sendTimingSnoopResp(pkt); +} + +bool +AddrMapper::isSnooping() const +{ + if (slavePort.getMasterPort().isSnooping()) + fatal("AddrMapper doesn't support remapping of snooping requests\n"); + return false; +} + +unsigned +AddrMapper::deviceBlockSizeMaster() +{ + return slavePort.peerBlockSize(); +} + +unsigned +AddrMapper::deviceBlockSizeSlave() +{ + return masterPort.peerBlockSize(); +} + +void +AddrMapper::recvRetryMaster() +{ + slavePort.sendRetry(); +} + +void +AddrMapper::recvRetrySlave() +{ + masterPort.sendRetry(); +} + +void +AddrMapper::recvRangeChange() +{ + slavePort.sendRangeChange(); +} + +RangeAddrMapper::RangeAddrMapper(const RangeAddrMapperParams* p) : + AddrMapper(p), + originalRanges(p->original_ranges), + remappedRanges(p->remapped_ranges) +{ + if (originalRanges.size() != remappedRanges.size()) + fatal("AddrMapper: original and shadowed range list must " + "be same size\n"); + + for (size_t x = 0; x < originalRanges.size(); x++) { + if (originalRanges[x].size() != remappedRanges[x].size()) + fatal("AddrMapper: original and shadowed range list elements" + " aren't all of the same size\n"); + } +} + +RangeAddrMapper* +RangeAddrMapperParams::create() +{ + return new RangeAddrMapper(this); +} + +Addr +RangeAddrMapper::remapAddr(Addr addr) const +{ + for (int i = 0; i < originalRanges.size(); ++i) { + if (originalRanges[i] == addr) { + Addr offset = addr - originalRanges[i].start; + return offset + remappedRanges[i].start; + } + } + + return addr; +} + +AddrRangeList +RangeAddrMapper::getAddrRanges() const +{ + AddrRangeList ranges; + AddrRangeList actualRanges = masterPort.getSlavePort().getAddrRanges(); + + for (AddrRangeIter r = actualRanges.begin(); r != actualRanges.end(); ++r) { + AddrRange range = *r; + + for (int j = 0; j < originalRanges.size(); ++j) { + if ((range.start < originalRanges[j].start && + range.end >= originalRanges[j].start) || + (range.start < originalRanges[j].end && + range.end >= originalRanges[j].end)) + fatal("Cannot remap range that intersects the original" + " ranges but are not a subset.\n"); + if (range.start >= originalRanges[j].start && + range.end <= originalRanges[j].end) { + // range is a subset + Addr offset = range.start - originalRanges[j].start; + range.start -= offset; + range.end -= offset; + } + ranges.push_back(range); + } + } + + return ranges; +} + + diff --git a/src/mem/addr_mapper.hh b/src/mem/addr_mapper.hh new file mode 100644 index 000000000..f469b26ba --- /dev/null +++ b/src/mem/addr_mapper.hh @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2012 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: Andreas Hansson + */ + +#ifndef __MEM_ADDR_MAPPER_HH__ +#define __MEM_ADDR_MAPPER_HH__ + +#include "mem/mem_object.hh" +#include "params/AddrMapper.hh" +#include "params/RangeAddrMapper.hh" + +/** + * An address mapper changes the packet addresses in going from the + * slave port side of the mapper to the master port side. When the + * slave port is queried for the address ranges, it also performs the + * necessary range updates. Note that snoop requests that travel from + * the master port (i.e. the memory side) to the slave port are + * currently not modified. + */ + +class AddrMapper : public MemObject +{ + + public: + + AddrMapper(const AddrMapperParams* params); + + virtual ~AddrMapper() { } + + virtual MasterPort& getMasterPort(const std::string& if_name, + int idx = -1); + + virtual SlavePort& getSlavePort(const std::string& if_name, + int idx = -1); + + virtual void init(); + + protected: + + /** + * This function does the actual remapping of one address to another. + * It is pure virtual in this case to to allow any implementation + * required. + * @param addr the address to remap + * @return the new address (can be unchanged) + */ + virtual Addr remapAddr(Addr addr) const = 0; + + class AddrMapperSenderState : public Packet::SenderState + { + + public: + + /** + * Construct a new sender state and remember the original one + * so that we can implement a stack. + * + * @param _origSenderState Sender state to remember + * @param _origAddr Address before remapping + */ + AddrMapperSenderState(SenderState* _origSenderState, + Addr _origAddr) + : origSenderState(_origSenderState), origAddr(_origAddr) + { } + + /** Destructor */ + ~AddrMapperSenderState() { } + + /** Pointer to old sender state of packet */ + SenderState* origSenderState; + + /** The original address the packet was destined for */ + Addr origAddr; + + }; + + class MapperMasterPort : public MasterPort + { + + public: + + MapperMasterPort(const std::string& _name, AddrMapper& _mapper) + : MasterPort(_name, &_mapper), mapper(_mapper) + { } + + protected: + + void recvFunctionalSnoop(PacketPtr pkt) + { + mapper.recvFunctionalSnoop(pkt); + } + + Tick recvAtomicSnoop(PacketPtr pkt) + { + return mapper.recvAtomicSnoop(pkt); + } + + bool recvTimingResp(PacketPtr pkt) + { + return mapper.recvTimingResp(pkt); + } + + void recvTimingSnoopReq(PacketPtr pkt) + { + mapper.recvTimingSnoopReq(pkt); + } + + void recvRangeChange() + { + mapper.recvRangeChange(); + } + + bool isSnooping() const + { + return mapper.isSnooping(); + } + + unsigned deviceBlockSize() const + { + return mapper.deviceBlockSizeMaster(); + } + + void recvRetry() + { + mapper.recvRetryMaster(); + } + + private: + + AddrMapper& mapper; + + }; + + /** Instance of master port, facing the memory side */ + MapperMasterPort masterPort; + + class MapperSlavePort : public SlavePort + { + + public: + + MapperSlavePort(const std::string& _name, AddrMapper& _mapper) + : SlavePort(_name, &_mapper), mapper(_mapper) + { } + + protected: + + void recvFunctional(PacketPtr pkt) + { + mapper.recvFunctional(pkt); + } + + Tick recvAtomic(PacketPtr pkt) + { + return mapper.recvAtomic(pkt); + } + + bool recvTimingReq(PacketPtr pkt) + { + return mapper.recvTimingReq(pkt); + } + + bool recvTimingSnoopResp(PacketPtr pkt) + { + return mapper.recvTimingSnoopResp(pkt); + } + + unsigned deviceBlockSize() const + { + return mapper.deviceBlockSizeSlave(); + } + + AddrRangeList getAddrRanges() const + { + return mapper.getAddrRanges(); + } + + void recvRetry() + { + mapper.recvRetrySlave(); + } + + private: + + AddrMapper& mapper; + + }; + + /** Instance of slave port, i.e. on the CPU side */ + MapperSlavePort slavePort; + + void recvFunctional(PacketPtr pkt); + + void recvFunctionalSnoop(PacketPtr pkt); + + Tick recvAtomic(PacketPtr pkt); + + Tick recvAtomicSnoop(PacketPtr pkt); + + bool recvTimingReq(PacketPtr pkt); + + bool recvTimingResp(PacketPtr pkt); + + void recvTimingSnoopReq(PacketPtr pkt); + + bool recvTimingSnoopResp(PacketPtr pkt); + + unsigned deviceBlockSizeMaster(); + + unsigned deviceBlockSizeSlave(); + + virtual AddrRangeList getAddrRanges() const = 0; + + bool isSnooping() const; + + void recvRetryMaster(); + + void recvRetrySlave(); + + void recvRangeChange(); +}; + +/** + * Range address mapper that maps a set of original ranges to a set of + * remapped ranges, where a specific range is of the same size + * (original and remapped), only with an offset. It's useful for cases + * where memory is mapped to two different locations + */ +class RangeAddrMapper : public AddrMapper +{ + + public: + + RangeAddrMapper(const RangeAddrMapperParams* p); + + ~RangeAddrMapper() { } + + AddrRangeList getAddrRanges() const; + + protected: + + /** + * This contains a list of ranges the should be remapped. It must + * be the exact same length as remappedRanges which describes what + * manipulation should be done to each range. + */ + std::vector originalRanges; + + /** + * This contains a list of ranges that addresses should be + * remapped to. See the description for originalRanges above + */ + std::vector remappedRanges; + + Addr remapAddr(Addr addr) const; + +}; + +#endif //__MEM_ADDR_MAPPER_HH__ diff --git a/src/mem/packet.hh b/src/mem/packet.hh index 7396048d6..fbcf185cc 100644 --- a/src/mem/packet.hh +++ b/src/mem/packet.hh @@ -491,6 +491,15 @@ class Packet : public Printable void clearDest() { dest = InvalidPortID; } Addr getAddr() const { assert(flags.isSet(VALID_ADDR)); return addr; } + /** + * Update the address of this packet mid-transaction. This is used + * by the address mapper to change an already set address to a new + * one based on the system configuration. It is intended to remap + * an existing address, so it asserts that the current address is + * valid. + */ + void setAddr(Addr _addr) { assert(flags.isSet(VALID_ADDR)); addr = _addr; } + unsigned getSize() const { assert(flags.isSet(VALID_SIZE)); return size; } Addr getOffset(int blkSize) const { return getAddr() & (Addr)(blkSize - 1); }