Architecture changes (only gem5 implementation right now):
- The register manager is gone. It's functionality is now encapsulated in the CPU classes. - For the client, there is the ConcreteCPU class that encapsulates the access to the CPU state (including registers) and architecture details. The correspondig objects for the CPUs inside the simulator can be accessed through the SimulatorController.getCPU() function. - Listener got a new ConcreteCPU* member to filter for which CPU the events should fire. The default NULL is used as wildcard for all aviable CPUs. The events respectively got a ConcreteCPU* member to indicate which CPU really fired the event. - For the server, there is CPUArchitecture to access the architecture details. git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1966 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -29,3 +29,4 @@ simulators/bochs/ltdlconf.h
|
|||||||
!simulators/bochs/plex86/kernel/freebsd/Makefile
|
!simulators/bochs/plex86/kernel/freebsd/Makefile
|
||||||
|
|
||||||
simulators/gem5/.hg
|
simulators/gem5/.hg
|
||||||
|
simulators/gem5/m5out/
|
||||||
|
|||||||
@ -33,6 +33,9 @@ OPTION( BUILD_OVP "Build OVP Variant?" OFF)
|
|||||||
OPTION( BUILD_QEMU "Build QEMU Variant?" OFF)
|
OPTION( BUILD_QEMU "Build QEMU Variant?" OFF)
|
||||||
OPTION( BUILD_T32 "Build Lauterbach Trace32 Variant?" OFF)
|
OPTION( BUILD_T32 "Build Lauterbach Trace32 Variant?" OFF)
|
||||||
|
|
||||||
|
OPTION( BUILD_X86 "Build for x86 guests?" ON)
|
||||||
|
OPTION( BUILD_ARM "Build for ARM guests?" OFF)
|
||||||
|
|
||||||
# FIXME: only add simulators/ to include_directories, and include, e.g.,
|
# FIXME: only add simulators/ to include_directories, and include, e.g.,
|
||||||
# bochs/bochs.h in Fail*. -> avoids naming conflicts (e.g., /usr/include/elf.h
|
# bochs/bochs.h in Fail*. -> avoids naming conflicts (e.g., /usr/include/elf.h
|
||||||
# vs. qemu/elf.h)
|
# vs. qemu/elf.h)
|
||||||
|
|||||||
@ -57,6 +57,9 @@
|
|||||||
#include "sim/system.hh"
|
#include "sim/system.hh"
|
||||||
#include "sim/full_system.hh"
|
#include "sim/full_system.hh"
|
||||||
|
|
||||||
|
#include "config/FailConfig.hpp"
|
||||||
|
#include "sal/SALInst.hpp"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace TheISA;
|
using namespace TheISA;
|
||||||
|
|
||||||
@ -288,6 +291,12 @@ AtomicSimpleCPU::readMem(Addr addr, uint8_t * data,
|
|||||||
|
|
||||||
assert(!pkt.isError());
|
assert(!pkt.isError());
|
||||||
|
|
||||||
|
// FAIL*
|
||||||
|
#ifdef CONFIG_EVENT_MEMREAD
|
||||||
|
fail::ConcreteCPU* cpu = &fail::simulator.getCPU(cpuId());
|
||||||
|
fail::simulator.onMemoryAccess(cpu, pkt.getAddr(), pkt.getSize(), false, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (req->isLLSC()) {
|
if (req->isLLSC()) {
|
||||||
TheISA::handleLockedRead(thread, req);
|
TheISA::handleLockedRead(thread, req);
|
||||||
}
|
}
|
||||||
@ -389,6 +398,12 @@ AtomicSimpleCPU::writeMem(uint8_t *data, unsigned size,
|
|||||||
dcache_access = true;
|
dcache_access = true;
|
||||||
assert(!pkt.isError());
|
assert(!pkt.isError());
|
||||||
|
|
||||||
|
// FAIL*
|
||||||
|
#ifdef CONFIG_EVENT_MEMWRITE
|
||||||
|
fail::ConcreteCPU* cpu = &fail::simulator.getCPU(cpuId());
|
||||||
|
fail::simulator.onMemoryAccess(cpu, pkt.getAddr(), pkt.getSize(), true, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (req->isSwap()) {
|
if (req->isSwap()) {
|
||||||
assert(res);
|
assert(res);
|
||||||
memcpy(res, pkt.getPtr<uint8_t>(), fullSize);
|
memcpy(res, pkt.getPtr<uint8_t>(), fullSize);
|
||||||
@ -482,6 +497,11 @@ AtomicSimpleCPU::tick()
|
|||||||
icache_latency = icachePort.sendAtomic(&ifetch_pkt);
|
icache_latency = icachePort.sendAtomic(&ifetch_pkt);
|
||||||
|
|
||||||
assert(!ifetch_pkt.isError());
|
assert(!ifetch_pkt.isError());
|
||||||
|
// FAIL*
|
||||||
|
#ifdef CONFIG_EVENT_MEMREAD
|
||||||
|
fail::ConcreteCPU* cpu = &fail::simulator.getCPU(cpuId());
|
||||||
|
fail::simulator.onMemoryAccess(cpu, ifetch_pkt.getAddr(), ifetch_pkt.getSize(), false, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
// ifetch_req is initialized to read the instruction directly
|
// ifetch_req is initialized to read the instruction directly
|
||||||
// into the CPU object's inst field.
|
// into the CPU object's inst field.
|
||||||
|
|||||||
@ -403,10 +403,6 @@ AbstractMemory::access(PacketPtr pkt)
|
|||||||
bytesRead[pkt->req->masterId()] += pkt->getSize();
|
bytesRead[pkt->req->masterId()] += pkt->getSize();
|
||||||
if (pkt->req->isInstFetch())
|
if (pkt->req->isInstFetch())
|
||||||
bytesInstRead[pkt->req->masterId()] += pkt->getSize();
|
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()) {
|
} else if (pkt->isWrite()) {
|
||||||
if (writeOK(pkt)) {
|
if (writeOK(pkt)) {
|
||||||
if (pmemAddr)
|
if (pmemAddr)
|
||||||
@ -415,10 +411,6 @@ AbstractMemory::access(PacketPtr pkt)
|
|||||||
TRACE_PACKET("Write");
|
TRACE_PACKET("Write");
|
||||||
numWrites[pkt->req->masterId()]++;
|
numWrites[pkt->req->masterId()]++;
|
||||||
bytesWritten[pkt->req->masterId()] += pkt->getSize();
|
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()) {
|
} else if (pkt->isInvalidate()) {
|
||||||
// no need to do anything
|
// no need to do anything
|
||||||
|
|||||||
@ -7,4 +7,7 @@
|
|||||||
#cmakedefine BUILD_QEMU
|
#cmakedefine BUILD_QEMU
|
||||||
#cmakedefine BUILD_T32
|
#cmakedefine BUILD_T32
|
||||||
|
|
||||||
|
#cmakedefine BUILD_X86
|
||||||
|
#cmakedefine BUILD_ARM
|
||||||
|
|
||||||
#endif // __VARIANT_CONFIG_HPP__
|
#endif // __VARIANT_CONFIG_HPP__
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
if(BUILD_BOCHS)
|
if(BUILD_BOCHS)
|
||||||
set(SRCS
|
set(SRCS
|
||||||
|
CPU.cc
|
||||||
|
CPUState.cc
|
||||||
Listener.cc
|
Listener.cc
|
||||||
ListenerManager.cc
|
ListenerManager.cc
|
||||||
SALConfig.cc
|
SALConfig.cc
|
||||||
@ -10,6 +12,8 @@ if(BUILD_BOCHS)
|
|||||||
)
|
)
|
||||||
elseif(BUILD_GEM5)
|
elseif(BUILD_GEM5)
|
||||||
set(SRCS
|
set(SRCS
|
||||||
|
CPU.cc
|
||||||
|
CPUState.cc
|
||||||
Listener.cc
|
Listener.cc
|
||||||
ListenerManager.cc
|
ListenerManager.cc
|
||||||
SALConfig.cc
|
SALConfig.cc
|
||||||
@ -17,8 +21,15 @@ elseif(BUILD_GEM5)
|
|||||||
SimulatorController.cc
|
SimulatorController.cc
|
||||||
gem5/Gem5Controller.cc
|
gem5/Gem5Controller.cc
|
||||||
)
|
)
|
||||||
|
if(BUILD_ARM)
|
||||||
|
set(SRCS ${SRCS}
|
||||||
|
gem5/Gem5ArmCPU.cc
|
||||||
|
)
|
||||||
|
endif(BUILD_ARM)
|
||||||
elseif(BUILD_OVP)
|
elseif(BUILD_OVP)
|
||||||
set(SRCS
|
set(SRCS
|
||||||
|
CPU.cc
|
||||||
|
CPUState.cc
|
||||||
Listener.cc
|
Listener.cc
|
||||||
ListenerManager.cc
|
ListenerManager.cc
|
||||||
SALConfig.cc
|
SALConfig.cc
|
||||||
@ -28,6 +39,8 @@ elseif(BUILD_OVP)
|
|||||||
)
|
)
|
||||||
elseif(BUILD_QEMU)
|
elseif(BUILD_QEMU)
|
||||||
set(SRCS
|
set(SRCS
|
||||||
|
CPU.cc
|
||||||
|
CPUState.cc
|
||||||
Listener.cc
|
Listener.cc
|
||||||
ListenerManager.cc
|
ListenerManager.cc
|
||||||
SALConfig.cc
|
SALConfig.cc
|
||||||
@ -38,6 +51,8 @@ elseif(BUILD_QEMU)
|
|||||||
)
|
)
|
||||||
elseif(BUILD_T32)
|
elseif(BUILD_T32)
|
||||||
set(SRCS
|
set(SRCS
|
||||||
|
CPU.cc
|
||||||
|
CPUState.cc
|
||||||
Listener.cc
|
Listener.cc
|
||||||
ListenerManager.cc
|
ListenerManager.cc
|
||||||
SALConfig.cc
|
SALConfig.cc
|
||||||
@ -48,6 +63,16 @@ elseif(BUILD_T32)
|
|||||||
)
|
)
|
||||||
endif(BUILD_BOCHS)
|
endif(BUILD_BOCHS)
|
||||||
|
|
||||||
|
if(BUILD_X86)
|
||||||
|
set(SRCS ${SRCS}
|
||||||
|
|
||||||
|
)
|
||||||
|
elseif(BUILD_ARM)
|
||||||
|
set(SRCS ${SRCS}
|
||||||
|
arm/arch.cc
|
||||||
|
)
|
||||||
|
endif(BUILD_X86)
|
||||||
|
|
||||||
# Don't include these sources if perf-stuff is disabled
|
# Don't include these sources if perf-stuff is disabled
|
||||||
# (reduces compiler overhead):
|
# (reduces compiler overhead):
|
||||||
if(CONFIG_FAST_WATCHPOINTS)
|
if(CONFIG_FAST_WATCHPOINTS)
|
||||||
|
|||||||
43
src/core/sal/CPU.cc
Normal file
43
src/core/sal/CPU.cc
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#include "CPU.hpp"
|
||||||
|
|
||||||
|
namespace fail {
|
||||||
|
|
||||||
|
// FIXME: Bochs specific? If not, at least get rid of this global variable.
|
||||||
|
int interrupt_to_fire = -1;
|
||||||
|
|
||||||
|
void CPUArchitecture::addRegister(Register* reg)
|
||||||
|
{
|
||||||
|
assert(!reg->isAssigned() && "FATAL ERROR: The register is already assigned!");
|
||||||
|
m_Registers.push_back(reg);
|
||||||
|
|
||||||
|
UniformRegisterSet* urs = getRegisterSetOfType(reg->getType());
|
||||||
|
if (urs == NULL) {
|
||||||
|
urs = new UniformRegisterSet(reg->getType());
|
||||||
|
m_RegisterSubsets.push_back(urs);
|
||||||
|
}
|
||||||
|
urs->m_add(reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
Register* CPUArchitecture::getRegister(size_t i) const
|
||||||
|
{
|
||||||
|
assert(i < m_Registers.size() && "FATAL ERROR: Invalid index provided!");
|
||||||
|
return m_Registers[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
UniformRegisterSet& CPUArchitecture::getRegisterSet(size_t i) const
|
||||||
|
{
|
||||||
|
assert(i < m_RegisterSubsets.size() && "FATAL ERROR: Invalid index provided!");
|
||||||
|
return *m_RegisterSubsets[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
UniformRegisterSet* CPUArchitecture::getRegisterSetOfType(RegisterType t) const
|
||||||
|
{
|
||||||
|
for (std::vector< UniformRegisterSet* >::const_iterator it = m_RegisterSubsets.begin();
|
||||||
|
it != m_RegisterSubsets.end(); it++) {
|
||||||
|
if ((*it)->getType() == t)
|
||||||
|
return *it;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end-of-namespace: fail
|
||||||
69
src/core/sal/CPU.hpp
Normal file
69
src/core/sal/CPU.hpp
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
#ifndef __CPU_HPP__
|
||||||
|
#define __CPU_HPP__
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Register.hpp"
|
||||||
|
|
||||||
|
namespace fail {
|
||||||
|
|
||||||
|
// TODO: Interrupt information?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class CPUArchitecture
|
||||||
|
* This is the base class for CPU architectures that can be used to merge informations and
|
||||||
|
* functionallity that every backend with the same target architecture will share. The classes
|
||||||
|
* directly derived from this are especially meant to be usable in campaigns, so they shouldn't
|
||||||
|
* contain any backend specific code.
|
||||||
|
*/
|
||||||
|
class CPUArchitecture
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Retrieves the total number of registers over all homogeneous sets.
|
||||||
|
* @return the total register count
|
||||||
|
*/
|
||||||
|
size_t registerCount() const { return m_Registers.size(); }
|
||||||
|
/**
|
||||||
|
* Retrieves the number of managed homogeneous register sets.
|
||||||
|
* @return the number of sets
|
||||||
|
*/
|
||||||
|
size_t registerSubsetCount() const { return m_RegisterSubsets.size(); }
|
||||||
|
/**
|
||||||
|
* Adds a new register to this set. The register object needs to be
|
||||||
|
* typed (see Register::getType).
|
||||||
|
* @param reg a pointer to the register object to be added
|
||||||
|
* @see getType()
|
||||||
|
*/
|
||||||
|
void addRegister(Register* reg);
|
||||||
|
/**
|
||||||
|
* Retrieves the \a i-th register.
|
||||||
|
* @return a pointer to the \a i-th register; if \a i is invalid, an
|
||||||
|
* assertion is thrown
|
||||||
|
*/
|
||||||
|
Register* getRegister(size_t i) const;
|
||||||
|
/**
|
||||||
|
* Gets the \a i-th register set.
|
||||||
|
* @param i the index of the set to be returned
|
||||||
|
* @return a reference to the uniform register set
|
||||||
|
* @see registerSubsetCount()
|
||||||
|
*/
|
||||||
|
UniformRegisterSet& getRegisterSet(size_t i) const;
|
||||||
|
/**
|
||||||
|
* Returns the set with register type \a t. The set can be used to
|
||||||
|
* loop over all registers of type \a t.
|
||||||
|
* @param t the type to check for
|
||||||
|
* @return a pointer to the retrieved register set (if found), NULL
|
||||||
|
* otherwise
|
||||||
|
*/
|
||||||
|
UniformRegisterSet* getRegisterSetOfType(RegisterType t) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::vector< Register* > m_Registers;
|
||||||
|
std::vector< UniformRegisterSet* > m_RegisterSubsets;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end-of-namespace: fail
|
||||||
|
|
||||||
|
#endif // __CPU_HPP__
|
||||||
47
src/core/sal/CPUState.cc
Normal file
47
src/core/sal/CPUState.cc
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#include "CPUState.hpp"
|
||||||
|
|
||||||
|
namespace fail {
|
||||||
|
|
||||||
|
// FIXME: Bochs specific? If not, at least get rid of this global variable.
|
||||||
|
int interrupt_to_fire = -1;
|
||||||
|
|
||||||
|
bool CPUState::isSuppressedInterrupt(unsigned interruptNum)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < m_SuppressedInterrupts.size(); i++)
|
||||||
|
if ((m_SuppressedInterrupts[i] == interruptNum ||
|
||||||
|
m_SuppressedInterrupts[i] == ANY_INTERRUPT) &&
|
||||||
|
interruptNum != (unsigned)interrupt_to_fire + 32) {
|
||||||
|
if ((int)interruptNum == interrupt_to_fire + 32) {
|
||||||
|
interrupt_to_fire = -1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CPUState::addSuppressedInterrupt(unsigned interruptNum)
|
||||||
|
{
|
||||||
|
// Check if already existing:
|
||||||
|
if (isSuppressedInterrupt(interruptNum+32))
|
||||||
|
return false; // already added: nothing to do here
|
||||||
|
|
||||||
|
if (interruptNum == ANY_INTERRUPT)
|
||||||
|
m_SuppressedInterrupts.push_back(interruptNum);
|
||||||
|
else
|
||||||
|
m_SuppressedInterrupts.push_back(interruptNum+32);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CPUState::removeSuppressedInterrupt(unsigned interruptNum)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < m_SuppressedInterrupts.size(); i++) {
|
||||||
|
if (m_SuppressedInterrupts[i] == interruptNum+32 ||
|
||||||
|
m_SuppressedInterrupts[i] == ANY_INTERRUPT)
|
||||||
|
m_SuppressedInterrupts.erase(m_SuppressedInterrupts.begin() + i);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end-of-namespace: fail
|
||||||
70
src/core/sal/CPUState.hpp
Normal file
70
src/core/sal/CPUState.hpp
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#ifndef __CPU_STATE_HPP__
|
||||||
|
#define __CPU_STATE_HPP__
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Register.hpp"
|
||||||
|
|
||||||
|
namespace fail {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class CPUArchitecture
|
||||||
|
* This is the base class for the CPU state without any architecture specific additions. It contains
|
||||||
|
* pure virtual functions for e.g. register acces and have to be overridden in the backend
|
||||||
|
* implementation.
|
||||||
|
*/
|
||||||
|
class CPUState
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Gets the content of the passed Register.
|
||||||
|
* @param reg the register to get the content from
|
||||||
|
*/
|
||||||
|
virtual regdata_t getRegisterContent(Register* reg) = 0;
|
||||||
|
/**
|
||||||
|
* Writes the passed value into the given register.
|
||||||
|
* @param reg the register that should be written to
|
||||||
|
* @param value the value that should be written into the register
|
||||||
|
*/
|
||||||
|
virtual void setRegisterContent(Register* reg, regdata_t value) = 0;
|
||||||
|
/**
|
||||||
|
* Returns the current instruction pointer.
|
||||||
|
* @return the current eip
|
||||||
|
*/
|
||||||
|
virtual address_t getInstructionPointer() = 0;
|
||||||
|
/**
|
||||||
|
* Returns the top address of the stack.
|
||||||
|
* @return the starting address of the stack
|
||||||
|
*/
|
||||||
|
virtual address_t getStackPointer() = 0;
|
||||||
|
/**
|
||||||
|
* Check whether the interrupt should be suppressed.
|
||||||
|
* @param interruptNum the interrupt-type id
|
||||||
|
* @return \c true if the interrupt is suppressed, \c false oterwise
|
||||||
|
*/
|
||||||
|
bool isSuppressedInterrupt(unsigned interruptNum);
|
||||||
|
/**
|
||||||
|
* Add a Interrupt to the list of suppressed.
|
||||||
|
* @param interruptNum the interrupt-type id
|
||||||
|
* @return \c true if sucessfully added, \c false otherwise (already
|
||||||
|
* existing)
|
||||||
|
*/
|
||||||
|
bool addSuppressedInterrupt(unsigned interruptNum);
|
||||||
|
/**
|
||||||
|
* Remove a Interrupt from the list of suppressed.
|
||||||
|
* @param interruptNum the interrupt-type id
|
||||||
|
* @return \c true if sucessfully removed, \c false otherwise (not found)
|
||||||
|
*/
|
||||||
|
bool removeSuppressedInterrupt(unsigned interruptNum);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::vector<unsigned> m_SuppressedInterrupts;
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME (see CPU.cc): Weird, homeless global variable
|
||||||
|
extern int interrupt_to_fire;
|
||||||
|
|
||||||
|
} // end-of-namespace: fail
|
||||||
|
|
||||||
|
#endif
|
||||||
20
src/core/sal/ConcreteCPU.hpp
Normal file
20
src/core/sal/ConcreteCPU.hpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#ifndef __CONCRETE_CPU_HPP__
|
||||||
|
#define __CONCRETE_CPU_HPP__
|
||||||
|
|
||||||
|
#if defined BUILD_BOCHS
|
||||||
|
#include "bochs/BochsCPU.hpp"
|
||||||
|
#elif defined BUILD_GEM5
|
||||||
|
#if defined BUILD_ARM
|
||||||
|
#include "gem5/Gem5ArmCPU.hpp"
|
||||||
|
#endif
|
||||||
|
#elif defined BUILD_OVP
|
||||||
|
#include "ovp/OVPConfig.hpp"
|
||||||
|
#elif defined BUILD_QEMU
|
||||||
|
#include "qemu/QEMUConfig.hpp"
|
||||||
|
#elif defined BUILD_T32
|
||||||
|
#include "t32/T32Config.hpp"
|
||||||
|
#else
|
||||||
|
#error SAL Config Target not defined
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // __CONCRETE_CPU_HPP__
|
||||||
@ -9,6 +9,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "SALConfig.hpp"
|
#include "SALConfig.hpp"
|
||||||
|
#include "ConcreteCPU.hpp"
|
||||||
|
|
||||||
namespace fail {
|
namespace fail {
|
||||||
|
|
||||||
@ -19,8 +20,21 @@ namespace fail {
|
|||||||
*/
|
*/
|
||||||
class BaseEvent {
|
class BaseEvent {
|
||||||
public:
|
public:
|
||||||
BaseEvent() { }
|
BaseEvent(ConcreteCPU* cpu = NULL) : m_CPU(cpu) { }
|
||||||
virtual ~BaseEvent() { }
|
virtual ~BaseEvent() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a pointer to the CPU that triggered this event.
|
||||||
|
* @return triggering CPU
|
||||||
|
*/
|
||||||
|
ConcreteCPU* getTriggerCPU() const { return m_CPU; }
|
||||||
|
/**
|
||||||
|
* Sets the pointer the CPU that triggered this event.
|
||||||
|
* @param cpu new CPU which caused this event
|
||||||
|
*/
|
||||||
|
void setTriggerCPU(ConcreteCPU* cpu) { m_CPU = cpu; }
|
||||||
|
protected:
|
||||||
|
ConcreteCPU* m_CPU;
|
||||||
};
|
};
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Specialized events:
|
// Specialized events:
|
||||||
@ -41,8 +55,8 @@ public:
|
|||||||
* @param trigger the triggering address of the breakpoint event
|
* @param trigger the triggering address of the breakpoint event
|
||||||
* @param address_space the address space identifier for this event
|
* @param address_space the address space identifier for this event
|
||||||
*/
|
*/
|
||||||
BPEvent(address_t trigger, address_t address_space)
|
BPEvent(address_t trigger, address_t address_space, ConcreteCPU* cpu = NULL)
|
||||||
: m_TriggerInstrPtr(trigger), m_AddressSpace(address_space) { }
|
: BaseEvent(cpu), m_TriggerInstrPtr(trigger), m_AddressSpace(address_space) { }
|
||||||
/**
|
/**
|
||||||
* Returns the instruction pointer that triggered this event.
|
* Returns the instruction pointer that triggered this event.
|
||||||
* @return triggering IP
|
* @return triggering IP
|
||||||
@ -88,8 +102,8 @@ private:
|
|||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Creates a new \c MemAccessEvent using default initialization values, i.e.
|
* Creates a new \c MemAccessEvent using default initialization values, i.e.
|
||||||
* \c setTriggerAddress(ANY_ADDR), \c setTriggerWidth(0), \c setTriggerAccessType(MEM_UNKNOWN)
|
* \c setTriggerAddress(ANY_ADDR), \c setTriggerWidth(0), \c setTriggerAccessType(MEM_UNKNOWN),
|
||||||
* and \c setTriggerInstructionPointer(ANY_ADDR).
|
* \c setTriggerInstructionPointer(ANY_ADDR) and setTriggerCPU(NULL).
|
||||||
*/
|
*/
|
||||||
MemAccessEvent()
|
MemAccessEvent()
|
||||||
: m_TriggerAddr(ANY_ADDR), m_TriggerWidth(0),
|
: m_TriggerAddr(ANY_ADDR), m_TriggerWidth(0),
|
||||||
@ -100,9 +114,11 @@ public:
|
|||||||
* @param width width of memory access (= # Bytes)
|
* @param width width of memory access (= # Bytes)
|
||||||
* @param triggerIP the instruction pointer that actually triggered the memory access
|
* @param triggerIP the instruction pointer that actually triggered the memory access
|
||||||
* @param type the type of memory access (r, w, rw)
|
* @param type the type of memory access (r, w, rw)
|
||||||
|
* @param cpu the cpu that triggered the event
|
||||||
*/
|
*/
|
||||||
MemAccessEvent(address_t triggerAddr, size_t width, address_t triggerIP, access_type_t type)
|
MemAccessEvent(address_t triggerAddr, size_t width, address_t triggerIP, access_type_t type,
|
||||||
: m_TriggerAddr(triggerAddr), m_TriggerWidth(width),
|
ConcreteCPU* cpu = NULL)
|
||||||
|
: BaseEvent(cpu), m_TriggerAddr(triggerAddr), m_TriggerWidth(width),
|
||||||
m_TriggerIP(triggerIP), m_AccessType(type) { }
|
m_TriggerIP(triggerIP), m_AccessType(type) { }
|
||||||
/**
|
/**
|
||||||
* Returns the specific memory address that actually triggered the event.
|
* Returns the specific memory address that actually triggered the event.
|
||||||
@ -163,16 +179,17 @@ private:
|
|||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Constructs a default initialized \c TroubleEvent, setting the trigger-number
|
* Constructs a default initialized \c TroubleEvent, setting the trigger-number
|
||||||
* to -1.
|
* to -1 and the trigger-CPU to NULL.
|
||||||
*/
|
*/
|
||||||
TroubleEvent() : m_TriggerNumber(-1) { }
|
TroubleEvent() : m_TriggerNumber(-1) { }
|
||||||
/**
|
/**
|
||||||
* Constructs a new \c TroubleEvent.
|
* Constructs a new \c TroubleEvent.
|
||||||
* @param triggerNum system and type specific number identifying the requestet
|
* @param triggerNum system and type specific number identifying the requestet
|
||||||
* "trouble-type"
|
* "trouble-type"
|
||||||
|
* @param cpu the CPU that triggered the event
|
||||||
*/
|
*/
|
||||||
TroubleEvent(int triggerNum)
|
TroubleEvent(int triggerNum, ConcreteCPU* cpu = NULL)
|
||||||
: m_TriggerNumber(triggerNum) { }
|
: BaseEvent(cpu), m_TriggerNumber(triggerNum) { }
|
||||||
/**
|
/**
|
||||||
* Sets the specific interrupt-/trap-number that actually triggered the event.
|
* Sets the specific interrupt-/trap-number that actually triggered the event.
|
||||||
* @param triggerNum system and type specific number identifying the requested
|
* @param triggerNum system and type specific number identifying the requested
|
||||||
@ -196,7 +213,7 @@ private:
|
|||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Constructs a default initialized \c InterruptEvent, setting the non maskable
|
* Constructs a default initialized \c InterruptEvent, setting the non maskable
|
||||||
* interrupt flag to \c false.
|
* interrupt flag to \c false and the CPU to NULL.
|
||||||
*/
|
*/
|
||||||
InterruptEvent() : m_IsNMI(false) { }
|
InterruptEvent() : m_IsNMI(false) { }
|
||||||
/**
|
/**
|
||||||
@ -204,8 +221,10 @@ public:
|
|||||||
* @param nmi the new NMI (non maskable interrupt) flag state
|
* @param nmi the new NMI (non maskable interrupt) flag state
|
||||||
* @param triggerNum system and type specific number identifying the requestet
|
* @param triggerNum system and type specific number identifying the requestet
|
||||||
* "trouble-type"
|
* "trouble-type"
|
||||||
|
* @param cpu the cpu that triggered the event
|
||||||
*/
|
*/
|
||||||
InterruptEvent(bool nmi, int triggerNum) : TroubleEvent(triggerNum), m_IsNMI(nmi) { }
|
InterruptEvent(bool nmi, int triggerNum, ConcreteCPU* cpu = NULL)
|
||||||
|
: TroubleEvent(triggerNum, cpu), m_IsNMI(nmi) { }
|
||||||
/**
|
/**
|
||||||
* Returns \c true if the interrupt is non maskable, \c false otherwise.
|
* Returns \c true if the interrupt is non maskable, \c false otherwise.
|
||||||
* @return \c true if NMI flag is set, \c false otherwise
|
* @return \c true if NMI flag is set, \c false otherwise
|
||||||
@ -258,8 +277,9 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Initialises an IOPortEvent
|
* Initialises an IOPortEvent
|
||||||
* @param data the data which has been communicated through the I/O port
|
* @param data the data which has been communicated through the I/O port
|
||||||
|
* @param cpu the cpu that triggered the event
|
||||||
*/
|
*/
|
||||||
IOPortEvent(unsigned char data = 0) : m_Data(data) { }
|
IOPortEvent(unsigned char data = 0, ConcreteCPU* cpu = NULL) : BaseEvent(cpu), m_Data(data) { }
|
||||||
/**
|
/**
|
||||||
* Returns the data sent to the specified port
|
* Returns the data sent to the specified port
|
||||||
*/
|
*/
|
||||||
@ -285,9 +305,10 @@ public:
|
|||||||
* or ANY_INSTR to match all jump-instructions
|
* or ANY_INSTR to match all jump-instructions
|
||||||
* @param flagreg \c true if the event has been triggered due to a
|
* @param flagreg \c true if the event has been triggered due to a
|
||||||
* specific FLAG register content, \c false otherwise
|
* specific FLAG register content, \c false otherwise
|
||||||
|
* @param cpu the CPU that triggered the event
|
||||||
*/
|
*/
|
||||||
JumpEvent(unsigned opcode = ANY_INSTR, bool flagreg = false)
|
JumpEvent(unsigned opcode = ANY_INSTR, bool flagreg = false, ConcreteCPU* cpu = NULL)
|
||||||
: m_OpcodeTrigger(opcode), m_FlagTriggered(flagreg) { }
|
: BaseEvent(cpu), m_OpcodeTrigger(opcode), m_FlagTriggered(flagreg) { }
|
||||||
/**
|
/**
|
||||||
* Retrieves the opcode of the jump-instruction.
|
* Retrieves the opcode of the jump-instruction.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -17,9 +17,11 @@ void BaseListener::onTrigger()
|
|||||||
bool TroubleListener::isMatching(const TroubleEvent* pEv) const
|
bool TroubleListener::isMatching(const TroubleEvent* pEv) const
|
||||||
{
|
{
|
||||||
for (unsigned i = 0; i < m_WatchNumbers.size(); i++) {
|
for (unsigned i = 0; i < m_WatchNumbers.size(); i++) {
|
||||||
if (m_WatchNumbers[i] == pEv->getTriggerNumber() ||
|
if (m_CPU == NULL || m_CPU == pEv->getTriggerCPU()) {
|
||||||
m_WatchNumbers[i] == ANY_TRAP)
|
if (m_WatchNumbers[i] == pEv->getTriggerNumber() ||
|
||||||
return true;
|
m_WatchNumbers[i] == ANY_TRAP)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -53,6 +55,8 @@ bool MemAccessListener::isMatching(const MemAccessEvent* pEv) const
|
|||||||
&& (m_WatchAddr >= pEv->getTriggerAddress() + pEv->getTriggerWidth()
|
&& (m_WatchAddr >= pEv->getTriggerAddress() + pEv->getTriggerWidth()
|
||||||
|| m_WatchAddr + m_WatchWidth <= pEv->getTriggerAddress())) {
|
|| m_WatchAddr + m_WatchWidth <= pEv->getTriggerAddress())) {
|
||||||
return false;
|
return false;
|
||||||
|
} else if (m_CPU != NULL && m_CPU != pEv->getTriggerCPU()) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -74,6 +78,9 @@ bool BPRangeListener::isMatching(const BPEvent* pEv) const
|
|||||||
{
|
{
|
||||||
if (!aspaceIsMatching(pEv->getAddressSpace()))
|
if (!aspaceIsMatching(pEv->getAddressSpace()))
|
||||||
return false;
|
return false;
|
||||||
|
if (m_CPU != NULL && m_CPU != pEv->getTriggerCPU()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if ((m_WatchStartAddr != ANY_ADDR && pEv->getTriggerInstructionPointer() < m_WatchStartAddr) ||
|
if ((m_WatchStartAddr != ANY_ADDR && pEv->getTriggerInstructionPointer() < m_WatchStartAddr) ||
|
||||||
(m_WatchEndAddr != ANY_ADDR && pEv->getTriggerInstructionPointer() > m_WatchEndAddr))
|
(m_WatchEndAddr != ANY_ADDR && pEv->getTriggerInstructionPointer() > m_WatchEndAddr))
|
||||||
return false;
|
return false;
|
||||||
@ -83,8 +90,10 @@ bool BPRangeListener::isMatching(const BPEvent* pEv) const
|
|||||||
bool BPSingleListener::isMatching(const BPEvent* pEv) const
|
bool BPSingleListener::isMatching(const BPEvent* pEv) const
|
||||||
{
|
{
|
||||||
if (aspaceIsMatching(pEv->getAddressSpace())) {
|
if (aspaceIsMatching(pEv->getAddressSpace())) {
|
||||||
if (m_WatchInstrPtr == ANY_ADDR || m_WatchInstrPtr == pEv->getTriggerInstructionPointer())
|
if (m_CPU == NULL || m_CPU == pEv->getTriggerCPU()) {
|
||||||
return true;
|
if (m_WatchInstrPtr == ANY_ADDR || m_WatchInstrPtr == pEv->getTriggerInstructionPointer())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "SALConfig.hpp"
|
#include "SALConfig.hpp"
|
||||||
#include "Event.hpp"
|
#include "Event.hpp"
|
||||||
|
#include "ConcreteCPU.hpp"
|
||||||
#include "perf/BufferInterface.hpp"
|
#include "perf/BufferInterface.hpp"
|
||||||
|
|
||||||
namespace fail {
|
namespace fail {
|
||||||
@ -26,9 +27,11 @@ protected:
|
|||||||
ExperimentFlow* m_Parent; //!< this listener belongs to experiment m_Parent
|
ExperimentFlow* m_Parent; //!< this listener belongs to experiment m_Parent
|
||||||
index_t m_Loc; //!< location of this listener object within the buffer-list
|
index_t m_Loc; //!< location of this listener object within the buffer-list
|
||||||
PerfBufferBase* m_Home; //!< ptr to performance buffer-list impl. or NULL of not existing
|
PerfBufferBase* m_Home; //!< ptr to performance buffer-list impl. or NULL of not existing
|
||||||
|
ConcreteCPU* m_CPU; //!< this listener should only fire for events from this cpu (all cpus if NULL)
|
||||||
public:
|
public:
|
||||||
BaseListener()
|
BaseListener(ConcreteCPU* cpu = NULL)
|
||||||
: m_OccCounter(1), m_OccCounterInit(1), m_Parent(NULL), m_Loc(INVALID_INDEX), m_Home(NULL)
|
: m_OccCounter(1), m_OccCounterInit(1), m_Parent(NULL), m_Loc(INVALID_INDEX), m_Home(NULL),
|
||||||
|
m_CPU(cpu)
|
||||||
{ }
|
{ }
|
||||||
virtual ~BaseListener();
|
virtual ~BaseListener();
|
||||||
/**
|
/**
|
||||||
@ -95,6 +98,15 @@ public:
|
|||||||
* @param pFlow the new parent ptr or \c NULL (= unknown identity)
|
* @param pFlow the new parent ptr or \c NULL (= unknown identity)
|
||||||
*/
|
*/
|
||||||
void setParent(ExperimentFlow* pFlow) { m_Parent = pFlow; }
|
void setParent(ExperimentFlow* pFlow) { m_Parent = pFlow; }
|
||||||
|
/**
|
||||||
|
* Returns the CPU for which the listener should fire it's events. Can be \c NULL for any cpu.
|
||||||
|
*/
|
||||||
|
ConcreteCPU* getCPU() const { return m_CPU; }
|
||||||
|
/**
|
||||||
|
* Sets the CPU for which the listener should fire it's events. \c Null can be used as a
|
||||||
|
* wildcard.
|
||||||
|
*/
|
||||||
|
void setCPU(ConcreteCPU* cpu) { m_CPU = cpu; }
|
||||||
/**
|
/**
|
||||||
* Sets the location of this listener within the buffer-list (which itself
|
* Sets the location of this listener within the buffer-list (which itself
|
||||||
* part of the buffer-list).
|
* part of the buffer-list).
|
||||||
@ -146,8 +158,8 @@ public:
|
|||||||
* ANY_ADDR can be used as a placeholder to allow debugging
|
* ANY_ADDR can be used as a placeholder to allow debugging
|
||||||
* in a random address space.
|
* in a random address space.
|
||||||
*/
|
*/
|
||||||
BPListener(address_t address_space = ANY_ADDR)
|
BPListener(address_t address_space = ANY_ADDR, ConcreteCPU* cpu = NULL)
|
||||||
: m_Data(ANY_ADDR, address_space) { }
|
: BaseListener(cpu), m_Data(ANY_ADDR, address_space) { }
|
||||||
/**
|
/**
|
||||||
* Returns the address space register of this listener.
|
* Returns the address space register of this listener.
|
||||||
*/
|
*/
|
||||||
@ -160,6 +172,14 @@ public:
|
|||||||
* Checks whether a given address space is matching.
|
* Checks whether a given address space is matching.
|
||||||
*/
|
*/
|
||||||
bool aspaceIsMatching(address_t address_space = ANY_ADDR) const;
|
bool aspaceIsMatching(address_t address_space = ANY_ADDR) const;
|
||||||
|
/**
|
||||||
|
* Sets the CPU that triggered this listener. Should not be used by experiment code.
|
||||||
|
*/
|
||||||
|
void setTriggerCPU(ConcreteCPU* cpu) { m_Data.setTriggerCPU(cpu); }
|
||||||
|
/**
|
||||||
|
* Returns the CPU that triggered this listener.
|
||||||
|
*/
|
||||||
|
ConcreteCPU* getTriggerCPU() { return m_Data.getTriggerCPU(); }
|
||||||
/**
|
/**
|
||||||
* Returns the instruction pointer that triggered this listener.
|
* Returns the instruction pointer that triggered this listener.
|
||||||
*/
|
*/
|
||||||
@ -194,8 +214,8 @@ public:
|
|||||||
* @param address_space the address space to be oberserved.
|
* @param address_space the address space to be oberserved.
|
||||||
* \see BPListener
|
* \see BPListener
|
||||||
*/
|
*/
|
||||||
BPSingleListener(address_t ip = 0, address_t address_space = ANY_ADDR)
|
BPSingleListener(address_t ip = 0, address_t address_space = ANY_ADDR, ConcreteCPU* cpu = NULL)
|
||||||
: BPListener(address_space), m_WatchInstrPtr(ip) { }
|
: BPListener(address_space, cpu), m_WatchInstrPtr(ip) { }
|
||||||
/**
|
/**
|
||||||
* Returns the instruction pointer this listener waits for.
|
* Returns the instruction pointer this listener waits for.
|
||||||
* @return the instruction pointer specified in the constructor or by
|
* @return the instruction pointer specified in the constructor or by
|
||||||
@ -230,8 +250,10 @@ public:
|
|||||||
* ANY_ADDR denotes the lower respectively the upper end of the address
|
* ANY_ADDR denotes the lower respectively the upper end of the address
|
||||||
* space.
|
* space.
|
||||||
*/
|
*/
|
||||||
BPRangeListener(address_t start = 0, address_t end = 0, address_t address_space = ANY_ADDR)
|
BPRangeListener(address_t start = 0, address_t end = 0, address_t address_space = ANY_ADDR,
|
||||||
: BPListener(address_space), m_WatchStartAddr(start), m_WatchEndAddr(end) { }
|
ConcreteCPU* cpu = NULL)
|
||||||
|
: BPListener(address_space, cpu), m_WatchStartAddr(start), m_WatchEndAddr(end)
|
||||||
|
{ }
|
||||||
/**
|
/**
|
||||||
* Returns the instruction pointer watch range of this listener.
|
* Returns the instruction pointer watch range of this listener.
|
||||||
* @return the listener's range
|
* @return the listener's range
|
||||||
@ -272,11 +294,13 @@ protected:
|
|||||||
MemAccessEvent::access_type_t m_WatchType;
|
MemAccessEvent::access_type_t m_WatchType;
|
||||||
MemAccessEvent m_Data;
|
MemAccessEvent m_Data;
|
||||||
public:
|
public:
|
||||||
MemAccessListener(MemAccessEvent::access_type_t type = MemAccessEvent::MEM_READWRITE)
|
MemAccessListener(MemAccessEvent::access_type_t type = MemAccessEvent::MEM_READWRITE,
|
||||||
: m_WatchAddr(ANY_ADDR), m_WatchWidth(1), m_WatchType(type) { }
|
ConcreteCPU* cpu = NULL)
|
||||||
|
: BaseListener(cpu), m_WatchAddr(ANY_ADDR), m_WatchWidth(1), m_WatchType(type) { }
|
||||||
MemAccessListener(address_t addr,
|
MemAccessListener(address_t addr,
|
||||||
MemAccessEvent::access_type_t type = MemAccessEvent::MEM_READWRITE)
|
MemAccessEvent::access_type_t type = MemAccessEvent::MEM_READWRITE,
|
||||||
: m_WatchAddr(addr), m_WatchWidth(1), m_WatchType(type) { }
|
ConcreteCPU* cpu = NULL)
|
||||||
|
: BaseListener(cpu), m_WatchAddr(addr), m_WatchWidth(1), m_WatchType(type) { }
|
||||||
/**
|
/**
|
||||||
* Returns the physical memory address to be observed.
|
* Returns the physical memory address to be observed.
|
||||||
*/
|
*/
|
||||||
@ -293,6 +317,14 @@ public:
|
|||||||
* Sets the width of the memory area being watched (defaults to 1).
|
* Sets the width of the memory area being watched (defaults to 1).
|
||||||
*/
|
*/
|
||||||
void setWatchWidth(size_t width) { m_WatchWidth = width; }
|
void setWatchWidth(size_t width) { m_WatchWidth = width; }
|
||||||
|
/**
|
||||||
|
* Sets the CPU that triggered this listener. Should not be used by experiment code.
|
||||||
|
*/
|
||||||
|
void setTriggerCPU(ConcreteCPU* cpu) { m_Data.setTriggerCPU(cpu); }
|
||||||
|
/**
|
||||||
|
* Returns the CPU that triggered this listener.
|
||||||
|
*/
|
||||||
|
ConcreteCPU* getTriggerCPU() { return m_Data.getTriggerCPU(); }
|
||||||
/**
|
/**
|
||||||
* Returns the specific physical memory address that actually triggered the
|
* Returns the specific physical memory address that actually triggered the
|
||||||
* listener.
|
* listener.
|
||||||
@ -351,10 +383,10 @@ public:
|
|||||||
*/
|
*/
|
||||||
class MemReadListener : public MemAccessListener {
|
class MemReadListener : public MemAccessListener {
|
||||||
public:
|
public:
|
||||||
MemReadListener()
|
MemReadListener(ConcreteCPU* cpu = NULL)
|
||||||
: MemAccessListener(MemAccessEvent::MEM_READ) { }
|
: MemAccessListener(MemAccessEvent::MEM_READ, cpu) { }
|
||||||
MemReadListener(address_t addr)
|
MemReadListener(address_t addr, ConcreteCPU* cpu = NULL)
|
||||||
: MemAccessListener(addr, MemAccessEvent::MEM_READ) { }
|
: MemAccessListener(addr, MemAccessEvent::MEM_READ, cpu) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -363,10 +395,10 @@ public:
|
|||||||
*/
|
*/
|
||||||
class MemWriteListener : public MemAccessListener {
|
class MemWriteListener : public MemAccessListener {
|
||||||
public:
|
public:
|
||||||
MemWriteListener()
|
MemWriteListener(ConcreteCPU* cpu = NULL)
|
||||||
: MemAccessListener(MemAccessEvent::MEM_READ) { }
|
: MemAccessListener(MemAccessEvent::MEM_READ, cpu) { }
|
||||||
MemWriteListener(address_t addr)
|
MemWriteListener(address_t addr, ConcreteCPU* cpu = NULL)
|
||||||
: MemAccessListener(addr, MemAccessEvent::MEM_WRITE) { }
|
: MemAccessListener(addr, MemAccessEvent::MEM_WRITE, cpu) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -382,8 +414,9 @@ protected:
|
|||||||
*/
|
*/
|
||||||
std::vector<unsigned> m_WatchNumbers;
|
std::vector<unsigned> m_WatchNumbers;
|
||||||
public:
|
public:
|
||||||
TroubleListener() { }
|
TroubleListener(ConcreteCPU* cpu = NULL) : BaseListener(cpu) { }
|
||||||
TroubleListener(unsigned troubleNumber) { addWatchNumber(troubleNumber); }
|
TroubleListener(unsigned troubleNumber, ConcreteCPU* cpu = NULL) : BaseListener(cpu)
|
||||||
|
{ addWatchNumber(troubleNumber); }
|
||||||
/**
|
/**
|
||||||
* Add an interrupt/trap-number which should be observed.
|
* Add an interrupt/trap-number which should be observed.
|
||||||
* @param troubleNumber number of an interrupt or trap
|
* @param troubleNumber number of an interrupt or trap
|
||||||
@ -408,6 +441,14 @@ public:
|
|||||||
* Checks whether a given interrupt-/trap-number is matching.
|
* Checks whether a given interrupt-/trap-number is matching.
|
||||||
*/
|
*/
|
||||||
bool isMatching(const TroubleEvent* pEv) const;
|
bool isMatching(const TroubleEvent* pEv) const;
|
||||||
|
/**
|
||||||
|
* Sets the CPU that triggered this listener. Should not be used by experiment code.
|
||||||
|
*/
|
||||||
|
void setTriggerCPU(ConcreteCPU* cpu) { m_Data.setTriggerCPU(cpu); }
|
||||||
|
/**
|
||||||
|
* Returns the CPU that triggered this listener.
|
||||||
|
*/
|
||||||
|
ConcreteCPU* getTriggerCPU() { return m_Data.getTriggerCPU(); }
|
||||||
/**
|
/**
|
||||||
* Sets the specific interrupt-/trap-number that actually triggered
|
* Sets the specific interrupt-/trap-number that actually triggered
|
||||||
* the listener. Should not be used by experiment code.
|
* the listener. Should not be used by experiment code.
|
||||||
@ -428,8 +469,9 @@ class InterruptListener : public TroubleListener {
|
|||||||
protected:
|
protected:
|
||||||
InterruptEvent m_Data; //!< event related data, e.g. NMI flag
|
InterruptEvent m_Data; //!< event related data, e.g. NMI flag
|
||||||
public:
|
public:
|
||||||
InterruptListener() { }
|
InterruptListener(ConcreteCPU* cpu = NULL) : TroubleListener(cpu) { }
|
||||||
InterruptListener(unsigned interrupt) { addWatchNumber(interrupt); }
|
InterruptListener(unsigned interrupt, ConcreteCPU* cpu = NULL) : TroubleListener(cpu)
|
||||||
|
{ addWatchNumber(interrupt); }
|
||||||
/**
|
/**
|
||||||
* Returns \c true if the interrupt is non maskable, \c false otherwise.
|
* Returns \c true if the interrupt is non maskable, \c false otherwise.
|
||||||
*/
|
*/
|
||||||
@ -446,8 +488,9 @@ public:
|
|||||||
*/
|
*/
|
||||||
class TrapListener : public TroubleListener {
|
class TrapListener : public TroubleListener {
|
||||||
public:
|
public:
|
||||||
TrapListener() { }
|
TrapListener(ConcreteCPU* cpu = NULL) : TroubleListener(cpu) { }
|
||||||
TrapListener(unsigned trap) { addWatchNumber(trap); }
|
TrapListener(unsigned trap, ConcreteCPU* cpu = NULL) : TroubleListener(cpu)
|
||||||
|
{ addWatchNumber(trap); }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -498,7 +541,8 @@ public:
|
|||||||
* \arg \c true Output on the given port is captured.
|
* \arg \c true Output on the given port is captured.
|
||||||
* \arg \c false Input on the given port is captured.
|
* \arg \c false Input on the given port is captured.
|
||||||
*/
|
*/
|
||||||
IOPortListener(unsigned port, bool out) : m_Port(port), m_Out(out) { }
|
IOPortListener(unsigned port, bool out, ConcreteCPU* cpu = NULL)
|
||||||
|
: BaseListener(cpu), m_Port(port), m_Out(out) { }
|
||||||
/**
|
/**
|
||||||
* Returns the data sent to the specified port
|
* Returns the data sent to the specified port
|
||||||
*/
|
*/
|
||||||
@ -515,6 +559,14 @@ public:
|
|||||||
* Sets the port which this listener is bound to.
|
* Sets the port which this listener is bound to.
|
||||||
*/
|
*/
|
||||||
void setPort(unsigned port) { m_Port = port; }
|
void setPort(unsigned port) { m_Port = port; }
|
||||||
|
/**
|
||||||
|
* Sets the CPU that triggered this listener. Should not be used by experiment code.
|
||||||
|
*/
|
||||||
|
void setTriggerCPU(ConcreteCPU* cpu) { m_Data.setTriggerCPU(cpu); }
|
||||||
|
/**
|
||||||
|
* Returns the CPU that triggered this listener.
|
||||||
|
*/
|
||||||
|
ConcreteCPU* getTriggerCPU() { return m_Data.getTriggerCPU(); }
|
||||||
/**
|
/**
|
||||||
* Checks whether a given port number is matching.
|
* Checks whether a given port number is matching.
|
||||||
* @param p The port number an I/O listener occured on
|
* @param p The port number an I/O listener occured on
|
||||||
@ -547,11 +599,20 @@ public:
|
|||||||
* @param opcode the opcode of the jump-instruction to be observed
|
* @param opcode the opcode of the jump-instruction to be observed
|
||||||
* or \c ANY_INSTR to match all jump-instructions
|
* or \c ANY_INSTR to match all jump-instructions
|
||||||
*/
|
*/
|
||||||
JumpListener(unsigned opcode = ANY_INSTR) : m_Data(opcode) { }
|
JumpListener(unsigned opcode = ANY_INSTR, ConcreteCPU* cpu = NULL)
|
||||||
|
: BaseListener(cpu), m_Data(opcode) { }
|
||||||
/**
|
/**
|
||||||
* Retrieves the opcode of the jump-instruction.
|
* Retrieves the opcode of the jump-instruction.
|
||||||
*/
|
*/
|
||||||
unsigned getOpcode() const { return m_Data.getTriggerOpcode(); }
|
unsigned getOpcode() const { return m_Data.getTriggerOpcode(); }
|
||||||
|
/**
|
||||||
|
* Sets the CPU that triggered this listener. Should not be used by experiment code.
|
||||||
|
*/
|
||||||
|
void setTriggerCPU(ConcreteCPU* cpu) { m_Data.setTriggerCPU(cpu); }
|
||||||
|
/**
|
||||||
|
* Returns the CPU that triggered this listener.
|
||||||
|
*/
|
||||||
|
ConcreteCPU* getTriggerCPU() { return m_Data.getTriggerCPU(); }
|
||||||
/**
|
/**
|
||||||
* Returns \c true, if the listener was triggered due to specific register
|
* Returns \c true, if the listener was triggered due to specific register
|
||||||
* content, \c false otherwise.
|
* content, \c false otherwise.
|
||||||
|
|||||||
@ -8,25 +8,6 @@ Register* UniformRegisterSet::getRegister(size_t i)
|
|||||||
return m_Regs[i];
|
return m_Regs[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
Register* RegisterManager::getRegister(size_t i)
|
|
||||||
{
|
|
||||||
assert(i < m_Registers.size() && "FATAL ERROR: Invalid index provided!");
|
|
||||||
return m_Registers[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegisterManager::add(Register* reg)
|
|
||||||
{
|
|
||||||
assert(!reg->isAssigned() && "FATAL ERROR: The register is already assigned!");
|
|
||||||
m_Registers.push_back(reg);
|
|
||||||
|
|
||||||
UniformRegisterSet* urs = getSetOfType(reg->getType());
|
|
||||||
if (urs == NULL) {
|
|
||||||
urs = new UniformRegisterSet(reg->getType());
|
|
||||||
m_Subsets.push_back(urs);
|
|
||||||
}
|
|
||||||
urs->m_add(reg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void UniformRegisterSet::m_add(Register* preg)
|
void UniformRegisterSet::m_add(Register* preg)
|
||||||
{
|
{
|
||||||
assert(!preg->m_Assigned &&
|
assert(!preg->m_Assigned &&
|
||||||
@ -36,33 +17,4 @@ void UniformRegisterSet::m_add(Register* preg)
|
|||||||
preg->m_Index = m_Regs.size()-1; // the index within the vector (set)
|
preg->m_Index = m_Regs.size()-1; // the index within the vector (set)
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t RegisterManager::count() const
|
|
||||||
{
|
|
||||||
return m_Registers.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
UniformRegisterSet& RegisterManager::getSet(size_t i)
|
|
||||||
{
|
|
||||||
assert(i < m_Subsets.size() && "FATAL ERROR: Invalid index provided!");
|
|
||||||
return *m_Subsets[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
UniformRegisterSet* RegisterManager::getSetOfType(RegisterType t)
|
|
||||||
{
|
|
||||||
for (std::vector< UniformRegisterSet* >::iterator it = m_Subsets.begin();
|
|
||||||
it != m_Subsets.end(); it++) {
|
|
||||||
if((*it)->getType() == t)
|
|
||||||
return *it;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegisterManager::clear()
|
|
||||||
{
|
|
||||||
for (std::vector< UniformRegisterSet* >::iterator it = m_Subsets.begin();
|
|
||||||
it != m_Subsets.end(); it++)
|
|
||||||
delete (*it);
|
|
||||||
m_Subsets.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end-of-namespace: fail
|
} // end-of-namespace: fail
|
||||||
|
|||||||
@ -20,7 +20,8 @@ namespace fail {
|
|||||||
*/
|
*/
|
||||||
enum RegisterType {
|
enum RegisterType {
|
||||||
RT_GP, //!< general purpose
|
RT_GP, //!< general purpose
|
||||||
RT_PC, //!< program counter / instruction pointer
|
RT_FP, //!< floating point register
|
||||||
|
RT_IP, //!< program counter / instruction pointer
|
||||||
RT_ST //!< status register
|
RT_ST //!< status register
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -61,17 +62,6 @@ public:
|
|||||||
* @return the width in bits
|
* @return the width in bits
|
||||||
*/
|
*/
|
||||||
regwidth_t getWidth() const { return m_Width; }
|
regwidth_t getWidth() const { return m_Width; }
|
||||||
/**
|
|
||||||
* Returns the data referenced by this register. In a concrete
|
|
||||||
* derived class this method has to be defined appropriately.
|
|
||||||
* @return the current data
|
|
||||||
*/
|
|
||||||
virtual regdata_t getData() /*!const*/ = 0;
|
|
||||||
/**
|
|
||||||
* Sets new data to be stored in this register.
|
|
||||||
* @param data the data to be written to the register
|
|
||||||
*/
|
|
||||||
virtual void setData(regdata_t data) = 0;
|
|
||||||
/**
|
/**
|
||||||
* Sets the (optional) name of this register.
|
* Sets the (optional) name of this register.
|
||||||
* @param name the textual register name, e.g. "EAX"
|
* @param name the textual register name, e.g. "EAX"
|
||||||
@ -116,7 +106,7 @@ private:
|
|||||||
std::vector< Register* > m_Regs; //!< the unique set of registers
|
std::vector< Register* > m_Regs; //!< the unique set of registers
|
||||||
RegisterType m_Type; //!< the overall type of this container (set)
|
RegisterType m_Type; //!< the overall type of this container (set)
|
||||||
void m_add(Register* preg);
|
void m_add(Register* preg);
|
||||||
friend class RegisterManager;
|
friend class CPUArchitecture;
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* The iterator of this class used to loop through the list of
|
* The iterator of this class used to loop through the list of
|
||||||
@ -171,104 +161,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual Register* first() { return getRegister(0); }
|
virtual Register* first() { return getRegister(0); }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* \class RegisterManager
|
|
||||||
* Represents a complete set of (inhomogeneous) registers specific to a concrete
|
|
||||||
* architecture, e.g. x86 or ARM.
|
|
||||||
*/
|
|
||||||
class RegisterManager {
|
|
||||||
protected:
|
|
||||||
std::vector< Register* > m_Registers;
|
|
||||||
//!< the managed set of homogeneous sets
|
|
||||||
std::vector< UniformRegisterSet* > m_Subsets;
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* The iterator of this class used to loop through the list of
|
|
||||||
* added registers. To retrieve an iterator to the first element, call
|
|
||||||
* begin(). end() returns the iterator, pointing after the last element.
|
|
||||||
* (This behaviour equals the STL iterator in C++.)
|
|
||||||
*/
|
|
||||||
typedef std::vector< Register* >::iterator iterator;
|
|
||||||
/**
|
|
||||||
* Returns an iterator to the beginning of the internal data structure.
|
|
||||||
* \code
|
|
||||||
* [1|2| ... |n]
|
|
||||||
* ^
|
|
||||||
* \endcode
|
|
||||||
*/
|
|
||||||
iterator begin() { return m_Registers.begin(); }
|
|
||||||
/**
|
|
||||||
* Returns an iterator to the end of the interal data structure.
|
|
||||||
* \code
|
|
||||||
* [1|2| ... |n]X
|
|
||||||
* ^
|
|
||||||
* \endcode
|
|
||||||
*/
|
|
||||||
iterator end() { return m_Registers.end(); }
|
|
||||||
|
|
||||||
RegisterManager() { }
|
|
||||||
~RegisterManager() { clear(); }
|
|
||||||
/**
|
|
||||||
* Retrieves the total number of registers over all homogeneous sets.
|
|
||||||
* @return the total register count
|
|
||||||
*/
|
|
||||||
virtual size_t count() const;
|
|
||||||
/**
|
|
||||||
* Retrieves the number of managed homogeneous register sets.
|
|
||||||
* @return the number of sets
|
|
||||||
*/
|
|
||||||
virtual size_t subsetCount() const { return m_Subsets.size(); }
|
|
||||||
/**
|
|
||||||
* Gets the \a i-th register set.
|
|
||||||
* @param i the index of the set to be returned
|
|
||||||
* @return a reference to the uniform register set
|
|
||||||
* @see subsetCount()
|
|
||||||
*/
|
|
||||||
virtual UniformRegisterSet& getSet(size_t i);
|
|
||||||
/**
|
|
||||||
* Returns the set with register type \a t. The set can be used to
|
|
||||||
* loop over all registers of type \a t.
|
|
||||||
* @param t the type to check for
|
|
||||||
* @return a pointer to the retrieved register set (if found), NULL
|
|
||||||
* otherwise
|
|
||||||
*/
|
|
||||||
virtual UniformRegisterSet* getSetOfType(RegisterType t);
|
|
||||||
/**
|
|
||||||
* Adds a new register to this set. The register object needs to be
|
|
||||||
* typed (see Register::getType).
|
|
||||||
* @param reg a pointer to the register object to be added
|
|
||||||
* @see getType()
|
|
||||||
*/
|
|
||||||
void add(Register* reg);
|
|
||||||
/**
|
|
||||||
* Retrieves the \a i-th register.
|
|
||||||
* @return a pointer to the \a i-th register; if \a i is invalid, an
|
|
||||||
* assertion is thrown
|
|
||||||
*/
|
|
||||||
Register* getRegister(size_t i);
|
|
||||||
/**
|
|
||||||
* Removes all registers and sets from the RegisterManager.
|
|
||||||
*/
|
|
||||||
virtual void clear();
|
|
||||||
/**
|
|
||||||
* Returns the current instruction pointer.
|
|
||||||
* @return the current eip
|
|
||||||
*/
|
|
||||||
virtual address_t getInstructionPointer() = 0;
|
|
||||||
/**
|
|
||||||
* Returns the top address of the stack.
|
|
||||||
* @return the starting address of the stack
|
|
||||||
*/
|
|
||||||
virtual address_t getStackPointer() = 0;
|
|
||||||
/**
|
|
||||||
* Retrieves the base ptr (holding the address of the
|
|
||||||
* current stack frame).
|
|
||||||
* @return the base pointer
|
|
||||||
*/
|
|
||||||
virtual address_t getBasePointer() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // end-of-namespace: fail
|
} // end-of-namespace: fail
|
||||||
|
|
||||||
#endif // __REGISTER_HPP__
|
#endif // __REGISTER_HPP__
|
||||||
|
|||||||
@ -7,8 +7,6 @@ namespace fail {
|
|||||||
|
|
||||||
// External reference declared in SALInst.hpp
|
// External reference declared in SALInst.hpp
|
||||||
ConcreteSimulatorController simulator;
|
ConcreteSimulatorController simulator;
|
||||||
// FIXME: Bochs specific? If not, at least get rid of this global variable.
|
|
||||||
int interrupt_to_fire = -1;
|
|
||||||
|
|
||||||
bool SimulatorController::addListener(BaseListener* li)
|
bool SimulatorController::addListener(BaseListener* li)
|
||||||
{
|
{
|
||||||
@ -52,15 +50,16 @@ void SimulatorController::initExperiments()
|
|||||||
/* empty. */
|
/* empty. */
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulatorController::onBreakpoint(address_t instrPtr, address_t address_space)
|
void SimulatorController::onBreakpoint(ConcreteCPU* cpu, address_t instrPtr, address_t address_space)
|
||||||
{
|
{
|
||||||
// Check for active breakpoint-events:
|
// Check for active breakpoint-events:
|
||||||
ListenerManager::iterator it = m_LstList.begin();
|
ListenerManager::iterator it = m_LstList.begin();
|
||||||
BPEvent tmp(instrPtr, address_space);
|
BPEvent tmp(instrPtr, address_space, cpu);
|
||||||
while (it != m_LstList.end()) {
|
while (it != m_LstList.end()) {
|
||||||
BaseListener* pLi = *it;
|
BaseListener* pLi = *it;
|
||||||
BPListener* pBreakpt = dynamic_cast<BPListener*>(pLi);
|
BPListener* pBreakpt = dynamic_cast<BPListener*>(pLi);
|
||||||
if (pBreakpt != NULL && pBreakpt->isMatching(&tmp)) {
|
if (pBreakpt != NULL && pBreakpt->isMatching(&tmp)) {
|
||||||
|
pBreakpt->setTriggerCPU(cpu);
|
||||||
pBreakpt->setTriggerInstructionPointer(instrPtr);
|
pBreakpt->setTriggerInstructionPointer(instrPtr);
|
||||||
it = m_LstList.makeActive(it);
|
it = m_LstList.makeActive(it);
|
||||||
// "it" has already been set to the next element (by calling
|
// "it" has already been set to the next element (by calling
|
||||||
@ -72,14 +71,14 @@ void SimulatorController::onBreakpoint(address_t instrPtr, address_t address_spa
|
|||||||
m_LstList.triggerActiveListeners();
|
m_LstList.triggerActiveListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulatorController::onMemoryAccess(address_t addr, size_t len,
|
void SimulatorController::onMemoryAccess(ConcreteCPU* cpu, address_t addr, size_t len,
|
||||||
bool is_write, address_t instrPtr)
|
bool is_write, address_t instrPtr)
|
||||||
{
|
{
|
||||||
MemAccessEvent::access_type_t accesstype =
|
MemAccessEvent::access_type_t accesstype =
|
||||||
is_write ? MemAccessEvent::MEM_WRITE
|
is_write ? MemAccessEvent::MEM_WRITE
|
||||||
: MemAccessEvent::MEM_READ;
|
: MemAccessEvent::MEM_READ;
|
||||||
|
|
||||||
MemAccessEvent tmp(addr, len, instrPtr, accesstype);
|
MemAccessEvent tmp(addr, len, instrPtr, accesstype, cpu);
|
||||||
ListenerManager::iterator it = m_LstList.begin();
|
ListenerManager::iterator it = m_LstList.begin();
|
||||||
while (it != m_LstList.end()) { // check for active listeners
|
while (it != m_LstList.end()) { // check for active listeners
|
||||||
BaseListener* pev = *it;
|
BaseListener* pev = *it;
|
||||||
@ -93,15 +92,16 @@ void SimulatorController::onMemoryAccess(address_t addr, size_t len,
|
|||||||
ev->setTriggerWidth(len);
|
ev->setTriggerWidth(len);
|
||||||
ev->setTriggerInstructionPointer(instrPtr);
|
ev->setTriggerInstructionPointer(instrPtr);
|
||||||
ev->setTriggerAccessType(accesstype);
|
ev->setTriggerAccessType(accesstype);
|
||||||
|
ev->setTriggerCPU(cpu);
|
||||||
it = m_LstList.makeActive(it);
|
it = m_LstList.makeActive(it);
|
||||||
}
|
}
|
||||||
m_LstList.triggerActiveListeners();
|
m_LstList.triggerActiveListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulatorController::onInterrupt(unsigned interruptNum, bool nmi)
|
void SimulatorController::onInterrupt(ConcreteCPU* cpu, unsigned interruptNum, bool nmi)
|
||||||
{
|
{
|
||||||
ListenerManager::iterator it = m_LstList.begin();
|
ListenerManager::iterator it = m_LstList.begin();
|
||||||
InterruptEvent tmp(nmi, interruptNum);
|
InterruptEvent tmp(nmi, interruptNum, cpu);
|
||||||
while (it != m_LstList.end()) { // check for active listeners
|
while (it != m_LstList.end()) { // check for active listeners
|
||||||
BaseListener* pev = *it;
|
BaseListener* pev = *it;
|
||||||
InterruptListener* pie = dynamic_cast<InterruptListener*>(pev);
|
InterruptListener* pie = dynamic_cast<InterruptListener*>(pev);
|
||||||
@ -111,53 +111,15 @@ void SimulatorController::onInterrupt(unsigned interruptNum, bool nmi)
|
|||||||
}
|
}
|
||||||
pie->setTriggerNumber(interruptNum);
|
pie->setTriggerNumber(interruptNum);
|
||||||
pie->setNMI(nmi);
|
pie->setNMI(nmi);
|
||||||
|
pie->setTriggerCPU(cpu);
|
||||||
it = m_LstList.makeActive(it);
|
it = m_LstList.makeActive(it);
|
||||||
}
|
}
|
||||||
m_LstList.triggerActiveListeners();
|
m_LstList.triggerActiveListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SimulatorController::isSuppressedInterrupt(unsigned interruptNum)
|
void SimulatorController::onTrap(ConcreteCPU* cpu, unsigned trapNum)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < m_SuppressedInterrupts.size(); i++)
|
TroubleEvent tmp(trapNum, cpu);
|
||||||
if ((m_SuppressedInterrupts[i] == interruptNum ||
|
|
||||||
m_SuppressedInterrupts[i] == ANY_INTERRUPT) &&
|
|
||||||
interruptNum != (unsigned)interrupt_to_fire + 32) {
|
|
||||||
if ((int)interruptNum == interrupt_to_fire + 32) {
|
|
||||||
interrupt_to_fire = -1;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SimulatorController::addSuppressedInterrupt(unsigned interruptNum)
|
|
||||||
{
|
|
||||||
// Check if already existing:
|
|
||||||
if (isSuppressedInterrupt(interruptNum+32))
|
|
||||||
return false; // already added: nothing to do here
|
|
||||||
|
|
||||||
if (interruptNum == ANY_INTERRUPT)
|
|
||||||
m_SuppressedInterrupts.push_back(interruptNum);
|
|
||||||
else
|
|
||||||
m_SuppressedInterrupts.push_back(interruptNum+32);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SimulatorController::removeSuppressedInterrupt(unsigned interruptNum)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < m_SuppressedInterrupts.size(); i++) {
|
|
||||||
if (m_SuppressedInterrupts[i] == interruptNum+32 ||
|
|
||||||
m_SuppressedInterrupts[i] == ANY_INTERRUPT)
|
|
||||||
m_SuppressedInterrupts.erase(m_SuppressedInterrupts.begin() + i);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimulatorController::onTrap(unsigned trapNum)
|
|
||||||
{
|
|
||||||
TroubleEvent tmp(trapNum);
|
|
||||||
ListenerManager::iterator it = m_LstList.begin();
|
ListenerManager::iterator it = m_LstList.begin();
|
||||||
while (it != m_LstList.end()) { // check for active listeners
|
while (it != m_LstList.end()) { // check for active listeners
|
||||||
BaseListener* pev = *it;
|
BaseListener* pev = *it;
|
||||||
@ -167,6 +129,7 @@ void SimulatorController::onTrap(unsigned trapNum)
|
|||||||
continue; // skip listener activation
|
continue; // skip listener activation
|
||||||
}
|
}
|
||||||
pte->setTriggerNumber(trapNum);
|
pte->setTriggerNumber(trapNum);
|
||||||
|
pte->setTriggerCPU(cpu);
|
||||||
it = m_LstList.makeActive(it);
|
it = m_LstList.makeActive(it);
|
||||||
}
|
}
|
||||||
m_LstList.triggerActiveListeners();
|
m_LstList.triggerActiveListeners();
|
||||||
@ -189,7 +152,7 @@ void SimulatorController::onGuestSystem(char data, unsigned port)
|
|||||||
m_LstList.triggerActiveListeners();
|
m_LstList.triggerActiveListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulatorController::onJump(bool flagTriggered, unsigned opcode)
|
void SimulatorController::onJump(ConcreteCPU* cpu, bool flagTriggered, unsigned opcode)
|
||||||
{
|
{
|
||||||
ListenerManager::iterator it = m_LstList.begin();
|
ListenerManager::iterator it = m_LstList.begin();
|
||||||
while (it != m_LstList.end()) { // check for active listeners
|
while (it != m_LstList.end()) { // check for active listeners
|
||||||
@ -197,6 +160,7 @@ void SimulatorController::onJump(bool flagTriggered, unsigned opcode)
|
|||||||
if (pje != NULL) {
|
if (pje != NULL) {
|
||||||
pje->setOpcode(opcode);
|
pje->setOpcode(opcode);
|
||||||
pje->setFlagTriggered(flagTriggered);
|
pje->setFlagTriggered(flagTriggered);
|
||||||
|
pje->setTriggerCPU(cpu);
|
||||||
it = m_LstList.makeActive(it);
|
it = m_LstList.makeActive(it);
|
||||||
continue; // dito.
|
continue; // dito.
|
||||||
}
|
}
|
||||||
@ -205,6 +169,19 @@ void SimulatorController::onJump(bool flagTriggered, unsigned opcode)
|
|||||||
m_LstList.triggerActiveListeners();
|
m_LstList.triggerActiveListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SimulatorController::addCPU(ConcreteCPU* cpu)
|
||||||
|
{
|
||||||
|
assert(cpu != NULL && "FATAL ERROR: Argument (cpu) cannot be NULL!");
|
||||||
|
m_CPUs.push_back(cpu);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConcreteCPU& SimulatorController::getCPU(size_t i) const
|
||||||
|
{
|
||||||
|
assert(i < m_CPUs.size() && "FATAL ERROR: Invalid index provided!");
|
||||||
|
return *m_CPUs[i];
|
||||||
|
}
|
||||||
|
|
||||||
void SimulatorController::addFlow(ExperimentFlow* flow)
|
void SimulatorController::addFlow(ExperimentFlow* flow)
|
||||||
{
|
{
|
||||||
// Store the (flow,corohandle)-tuple internally and create its coroutine:
|
// Store the (flow,corohandle)-tuple internally and create its coroutine:
|
||||||
|
|||||||
@ -9,12 +9,12 @@
|
|||||||
#include "efw/CoroutineManager.hpp"
|
#include "efw/CoroutineManager.hpp"
|
||||||
#include "ListenerManager.hpp"
|
#include "ListenerManager.hpp"
|
||||||
#include "SALConfig.hpp"
|
#include "SALConfig.hpp"
|
||||||
|
#include "ConcreteCPU.hpp"
|
||||||
|
|
||||||
namespace fail {
|
namespace fail {
|
||||||
|
|
||||||
// Incomplete types suffice here:
|
// Incomplete types suffice here:
|
||||||
class ExperimentFlow;
|
class ExperimentFlow;
|
||||||
class RegisterManager;
|
|
||||||
class MemoryManager;
|
class MemoryManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,16 +34,23 @@ class SimulatorController {
|
|||||||
protected:
|
protected:
|
||||||
ListenerManager m_LstList; //!< storage where listeners are being buffered
|
ListenerManager m_LstList; //!< storage where listeners are being buffered
|
||||||
CoroutineManager m_Flows; //!< managed experiment flows
|
CoroutineManager m_Flows; //!< managed experiment flows
|
||||||
RegisterManager *m_Regs; //!< access to cpu register
|
|
||||||
MemoryManager *m_Mem; //!< access to memory pool
|
MemoryManager *m_Mem; //!< access to memory pool
|
||||||
std::vector<unsigned> m_SuppressedInterrupts; //!< list of suppressed interrupts
|
std::vector< ConcreteCPU* > m_CPUs; //!< list of cpus in the target system
|
||||||
friend class ListenerManager; //!< "outsources" the listener management
|
friend class ListenerManager; //!< "outsources" the listener management
|
||||||
public:
|
public:
|
||||||
SimulatorController()
|
SimulatorController()
|
||||||
: m_Regs(NULL), m_Mem(NULL) { }
|
: m_Mem(NULL) { }
|
||||||
SimulatorController(RegisterManager* regs, MemoryManager* mem)
|
SimulatorController(MemoryManager* mem)
|
||||||
: m_Regs(regs), m_Mem(mem) { }
|
: m_Mem(mem) { }
|
||||||
virtual ~SimulatorController() { }
|
virtual ~SimulatorController()
|
||||||
|
{
|
||||||
|
std::vector< ConcreteCPU* >::iterator it = m_CPUs.begin();
|
||||||
|
while(it != m_CPUs.end())
|
||||||
|
{
|
||||||
|
delete *it;
|
||||||
|
it = m_CPUs.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* @brief Initialization function each implementation needs to call on
|
* @brief Initialization function each implementation needs to call on
|
||||||
* startup
|
* startup
|
||||||
@ -63,12 +70,14 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Breakpoint handler. This routine needs to be called in the simulator
|
* Breakpoint handler. This routine needs to be called in the simulator
|
||||||
* specific backend each time a breakpoint occurs.
|
* specific backend each time a breakpoint occurs.
|
||||||
|
* @param cpu the CPU that reached the breakpoint
|
||||||
* @param instrPtr the instruction pointer of the breakpoint
|
* @param instrPtr the instruction pointer of the breakpoint
|
||||||
* @param address_space the address space it should occur in
|
* @param address_space the address space it should occur in
|
||||||
*/
|
*/
|
||||||
void onBreakpoint(address_t instrPtr, address_t address_space);
|
void onBreakpoint(ConcreteCPU* cpu, address_t instrPtr, address_t address_space);
|
||||||
/**
|
/**
|
||||||
* Memory access handler (read/write).
|
* Memory access handler (read/write).
|
||||||
|
* @param cpu the CPU that accessed the memory
|
||||||
* @param addr the accessed memory address
|
* @param addr the accessed memory address
|
||||||
* @param len the length of the accessed memory
|
* @param len the length of the accessed memory
|
||||||
* @param is_write \c true if memory is written, \c false if read
|
* @param is_write \c true if memory is written, \c false if read
|
||||||
@ -77,18 +86,20 @@ public:
|
|||||||
*
|
*
|
||||||
* FIXME: should instrPtr be part of this interface?
|
* FIXME: should instrPtr be part of this interface?
|
||||||
*/
|
*/
|
||||||
void onMemoryAccess(address_t addr, size_t len, bool is_write, address_t instrPtr);
|
void onMemoryAccess(ConcreteCPU* cpu, address_t addr, size_t len, bool is_write, address_t instrPtr);
|
||||||
/**
|
/**
|
||||||
* Interrupt handler.
|
* Interrupt handler.
|
||||||
|
* @param cpu the CPU that caused the interrupt
|
||||||
* @param interruptNum the interrupt-type id
|
* @param interruptNum the interrupt-type id
|
||||||
* @param nmi nmi-value from guest-system
|
* @param nmi nmi-value from guest-system
|
||||||
*/
|
*/
|
||||||
void onInterrupt(unsigned interruptNum, bool nmi);
|
void onInterrupt(ConcreteCPU* cpu, unsigned interruptNum, bool nmi);
|
||||||
/**
|
/**
|
||||||
* Trap handler.
|
* Trap handler.
|
||||||
|
* @param cpu the CPU that caused the trap
|
||||||
* @param trapNum the trap-type id
|
* @param trapNum the trap-type id
|
||||||
*/
|
*/
|
||||||
void onTrap(unsigned trapNum);
|
void onTrap(ConcreteCPU* cpu, unsigned trapNum);
|
||||||
/**
|
/**
|
||||||
* Guest system communication handler.
|
* Guest system communication handler.
|
||||||
* @param data the "message" from the guest system
|
* @param data the "message" from the guest system
|
||||||
@ -97,11 +108,12 @@ public:
|
|||||||
void onGuestSystem(char data, unsigned port);
|
void onGuestSystem(char data, unsigned port);
|
||||||
/**
|
/**
|
||||||
* (Conditional) Jump-instruction handler.
|
* (Conditional) Jump-instruction handler.
|
||||||
|
* @param cpu the CPU that did the jump
|
||||||
* @param flagTriggered \c true if the jump was triggered due to a
|
* @param flagTriggered \c true if the jump was triggered due to a
|
||||||
* specific FLAG (zero/carry/sign/overflow/parity flag)
|
* specific FLAG (zero/carry/sign/overflow/parity flag)
|
||||||
* @param opcode the opcode of the conrecete jump instruction
|
* @param opcode the opcode of the conrecete jump instruction
|
||||||
*/
|
*/
|
||||||
void onJump(bool flagTriggered, unsigned opcode);
|
void onJump(ConcreteCPU* cpu, bool flagTriggered, unsigned opcode);
|
||||||
/* ********************************************************************
|
/* ********************************************************************
|
||||||
* Simulator Controller & Access API:
|
* Simulator Controller & Access API:
|
||||||
* ********************************************************************/
|
* ********************************************************************/
|
||||||
@ -127,35 +139,17 @@ public:
|
|||||||
*/
|
*/
|
||||||
void terminate(int exCode = EXIT_SUCCESS) __attribute__ ((noreturn));
|
void terminate(int exCode = EXIT_SUCCESS) __attribute__ ((noreturn));
|
||||||
/**
|
/**
|
||||||
* Check whether the interrupt should be suppressed.
|
* Adds a new CPU to the CPU list. Listener/Events and experiment code can require that all
|
||||||
* @param interruptNum the interrupt-type id
|
* CPUs of the simulated system are added. So it's recommend to add them early in the backend
|
||||||
* @return \c true if the interrupt is suppressed, \c false oterwise
|
* implementation (especially before the experiment code runs).
|
||||||
|
* @param cpu the cpu that should be added to the list
|
||||||
*/
|
*/
|
||||||
bool isSuppressedInterrupt(unsigned interruptNum);
|
bool addCPU(ConcreteCPU* cpu);
|
||||||
/**
|
/**
|
||||||
* Add a Interrupt to the list of suppressed.
|
* Gets the CPU with the provided id.
|
||||||
* @param interruptNum the interrupt-type id
|
* @oaram id the id of the CPU to get
|
||||||
* @return \c true if sucessfully added, \c false otherwise (already
|
|
||||||
* existing)
|
|
||||||
*/
|
*/
|
||||||
bool addSuppressedInterrupt(unsigned interruptNum);
|
ConcreteCPU& getCPU(size_t id) const;
|
||||||
/**
|
|
||||||
* Remove a Interrupt from the list of suppressed.
|
|
||||||
* @param interruptNum the interrupt-type id
|
|
||||||
* @return \c true if sucessfully removed, \c false otherwise (not found)
|
|
||||||
*/
|
|
||||||
bool removeSuppressedInterrupt(unsigned interruptNum);
|
|
||||||
/**
|
|
||||||
* Returns the (constant) initialized register manager.
|
|
||||||
* @return a reference to the register manager
|
|
||||||
*/
|
|
||||||
RegisterManager& getRegisterManager() { return *m_Regs; }
|
|
||||||
const RegisterManager& getRegisterManager() const { return *m_Regs; }
|
|
||||||
/**
|
|
||||||
* Sets the register manager.
|
|
||||||
* @param pReg the new register manager (or a concrete derived class of \c RegisterManager)
|
|
||||||
*/
|
|
||||||
void setRegisterManager(RegisterManager* pReg) { m_Regs = pReg; }
|
|
||||||
/**
|
/**
|
||||||
* Returns the (constant) initialized memory manager.
|
* Returns the (constant) initialized memory manager.
|
||||||
* @return a reference to the memory manager
|
* @return a reference to the memory manager
|
||||||
@ -243,9 +237,6 @@ public:
|
|||||||
void toggle(ExperimentFlow* pfl) { m_Flows.toggle(pfl); }
|
void toggle(ExperimentFlow* pfl) { m_Flows.toggle(pfl); }
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME (see SimulatorController.cc): Weird, homeless global variable
|
|
||||||
extern int interrupt_to_fire;
|
|
||||||
|
|
||||||
} // end-of-namespace: fail
|
} // end-of-namespace: fail
|
||||||
|
|
||||||
#endif // __SIMULATOR_CONTROLLER_HPP__
|
#endif // __SIMULATOR_CONTROLLER_HPP__
|
||||||
|
|||||||
32
src/core/sal/arm/arch.cc
Normal file
32
src/core/sal/arm/arch.cc
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#include "arch.hpp"
|
||||||
|
#include "../Register.hpp"
|
||||||
|
|
||||||
|
namespace fail {
|
||||||
|
|
||||||
|
ArmArchitecture::ArmArchitecture()
|
||||||
|
{
|
||||||
|
fillRegisterList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArmArchitecture::fillRegisterList()
|
||||||
|
{
|
||||||
|
// TODO: Add missing registers
|
||||||
|
// 16x 32-Bit GP Registers
|
||||||
|
for (int i=0; i<16; i++)
|
||||||
|
{
|
||||||
|
Register *reg = new Register(i, RT_GP, 32);
|
||||||
|
addRegister(reg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ArmArchitecture::~ArmArchitecture()
|
||||||
|
{
|
||||||
|
std::vector< Register* >::iterator it = m_Registers.begin();
|
||||||
|
while(it != m_Registers.end())
|
||||||
|
{
|
||||||
|
delete *it;
|
||||||
|
it = m_Registers.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end-of-namespace: fail
|
||||||
87
src/core/sal/arm/arch.hpp
Normal file
87
src/core/sal/arm/arch.hpp
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
#ifndef __ARM_ARCH_HPP__
|
||||||
|
#define __ARM_ARCH_HPP__
|
||||||
|
|
||||||
|
#include "../CPU.hpp"
|
||||||
|
#include "../CPUState.hpp"
|
||||||
|
|
||||||
|
namespace fail {
|
||||||
|
/**
|
||||||
|
* \class ArmArchitecture
|
||||||
|
* This class adds ARM specific functionality to the base architecture. This can be used for every
|
||||||
|
* simulator backend that runs on ARM.
|
||||||
|
*/
|
||||||
|
class ArmArchitecture : public CPUArchitecture
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ArmArchitecture();
|
||||||
|
~ArmArchitecture();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void fillRegisterList();
|
||||||
|
};
|
||||||
|
|
||||||
|
class ArmCPUState : public CPUState
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual regdata_t getRegisterContent(Register* reg) = 0;
|
||||||
|
|
||||||
|
virtual address_t getInstructionPointer() = 0;
|
||||||
|
virtual address_t getStackPointer() = 0;
|
||||||
|
/**
|
||||||
|
* Returns the current Link Register.
|
||||||
|
* @return the current lr
|
||||||
|
*/
|
||||||
|
virtual address_t getLinkRegister() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum GPRegIndex
|
||||||
|
{
|
||||||
|
RI_R0,
|
||||||
|
RI_R1,
|
||||||
|
RI_R2,
|
||||||
|
RI_R3,
|
||||||
|
RI_R4,
|
||||||
|
RI_R5,
|
||||||
|
RI_R6,
|
||||||
|
RI_R7,
|
||||||
|
RI_R8,
|
||||||
|
RI_R9,
|
||||||
|
RI_R10,
|
||||||
|
RI_R11,
|
||||||
|
RI_R12,
|
||||||
|
RI_R13,
|
||||||
|
RI_SP = RI_R13,
|
||||||
|
RI_R14,
|
||||||
|
RI_LR = RI_R14,
|
||||||
|
RI_R15,
|
||||||
|
RI_IP = RI_R15,
|
||||||
|
|
||||||
|
RI_R13_SVC,
|
||||||
|
RI_R14_SVC,
|
||||||
|
|
||||||
|
RI_R13_MON,
|
||||||
|
RI_R14_MON,
|
||||||
|
|
||||||
|
RI_R13_ABT,
|
||||||
|
RI_R14_ABT,
|
||||||
|
|
||||||
|
RI_R13_UND,
|
||||||
|
RI_R14_UND,
|
||||||
|
|
||||||
|
RI_R13_IRQ,
|
||||||
|
RI_R14_IRQ,
|
||||||
|
|
||||||
|
RI_R8_FIQ,
|
||||||
|
RI_R9_FIQ,
|
||||||
|
RI_R10_FIQ,
|
||||||
|
RI_R11_FIQ,
|
||||||
|
RI_R12_FIQ,
|
||||||
|
RI_R13_FIQ,
|
||||||
|
RI_R14_FIQ
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Enum for misc registers
|
||||||
|
|
||||||
|
} // end-of-namespace: fail
|
||||||
|
|
||||||
|
#endif // __ARM_ARCH_HPP__
|
||||||
59
src/core/sal/gem5/Gem5ArmCPU.cc
Normal file
59
src/core/sal/gem5/Gem5ArmCPU.cc
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#include "Gem5ArmCPU.hpp"
|
||||||
|
|
||||||
|
namespace fail {
|
||||||
|
|
||||||
|
regdata_t Gem5ArmCPU::getRegisterContent(Register* reg)
|
||||||
|
{
|
||||||
|
switch (reg->getType()) {
|
||||||
|
case RT_GP:
|
||||||
|
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 getRegisterContent(getRegister(RI_IP));
|
||||||
|
}
|
||||||
|
|
||||||
|
// This shouldn't be reached if a valid register is passed
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
address_t Gem5ArmCPU::getInstructionPointer()
|
||||||
|
{
|
||||||
|
return getRegisterContent(getRegister(RI_IP));
|
||||||
|
}
|
||||||
|
|
||||||
|
address_t Gem5ArmCPU::getStackPointer()
|
||||||
|
{
|
||||||
|
return getRegisterContent(getRegister(RI_SP));
|
||||||
|
}
|
||||||
|
|
||||||
|
address_t Gem5ArmCPU::getLinkRegister()
|
||||||
|
{
|
||||||
|
return getRegisterContent(getRegister(RI_LR));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end-of-namespace: fail
|
||||||
32
src/core/sal/gem5/Gem5ArmCPU.hpp
Normal file
32
src/core/sal/gem5/Gem5ArmCPU.hpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef __GEM5_ARM_CPU_HPP__
|
||||||
|
#define __GEM5_ARM_CPU_HPP__
|
||||||
|
|
||||||
|
#include "../arm/arch.hpp"
|
||||||
|
|
||||||
|
#include "sim/system.hh"
|
||||||
|
|
||||||
|
namespace fail {
|
||||||
|
|
||||||
|
class Gem5ArmCPU : public ArmArchitecture, public ArmCPUState
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Gem5ArmCPU(unsigned int id, System* system) : m_Id(id), m_System(system) {}
|
||||||
|
regdata_t getRegisterContent(Register* reg);
|
||||||
|
void setRegisterContent(Register* reg, regdata_t value);
|
||||||
|
|
||||||
|
address_t getInstructionPointer();
|
||||||
|
address_t getStackPointer();
|
||||||
|
address_t getLinkRegister();
|
||||||
|
|
||||||
|
unsigned int getId() { return m_Id; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned int m_Id;
|
||||||
|
System* m_System;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef Gem5ArmCPU ConcreteCPU;
|
||||||
|
|
||||||
|
} // end-of-namespace: fail
|
||||||
|
|
||||||
|
#endif // __GEM5_ARM_CPU_HPP__
|
||||||
@ -3,8 +3,25 @@
|
|||||||
|
|
||||||
#include "../Listener.hpp"
|
#include "../Listener.hpp"
|
||||||
|
|
||||||
|
#include "sim/system.hh"
|
||||||
|
|
||||||
namespace fail {
|
namespace fail {
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
for (int i = 0; i < sys->numContexts(); i++) {
|
||||||
|
ConcreteCPU* cpu = new ConcreteCPU(sys->getThreadContext(i)->cpuId(), System::systemList.front());
|
||||||
|
addCPU(cpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
SimulatorController::startup();
|
||||||
|
}
|
||||||
|
|
||||||
bool Gem5Controller::save(const std::string &path)
|
bool Gem5Controller::save(const std::string &path)
|
||||||
{
|
{
|
||||||
connector.save(path);
|
connector.save(path);
|
||||||
@ -23,27 +40,4 @@ void Gem5Controller::reboot()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gem5Controller::onBreakpoint(address_t instrPtr, address_t address_space)
|
|
||||||
{
|
|
||||||
bool do_fire = false;
|
|
||||||
// Check for active breakpoint-events:
|
|
||||||
ListenerManager::iterator it = m_LstList.begin();
|
|
||||||
BPEvent tmp(instrPtr, address_space);
|
|
||||||
while (it != m_LstList.end()) {
|
|
||||||
BaseListener* pLi = *it;
|
|
||||||
BPListener* pBreakpt = dynamic_cast<BPListener*>(pLi);
|
|
||||||
if (pBreakpt != NULL && pBreakpt->isMatching(&tmp)) {
|
|
||||||
pBreakpt->setTriggerInstructionPointer(instrPtr);
|
|
||||||
it = m_LstList.makeActive(it);
|
|
||||||
do_fire = true;
|
|
||||||
// "it" has already been set to the next element (by calling
|
|
||||||
// makeActive()):
|
|
||||||
continue; // -> skip iterator increment
|
|
||||||
}
|
|
||||||
it++;
|
|
||||||
}
|
|
||||||
if (do_fire)
|
|
||||||
m_LstList.triggerActiveListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end-of-namespace: fail
|
} // end-of-namespace: fail
|
||||||
|
|||||||
@ -14,14 +14,7 @@ namespace fail {
|
|||||||
*/
|
*/
|
||||||
class Gem5Controller : public SimulatorController {
|
class Gem5Controller : public SimulatorController {
|
||||||
public:
|
public:
|
||||||
void startup()
|
void startup();
|
||||||
{
|
|
||||||
SimulatorController::startup();
|
|
||||||
|
|
||||||
m_Mem = new Gem5MemoryManager(System::systemList.front());
|
|
||||||
}
|
|
||||||
|
|
||||||
void onBreakpoint(address_t instrPtr, address_t address_space);
|
|
||||||
|
|
||||||
bool save(const std::string &path);
|
bool save(const std::string &path);
|
||||||
void restore(const std::string &path);
|
void restore(const std::string &path);
|
||||||
|
|||||||
@ -15,7 +15,7 @@ class Gem5Breakpoint : public PCEvent
|
|||||||
public:
|
public:
|
||||||
Gem5Breakpoint(PCEventQueue* queue, Addr ip)
|
Gem5Breakpoint(PCEventQueue* queue, Addr ip)
|
||||||
: PCEvent(queue, "Fail* experiment breakpoint", ip) {}
|
: PCEvent(queue, "Fail* experiment breakpoint", ip) {}
|
||||||
virtual void process(ThreadContext *tc) { fail::simulator.onBreakpoint(this->evpc, fail::ANY_ADDR); }
|
virtual void process(ThreadContext *tc) { fail::simulator.onBreakpoint(&fail::simulator.getCPU(tc->cpuId()), this->evpc, fail::ANY_ADDR); }
|
||||||
};
|
};
|
||||||
|
|
||||||
aspect Gem5Listener
|
aspect Gem5Listener
|
||||||
|
|||||||
@ -9,7 +9,7 @@ env.Prepend(CPPPATH=Dir('../../../../../build/src/core/'))
|
|||||||
env.Append(CXXFLAGS = '-Wno-deprecated')
|
env.Append(CXXFLAGS = '-Wno-deprecated')
|
||||||
|
|
||||||
env.Prepend(LIBPATH=Dir('../../../../../build/lib/'))
|
env.Prepend(LIBPATH=Dir('../../../../../build/lib/'))
|
||||||
gStaticLibs = ['-lfail-sal', '-lfail-hsc-simple', '-lfail-comm', '-lfail-cpn', '-lfail-efw', '-lfail-util', '-lpcl']
|
gStaticLibs = ['-lfail-sal', '-lfail-arch-test', '-lfail-comm', '-lfail-cpn', '-lfail-efw', '-lfail-util', '-lpcl', '-lprotobuf']
|
||||||
|
|
||||||
if (len(gStaticLibs)>0):
|
if (len(gStaticLibs)>0):
|
||||||
linkFlags = ['-Wl,--start-group']
|
linkFlags = ['-Wl,--start-group']
|
||||||
|
|||||||
Reference in New Issue
Block a user