Merge "gem5 build system improved"
This commit is contained in:
@ -3,5 +3,37 @@ if(BUILD_GEM5)
|
||||
message(STATUS "[${PROJECT_NAME}] Building gem5 variant ...")
|
||||
SET(VARIANT gem5)
|
||||
|
||||
#set(gem5_src_dir ${PROJECT_SOURCE_DIR}/simulators/gem5)
|
||||
set(gem5_src_dir ${PROJECT_SOURCE_DIR}/simulators/gem5)
|
||||
set(gem5_wrapper ${PROJECT_SOURCE_DIR}/src/core/sal/gem5)
|
||||
set(gem5_build_config build/ARM/gem5.debug)
|
||||
set(core_count 9)
|
||||
|
||||
# FIXMEs:
|
||||
# - incremental builds working?
|
||||
# - dependency for modified .cc files not correctly checked
|
||||
# - core_count should be derived from the parent make -jX parameter
|
||||
# - make gem5_build_config configurable in CMake
|
||||
# (alternative: gem5_build_config is set based on the CMake build
|
||||
# config, e.g., "Debug" or "Release")
|
||||
|
||||
# Enable ExternalProject CMake module
|
||||
include(ExternalProject)
|
||||
|
||||
# Use cmake's external project feature to build gem5 (and link FailGem5)
|
||||
ExternalProject_Add(
|
||||
FailGem5_binary_external # the (unique) name of this custom target (= external project)
|
||||
# Disable update, patch and configure step:
|
||||
UPDATE_COMMAND ""
|
||||
PATCH_COMMAND ""
|
||||
CONFIGURE_COMMAND ""
|
||||
SOURCE_DIR ${gem5_src_dir}
|
||||
BINARY_DIR ${gem5_src_dir}
|
||||
# Build gem5 using scons build system:
|
||||
BUILD_COMMAND scons EXTRAS=${gem5_wrapper} ${gem5_build_config} -j${core_count}
|
||||
# Disable install step (for now)
|
||||
INSTALL_COMMAND ""
|
||||
)
|
||||
|
||||
# Build "fail" library first (will be statically linked to gem5)
|
||||
add_dependencies(FailGem5_binary_external fail)
|
||||
endif(BUILD_GEM5)
|
||||
|
||||
@ -1,43 +1,17 @@
|
||||
#include "Gem5ArmCPU.hpp"
|
||||
|
||||
#include "Gem5Wrapper.hpp"
|
||||
|
||||
namespace fail {
|
||||
|
||||
regdata_t Gem5ArmCPU::getRegisterContent(Register* reg) const
|
||||
{
|
||||
switch (reg->getType()) {
|
||||
case RT_GP:
|
||||
if (reg->getIndex() == 15) {
|
||||
return m_System->getThreadContext(m_Id)->pcState().pc();
|
||||
}
|
||||
return m_System->getThreadContext(m_Id)->readIntReg(reg->getIndex());
|
||||
case RT_FP:
|
||||
return m_System->getThreadContext(m_Id)->readFloatReg(reg->getIndex());
|
||||
case RT_ST:
|
||||
return m_System->getThreadContext(m_Id)->readMiscReg(reg->getIndex());
|
||||
case RT_IP:
|
||||
return m_System->getThreadContext(m_Id)->pcState().pc();
|
||||
}
|
||||
|
||||
// This shouldn't be reached if a valid register is passed
|
||||
// TODO: assertion?
|
||||
return 0;
|
||||
return GetRegisterContent(m_System, m_Id, reg->getType(), reg->getIndex());
|
||||
}
|
||||
|
||||
void Gem5ArmCPU::setRegisterContent(Register* reg, regdata_t value)
|
||||
{
|
||||
switch (reg->getType()) {
|
||||
case RT_GP:
|
||||
m_System->getThreadContext(m_Id)->setIntReg(reg->getIndex(), value);
|
||||
break;
|
||||
case RT_FP:
|
||||
m_System->getThreadContext(m_Id)->setFloatReg(reg->getIndex(), value);
|
||||
break;
|
||||
case RT_ST:
|
||||
return m_System->getThreadContext(m_Id)->setMiscReg(reg->getIndex(), value);
|
||||
case RT_IP:
|
||||
return setRegisterContent(getRegister(RI_IP), value);
|
||||
}
|
||||
// TODO: assertion?
|
||||
SetRegisterContent(m_System, m_Id, reg->getType(), reg->getIndex(), value);
|
||||
}
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
@ -4,7 +4,8 @@
|
||||
#include "../arm/ArmArchitecture.hpp"
|
||||
#include "../arm/ArmCPUState.hpp"
|
||||
|
||||
#include "sim/system.hh"
|
||||
// gem5 forward declarations:
|
||||
class System;
|
||||
|
||||
namespace fail {
|
||||
|
||||
@ -17,6 +18,9 @@ namespace fail {
|
||||
* while \c ArmCPUState encapsulates the CPU state (e.g. register \a content).
|
||||
*/
|
||||
class Gem5ArmCPU : public ArmArchitecture, public ArmCPUState {
|
||||
private:
|
||||
unsigned int m_Id; //!< the unique ID of this CPU
|
||||
System* m_System; //!< the gem5 system object
|
||||
public:
|
||||
/**
|
||||
* Creates a new gem5 CPU for ARM based targets.
|
||||
@ -60,9 +64,6 @@ public:
|
||||
* @return the unique ID of \c this CPU object
|
||||
*/
|
||||
unsigned int getId() const { return m_Id; }
|
||||
private:
|
||||
unsigned int m_Id; //!< the unique ID of this CPU
|
||||
System* m_System; //!< the gem5 system object
|
||||
};
|
||||
|
||||
typedef Gem5ArmCPU ConcreteCPU; //!< the concrete CPU type for ARM + gem5
|
||||
|
||||
18
src/core/sal/gem5/Gem5Breakpoint.hpp
Normal file
18
src/core/sal/gem5/Gem5Breakpoint.hpp
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef __GEM5_BREAKPOINT_HPP__
|
||||
#define __GEM5_BREAKPOINT_HPP__
|
||||
|
||||
#include "../SALConfig.hpp"
|
||||
#include "cpu/pc_event.hh"
|
||||
|
||||
namespace fail {
|
||||
|
||||
class Gem5Breakpoint : public PCEvent {
|
||||
public:
|
||||
Gem5Breakpoint(PCEventQueue* queue, Addr ip)
|
||||
: PCEvent(queue, "Fail* experiment breakpoint", ip) { }
|
||||
virtual void process(ThreadContext *tc);
|
||||
};
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
#endif // __GEM5_BREAKPOINT_HPP__
|
||||
@ -6,15 +6,20 @@
|
||||
#ifndef __GEM5_CONFIG_HPP__
|
||||
#define __GEM5_CONFIG_HPP__
|
||||
|
||||
#include "base/types.hh"
|
||||
#include <stdint.h>
|
||||
|
||||
namespace fail {
|
||||
|
||||
typedef Addr guest_address_t; //!< the guest memory address type
|
||||
/**
|
||||
* The guest memory address type
|
||||
*
|
||||
* @note Keep this sync with src/base/types.hh:68 ("typedef uint64_t Addr;")
|
||||
*/
|
||||
typedef uint64_t guest_address_t;
|
||||
// TODO: Set Host Address Type
|
||||
typedef void* host_address_t; //!< the host memory address type
|
||||
typedef uint64_t register_data_t; //!< register data type (gem5 always uses 64 bit for registers)
|
||||
typedef int timer_t; //!< type of timer IDs
|
||||
typedef uint64_t register_data_t; //!< register data type (gem5 always uses 64 bit for registers)
|
||||
typedef int timer_t; //!< type of timer IDs
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
#if 0
|
||||
#include "Gem5Connector.hpp"
|
||||
|
||||
#include "base/trace.hh"
|
||||
@ -23,3 +24,5 @@ void Gem5Connector::restore(const std::string &path)
|
||||
|
||||
root->loadState(&cp);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
#if 0
|
||||
// TODO: Incorporate this code into Gem5Controller.{hpp,cc}
|
||||
|
||||
#ifndef __GEM5_CONNECTOR_HPP__
|
||||
#define __GEM5_CONNECTOR_HPP__
|
||||
|
||||
@ -17,3 +20,4 @@ public:
|
||||
extern Gem5Connector connector;
|
||||
|
||||
#endif // __GEM5_CONNECTOR_HPP__
|
||||
#endif
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
#include "Gem5Controller.hpp"
|
||||
#include "Gem5Connector.hpp"
|
||||
//#include "Gem5Connector.hpp"
|
||||
|
||||
#include "../Listener.hpp"
|
||||
|
||||
#include "sim/system.hh"
|
||||
#include "Gem5Wrapper.hpp"
|
||||
|
||||
namespace fail {
|
||||
|
||||
@ -11,11 +11,12 @@ void Gem5Controller::startup()
|
||||
{
|
||||
// Assuming there is only one defined system should be sufficient for most cases. More systems
|
||||
// are only used for switching cpu model or caches during a simulation run.
|
||||
System* sys = System::systemList.front();
|
||||
m_Mem = new Gem5MemoryManager(sys);
|
||||
m_System = GetSystemObject();
|
||||
m_Mem = new Gem5MemoryManager(m_System);
|
||||
|
||||
for (int i = 0; i < sys->numContexts(); i++) {
|
||||
ConcreteCPU* cpu = new ConcreteCPU(sys->getThreadContext(i)->cpuId(), System::systemList.front());
|
||||
int numCtxs = GetNumberOfContexts(m_System);
|
||||
for (int i = 0; i < numCtxs; i++) {
|
||||
ConcreteCPU* cpu = new ConcreteCPU(GetCPUId(m_System, i), m_System);
|
||||
addCPU(cpu);
|
||||
}
|
||||
|
||||
@ -35,14 +36,14 @@ Gem5Controller::~Gem5Controller()
|
||||
|
||||
bool Gem5Controller::save(const std::string &path)
|
||||
{
|
||||
connector.save(path); // FIXME: not working?!
|
||||
// connector.save(path); // FIXME: not working?!
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Gem5Controller::restore(const std::string &path)
|
||||
{
|
||||
connector.restore(path); // FIXME: not working?!
|
||||
// connector.restore(path); // FIXME: not working?!
|
||||
}
|
||||
|
||||
// TODO: Implement reboot
|
||||
|
||||
@ -4,7 +4,8 @@
|
||||
#include "../SimulatorController.hpp"
|
||||
#include "Gem5Memory.hpp"
|
||||
|
||||
#include "sim/system.hh"
|
||||
// gem5 forward declarations:
|
||||
class System;
|
||||
|
||||
namespace fail {
|
||||
|
||||
@ -14,6 +15,8 @@ namespace fail {
|
||||
* Gem5-specific implementation of a SimulatorController.
|
||||
*/
|
||||
class Gem5Controller : public SimulatorController {
|
||||
private:
|
||||
System* m_System; //!< the gem5 system object
|
||||
public:
|
||||
void startup();
|
||||
~Gem5Controller();
|
||||
|
||||
@ -6,19 +6,6 @@
|
||||
|
||||
#if defined(BUILD_GEM5) && defined(CONFIG_EVENT_BREAKPOINTS) && !defined(CONFIG_EVENT_BREAKPOINTS_RANGE)
|
||||
|
||||
#include "../SALInst.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(&fail::simulator.getCPU(tc->cpuId()), this->evpc, fail::ANY_ADDR); }
|
||||
};
|
||||
|
||||
aspect Gem5Listener {
|
||||
advice "fail::BPSingleListener" : slice class {
|
||||
private:
|
||||
@ -26,18 +13,13 @@ aspect Gem5Listener {
|
||||
public:
|
||||
virtual bool onAddition()
|
||||
{
|
||||
System* sys = *System::systemList.begin();
|
||||
m_Breakpoint = new Gem5Breakpoint(&sys->pcEventQueue, this->m_WatchInstrPtr);
|
||||
|
||||
m_Breakpoint = OnBreakpointAddition(Gem5Breakpoint* bp, address_t watchInstrPtr)
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void onDeletion()
|
||||
{
|
||||
if (m_Breakpoint) {
|
||||
delete m_Breakpoint;
|
||||
m_Breakpoint = 0;
|
||||
}
|
||||
OnBreakpointDeletion(m_Breakpoint);
|
||||
m_Breakpoint = 0;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@ -2,12 +2,10 @@
|
||||
#define __GEM5_MEMORY_HPP__
|
||||
|
||||
#include "../Memory.hpp"
|
||||
#include "Gem5Wrapper.hpp"
|
||||
|
||||
#include "sim/system.hh"
|
||||
#include "mem/packet.hh"
|
||||
#include "mem/physical.hh"
|
||||
|
||||
//class System;
|
||||
// gem5 forward declarations:
|
||||
class System;
|
||||
|
||||
namespace fail {
|
||||
|
||||
@ -17,56 +15,30 @@ namespace fail {
|
||||
* MemoryManager to provide access to gem5's memory pool.
|
||||
*/
|
||||
class Gem5MemoryManager : public MemoryManager {
|
||||
public:
|
||||
Gem5MemoryManager(System* system) : m_System(system), m_Mem(&system->getPhysMem()) { }
|
||||
|
||||
size_t getPoolSize() const { return m_Mem->totalSize(); }
|
||||
host_address_t getStartAddr() const { return 0; }
|
||||
|
||||
byte_t getByte(guest_address_t addr)
|
||||
{
|
||||
Request req(addr, 1, Request::PHYSICAL, 0);
|
||||
|
||||
Packet pkt(&req, MemCmd::ReadReq);
|
||||
byte_t data;
|
||||
pkt.dataStatic(&data);
|
||||
|
||||
m_Mem->functionalAccess(&pkt);
|
||||
return data;
|
||||
}
|
||||
|
||||
void getBytes(guest_address_t addr, size_t cnt, void *dest)
|
||||
{
|
||||
Request req(addr, cnt, Request::PHYSICAL, 0);
|
||||
|
||||
Packet pkt(&req, MemCmd::ReadReq);
|
||||
pkt.dataStatic(dest);
|
||||
|
||||
m_Mem->functionalAccess(&pkt);
|
||||
}
|
||||
|
||||
void setByte(guest_address_t addr, byte_t data)
|
||||
{
|
||||
Request req(addr, 1, Request::PHYSICAL, 0);
|
||||
|
||||
Packet pkt(&req, MemCmd::WriteReq);
|
||||
pkt.dataStatic(&data);
|
||||
|
||||
m_Mem->functionalAccess(&pkt);
|
||||
}
|
||||
|
||||
void setBytes(guest_address_t addr, size_t cnt, void const *src)
|
||||
{
|
||||
Request req(addr, cnt, Request::PHYSICAL, 0);
|
||||
|
||||
Packet pkt(&req, MemCmd::WriteReq);
|
||||
pkt.dataStatic(src);
|
||||
|
||||
m_Mem->functionalAccess(&pkt);
|
||||
}
|
||||
private:
|
||||
System* m_System;
|
||||
PhysicalMemory* m_Mem;
|
||||
public:
|
||||
Gem5MemoryManager(System* sys) : m_System(sys) { }
|
||||
size_t getPoolSize() const { return GetPoolSize(m_System); }
|
||||
host_address_t getStartAddr() const { return 0; }
|
||||
byte_t getByte(guest_address_t addr)
|
||||
{
|
||||
byte_t data;
|
||||
ReadMemory(m_System, addr, 1, &data);
|
||||
return data;
|
||||
}
|
||||
void getBytes(guest_address_t addr, size_t cnt, void *dest)
|
||||
{
|
||||
ReadMemory(m_System, addr, cnt, dest);
|
||||
}
|
||||
void setByte(guest_address_t addr, byte_t data)
|
||||
{
|
||||
WriteMemory(m_System, addr, 1, &data);
|
||||
}
|
||||
void setBytes(guest_address_t addr, size_t cnt, void const *src)
|
||||
{
|
||||
WriteMemory(m_System, addr, cnt, src);
|
||||
}
|
||||
};
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
101
src/core/sal/gem5/Gem5Wrapper.cc
Normal file
101
src/core/sal/gem5/Gem5Wrapper.cc
Normal file
@ -0,0 +1,101 @@
|
||||
#include "../SALInst.hpp"
|
||||
#include "Gem5Wrapper.hpp"
|
||||
#include "Gem5Breakpoint.hpp"
|
||||
|
||||
#include "sim/system.hh"
|
||||
#include "mem/packet.hh"
|
||||
#include "mem/physical.hh"
|
||||
|
||||
namespace fail {
|
||||
|
||||
// Register-/Memory-related:
|
||||
regdata_t GetRegisterContent(System* sys, unsigned int id, RegisterType type, size_t idx)
|
||||
{
|
||||
switch (type) {
|
||||
case RT_GP:
|
||||
if (idx == 15) {
|
||||
return sys->getThreadContext(id)->pcState().pc();
|
||||
}
|
||||
return sys->getThreadContext(id)->readIntReg(idx);
|
||||
case RT_FP: return sys->getThreadContext(id)->readFloatReg(idx); // FIXME: correct?! (FP <-> Float?!)
|
||||
case RT_ST: return sys->getThreadContext(id)->readMiscReg(idx);
|
||||
case RT_IP: return sys->getThreadContext(id)->pcState().pc();
|
||||
}
|
||||
// This shouldn't be reached if a valid register is passed
|
||||
assert(false && "FATAL ERROR: invalid register type (should never be reached)!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SetRegisterContent(System* sys, unsigned int id, RegisterType type, size_t idx,
|
||||
regdata_t value)
|
||||
{
|
||||
switch (type) {
|
||||
case RT_GP: sys->getThreadContext(id)->setIntReg(idx, value); break;
|
||||
case RT_FP: sys->getThreadContext(id)->setFloatReg(idx, value); break; // FIXME: correct?! (FP <-> Float?!)
|
||||
case RT_ST: sys->getThreadContext(id)->setMiscReg(idx, value); break;
|
||||
case RT_IP: sys->getThreadContext(id)->pcState().pc(static_cast<Addr>(value)); break;
|
||||
}
|
||||
// This shouldn't be reached if a valid register is passed
|
||||
assert(false && "FATAL ERROR: invalid register type (should never be reached)!");
|
||||
}
|
||||
|
||||
void ReadMemory(System* sys, guest_address_t addr, size_t cnt, void *dest)
|
||||
{
|
||||
Request req(addr, cnt, Request::PHYSICAL, 0);
|
||||
|
||||
Packet pkt(&req, MemCmd::ReadReq);
|
||||
pkt.dataStatic(dest);
|
||||
|
||||
sys->getPhysMem().functionalAccess(&pkt);
|
||||
}
|
||||
|
||||
void WriteMemory(System* sys, guest_address_t addr, size_t cnt, void const *src)
|
||||
{
|
||||
Request req(addr, cnt, Request::PHYSICAL, 0);
|
||||
|
||||
Packet pkt(&req, MemCmd::WriteReq);
|
||||
pkt.dataStatic(src);
|
||||
|
||||
sys->getPhysMem().functionalAccess(&pkt);
|
||||
}
|
||||
|
||||
size_t GetPoolSize(System* sys) { return sys->getPhysMem().totalSize(); }
|
||||
|
||||
// Breakpoint-related:
|
||||
void Gem5Breakpoint::process(ThreadContext *tc)
|
||||
{
|
||||
fail::simulator.onBreakpoint(&fail::simulator.getCPU(tc->cpuId()), this->evpc, fail::ANY_ADDR);
|
||||
}
|
||||
|
||||
Gem5Breakpoint* OnBreakpointAddition(address_t watchInstrPtr)
|
||||
{
|
||||
System* sys = *System::systemList.begin();
|
||||
// FIXME: begin() vs. front() (see Gem5Controller::startup())
|
||||
// FIXME: Provide "sys" using the simulator-inst?
|
||||
return new Gem5Breakpoint(&sys->pcEventQueue, watchInstrPtr);
|
||||
}
|
||||
|
||||
void OnBreakpointDeletion(Gem5Breakpoint* bp)
|
||||
{
|
||||
if (bp) {
|
||||
delete bp; // TODO: required?
|
||||
}
|
||||
}
|
||||
|
||||
// Controller-related:
|
||||
unsigned int GetCPUId(System* sys, int context)
|
||||
{
|
||||
return sys->getThreadContext(context)->cpuId();
|
||||
}
|
||||
|
||||
System* GetSystemObject()
|
||||
{
|
||||
return System::systemList.front();
|
||||
}
|
||||
|
||||
int GetNumberOfContexts(System* sys)
|
||||
{
|
||||
return sys->numContexts();
|
||||
}
|
||||
|
||||
} // end-of-namespace: fail
|
||||
33
src/core/sal/gem5/Gem5Wrapper.hpp
Normal file
33
src/core/sal/gem5/Gem5Wrapper.hpp
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef __GEM5_WRAPPER_HPP__
|
||||
#define __GEM5_WRAPPER_HPP__
|
||||
|
||||
#include "../Register.hpp"
|
||||
#include "../SALConfig.hpp"
|
||||
|
||||
// gem5 forward declarations:
|
||||
class System;
|
||||
|
||||
namespace fail {
|
||||
|
||||
class Gem5Breakpoint;
|
||||
|
||||
// Register-/Memory-related:
|
||||
regdata_t GetRegisterContent(System* sys, unsigned int id, RegisterType type, size_t idx);
|
||||
void SetRegisterContent(System* sys, unsigned int id, RegisterType type, size_t idx,
|
||||
regdata_t value);
|
||||
void WriteMemory(System* sys, guest_address_t addr, size_t cnt, void const *src);
|
||||
void ReadMemory(System* sys, guest_address_t addr, size_t cnt, void *dest);
|
||||
size_t GetPoolSize(System* sys);
|
||||
|
||||
// Breakpoint-related:
|
||||
Gem5Breakpoint* OnBreakpointAddition(address_t watchInstrPtr);
|
||||
void OnBreakpointDeletion(Gem5Breakpoint* bp);
|
||||
|
||||
// Controller-related:
|
||||
unsigned int GetCPUId(System* sys, int context);
|
||||
System* GetSystemObject();
|
||||
int GetNumberOfContexts(System* sys);
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
#endif // __GEM5_WRAPPER_HPP__
|
||||
@ -25,4 +25,4 @@ if (len(gStaticLibs)>0):
|
||||
DebugFlag('FailState')
|
||||
CompoundFlag('Fail', ['FailState'])
|
||||
|
||||
Source('Gem5Connector.cc')
|
||||
Source('Gem5Wrapper.cc')
|
||||
|
||||
Reference in New Issue
Block a user