cpu: Add support for instructions that zero cache lines.
This commit is contained in:
parent
6bed6e0352
commit
90b1775a8f
|
@ -90,6 +90,7 @@ BaseDynInst<Impl>::initVars()
|
||||||
effAddr = 0;
|
effAddr = 0;
|
||||||
physEffAddr = 0;
|
physEffAddr = 0;
|
||||||
readyRegs = 0;
|
readyRegs = 0;
|
||||||
|
memReqFlags = 0;
|
||||||
|
|
||||||
status.reset();
|
status.reset();
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012 ARM Limited
|
* Copyright (c) 2012-2013 ARM Limited
|
||||||
* All rights reserved
|
* All rights reserved
|
||||||
*
|
*
|
||||||
* The license below extends only to copyright in the software and shall
|
* The license below extends only to copyright in the software and shall
|
||||||
|
@ -361,7 +361,7 @@ class LSQUnit {
|
||||||
/** Constructs a store queue entry for a given instruction. */
|
/** Constructs a store queue entry for a given instruction. */
|
||||||
SQEntry(DynInstPtr &_inst)
|
SQEntry(DynInstPtr &_inst)
|
||||||
: inst(_inst), req(NULL), sreqLow(NULL), sreqHigh(NULL), size(0),
|
: inst(_inst), req(NULL), sreqLow(NULL), sreqHigh(NULL), size(0),
|
||||||
isSplit(0), canWB(0), committed(0), completed(0)
|
isSplit(0), canWB(0), committed(0), completed(0), isAllZeros(0)
|
||||||
{
|
{
|
||||||
std::memset(data, 0, sizeof(data));
|
std::memset(data, 0, sizeof(data));
|
||||||
}
|
}
|
||||||
|
@ -384,6 +384,11 @@ class LSQUnit {
|
||||||
bool committed;
|
bool committed;
|
||||||
/** Whether or not the store is completed. */
|
/** Whether or not the store is completed. */
|
||||||
bool completed;
|
bool completed;
|
||||||
|
/** Does this request write all zeros and thus doesn't
|
||||||
|
* have any data attached to it. Used for cache block zero
|
||||||
|
* style instructs (ARM DC ZVA; ALPHA WH64)
|
||||||
|
*/
|
||||||
|
bool isAllZeros;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -691,13 +696,18 @@ LSQUnit<Impl>::read(Request *req, Request *sreqLow, Request *sreqHigh,
|
||||||
// Get shift amount for offset into the store's data.
|
// Get shift amount for offset into the store's data.
|
||||||
int shift_amt = req->getVaddr() - storeQueue[store_idx].inst->effAddr;
|
int shift_amt = req->getVaddr() - storeQueue[store_idx].inst->effAddr;
|
||||||
|
|
||||||
memcpy(data, storeQueue[store_idx].data + shift_amt,
|
if (storeQueue[store_idx].isAllZeros)
|
||||||
|
memset(data, 0, req->getSize());
|
||||||
|
else
|
||||||
|
memcpy(data, storeQueue[store_idx].data + shift_amt,
|
||||||
req->getSize());
|
req->getSize());
|
||||||
|
|
||||||
assert(!load_inst->memData);
|
assert(!load_inst->memData);
|
||||||
load_inst->memData = new uint8_t[64];
|
load_inst->memData = new uint8_t[req->getSize()];
|
||||||
|
if (storeQueue[store_idx].isAllZeros)
|
||||||
memcpy(load_inst->memData,
|
memset(load_inst->memData, 0, req->getSize());
|
||||||
|
else
|
||||||
|
memcpy(load_inst->memData,
|
||||||
storeQueue[store_idx].data + shift_amt, req->getSize());
|
storeQueue[store_idx].data + shift_amt, req->getSize());
|
||||||
|
|
||||||
DPRINTF(LSQUnit, "Forwarding from store idx %i to load to "
|
DPRINTF(LSQUnit, "Forwarding from store idx %i to load to "
|
||||||
|
@ -777,7 +787,7 @@ LSQUnit<Impl>::read(Request *req, Request *sreqLow, Request *sreqHigh,
|
||||||
load_inst->seqNum, load_inst->pcState());
|
load_inst->seqNum, load_inst->pcState());
|
||||||
|
|
||||||
assert(!load_inst->memData);
|
assert(!load_inst->memData);
|
||||||
load_inst->memData = new uint8_t[64];
|
load_inst->memData = new uint8_t[req->getSize()];
|
||||||
|
|
||||||
++usedPorts;
|
++usedPorts;
|
||||||
|
|
||||||
|
@ -916,7 +926,9 @@ LSQUnit<Impl>::write(Request *req, Request *sreqLow, Request *sreqHigh,
|
||||||
storeQueue[store_idx].sreqHigh = sreqHigh;
|
storeQueue[store_idx].sreqHigh = sreqHigh;
|
||||||
unsigned size = req->getSize();
|
unsigned size = req->getSize();
|
||||||
storeQueue[store_idx].size = size;
|
storeQueue[store_idx].size = size;
|
||||||
assert(size <= sizeof(storeQueue[store_idx].data));
|
storeQueue[store_idx].isAllZeros = req->getFlags() & Request::CACHE_BLOCK_ZERO;
|
||||||
|
assert(size <= sizeof(storeQueue[store_idx].data) ||
|
||||||
|
(req->getFlags() & Request::CACHE_BLOCK_ZERO));
|
||||||
|
|
||||||
// Split stores can only occur in ISAs with unaligned memory accesses. If
|
// Split stores can only occur in ISAs with unaligned memory accesses. If
|
||||||
// a store request has been split, sreqLow and sreqHigh will be non-null.
|
// a store request has been split, sreqLow and sreqHigh will be non-null.
|
||||||
|
@ -924,7 +936,8 @@ LSQUnit<Impl>::write(Request *req, Request *sreqLow, Request *sreqHigh,
|
||||||
storeQueue[store_idx].isSplit = true;
|
storeQueue[store_idx].isSplit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(storeQueue[store_idx].data, data, size);
|
if (!(req->getFlags() & Request::CACHE_BLOCK_ZERO))
|
||||||
|
memcpy(storeQueue[store_idx].data, data, size);
|
||||||
|
|
||||||
// This function only writes the data to the store queue, so no fault
|
// This function only writes the data to the store queue, so no fault
|
||||||
// can happen here.
|
// can happen here.
|
||||||
|
|
|
@ -816,9 +816,12 @@ LSQUnit<Impl>::writebackStores()
|
||||||
storeQueue[storeWBIdx].committed = true;
|
storeQueue[storeWBIdx].committed = true;
|
||||||
|
|
||||||
assert(!inst->memData);
|
assert(!inst->memData);
|
||||||
inst->memData = new uint8_t[64];
|
inst->memData = new uint8_t[req->getSize()];
|
||||||
|
|
||||||
memcpy(inst->memData, storeQueue[storeWBIdx].data, req->getSize());
|
if (storeQueue[storeWBIdx].isAllZeros)
|
||||||
|
memset(inst->memData, 0, req->getSize());
|
||||||
|
else
|
||||||
|
memcpy(inst->memData, storeQueue[storeWBIdx].data, req->getSize());
|
||||||
|
|
||||||
MemCmd command =
|
MemCmd command =
|
||||||
req->isSwap() ? MemCmd::SwapReq :
|
req->isSwap() ? MemCmd::SwapReq :
|
||||||
|
|
|
@ -399,6 +399,16 @@ Fault
|
||||||
AtomicSimpleCPU::writeMem(uint8_t *data, unsigned size,
|
AtomicSimpleCPU::writeMem(uint8_t *data, unsigned size,
|
||||||
Addr addr, unsigned flags, uint64_t *res)
|
Addr addr, unsigned flags, uint64_t *res)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
static uint8_t zero_array[64] = {};
|
||||||
|
|
||||||
|
if (data == NULL) {
|
||||||
|
assert(size <= 64);
|
||||||
|
assert(flags & Request::CACHE_BLOCK_ZERO);
|
||||||
|
// This must be a cache block cleaning request
|
||||||
|
data = zero_array;
|
||||||
|
}
|
||||||
|
|
||||||
// use the CPU's statically allocated write request and packet objects
|
// use the CPU's statically allocated write request and packet objects
|
||||||
Request *req = &data_write_req;
|
Request *req = &data_write_req;
|
||||||
|
|
||||||
|
|
|
@ -472,14 +472,20 @@ TimingSimpleCPU::writeMem(uint8_t *data, unsigned size,
|
||||||
Addr addr, unsigned flags, uint64_t *res)
|
Addr addr, unsigned flags, uint64_t *res)
|
||||||
{
|
{
|
||||||
uint8_t *newData = new uint8_t[size];
|
uint8_t *newData = new uint8_t[size];
|
||||||
memcpy(newData, data, size);
|
|
||||||
|
|
||||||
const int asid = 0;
|
const int asid = 0;
|
||||||
const ThreadID tid = 0;
|
const ThreadID tid = 0;
|
||||||
const Addr pc = thread->instAddr();
|
const Addr pc = thread->instAddr();
|
||||||
unsigned block_size = cacheLineSize();
|
unsigned block_size = cacheLineSize();
|
||||||
BaseTLB::Mode mode = BaseTLB::Write;
|
BaseTLB::Mode mode = BaseTLB::Write;
|
||||||
|
|
||||||
|
if (data == NULL) {
|
||||||
|
assert(flags & Request::CACHE_BLOCK_ZERO);
|
||||||
|
// This must be a cache block cleaning request
|
||||||
|
memset(newData, 0, size);
|
||||||
|
} else {
|
||||||
|
memcpy(newData, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
if (traceData) {
|
if (traceData) {
|
||||||
traceData->setAddr(addr);
|
traceData->setAddr(addr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,11 @@ class Request
|
||||||
/** This request is made in privileged mode. */
|
/** This request is made in privileged mode. */
|
||||||
static const FlagsType PRIVILEGED = 0x00008000;
|
static const FlagsType PRIVILEGED = 0x00008000;
|
||||||
|
|
||||||
|
/** This is a write that is targeted and zeroing an entire cache block.
|
||||||
|
* There is no need for a read/modify/write
|
||||||
|
*/
|
||||||
|
static const FlagsType CACHE_BLOCK_ZERO = 0x00010000;
|
||||||
|
|
||||||
/** The request should not cause a memory access. */
|
/** The request should not cause a memory access. */
|
||||||
static const FlagsType NO_ACCESS = 0x00080000;
|
static const FlagsType NO_ACCESS = 0x00080000;
|
||||||
/** This request will lock or unlock the accessed memory. When used with
|
/** This request will lock or unlock the accessed memory. When used with
|
||||||
|
|
Loading…
Reference in a new issue