from m5.params import *
from m5.SimObject import SimObject
class Hello(SimObject):
type = 'Hello'
cxx_header = "tutorial/hello.hh"
#ifndef __TUTORIAL_HELLO_HH__
#define __TUTORIAL_HELLO_HH__
#include "params/Hello.hh"
#include "sim/sim_object.hh"
class Hello : public SimObject
{
public:
Hello(HelloParams *p);
};
#endif // __TUTORIAL_HELLO_HH__
#include "tutorial/hello.hh"
#include <iostream>
Hello::Hello(HelloParams *params) : SimObject(params)
{
std::cout << "Hello World! From a SimObject!" << std::endl;
}
Hello*
HelloParams::create()
{
return new Hello(this);
}
Import('*')
SimObject('Hello.py')
Source('hello.cc')
import m5
from m5.objects import *
root = Root(full_system = False)
root.hello = Hello()
m5.instantiate()
print "Beginning simulation!"
exit_event = m5.simulate()
print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_event.getCause())
build/X86/gem5.opt configs/tutorial/hello_run.py
build/X86/gem5.opt --debug-flags=DRAM configs/learning_gem5/part1/simple.py | head -n 50
build/X86/gem5.opt --debug-help
DebugFlag('HelloDebug')
#include "debug/HelloDebug.hh"
...
DPRINTF(HelloDebug, "Created the hello object\n");
build/X86/gem5.opt --debug-flags=HelloDebug configs/tutorial/hello_run.py
build/X86/gem5.opt --debug-flags=DRAM configs/learning_gem5/part1/simple.py | head -n 50
build/X86/gem5.opt --debug-flags=Exec configs/learning_gem5/part1/simple.py | head -n 50
private:
void processEvent();
EventWrapper<Hello, &Hello::processEvent> event;
Hello::Hello(HelloParams *params) :
SimObject(params), event([this]{processEvent();}, name())
void
Hello::processEvent()
{
DPRINTF(HelloDebug, "Hello world! Processing the event!\n");
}
void startup();
void
Hello::startup()
{
schedule(event, 100);
}
Hello::Hello(HelloParams *params) :
SimObject(params),
event([this]{processEvent();}, name()),
latency(100), timesLeft(10)
void
Hello::startup()
{
schedule(event, latency);
}
void
Hello::processEvent()
{
timesLeft--;
DPRINTF(HelloDebug, "Hello world! Processing the event! %d left\n",
timesLeft);
if (timesLeft <= 0) {
DPRINTF(HelloDebug, "Done firing!\n");
} else {
schedule(event, curTick() + latency);
}
}
class Hello(SimObject):
type = 'Hello'
cxx_header = "tutorial/hello.hh"
time_to_wait = Param.Latency("Time before firing the event")
number_of_fires = Param.Int(1, "Number of times to fire the event before "
"goodbye")
Hello::Hello(HelloParams *params) :
SimObject(params),
event([this]{processEvent();}, name()),
latency(params->time_to_wait),
timesLeft(params->number_of_fires)
root.hello = Hello(time_to_wait = '2us')
root.hello = Hello()
root.hello.time_to_wait = '2us'
root.hello.number_of_fires = 10
...
from MemObject import MemObject
class Hello(MemObject):
...
inst_port = SlavePort("CPU side port, receives requests")
data_port = SlavePort("CPU side port, receives requests")
mem_side = MasterPort("Memory side port, sends requests")
#include "mem/mem_object.hh"
Hello : public MemObject
class CPUSidePort : public SlavePort
{
private:
Hello *owner;
public:
CPUSidePort(const std::string& name, Hello *owner) :
SlavePort(name, owner), owner(owner)
{ }
AddrRangeList getAddrRanges() const override;
protected:
Tick recvAtomic(PacketPtr pkt) override { panic("recvAtomic unimpl."); }
void recvFunctional(PacketPtr pkt) override;
bool recvTimingReq(PacketPtr pkt) override;
void recvRespRetry() override;
};
class MemSidePort : public MasterPort
{
private:
Hello *owner;
public:
MemSidePort(const std::string& name, Hello *owner) :
MasterPort(name, owner), owner(owner)
{ }
protected:
bool recvTimingResp(PacketPtr pkt) override;
void recvReqRetry() override;
void recvRangeChange() override;
};
class Hello : public MemObject
{
private:
<CPUSidePort declaration>
<MemSidePort declaration>
CPUSidePort instPort;
CPUSidePort dataPort;
MemSidePort memPort;
public:
Hello(HelloParams *params);
BaseMasterPort& getMasterPort(const std::string& if_name,
PortID idx = InvalidPortID) override;
BaseSlavePort& getSlavePort(const std::string& if_name,
PortID idx = InvalidPortID) override;
};
Hello::Hello(HelloParams *params) :
MemObject(params),
instPort(params->name + ".inst_port", this),
dataPort(params->name + ".data_port", this),
memPort(params->name + ".mem_side", this),
{
}
BaseMasterPort&
Hello::getMasterPort(const std::string& if_name, PortID idx)
{
if (if_name == "mem_side") {
return memPort;
} else {
return MemObject::getMasterPort(if_name, idx);
}
}
BaseSlavePort&
Hello::getSlavePort(const std::string& if_name, PortID idx)
{
if (if_name == "inst_port") {
return instPort;
} else if (if_name == "data_port") {
return dataPort;
} else {
return MemObject::getSlavePort(if_name, idx);
}
}
AddrRangeList
Hello::CPUSidePort::getAddrRanges() const
{
return owner->getAddrRanges();
}
AddrRangeList
Hello::getAddrRanges() const
{
DPRINTF(HelloDebug, "Sending new ranges\n");
return memPort.getAddrRanges();
}
void
Hello::CPUSidePort::recvFunctional(PacketPtr pkt)
{
return owner->handleFunctional(pkt);
}
void
Hello::handleFunctional(PacketPtr pkt)
{
memPort.sendFunctional(pkt);
}
void
Hello::MemSidePort::recvRangeChange()
{
owner->sendRangeChange();
}
void
Hello::sendRangeChange()
{
instPort.sendRangeChange();
dataPort.sendRangeChange();
}
AddrRangeList getAddrRanges() const;
void handleFunctional(PacketPtr pkt);
void sendRangeChange();
bool handleRequest(PacketPtr pkt);
bool handleResponse(PacketPtr pkt);
bool
Hello::CPUSidePort::recvTimingReq(PacketPtr pkt)
{
if (!owner->handleRequest(pkt)) {
needRetry = true;
return false;
} else {
return true;
}
}
class CPUSidePort : public SlavePort
{
bool needRetry;
...
CPUSidePort(const std::string& name, Hello *owner) :
SlavePort(name, owner), owner(owner), needRetry(false)
bool
Hello::handleRequest(PacketPtr pkt)
{
if (blocked) {
return false;
}
DPRINTF(HelloDebug, "Got request for addr %#x\n", pkt->getAddr());
blocked = true;
memPort.sendPacket(pkt);
return true;
}
bool blocked;
void
Hello::MemSidePort::sendPacket(PacketPtr pkt)
{
panic_if(blockedPacket != nullptr, "Should never try to send if blocked!");
if (!sendTimingReq(pkt)) {
blockedPacket = pkt;
}
}
class MemSidePort : public MasterPort {
PacketPtr blockedPacket;
public:
void sendPacket(PacketPtr pkt);
void
Hello::MemSidePort::recvReqRetry()
{
assert(blockedPacket != nullptr);
PacketPtr pkt = blockedPacket;
blockedPacket = nullptr;
sendPacket(pkt);
}
bool
Hello::MemSidePort::recvTimingResp(PacketPtr pkt)
{
return owner->handleResponse(pkt);
}
bool
Hello::handleResponse(PacketPtr pkt)
{
assert(blocked);
DPRINTF(HelloDebug, "Got response for addr %#x\n", pkt->getAddr());
blocked = false;
// Simply forward to the memory port
if (pkt->req->isInstFetch()) {
instPort.sendPacket(pkt);
} else {
dataPort.sendPacket(pkt);
}
return true;
}
class CPUSidePort : public SlavePort
{
PacketPtr blockedPacket;
// ADD TO THE CONSTRUCTOR!!!!
, blockedPacket(nullptr)
public:
void sendPacket(PacketPtr pkt);
void
Hello::CPUSidePort::sendPacket(PacketPtr pkt)
{
panic_if(blockedPacket != nullptr, "Should never try to send if blocked!");
if (!sendTimingResp(pkt)) {
blockedPacket = pkt;
}
}
void
Hello::CPUSidePort::recvRespRetry()
{
assert(blockedPacket != nullptr);
PacketPtr pkt = blockedPacket;
blockedPacket = nullptr;
sendPacket(pkt);
}
class CPUSidePort : public SlavePort {
public:
void trySendRetry();
void
Hello::CPUSidePort::trySendRetry()
{
if (needRetry && blockedPacket == nullptr) {
needRetry = false;
DPRINTF(HelloDebug, "Sending retry req for %d\n", id);
sendRetryReq();
}
}
Hello::handleResponse(PacketPtr pkt)
{
instPort.trySendRetry();
dataPort.trySendRetry();
system.cpu = TimingSimpleCPU()
system.memobj = Hello()
system.cpu.icache_port = system.memobj.inst_port
system.cpu.dcache_port = system.memobj.data_port
system.membus = SystemXBar()
system.memobj.mem_side = system.membus.slave
from m5.proxy import *
latency = Param.Cycles(1, "Cycles taken on a hit or to resolve a miss")
size = Param.MemorySize('16kB', "The size of the cache")
system = Param.System(Parent.any, "The system this cache is part of")
#include "sim/system.hh"
latency(params->latency),
blockSize(params->system->cacheLineSize()),
capacity(params->size / blockSize),
private:
Cycles latency; **** NOW CYCLE
int blockSize;
// Number of blocks in the cache
uint32_t capacity;
bool
Hello::handleRequest(PacketPtr pkt, int port_id)
{
if (blocked) {
return false;
}
DPRINTF(HelloDebug, "Got request for addr %#x\n", pkt->getAddr());
blocked = true;
schedule(new EventFunctionWrapper([this, pkt]{ accessTiming(pkt); },
name() + ".access",
true), // auto delete
clockEdge(latency));
return true;
}
void accessTiming(PacketPtr pkt);
void
Hello::accessTiming(PacketPtr pkt)
{
bool hit = accessFunctional(pkt);
if (hit) {
pkt->makeResponse();
blocked = false;
if (pkt->req->isInstFetch()) {
instPort.sendPacket(pkt);
} else {
dataPort.sendPacket(pkt);
}
instPort.trySendRetry();
dataPort.trySendRetry();
} else {
<miss handling>
}
}
void
Hello::accessTiming(PacketPtr pkt)
{
bool hit = accessFunctional(pkt);
if (hit) {
<....>
} else {
Addr addr = pkt->getAddr();
Addr block_addr = pkt->getBlockAddr(blockSize);
unsigned size = pkt->getSize();
DPRINTF(HelloDebug, "Upgrading packet to block size\n");
panic_if(addr - block_addr + size > blockSize,
"Cannot handle accesses that span multiple cache lines");
assert(pkt->needsResponse());
MemCmd cmd;
if (pkt->isWrite() || pkt->isRead()) {
cmd = MemCmd::ReadReq;
} else {
panic("Unknown packet type in upgrade size");
}
// packet automatically aligned to block size!
PacketPtr new_pkt = new Packet(pkt->req, cmd, blockSize);
new_pkt->allocate();
outstandingPacket = pkt; // Save original packet
memPort.sendPacket(new_pkt);
}
}
PacketPtr outstandingPacket;
bool
Hello::handleResponse(PacketPtr pkt)
{
assert(blocked);
DPRINTF(HelloDebug, "Got response for addr %#x\n", pkt->getAddr());
insert(pkt);
assert(outstandingPacket != nullptr);
accessFunctional(outstandingPacket);
outstandingPacket->makeResponse();
delete pkt;
pkt = outstandingPacket;
outstandingPacket = nullptr;
sendResponse(pkt);
return true;
}
#include <unordered_map>
void insert(PacketPtr pkt);
bool accessFunctional(PacketPtr pkt);
std::unordered_map<Addr, uint8_t*> cacheStore;
bool
Hello::accessFunctional(PacketPtr pkt)
{
Addr block_addr = pkt->getBlockAddr(blockSize);
auto it = cacheStore.find(block_addr);
if (it != cacheStore.end()) {
if (pkt->isWrite()) {
pkt->writeDataToBlock(it->second, blockSize);
} else if (pkt->isRead()) {
pkt->setDataFromBlock(it->second, blockSize);
} else {
panic("Unknown packet type!");
}
return true;
}
return false;
}
void
Hello::insert(PacketPtr pkt)
{
if (cacheStore.size() >= capacity) {
auto block = cacheStore.begin(); // Replace the "first" element
// WE don't track clean/dirty, so write back everything
RequestPtr req = new Request(block->first, blockSize, 0, 0);
PacketPtr new_pkt = new Packet(req, MemCmd::WritebackDirty, blockSize);
new_pkt->dataDynamic(block->second); // This will be deleted later
DPRINTF(HelloDebug, "Writing packet back %s\n", pkt->print());
memPort.sendTimingReq(new_pkt);
cacheStore.erase(block->first);
}
// Make the miss request.
uint8_t *data = new uint8_t[blockSize];
cacheStore[pkt->getAddr()] = data;
pkt->writeDataToBlock(data, blockSize);
}
void
Hello::handleFunctional(PacketPtr pkt)
{
accessFunctional(pkt); // can ignore hit/miss
memPort.sendFunctional(pkt);
}
system.memobj = Hello(size='1kB')