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)),
285 "Should only see read and writes at memory controller, "
329 if (needs_response) {
344 !
i->pkt->matchAddr(pkt)) {
391 DPRINTF(Drain,
"Draining of CfiMemory complete\n");
415 if (if_name !=
"port") {
426 DPRINTF(Drain,
"CfiMemory Queue has requests, waiting to drain\n");
466 ranges.push_back(
mem.getAddrRange());
473 return mem.recvAtomic(pkt);
480 return mem.recvAtomicBackdoor(pkt, _backdoor);
486 mem.recvFunctional(pkt);
492 return mem.recvTimingReq(pkt);
519 const uint16_t value = pkt->
getUintX(ByteOrder::little) & 0xffff;
520 const auto new_cmd =
static_cast<CfiCommand>(value & 0xff);
577 auto buffer_size = (value + 1) *
sizeof(uint32_t);
609 panic(
"Invalid Write State\n");
636 panic(
"Invalid Read State\n");
641 value |= (value << 16);
644 pkt->
setUintX(value, ByteOrder::little);
655 switch ((flash_address & 0xff) /
bankWidth) {
664 warn(
"Invalid Device Identifier code: %d\n", flash_address & 0xff);
674 DPRINTF(CFI,
"CFI Command: Read Array\n");
678 DPRINTF(CFI,
"CFI Command: Read Device Identifier\n");
682 DPRINTF(CFI,
"CFI Command: CFI Query\n");
686 DPRINTF(CFI,
"CFI Command: Read Status Register\n");
690 DPRINTF(CFI,
"CFI Command: Clear Status Register\n");
694 DPRINTF(CFI,
"CFI Command: Buffered Program Confirm\n");
697 DPRINTF(CFI,
"CFI Command: Erase Block Setup\n");
702 DPRINTF(CFI,
"CFI Command: Lock Block Setup\n");
706 DPRINTF(CFI,
"CFI Command: Word Program\n");
711 DPRINTF(CFI,
"CFI Command: Buffered Program Setup\n");
721 panic(
"Don't know what to do with %#x\n",
722 static_cast<uint16_t
>(new_cmd));
733 "Acessing invalid entry in CFI query table (addr=%#x)",
742 auto host_address = parent.toHostAddr(pkt->
getAddr());
743 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....
T * getPtr()
get a pointer to the data ptr.
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 ...
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.
bool trySatisfyFunctional(PacketPtr other)
Check a functional request against a memory value stored in another packet (i.e.
const std::string & cmdString() const
Return the string name of the cmd field (for debugging and tracing).
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 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.
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.
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
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()