Restructured the gem5 backend:
- FailGem5Device is gone. - There are now changes directly made to the gem5 source. - Gem5Connector is a helper class that is compiled inside the gem5 context to workaround problems with gem5 header in fail. Things that are working: - BPSingleListener - MemAccessListener - Save and restore simulator state git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1820 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
@ -76,6 +76,11 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// FAIL*
|
||||
// don't use unordered map with aspect c++ compiler
|
||||
#undef HAVE_STD_UNORDERED_MAP
|
||||
#undef HAVE_STD_TR1_UNORDERED_MAP
|
||||
|
||||
// set a default value of 0
|
||||
#ifndef HAVE_STD_UNORDERED_MAP
|
||||
#define HAVE_STD_UNORDERED_MAP 0
|
||||
|
||||
@ -81,6 +81,9 @@
|
||||
#include "sim/stats.hh"
|
||||
#include "sim/system.hh"
|
||||
|
||||
#include "sal/SALInst.hpp"
|
||||
#include "config/FailConfig.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace TheISA;
|
||||
|
||||
@ -329,6 +332,10 @@ BaseSimpleCPU::checkForInterrupts()
|
||||
Fault interrupt = interrupts->getInterrupt(tc);
|
||||
|
||||
if (interrupt != NoFault) {
|
||||
// FAIL*
|
||||
#ifdef CONFIG_EVENT_INTERRUPT
|
||||
fail::simulator.onInterrupt(dynamic_cast<ArmFault*>(interrupt.get())->offset(), false);
|
||||
#endif
|
||||
fetchOffset = 0;
|
||||
interrupts->updateIntrInfo(tc);
|
||||
interrupt->invoke(tc);
|
||||
|
||||
@ -62,6 +62,9 @@
|
||||
#include "mem/packet_access.hh"
|
||||
#include "sim/system.hh"
|
||||
|
||||
#include "config/FailConfig.hpp"
|
||||
#include "sal/SALInst.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
AbstractMemory::AbstractMemory(const Params *p) :
|
||||
@ -400,6 +403,10 @@ AbstractMemory::access(PacketPtr pkt)
|
||||
bytesRead[pkt->req->masterId()] += pkt->getSize();
|
||||
if (pkt->req->isInstFetch())
|
||||
bytesInstRead[pkt->req->masterId()] += pkt->getSize();
|
||||
// FAIL*
|
||||
#ifdef CONFIG_EVENT_MEMREAD
|
||||
fail::simulator.onMemoryAccess(pkt->getAddr(), pkt->getSize(), false, 0);
|
||||
#endif
|
||||
} else if (pkt->isWrite()) {
|
||||
if (writeOK(pkt)) {
|
||||
if (pmemAddr)
|
||||
@ -408,6 +415,10 @@ AbstractMemory::access(PacketPtr pkt)
|
||||
TRACE_PACKET("Write");
|
||||
numWrites[pkt->req->masterId()]++;
|
||||
bytesWritten[pkt->req->masterId()] += pkt->getSize();
|
||||
// FAIL*
|
||||
#ifdef CONFIG_EVENT_MEMWRITE
|
||||
fail::simulator.onMemoryAccess(pkt->getAddr(), pkt->getSize(), true, 0);
|
||||
#endif
|
||||
}
|
||||
} else if (pkt->isInvalidate()) {
|
||||
// no need to do anything
|
||||
@ -432,11 +443,19 @@ AbstractMemory::functionalAccess(PacketPtr pkt)
|
||||
if (pmemAddr)
|
||||
memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
|
||||
TRACE_PACKET("Read");
|
||||
// FAIL*
|
||||
#ifdef CONFIG_EVENT_MEMREAD
|
||||
fail::simulator.onMemoryAccess(pkt->getAddr(), pkt->getSize(), false, 0);
|
||||
#endif
|
||||
pkt->makeResponse();
|
||||
} else if (pkt->isWrite()) {
|
||||
if (pmemAddr)
|
||||
memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize());
|
||||
TRACE_PACKET("Write");
|
||||
// FAIL*
|
||||
#ifdef CONFIG_EVENT_MEMWRITE
|
||||
fail::simulator.onMemoryAccess(pkt->getAddr(), pkt->getSize(), true, 0);
|
||||
#endif
|
||||
pkt->makeResponse();
|
||||
} else if (pkt->isPrint()) {
|
||||
Packet::PrintReqState *prs =
|
||||
|
||||
@ -37,6 +37,8 @@
|
||||
#include "sim/full_system.hh"
|
||||
#include "sim/root.hh"
|
||||
|
||||
#include "sal/SALInst.hpp"
|
||||
|
||||
Root *Root::_root = NULL;
|
||||
|
||||
/*
|
||||
@ -126,6 +128,14 @@ Root::loadState(Checkpoint *cp)
|
||||
timeSyncEnable(params()->time_sync_enable);
|
||||
}
|
||||
|
||||
|
||||
// FAIL*
|
||||
void
|
||||
Root::startup()
|
||||
{
|
||||
fail::simulator.startup();
|
||||
}
|
||||
|
||||
void
|
||||
Root::serialize(std::ostream &os)
|
||||
{
|
||||
|
||||
@ -112,6 +112,9 @@ class Root : public SimObject
|
||||
*/
|
||||
void initState();
|
||||
|
||||
// FAIL*
|
||||
void startup();
|
||||
|
||||
virtual void serialize(std::ostream &os);
|
||||
virtual void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
|
||||
|
||||
@ -18,7 +18,6 @@ elseif(BUILD_GEM5)
|
||||
SimulatorController.cc
|
||||
perf/BreakpointBuffer.cc
|
||||
gem5/Gem5Controller.cc
|
||||
gem5/Gem5PCEvents.cc
|
||||
)
|
||||
elseif(BUILD_OVP)
|
||||
set(SRCS
|
||||
|
||||
@ -1,127 +0,0 @@
|
||||
#include "FailGem5Device.hpp"
|
||||
|
||||
#include "debug/Fail.hh"
|
||||
#include "sim/system.hh"
|
||||
#include "arch/arm/decoder.hh"
|
||||
#include "cpu/simple/base.hh"
|
||||
|
||||
#include "../SALInst.hpp"
|
||||
#include "Gem5PCEvents.hpp"
|
||||
|
||||
#include <bitset>
|
||||
|
||||
FailGem5Device::FailGem5Device(Params *p)
|
||||
: BasicPioDevice(p)
|
||||
{
|
||||
pioSize = 0x60;
|
||||
}
|
||||
|
||||
void FailGem5Device::startup()
|
||||
{
|
||||
// TODO: Find a better way/position to start single stepping.
|
||||
// It's not possible to fetch the instruction at Adress 0x0
|
||||
m_BreakpointNotTaken = new Gem5InstructionEvent(this, &sys->pcEventQueue, 0x80000000);
|
||||
fail::simulator.startup();
|
||||
}
|
||||
|
||||
void FailGem5Device::activateSingleStepMode()
|
||||
{
|
||||
setNextBreakpoints(sys->getThreadContext(0));
|
||||
}
|
||||
|
||||
void FailGem5Device::deactivateSingleStepMode()
|
||||
{
|
||||
clearBreakpoints();
|
||||
}
|
||||
|
||||
void FailGem5Device::setNextBreakpoints(ThreadContext *tc)
|
||||
{
|
||||
clearBreakpoints();
|
||||
|
||||
// Get the instruction at the current program counter
|
||||
MachInst inst;
|
||||
PCState pc = tc->pcState();
|
||||
tc->getVirtProxy().readBlob(pc.pc(), (uint8_t*)&inst, sizeof(MachInst));
|
||||
|
||||
// Decode the instruction
|
||||
ArmISA::Decoder* decoder = tc->getDecoderPtr();
|
||||
BaseSimpleCPU* cpu = dynamic_cast<BaseSimpleCPU*>(tc->getCpuPtr());
|
||||
Addr fetchPC = (pc.pc() & cpu->PCMask) + cpu->fetchOffset;
|
||||
decoder->moreBytes(pc, fetchPC, inst);
|
||||
StaticInstPtr si = decoder->decode(pc);
|
||||
|
||||
// Set breakpoints
|
||||
// First breakpoint is always the next pc
|
||||
// FIXME: Doesn't work properly in Thumb or Thumb2 mode
|
||||
m_BreakpointNotTaken = new Gem5InstructionEvent(this, &sys->pcEventQueue, pc.npc());
|
||||
|
||||
// Second breakpoint will only be set if there is a possible change in control flow
|
||||
DPRINTF(Fail, "Instruction Name: %s\n", si->getName());
|
||||
|
||||
if(si->getName().compare("bx") == 0)
|
||||
{
|
||||
DPRINTF(Fail, "BX instruction\n");
|
||||
Addr target = tc->readIntReg(si->machInst.rm);
|
||||
m_BreakpointTaken = new Gem5InstructionEvent(this, &sys->pcEventQueue, target);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for a pop instruction with the pc as target
|
||||
if(si->getName().compare("ldmstm") == 0)
|
||||
{
|
||||
std::bitset<16> regs(si->machInst.regList);
|
||||
if(regs.test(15)) // Bit 15 = pc
|
||||
{
|
||||
DPRINTF(Fail, "LDMSTM with pc as target\n");
|
||||
Addr mem = tc->readIntReg(si->machInst.rn) + 4*(regs.count()-1);
|
||||
|
||||
Addr target;
|
||||
tc->getVirtProxy().readBlob(mem, (uint8_t*)&target, sizeof(Addr));
|
||||
DPRINTF(Fail, "Value loaded into pc: %x\n", target);
|
||||
|
||||
m_BreakpointTaken = new Gem5InstructionEvent(this, &sys->pcEventQueue, target);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
PCState bpc;
|
||||
if(si->hasBranchTarget(pc, tc, bpc))
|
||||
{
|
||||
DPRINTF(Fail, "Immediate branch\n");
|
||||
if (bpc.pc() != pc.npc())
|
||||
{
|
||||
m_BreakpointTaken = new Gem5InstructionEvent(this, &sys->pcEventQueue, bpc.pc());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FailGem5Device::clearBreakpoints()
|
||||
{
|
||||
if(m_BreakpointTaken)
|
||||
{
|
||||
delete m_BreakpointTaken;
|
||||
m_BreakpointTaken = 0;
|
||||
}
|
||||
if(m_BreakpointNotTaken)
|
||||
{
|
||||
delete m_BreakpointNotTaken;
|
||||
m_BreakpointNotTaken = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Tick FailGem5Device::read(PacketPtr pkt)
|
||||
{
|
||||
return pioDelay;
|
||||
}
|
||||
|
||||
Tick FailGem5Device::write(PacketPtr pkt)
|
||||
{
|
||||
return pioDelay;
|
||||
}
|
||||
|
||||
FailGem5Device* FailGem5DeviceParams::create()
|
||||
{
|
||||
return new FailGem5Device(this);
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
#ifndef __FAILGEM5_DEVICE_HH__
|
||||
#define __FAILGEM5_DEVICE_HH__
|
||||
|
||||
#include "dev/io_device.hh"
|
||||
#include "params/FailGem5Device.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
|
||||
class Gem5InstructionEvent;
|
||||
|
||||
class FailGem5Device : public BasicPioDevice
|
||||
{
|
||||
|
||||
public:
|
||||
typedef FailGem5DeviceParams Params;
|
||||
FailGem5Device(Params *p);
|
||||
|
||||
void setNextBreakpoints(ThreadContext *tc);
|
||||
|
||||
virtual void startup();
|
||||
virtual Tick read(PacketPtr pkt);
|
||||
virtual Tick write(PacketPtr pkt);
|
||||
|
||||
private:
|
||||
Gem5InstructionEvent* m_BreakpointTaken;
|
||||
Gem5InstructionEvent* m_BreakpointNotTaken;
|
||||
|
||||
void activateSingleStepMode();
|
||||
void deactivateSingleStepMode();
|
||||
void clearBreakpoints();
|
||||
};
|
||||
|
||||
#endif // __FAILGEM5_DEVICE_HH__
|
||||
@ -1,5 +0,0 @@
|
||||
from Device import BasicPioDevice
|
||||
|
||||
class FailGem5Device(BasicPioDevice):
|
||||
type = 'FailGem5Device'
|
||||
|
||||
@ -7,7 +7,6 @@
|
||||
#define __GEM5_CONFIG_HPP__
|
||||
|
||||
#include "base/types.hh"
|
||||
//#include "arch/arm/registers.hh"
|
||||
|
||||
namespace fail {
|
||||
|
||||
|
||||
25
src/core/sal/gem5/Gem5Connector.cc
Normal file
25
src/core/sal/gem5/Gem5Connector.cc
Normal file
@ -0,0 +1,25 @@
|
||||
#include "Gem5Connector.hpp"
|
||||
|
||||
#include "base/trace.hh"
|
||||
#include "debug/FailState.hh"
|
||||
#include "sim/root.hh"
|
||||
|
||||
Gem5Connector connector;
|
||||
|
||||
void Gem5Connector::save(const std::string &path)
|
||||
{
|
||||
DPRINTF(FailState, "Saving state to %s.\n", path);
|
||||
|
||||
Root* root = Root::root();
|
||||
root->Serializable::serializeAll(path);
|
||||
}
|
||||
|
||||
void Gem5Connector::restore(const std::string &path)
|
||||
{
|
||||
DPRINTF(FailState, "Restoring state from %s.\n", path);
|
||||
|
||||
Root* root = Root::root();
|
||||
Checkpoint cp(path);
|
||||
|
||||
root->loadState(&cp);
|
||||
}
|
||||
20
src/core/sal/gem5/Gem5Connector.hpp
Normal file
20
src/core/sal/gem5/Gem5Connector.hpp
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef __GEM5_CONNECTOR_HPP__
|
||||
#define __GEM5_CONNECTOR_HPP__
|
||||
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* \class Gem5Connector
|
||||
* This class will be compiled inside the gem5 context and provides the
|
||||
* Gem5Controller a way to call gem5 functions.
|
||||
*/
|
||||
class Gem5Connector
|
||||
{
|
||||
public:
|
||||
void save(const std::string &path);
|
||||
void restore(const std::string &path);
|
||||
};
|
||||
|
||||
extern Gem5Connector connector;
|
||||
|
||||
#endif // __GEM5_CONNECTOR_HPP__
|
||||
@ -1,35 +1,23 @@
|
||||
#include "Gem5Controller.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include "Gem5Connector.hpp"
|
||||
|
||||
#include "../Listener.hpp"
|
||||
|
||||
#include "sim/core.hh"
|
||||
#include "sim/sim_exit.hh"
|
||||
//#include "sim/root.hh"
|
||||
|
||||
namespace fail {
|
||||
|
||||
bool Gem5Controller::save(const std::string &path)
|
||||
{
|
||||
// Takes a snapshot in the m5out dir
|
||||
Tick when = curTick() + 1;
|
||||
exitSimLoop("checkpoint", 0, when, 0);
|
||||
|
||||
// This could be a version to take snapshots with a specified name
|
||||
/*Root* root = Root::root();
|
||||
connector.save(path);
|
||||
|
||||
std::ofstream file(path.c_str());
|
||||
root->serialize(file);
|
||||
file.close();*/
|
||||
return false; // TODO
|
||||
return true;
|
||||
}
|
||||
|
||||
void Gem5Controller::restore(const std::string &path)
|
||||
{
|
||||
|
||||
connector.restore(path);
|
||||
}
|
||||
|
||||
// TODO: Implement reboot
|
||||
void Gem5Controller::reboot()
|
||||
{
|
||||
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
#ifndef __GEM5_CONTROLLER_HPP__
|
||||
#define __GEM5_CONTROLLER_HPP__
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "../SimulatorController.hpp"
|
||||
|
||||
namespace fail {
|
||||
|
||||
/**
|
||||
* \class Gem5Controller
|
||||
* gem5-specific implementation of a SimulatorController.
|
||||
*/
|
||||
class Gem5Controller : public SimulatorController {
|
||||
public:
|
||||
void onBreakpoint(address_t instrPtr, address_t address_space);
|
||||
@ -18,4 +20,4 @@ public:
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
#endif // __GEM_CONTROLLER_HPP__
|
||||
#endif // __GEM5_CONTROLLER_HPP__
|
||||
|
||||
@ -1,25 +1,30 @@
|
||||
#ifndef __GEM5LISTENER_AH__
|
||||
#define __GEM5LISTENER_AH__
|
||||
#ifndef __GEM5_LISTENER_AH__
|
||||
#define __GEM5_LISTENER_AH__
|
||||
|
||||
#include "config/VariantConfig.hpp"
|
||||
#include "config/FailConfig.hpp"
|
||||
#include "../SALInst.hpp"
|
||||
|
||||
#if defined(BUILD_GEM5) && defined(CONFIG_EVENT_BREAKPOINTS)
|
||||
|
||||
#include "Gem5PCEvents.hpp"
|
||||
#include "sim/system.hh"
|
||||
#include "cpu/pc_event.hh"
|
||||
|
||||
class Gem5Breakpoint : public PCEvent
|
||||
{
|
||||
public:
|
||||
Gem5Breakpoint(PCEventQueue* queue, Addr ip)
|
||||
: PCEvent(queue, "Fail* experiment breakpoint", ip) {}
|
||||
virtual void process(ThreadContext *tc) { fail::simulator.onBreakpoint(this->evpc, fail::ANY_ADDR); }
|
||||
};
|
||||
|
||||
aspect Gem5Listener
|
||||
{
|
||||
advice "fail::BPSingleListener" : slice class
|
||||
{
|
||||
private:
|
||||
Gem5BreakpointEvent* m_Breakpoint;
|
||||
Gem5Breakpoint* m_Breakpoint;
|
||||
public:
|
||||
virtual bool onAddition()
|
||||
{
|
||||
System* sys = *System::systemList.begin();
|
||||
m_Breakpoint = new Gem5BreakpointEvent(&sys->pcEventQueue, this->m_WatchInstrPtr);
|
||||
m_Breakpoint = new Gem5Breakpoint(&sys->pcEventQueue, this->m_WatchInstrPtr);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -35,5 +40,5 @@ aspect Gem5Listener
|
||||
};
|
||||
};
|
||||
|
||||
#endif // BUILD_GEM5 && CONFIG_EVENT_BREAKPOINTS
|
||||
#endif // __GEM5LISTENER_AH__
|
||||
#endif // __GEM5_LISTENER_AH__
|
||||
|
||||
|
||||
@ -1,14 +0,0 @@
|
||||
#include "Gem5PCEvents.hpp"
|
||||
#include "../SALInst.hpp"
|
||||
|
||||
#include "cpu/thread_context.hh"
|
||||
|
||||
void Gem5BreakpointEvent::process(ThreadContext *tc)
|
||||
{
|
||||
fail::simulator.onBreakpoint(this->evpc, fail::ANY_ADDR);
|
||||
}
|
||||
|
||||
void Gem5InstructionEvent::process(ThreadContext *tc)
|
||||
{
|
||||
m_FailDevice->setNextBreakpoints(tc);
|
||||
}
|
||||
@ -1,27 +0,0 @@
|
||||
#ifndef __GEM5_PCEVENTS_HPP__
|
||||
#define __GEM5_PCEVENTS_HPP__
|
||||
|
||||
#include "cpu/pc_event.hh"
|
||||
|
||||
#include "FailGem5Device.hpp"
|
||||
|
||||
class Gem5BreakpointEvent : public PCEvent
|
||||
{
|
||||
public:
|
||||
Gem5BreakpointEvent(PCEventQueue* queue, Addr ip)
|
||||
: PCEvent(queue, "Fail breakpoint event", ip) {}
|
||||
virtual void process(ThreadContext *tc);
|
||||
};
|
||||
|
||||
class Gem5InstructionEvent : public PCEvent
|
||||
{
|
||||
public:
|
||||
Gem5InstructionEvent(FailGem5Device* device, PCEventQueue* queue, Addr ip)
|
||||
: PCEvent(queue, "Fail instruction event", ip), m_FailDevice(device) {}
|
||||
virtual void process(ThreadContext *tc);
|
||||
|
||||
private:
|
||||
FailGem5Device* m_FailDevice;
|
||||
};
|
||||
|
||||
#endif // __GEM5_PCEVENTS_HPP__
|
||||
@ -6,6 +6,8 @@ if env['TARGET_ISA'] == 'no':
|
||||
env.Prepend(CPPPATH=Dir('../../../../../src/core/'))
|
||||
env.Prepend(CPPPATH=Dir('../../../../../build/src/core/'))
|
||||
|
||||
env.Append(CXXFLAGS = '-Wno-deprecated')
|
||||
|
||||
env.Prepend(LIBPATH=Dir('../../../../../build/lib/'))
|
||||
gStaticLibs = ['-lfail-sal', '-lfail-hsc-simple', '-lfail-comm', '-lfail-cpn', '-lfail-efw', '-lfail-util', '-lpcl']
|
||||
|
||||
@ -20,6 +22,7 @@ if (len(gStaticLibs)>0):
|
||||
env.Append(LINKCOM = ' $GEN_LIB_BUILD_STATIC')
|
||||
|
||||
|
||||
SimObject('FailGem5Device.py')
|
||||
Source('FailGem5Device.cc')
|
||||
DebugFlag('Fail')
|
||||
DebugFlag('FailState')
|
||||
CompoundFlag('Fail', ['FailState'])
|
||||
|
||||
Source('Gem5Connector.cc')
|
||||
|
||||
Reference in New Issue
Block a user