summaryrefslogtreecommitdiff
path: root/src/mem
diff options
context:
space:
mode:
authorGiacomo Gabrielli <giacomo.gabrielli@arm.com>2017-07-07 14:13:11 +0100
committerGiacomo Gabrielli <giacomo.gabrielli@arm.com>2019-05-11 12:48:58 +0000
commitc58cb8c9dbeef377da180f1fdaaa1c0eadf85550 (patch)
tree7591abeb888d8c8e645332749bcaea627628f9bf /src/mem
parentd0e4cdc9c36466a3dbef8c9f9f509cce8f1a6c34 (diff)
downloadgem5-c58cb8c9dbeef377da180f1fdaaa1c0eadf85550.tar.xz
cpu,mem: Add support for partial loads/stores and wide mem. accesses
This changeset adds support for partial (or masked) loads/stores, i.e. loads/stores that can disable accesses to individual bytes within the target address range. In addition, this changeset extends the code to crack memory accesses across most CPU models (TimingSimpleCPU still TBD), so that arbitrarily wide memory accesses are supported. These changes are required for supporting ISAs with wide vectors. Additional authors: - Gabor Dozsa <gabor.dozsa@arm.com> - Tiago Muck <tiago.muck@arm.com> Change-Id: Ibad33541c258ad72925c0b1d5abc3e5e8bf92d92 Signed-off-by: Giacomo Gabrielli <giacomo.gabrielli@arm.com> Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/13518 Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: Nikos Nikoleris <nikos.nikoleris@arm.com> Maintainer: Nikos Nikoleris <nikos.nikoleris@arm.com>
Diffstat (limited to 'src/mem')
-rw-r--r--src/mem/abstract_mem.cc2
-rw-r--r--src/mem/cache/cache.cc3
-rw-r--r--src/mem/packet.hh35
-rw-r--r--src/mem/request.hh27
4 files changed, 63 insertions, 4 deletions
diff --git a/src/mem/abstract_mem.cc b/src/mem/abstract_mem.cc
index f7b02ce17..a998530fd 100644
--- a/src/mem/abstract_mem.cc
+++ b/src/mem/abstract_mem.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2012,2017 ARM Limited
+ * Copyright (c) 2010-2012,2017-2018 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
diff --git a/src/mem/cache/cache.cc b/src/mem/cache/cache.cc
index 494a998a5..b72ff4261 100644
--- a/src/mem/cache/cache.cc
+++ b/src/mem/cache/cache.cc
@@ -297,7 +297,8 @@ Cache::promoteWholeLineWrites(PacketPtr pkt)
{
// Cache line clearing instructions
if (doFastWrites && (pkt->cmd == MemCmd::WriteReq) &&
- (pkt->getSize() == blkSize) && (pkt->getOffset(blkSize) == 0)) {
+ (pkt->getSize() == blkSize) && (pkt->getOffset(blkSize) == 0) &&
+ !pkt->isMaskedWrite()) {
pkt->cmd = MemCmd::WriteLineReq;
DPRINTF(Cache, "packet promoted from Write to WriteLineReq\n");
}
diff --git a/src/mem/packet.hh b/src/mem/packet.hh
index 93b3ad5de..130cc41ad 100644
--- a/src/mem/packet.hh
+++ b/src/mem/packet.hh
@@ -1092,6 +1092,7 @@ class Packet : public Printable
getPtr()
{
assert(flags.isSet(STATIC_DATA|DYNAMIC_DATA));
+ assert(!isMaskedWrite());
return (T*)data;
}
@@ -1180,10 +1181,11 @@ class Packet : public Printable
// same pointer from source to destination and back
assert(p != getPtr<uint8_t>() || flags.isSet(STATIC_DATA));
- if (p != getPtr<uint8_t>())
+ if (p != getPtr<uint8_t>()) {
// for packet with allocated dynamic data, we copy data from
// one to the other, e.g. a forwarded response to a response
std::memcpy(getPtr<uint8_t>(), p, getSize());
+ }
}
/**
@@ -1203,7 +1205,19 @@ class Packet : public Printable
void
writeData(uint8_t *p) const
{
- std::memcpy(p, getConstPtr<uint8_t>(), getSize());
+ if (!isMaskedWrite()) {
+ std::memcpy(p, getConstPtr<uint8_t>(), getSize());
+ } else {
+ assert(req->getByteEnable().size() == getSize());
+ // Write only the enabled bytes
+ const uint8_t *base = getConstPtr<uint8_t>();
+ for (int i = 0; i < getSize(); i++) {
+ if (req->getByteEnable()[i]) {
+ p[i] = *(base + i);
+ }
+ // Disabled bytes stay untouched
+ }
+ }
}
/**
@@ -1268,6 +1282,17 @@ class Packet : public Printable
bool
trySatisfyFunctional(PacketPtr other)
{
+ if (other->isMaskedWrite()) {
+ // Do not forward data if overlapping with a masked write
+ if (_isSecure == other->isSecure() &&
+ getAddr() <= (other->getAddr() + other->getSize() - 1) &&
+ other->getAddr() <= (getAddr() + getSize() - 1)) {
+ warn("Trying to check against a masked write, skipping."
+ " (addr: 0x%x, other addr: 0x%x)", getAddr(),
+ other->getAddr());
+ }
+ return false;
+ }
// all packets that are carrying a payload should have a valid
// data pointer
return trySatisfyFunctional(other, other->getAddr(), other->isSecure(),
@@ -1296,6 +1321,12 @@ class Packet : public Printable
return cmd == MemCmd::CleanEvict || cmd == MemCmd::WritebackClean;
}
+ bool
+ isMaskedWrite() const
+ {
+ return (cmd == MemCmd::WriteReq && !req->getByteEnable().empty());
+ }
+
/**
* Check a functional request against a memory value represented
* by a base/size pair and an associated data array. If the
diff --git a/src/mem/request.hh b/src/mem/request.hh
index 2a53c21a4..324ae382e 100644
--- a/src/mem/request.hh
+++ b/src/mem/request.hh
@@ -320,6 +320,9 @@ class Request
*/
unsigned _size;
+ /** Byte-enable mask for writes. */
+ std::vector<bool> _byteEnable;
+
/** The requestor ID which is unique in the system for all ports
* that are capable of issuing a transaction
*/
@@ -567,6 +570,9 @@ class Request
* Generate two requests as if this request had been split into two
* pieces. The original request can't have been translated already.
*/
+ // TODO: this function is still required by TimingSimpleCPU - should be
+ // removed once TimingSimpleCPU will support arbitrarily long multi-line
+ // mem. accesses
void splitOnVaddr(Addr split_addr, RequestPtr &req1, RequestPtr &req2)
{
assert(privateFlags.isSet(VALID_VADDR));
@@ -577,6 +583,14 @@ class Request
req1->_size = split_addr - _vaddr;
req2->_vaddr = split_addr;
req2->_size = _size - req1->_size;
+ if (!_byteEnable.empty()) {
+ req1->_byteEnable = std::vector<bool>(
+ _byteEnable.begin(),
+ _byteEnable.begin() + req1->_size);
+ req2->_byteEnable = std::vector<bool>(
+ _byteEnable.begin() + req1->_size,
+ _byteEnable.end());
+ }
}
/**
@@ -628,6 +642,19 @@ class Request
return _size;
}
+ const std::vector<bool>&
+ getByteEnable() const
+ {
+ return _byteEnable;
+ }
+
+ void
+ setByteEnable(const std::vector<bool>& be)
+ {
+ assert(be.empty() || be.size() == _size);
+ _byteEnable = be;
+ }
+
/** Accessor for time. */
Tick
time() const