48#include "debug/CFI.hh"
49#include "debug/Drain.hh"
66 locked[blockIdx(block_address)] =
true;
72 locked[blockIdx(block_address)] =
false;
90 return block_address / blockSize;
97 if (buffer_size > MAX_BUFFER_SIZE) {
98 buffer_size = MAX_BUFFER_SIZE;
101 buffer.resize(buffer_size);
102 std::fill(buffer.begin(), buffer.end(), 0);
108 void *data_ptr, ssize_t
size)
110 if (bytesWritten >= buffer.size())
113 if (bytesWritten == 0) {
114 blockPointer = flash_address;
117 const Addr offset = flash_address - blockPointer;
119 if (flash_address < blockPointer || offset >= MAX_BUFFER_SIZE)
122 std::memcpy(buffer.data() +
offset, data_ptr,
size);
123 bytesWritten +=
size;
131 if (parent.blocks.isLocked(blockPointer)) {
134 std::memcpy(parent.toHostAddr(parent.start() + blockPointer),
135 buffer.data(), bytesWritten);
162 dequeueEvent([
this]{ dequeue(); },
name()),
164 vendorID(
p.vendor_id),
165 deviceID(
p.device_id),
166 bankWidth(
p.bank_width),
167 readState(CfiCommand::READ_ARRAY), writeState(CfiCommand::NO_CMD),
168 statusRegister(STATUS_READY),
169 blocks(*
this, size() /
p.blk_size,
p.blk_size),
170 programBuffer(*
this),
172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
209 static_cast<uint8_t
>(log2(size())),
213 static_cast<uint8_t
>(
bits(
log2i(ProgramBuffer::MAX_BUFFER_SIZE), 7, 0)),
214 static_cast<uint8_t
>(
bits(
log2i(ProgramBuffer::MAX_BUFFER_SIZE), 15, 8)),
218 static_cast<uint8_t
>(
bits(blocks.number(), 7, 0)),
219 static_cast<uint8_t
>(
bits(blocks.number(), 15, 8)),
220 static_cast<uint8_t
>(
bits(blocks.size(), 7, 0)),
221 static_cast<uint8_t
>(
bits(blocks.size(), 15, 8)),
293 "Should only see read and writes at memory controller, "
337 if (needs_response) {
352 !
i->pkt->matchAddr(pkt)) {
399 DPRINTF(Drain,
"Draining of CfiMemory complete\n");
423 if (if_name !=
"port") {
434 DPRINTF(Drain,
"CfiMemory Queue has requests, waiting to drain\n");
474 ranges.push_back(
mem.getAddrRange());
481 return mem.recvAtomic(pkt);
488 return mem.recvAtomicBackdoor(pkt, _backdoor);
494 mem.recvFunctional(pkt);
501 mem.recvMemBackdoorReq(req, _backdoor);
507 return mem.recvTimingReq(pkt);
534 const uint16_t value = pkt->
getUintX(ByteOrder::little) & 0xffff;
535 const auto new_cmd =
static_cast<CfiCommand>(value & 0xff);
592 auto buffer_size = (value + 1) *
sizeof(uint32_t);
624 panic(
"Invalid Write State\n");
651 panic(
"Invalid Read State\n");
656 value |= (value << 16);
659 pkt->
setUintX(value, ByteOrder::little);
670 switch ((flash_address & 0xff) /
bankWidth) {
679 warn(
"Invalid Device Identifier code: %d\n", flash_address & 0xff);
689 DPRINTF(CFI,
"CFI Command: Read Array\n");
693 DPRINTF(CFI,
"CFI Command: Read Device Identifier\n");
697 DPRINTF(CFI,
"CFI Command: CFI Query\n");
701 DPRINTF(CFI,
"CFI Command: Read Status Register\n");
705 DPRINTF(CFI,
"CFI Command: Clear Status Register\n");
709 DPRINTF(CFI,
"CFI Command: Buffered Program Confirm\n");
712 DPRINTF(CFI,
"CFI Command: Erase Block Setup\n");
717 DPRINTF(CFI,
"CFI Command: Lock Block Setup\n");
721 DPRINTF(CFI,
"CFI Command: Word Program\n");
726 DPRINTF(CFI,
"CFI Command: Buffered Program Setup\n");
736 panic(
"Don't know what to do with %#x\n",
737 static_cast<uint16_t
>(new_cmd));
748 "Acessing invalid entry in CFI query table (addr=%#x)",
757 auto host_address = parent.toHostAddr(pkt->
getAddr());
758 std::memset(host_address, 0xff, blockSize);
virtual std::string name() const
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
void pushLabel(const std::string &lbl)
Push label for PrintReq (safe to call unconditionally).
void setUintX(uint64_t w, ByteOrder endian)
Set the value in the word w after truncating it to the length of the packet and then byteswapping it ...
const std::string & cmdString() const
Return the string name of the cmd field (for debugging and tracing).
bool needsResponse() const
uint32_t payloadDelay
The extra pipelining delay from seeing the packet until the end of payload is transmitted by the comp...
void makeResponse()
Take a request packet and modify it in place to be suitable for returning as a response to that reque...
uint32_t headerDelay
The extra delay from seeing the packet until the header is transmitted.
T * getPtr()
get a pointer to the data ptr.
bool trySatisfyFunctional(PacketPtr other)
Check a functional request against a memory value stored in another packet (i.e.
uint64_t getUintX(ByteOrder endian) const
Get the data in the packet byte swapped from the specified endianness and zero-extended to 64 bits.
void popLabel()
Pop label for PrintReq (safe to call unconditionally).
bool cacheResponding() const
Ports are used to interface objects to each other.
bool isConnected() const
Is this port currently connected to a peer?
A ResponsePort is a specialization of a port.
bool sendTimingResp(PacketPtr pkt)
Attempt to send a timing response to the request port by calling its corresponding receive function.
void sendRangeChange() const
Called by the owner to send a range change.
void sendRetryReq()
Send a retry to the request port that previously attempted a sendTimingReq to this response port and ...
An abstract memory represents a contiguous block of physical memory, with an associated address range...
void access(PacketPtr pkt)
Perform an untimed memory access and update all the state (e.g.
uint64_t size() const
Get the memory size.
void functionalAccess(PacketPtr pkt)
Perform an untimed memory read or write without changing anything but the memory itself.
Addr start() const
Get the start address.
A deferred packet stores a packet along with its scheduled transmission time.
MemoryPort(const std::string &_name, CfiMemory &_memory)
AddrRangeList getAddrRanges() const override
Get a list of the non-overlapping address ranges the owner is responsible for.
Tick recvAtomicBackdoor(PacketPtr pkt, MemBackdoorPtr &_backdoor) override
Receive an atomic request packet from the peer, and optionally provide a backdoor to the data being a...
void recvFunctional(PacketPtr pkt) override
Receive a functional request packet from the peer.
bool recvTimingReq(PacketPtr pkt) override
Receive a timing request from the peer.
void recvMemBackdoorReq(const MemBackdoorReq &req, MemBackdoorPtr &_backdoor) override
Receive a request for a back door to a range of memory.
void recvRespRetry() override
Called by the peer if sendTimingResp was called on this protocol (causing recvTimingResp to be called...
Tick recvAtomic(PacketPtr pkt) override
Receive an atomic request packet from the peer.
CfiMemory: This is modelling a flash memory adhering to the Common Flash Interface (CFI):
EventFunctionWrapper releaseEvent
static const uint8_t STATUS_ERASE_ERROR
Possible in the status register.
void recvFunctional(PacketPtr pkt)
CfiCommand readState
Previous command (issued in the previous write cycle)
Tick recvAtomic(PacketPtr pkt)
uint64_t readDeviceID(Addr flash_address) const
Helper function to read the device identifier after the read state machine is put in the CfiCommand::...
static const uint8_t STATUS_PROGRAM_LOCK_BIT
bool isBusy
Track the state of the memory as either idle or busy, no need for an enum with only two states.
EventFunctionWrapper dequeueEvent
static const uint8_t STATUS_LOCK_ERROR
static const uint8_t STATUS_READY
std::list< DeferredPacket > packetQueue
Internal (unbounded) storage to mimic the delay caused by the actual memory access.
Port & getPort(const std::string &if_name, PortID idx=InvalidPortID) override
Get a port with a given name and index.
void recvMemBackdoorReq(const MemBackdoorReq &req, MemBackdoorPtr &_backdoor)
ProgramBuffer programBuffer
bool recvTimingReq(PacketPtr pkt)
void write(PacketPtr pkt)
Write request to the CFI Memory.
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
DrainState drain() override
Draining is the process of clearing out the states of SimObjects.These are the SimObjects that are pa...
CfiMemory(const CfiMemoryParams &p)
void handleCommand(CfiCommand command)
Service a new command issued to the flash device.
const uint8_t numberOfChips
Tick recvAtomicBackdoor(PacketPtr pkt, MemBackdoorPtr &_backdoor)
@ BUFFER_SIZE_READ
This is not a real command, but it is used by the internal model only to represent the 2nd write cycl...
@ BUFFERED_PROGRAM_CONFIRM
Tick getLatency() const
Detemine the latency.
bool retryReq
Remember if we have to retry an outstanding request that arrived while we were busy.
uint64_t cfiQuery(Addr addr)
Return the selected entry in the CFI table.
void read(PacketPtr pkt)
Read request to the CFI Memory.
uint8_t cfiQueryTable[61]
void unserialize(CheckpointIn &cp) override
Unserialize an object.
void release()
Release the memory after being busy and send a retry if a request was rejected in the meanwhile.
void cfiAccess(PacketPtr pkt)
Make a read/write access to the CFI Memory.
bool retryResp
Remember if we failed to send a response and are awaiting a retry.
std::unique_ptr< Packet > pendingDelete
Upstream caches need this packet until true is returned, so hold it for deletion until a subsequent c...
const Tick latency_var
Fudge factor added to the latency.
void dequeue()
Dequeue a packet from our internal packet queue and move it to the port where it will be sent as soon...
void serialize(CheckpointOut &cp) const override
Serialize an object.
const Tick latency
Latency from that a request is accepted until the response is ready to be sent.
const double bandwidth
Bandwidth in ticks per byte.
static constexpr int log2i(int value)
Calculate the log2 of a power of 2 integer.
std::enable_if_t< std::is_integral_v< T >, T > random()
Use the SFINAE idiom to choose an implementation based on whether the type is integral or floating po...
constexpr T bits(T val, unsigned first, unsigned last)
Extract the bitfield from position 'first' to 'last' (inclusive) from 'val' and right justify it.
void signalDrainDone() const
Signal that an object is drained.
DrainState drainState() const
Return the current drain state of an object.
DrainState
Object drain/handover states.
@ Draining
Draining buffers pending serialization/handover.
@ Drained
Buffers drained, ready for serialization/handover.
bool scheduled() const
Determine if the current event is scheduled.
void schedule(Event &event, Tick when)
void reschedule(Event &event, Tick when, bool always=false)
#define panic(...)
This implements a cprintf based panic() function.
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
#define UNSERIALIZE_CONTAINER(member)
#define SERIALIZE_ENUM(scalar)
#define UNSERIALIZE_OBJ(obj)
#define SERIALIZE_OBJ(obj)
This macro serializes an object into its own section.
#define SERIALIZE_CONTAINER(member)
#define UNSERIALIZE_ENUM(scalar)
virtual Port & getPort(const std::string &if_name, PortID idx=InvalidPortID)
Get a port with a given name and index.
virtual void init()
init() is called after all C++ SimObjects have been created and all ports are connected.
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Tick curTick()
The universal simulation clock.
std::ostream CheckpointOut
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
uint64_t Tick
Tick count type.
#define UNSERIALIZE_SCALAR(scalar)
#define SERIALIZE_SCALAR(scalar)
uint32_t blockIdx(Addr block_address) const
void lock(Addr block_address)
Lock the block pointed by the block_address parameter.
void erase(PacketPtr pkt)
Erase a single block.
void unlock(Addr block_address)
Unlock the block pointed by the block_address parameter.
bool isLocked(Addr block_address) const
Return true if the block pointed by the block_address parameter is locked.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
std::vector< bool > locked
void serialize(CheckpointOut &cp) const override
Serialize an object.
void serialize(CheckpointOut &cp) const override
Serialize an object.
void setup(ssize_t buffer_size)
Start buffering.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
bool write(Addr flash_address, void *data_ptr, ssize_t size)
Write data into the buffer.
const std::string & name()