event data outsourced, SAL config flags revised, tiny coding-style fixes.
git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1462 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
@ -3,7 +3,7 @@ if(BUILD_BOCHS)
|
||||
BufferCache.cc
|
||||
Listener.cc
|
||||
ListenerManager.cc
|
||||
Memory.cc
|
||||
SALConfig.cc
|
||||
Register.cc
|
||||
SimulatorController.cc
|
||||
bochs/BochsController.cc
|
||||
@ -14,7 +14,7 @@ elseif(BUILD_OVP)
|
||||
BufferCache.cc
|
||||
Listener.cc
|
||||
ListenerManager.cc
|
||||
Memory.cc
|
||||
SALConfig.cc
|
||||
Register.cc
|
||||
SimulatorController.cc
|
||||
${VARIANT}/OVPController.cc
|
||||
@ -24,7 +24,7 @@ elseif(BUILD_GEM5)
|
||||
BufferCache.cc
|
||||
Listener.cc
|
||||
ListenerManager.cc
|
||||
Memory.cc
|
||||
SALConfig.cc
|
||||
Register.cc
|
||||
SimulatorController.cc
|
||||
gem5/Gem5Controller.cc
|
||||
|
||||
329
src/core/sal/Event.hpp
Normal file
329
src/core/sal/Event.hpp
Normal file
@ -0,0 +1,329 @@
|
||||
#ifndef __EVENT_HPP__
|
||||
#define __EVENT_HPP__
|
||||
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <iostream>
|
||||
|
||||
#include "SALConfig.hpp"
|
||||
|
||||
namespace fail {
|
||||
|
||||
/**
|
||||
* \class BaseEvent
|
||||
* This is the base class for all event types. It just encapsulates the
|
||||
* information reported by the simulator-backend when triggering an "event".
|
||||
*/
|
||||
class BaseEvent {
|
||||
public:
|
||||
BaseEvent() { }
|
||||
virtual ~BaseEvent() { }
|
||||
};
|
||||
// ----------------------------------------------------------------------------
|
||||
// Specialized events:
|
||||
//
|
||||
|
||||
/**
|
||||
* \class BPEvent
|
||||
* A Breakpoint event to observe instruction changes within a given address space.
|
||||
*/
|
||||
class BPEvent : virtual public BaseEvent {
|
||||
protected:
|
||||
address_t m_TriggerInstrPtr; //!< the address which triggered the event
|
||||
public:
|
||||
/**
|
||||
* Creates a new breakpoint event. The range information is specific to
|
||||
* the subclasses.
|
||||
* @param trigger the triggering address of the breakpoint event
|
||||
*/
|
||||
BPEvent(address_t trigger) : m_TriggerInstrPtr(trigger) { }
|
||||
/**
|
||||
* Returns the instruction pointer that triggered this event.
|
||||
* @return triggering IP
|
||||
*/
|
||||
address_t getTriggerInstructionPointer() const { return m_TriggerInstrPtr; }
|
||||
/**
|
||||
* Sets the instruction pointer that triggered this event.
|
||||
* @param iptr new IP which caused this event
|
||||
*/
|
||||
void setTriggerInstructionPointer(address_t iptr) { m_TriggerInstrPtr = iptr; }
|
||||
};
|
||||
|
||||
/**
|
||||
* \class MemAccessEvent
|
||||
* Observes memory read/write accesses.
|
||||
* FIXME? currently >8-bit accesses only match if their lowest address is being watched
|
||||
* (e.g., a 32-bit write to 0x4 also accesses 0x7, but this cannot be matched)
|
||||
*/
|
||||
class MemAccessEvent : virtual public BaseEvent {
|
||||
public:
|
||||
enum access_type_t {
|
||||
MEM_UNKNOWN = 0x0, //!< internal initialization flag, indicating an uninitialized state
|
||||
MEM_READ = 0x1, //!< read access flag
|
||||
MEM_WRITE = 0x2, //!< write access flag
|
||||
MEM_READWRITE = 0x3 //!< read and write access flag
|
||||
};
|
||||
private:
|
||||
//! Specific guest system *memory* address that actually triggered the event.
|
||||
address_t m_TriggerAddr;
|
||||
//! Width of the memory access (# bytes).
|
||||
size_t m_TriggerWidth;
|
||||
//! Address of the \b instruction that caused the memory access.
|
||||
address_t m_TriggerIP;
|
||||
//! Memory access type at m_TriggerAddr.
|
||||
access_type_t m_AccessType;
|
||||
public:
|
||||
/**
|
||||
* Creates a new \c MemAccessEvent using default initialization values, i.e.
|
||||
* \c setTriggerAddress(ANY_ADDR), \c setTriggerWidth(0), \c setTriggerAccessType(MEM_UNKNOWN)
|
||||
* and \c setTriggerInstructionPointer(ANY_ADDR).
|
||||
*/
|
||||
MemAccessEvent()
|
||||
: m_TriggerAddr(ANY_ADDR), m_TriggerWidth(0),
|
||||
m_TriggerIP(ANY_ADDR), m_AccessType(MEM_UNKNOWN) { }
|
||||
/**
|
||||
* Creates a new \c MemAccessEvent and initializes the provided values.
|
||||
* @param triggerAddr actual address that triggered the event
|
||||
* @param width width of memory access (= # Bytes)
|
||||
* @param triggerIP the instruction pointer that actually triggered the memory access
|
||||
* @param type the type of memory access (r, w, rw)
|
||||
*/
|
||||
MemAccessEvent(address_t triggerAddr, size_t width, address_t triggerIP, access_type_t type)
|
||||
: m_TriggerAddr(triggerAddr), m_TriggerWidth(width),
|
||||
m_TriggerIP(triggerIP), m_AccessType(type) { }
|
||||
/**
|
||||
* Returns the specific memory address that actually triggered the event.
|
||||
* @return the triggering address
|
||||
*/
|
||||
address_t getTriggerAddress() const { return m_TriggerAddr; }
|
||||
/**
|
||||
* Sets the specific memory address that actually triggered the event.
|
||||
* Should not be used by experiment code.
|
||||
* @param addr the new triggering address
|
||||
*/
|
||||
void setTriggerAddress(address_t addr) { m_TriggerAddr = addr; }
|
||||
/**
|
||||
* Returns the specific number of bytes read or written at \c getTriggerAddress().
|
||||
* @return the width of the memory access
|
||||
*/
|
||||
size_t getTriggerWidth() const { return m_TriggerWidth; }
|
||||
/**
|
||||
* Sets the specific memory access width.
|
||||
* @param new width (number of bytes)
|
||||
*/
|
||||
void setTriggerWidth(size_t width) { m_TriggerWidth = width; }
|
||||
/**
|
||||
* Returns the address of the instruction causing this memory access.
|
||||
* @return triggering IP
|
||||
*/
|
||||
address_t getTriggerInstructionPointer() const { return m_TriggerIP; }
|
||||
/**
|
||||
* Sets the address of the instruction causing this memory access.
|
||||
* @param addr new triggering IP
|
||||
*/
|
||||
void setTriggerInstructionPointer(address_t addr) { m_TriggerIP = addr; }
|
||||
/**
|
||||
* Returns type (MEM_READ || MEM_WRITE) of the memory access that
|
||||
* triggered this event.
|
||||
* @return the type of memory access (r or w) of this event
|
||||
*/
|
||||
access_type_t getTriggerAccessType() const { return m_AccessType; }
|
||||
/**
|
||||
* Sets type of the memory access that triggered this event.
|
||||
* @param type type of memory access
|
||||
*/
|
||||
void setTriggerAccessType(access_type_t type) { m_AccessType = type; }
|
||||
};
|
||||
|
||||
/**
|
||||
* \class TroubleEvent
|
||||
* Observes interrupt/trap activties.
|
||||
*/
|
||||
class TroubleEvent : virtual public BaseEvent {
|
||||
private:
|
||||
/**
|
||||
* Specific guest system interrupt/trap number that actually
|
||||
* trigger the event.
|
||||
*/
|
||||
int m_TriggerNumber;
|
||||
public:
|
||||
/**
|
||||
* Constructs a default initialized \c TroubleEvent, setting the trigger-number
|
||||
* to -1.
|
||||
*/
|
||||
TroubleEvent() : m_TriggerNumber(-1) { }
|
||||
/**
|
||||
* Constructs a new \c TroubleEvent.
|
||||
* @param triggerNum system and type specific number identifying the requestet
|
||||
* "trouble-type"
|
||||
*/
|
||||
TroubleEvent(int triggerNum)
|
||||
: m_TriggerNumber(triggerNum) { }
|
||||
/**
|
||||
* Sets the specific interrupt-/trap-number that actually triggered the event.
|
||||
* @param triggerNum system and type specific number identifying the requested
|
||||
* "trouble-type"
|
||||
*/
|
||||
void setTriggerNumber(unsigned triggerNum) { m_TriggerNumber = triggerNum; }
|
||||
/**
|
||||
* Returns the specific interrupt-/trap-number that actually triggered the event.
|
||||
* @return the trigger number
|
||||
*/
|
||||
unsigned getTriggerNumber() const { return m_TriggerNumber; }
|
||||
};
|
||||
|
||||
/**
|
||||
* \class InterruptEvent
|
||||
* Observes interrupts of the guest system.
|
||||
*/
|
||||
class InterruptEvent : virtual public TroubleEvent {
|
||||
private:
|
||||
bool m_IsNMI; //!< non maskable interrupt flag
|
||||
public:
|
||||
/**
|
||||
* Constructs a default initialized \c InterruptEvent, setting the non maskable
|
||||
* interrupt flag to \c false.
|
||||
*/
|
||||
InterruptEvent() : m_IsNMI(false) { }
|
||||
/**
|
||||
* Creates a new \c InterruptEvent.
|
||||
* @param nmi the new NMI (non maskable interrupt) flag state
|
||||
*/
|
||||
InterruptEvent(bool nmi) : m_IsNMI(nmi) { }
|
||||
/**
|
||||
* Returns \c true if the interrupt is non maskable, \c false otherwise.
|
||||
* @return \c true if NMI flag is set, \c false otherwise
|
||||
*/
|
||||
bool isNMI() { return m_IsNMI; }
|
||||
/**
|
||||
* Sets the interrupt type (non maskable or not).
|
||||
* @param nmi the new NMI (non maskable interrupt) flag state
|
||||
*/
|
||||
void setNMI(bool enabled) { m_IsNMI = enabled; }
|
||||
};
|
||||
|
||||
/**
|
||||
* \class GuestEvent
|
||||
* Used to receive data from the guest system.
|
||||
*/
|
||||
// FIXME: cf. GuestListener
|
||||
class GuestEvent : virtual public BaseEvent {
|
||||
private:
|
||||
char m_Data; //!< guest event data
|
||||
unsigned m_Port; //!< communication port
|
||||
public:
|
||||
GuestEvent() : m_Data(0), m_Port(0) { }
|
||||
/**
|
||||
* Returns the data, transmitted by the guest system.
|
||||
*/
|
||||
char getData() const { return m_Data; }
|
||||
/**
|
||||
* Sets the data which had been transmitted by the guest system.
|
||||
*/
|
||||
void setData(char data) { m_Data = data; }
|
||||
/**
|
||||
* Returns the data length, transmitted by the guest system.
|
||||
*/
|
||||
unsigned getPort() const { return m_Port; }
|
||||
/**
|
||||
* Sets the data length which had been transmitted by the guest system.
|
||||
*/
|
||||
void setPort(unsigned port) { m_Port = port; }
|
||||
};
|
||||
|
||||
/**
|
||||
* \class IOPortEvent
|
||||
* Observes I/O access on architectures with a separate I/O access mechanism (e.g. IA-32)
|
||||
*/
|
||||
class IOPortEvent : virtual public BaseEvent {
|
||||
private:
|
||||
unsigned char m_Data;
|
||||
public:
|
||||
/**
|
||||
* Initialises an IOPortEvent
|
||||
* @param data the data which has been communicated through the I/O port
|
||||
*/
|
||||
IOPortEvent(unsigned char data = 0) : m_Data(data) { }
|
||||
/**
|
||||
* Returns the data sent to the specified port
|
||||
*/
|
||||
unsigned char getData() const { return m_Data; }
|
||||
/**
|
||||
* Sets the data which had been transmitted.
|
||||
*/
|
||||
void setData(unsigned char data) { m_Data = data; }
|
||||
};
|
||||
|
||||
/**
|
||||
* \class JumpEvent
|
||||
* JumpEvents are used to observe conditional jumps (if...else if...else).
|
||||
*/
|
||||
class JumpEvent : virtual public BaseEvent {
|
||||
private:
|
||||
unsigned m_OpcodeTrigger;
|
||||
bool m_FlagTriggered;
|
||||
public:
|
||||
/**
|
||||
* Constructs a new event object.
|
||||
* @param opcode the opcode of the jump-instruction to be observed
|
||||
* or ANY_INSTR to match all jump-instructions
|
||||
* @param flagreg \c true if the event has been triggered due to a
|
||||
* specific FLAG register content, \c false otherwise
|
||||
*/
|
||||
JumpEvent(unsigned opcode = ANY_INSTR, bool flagreg = false)
|
||||
: m_OpcodeTrigger(opcode), m_FlagTriggered(flagreg) { }
|
||||
/**
|
||||
* Retrieves the opcode of the jump-instruction.
|
||||
*/
|
||||
unsigned getTriggerOpcode() const { return m_OpcodeTrigger; }
|
||||
/**
|
||||
* Returns \c true, if the event was triggered due to specific register
|
||||
* content, \c false otherwise.
|
||||
*/
|
||||
bool isRegisterTriggered() const { return !m_FlagTriggered; }
|
||||
/**
|
||||
* Returns \c true, of the event was triggered due to specific FLAG
|
||||
* state, \c false otherwise. This is the common case.
|
||||
*/
|
||||
bool isFlagTriggered() const { return m_FlagTriggered; }
|
||||
/**
|
||||
* Sets the requestet jump-instruction opcode.
|
||||
*/
|
||||
void setTriggerOpcode(unsigned oc) { oc = m_OpcodeTrigger; }
|
||||
/**
|
||||
* Sets the trigger flag.
|
||||
*/
|
||||
void setFlagTriggered(bool flagTriggered) { m_FlagTriggered = flagTriggered; }
|
||||
};
|
||||
|
||||
/**
|
||||
* \class GenericTimerEvent
|
||||
* This event type is used to encapsulate timeout-specific data.
|
||||
*/
|
||||
class GenericTimerEvent : public BaseEvent {
|
||||
protected:
|
||||
timer_id_t m_Id; //!< internal timer id (sim-specific)
|
||||
public:
|
||||
/**
|
||||
* Creates a new timer event.
|
||||
*/
|
||||
GenericTimerEvent(timer_id_t id = INVALID_TIMER) : m_Id(id) { }
|
||||
~GenericTimerEvent() { }
|
||||
/**
|
||||
* Retrieves the internal timer id. Maybe useful for debug output.
|
||||
* @return the timer id or \c INVALID_TIMER if the timer is invalid
|
||||
*/
|
||||
timer_id_t getId() const { return m_Id; }
|
||||
/**
|
||||
* Sets the internal timer id. This should not be used by the experiment.
|
||||
* @param id the new timer id, given by the underlying simulator-backend
|
||||
*/
|
||||
void setId(timer_id_t id) { m_Id = id; }
|
||||
};
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
#endif // __EVENT_HPP__
|
||||
@ -34,13 +34,13 @@ bool TroubleListener::addWatchNumber(unsigned troubleNumber)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MemAccessListener::isMatching(address_t addr, size_t width, accessType_t accesstype) const
|
||||
bool MemAccessListener::isMatching(address_t addr, size_t width,
|
||||
MemAccessEvent::access_type_t accesstype) const
|
||||
{
|
||||
if (!(m_WatchType & accesstype)) {
|
||||
return false;
|
||||
} else if (m_WatchAddr != ANY_ADDR
|
||||
&& (m_WatchAddr >= addr + width
|
||||
|| m_WatchAddr + m_WatchWidth <= addr)) {
|
||||
&& (m_WatchAddr >= addr + width || m_WatchAddr + m_WatchWidth <= addr)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@ -9,19 +9,15 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "SALConfig.hpp"
|
||||
#include "Event.hpp"
|
||||
|
||||
namespace fail {
|
||||
|
||||
class ExperimentFlow;
|
||||
|
||||
//! address wildcard (e.g. for BPListeners)
|
||||
const address_t ANY_ADDR = static_cast<address_t>(-1);
|
||||
//! instruction wildcard
|
||||
const unsigned ANY_INSTR = static_cast<unsigned>(-1);
|
||||
//! trap wildcard
|
||||
const unsigned ANY_TRAP = static_cast<unsigned>(-1);
|
||||
//! interrupt wildcard
|
||||
const unsigned ANY_INTERRUPT = static_cast<unsigned>(-1);
|
||||
// FIXME(?): Maybe it suffices to provide a "setEventData" method in order to
|
||||
// set the event data at once. (Consequently, all actual setters for
|
||||
// attributes of the event-data objects could be removed.)
|
||||
|
||||
/**
|
||||
* \class BaseListener
|
||||
@ -115,8 +111,8 @@ public:
|
||||
*/
|
||||
class BPListener : virtual public BaseListener {
|
||||
private:
|
||||
BPEvent m_Data;
|
||||
address_t m_CR3;
|
||||
address_t m_TriggerInstrPtr;
|
||||
public:
|
||||
/**
|
||||
* Creates a new breakpoint listener. The range information is specific to
|
||||
@ -128,7 +124,7 @@ public:
|
||||
* in a random address space.
|
||||
*/
|
||||
BPListener(address_t address_space = ANY_ADDR)
|
||||
: m_CR3(address_space), m_TriggerInstrPtr(ANY_ADDR) { }
|
||||
: m_Data(address_space), m_CR3(ANY_ADDR) { }
|
||||
/**
|
||||
* Returns the address space register of this listener.
|
||||
*/
|
||||
@ -148,12 +144,12 @@ public:
|
||||
/**
|
||||
* Returns the instruction pointer that triggered this listener.
|
||||
*/
|
||||
address_t getTriggerInstructionPointer() const { return m_TriggerInstrPtr; }
|
||||
address_t getTriggerInstructionPointer() const { return m_Data.getTriggerInstructionPointer(); }
|
||||
/**
|
||||
* Sets the instruction pointer that triggered this listener. Should not
|
||||
* be used by experiment code.
|
||||
*/
|
||||
void setTriggerInstructionPointer(address_t iptr) { m_TriggerInstrPtr = iptr; }
|
||||
void setTriggerInstructionPointer(address_t iptr) { m_Data.setTriggerInstructionPointer(iptr); }
|
||||
};
|
||||
|
||||
/**
|
||||
@ -183,14 +179,12 @@ public:
|
||||
* @return the instruction pointer specified in the constructor or by
|
||||
* calling \c setWatchInstructionPointer()
|
||||
*/
|
||||
address_t getWatchInstructionPointer() const
|
||||
{ return m_WatchInstrPtr; }
|
||||
address_t getWatchInstructionPointer() const { return m_WatchInstrPtr; }
|
||||
/**
|
||||
* Sets the instruction pointer this listener waits for.
|
||||
* @param iptr the new instruction ptr to wait for
|
||||
*/
|
||||
void setWatchInstructionPointer(address_t iptr)
|
||||
{ m_WatchInstrPtr = iptr; }
|
||||
void setWatchInstructionPointer(address_t iptr) { m_WatchInstrPtr = iptr; }
|
||||
/**
|
||||
* Checks whether a given address is matching.
|
||||
* @param addr address to check
|
||||
@ -216,8 +210,7 @@ public:
|
||||
* space.
|
||||
*/
|
||||
BPRangeListener(address_t start = 0, address_t end = 0, address_t address_space = ANY_ADDR)
|
||||
: BPListener(address_space), m_WatchStartAddr(start), m_WatchEndAddr(end)
|
||||
{ }
|
||||
: BPListener(address_space), m_WatchStartAddr(start), m_WatchEndAddr(end) { }
|
||||
/**
|
||||
* Returns the instruction pointer watch range of this listener.
|
||||
* @return the listener's range
|
||||
@ -246,13 +239,6 @@ public:
|
||||
* Observes memory read/write accesses.
|
||||
*/
|
||||
class MemAccessListener : virtual public BaseListener {
|
||||
public:
|
||||
enum accessType_t {
|
||||
MEM_UNKNOWN = 0x0,
|
||||
MEM_READ = 0x1,
|
||||
MEM_WRITE = 0x2,
|
||||
MEM_READWRITE = 0x3
|
||||
};
|
||||
private:
|
||||
//! Specific physical guest system address to watch, or ANY_ADDR.
|
||||
address_t m_WatchAddr;
|
||||
@ -262,25 +248,14 @@ private:
|
||||
* Memory access type we want to watch
|
||||
* (MEM_READ || MEM_WRITE || MEM_READWRITE).
|
||||
*/
|
||||
accessType_t m_WatchType;
|
||||
//! Specific physical guest system address that actually triggered the listener.
|
||||
address_t m_TriggerAddr;
|
||||
//! Width of the memory access (# bytes).
|
||||
size_t m_TriggerWidth;
|
||||
//! Address of the instruction that caused the memory access.
|
||||
address_t m_TriggerIP;
|
||||
//! Memory access type at m_TriggerAddr.
|
||||
accessType_t m_AccessType;
|
||||
MemAccessEvent::access_type_t m_WatchType;
|
||||
MemAccessEvent m_Data;
|
||||
public:
|
||||
MemAccessListener(accessType_t watchtype = MEM_READWRITE)
|
||||
: m_WatchAddr(ANY_ADDR), m_WatchWidth(1), m_WatchType(watchtype),
|
||||
m_TriggerAddr(ANY_ADDR), m_TriggerIP(ANY_ADDR),
|
||||
m_AccessType(MEM_UNKNOWN) { }
|
||||
MemAccessListener(address_t addr,
|
||||
accessType_t watchtype = MEM_READWRITE)
|
||||
: m_WatchAddr(addr), m_WatchWidth(1), m_WatchType(watchtype),
|
||||
m_TriggerAddr(ANY_ADDR), m_TriggerIP(ANY_ADDR),
|
||||
m_AccessType(MEM_UNKNOWN) { }
|
||||
MemAccessListener(MemAccessEvent::access_type_t type = MemAccessEvent::MEM_READWRITE)
|
||||
: m_WatchAddr(ANY_ADDR), m_WatchWidth(1), m_WatchType(type) { }
|
||||
MemAccessListener(address_t addr,
|
||||
MemAccessEvent::access_type_t type = MemAccessEvent::MEM_READWRITE)
|
||||
: m_WatchAddr(addr), m_WatchWidth(1), m_WatchType(type) { }
|
||||
/**
|
||||
* Returns the physical memory address to be observed.
|
||||
*/
|
||||
@ -300,51 +275,53 @@ public:
|
||||
/**
|
||||
* Checks whether a given physical memory access is matching.
|
||||
*/
|
||||
bool isMatching(address_t addr, size_t width, accessType_t accesstype) const;
|
||||
bool isMatching(address_t addr, size_t width, MemAccessEvent::access_type_t accesstype) const;
|
||||
/**
|
||||
* Returns the specific physical memory address that actually triggered the
|
||||
* listener.
|
||||
*/
|
||||
address_t getTriggerAddress() const { return m_TriggerAddr; }
|
||||
address_t getTriggerAddress() const { return m_Data.getTriggerAddress(); }
|
||||
/**
|
||||
* Sets the specific physical memory address that actually triggered the
|
||||
* listener. Should not be used by experiment code.
|
||||
*/
|
||||
void setTriggerAddress(address_t addr) { m_TriggerAddr = addr; }
|
||||
void setTriggerAddress(address_t addr) { m_Data.setTriggerAddress(addr); }
|
||||
/**
|
||||
* Returns the width (in bytes) of the memory access that triggered this
|
||||
* listener.
|
||||
*/
|
||||
size_t getTriggerWidth() const { return m_TriggerWidth; }
|
||||
size_t getTriggerWidth() const { return m_Data.getTriggerWidth(); }
|
||||
/**
|
||||
* Sets the width (in bytes) of the memory access that triggered this
|
||||
* listener. Should not be used by experiment code.
|
||||
*/
|
||||
void setTriggerWidth(size_t width) { m_TriggerWidth = width; }
|
||||
void setTriggerWidth(size_t width) { m_Data.setTriggerWidth(width); }
|
||||
/**
|
||||
* Returns the address of the instruction causing this memory access.
|
||||
*/
|
||||
address_t getTriggerInstructionPointer() const { return m_TriggerIP; }
|
||||
address_t getTriggerInstructionPointer() const { return m_Data.getTriggerInstructionPointer(); }
|
||||
/**
|
||||
* Sets the address of the instruction causing this memory access. Should
|
||||
* not be used by experiment code.
|
||||
*/
|
||||
void setTriggerInstructionPointer(address_t addr) { m_TriggerIP = addr; }
|
||||
void setTriggerInstructionPointer(address_t addr) { m_Data.setTriggerInstructionPointer(addr); }
|
||||
/**
|
||||
* Returns type (MEM_READ || MEM_WRITE) of the memory access that triggered
|
||||
* this listener.
|
||||
*/
|
||||
accessType_t getTriggerAccessType() const { return m_AccessType; }
|
||||
MemAccessEvent::access_type_t getTriggerAccessType() const
|
||||
{ return m_Data.getTriggerAccessType(); }
|
||||
/**
|
||||
* Sets type of the memory access that triggered this listener. Should not
|
||||
* be used by experiment code.
|
||||
* Sets the type of the memory access that triggered this listener.
|
||||
* Should not be used by experiment code.
|
||||
*/
|
||||
void setTriggerAccessType(accessType_t type) { m_AccessType = type; }
|
||||
void setTriggerAccessType(MemAccessEvent::access_type_t type)
|
||||
{ m_Data.setTriggerAccessType(type); }
|
||||
/**
|
||||
* Returns memory access types (MEM_READ || MEM_WRITE || MEM_READWRITE)
|
||||
* this listener watches. Should not be used by experiment code.
|
||||
*/
|
||||
accessType_t getWatchAccessType() const { return m_WatchType; }
|
||||
MemAccessEvent::access_type_t getWatchAccessType() const { return m_WatchType; }
|
||||
};
|
||||
|
||||
/**
|
||||
@ -354,9 +331,9 @@ public:
|
||||
class MemReadListener : virtual public MemAccessListener {
|
||||
public:
|
||||
MemReadListener()
|
||||
: MemAccessListener(MEM_READ) { }
|
||||
: MemAccessListener(MemAccessEvent::MEM_READ) { }
|
||||
MemReadListener(address_t addr)
|
||||
: MemAccessListener(addr, MEM_READ) { }
|
||||
: MemAccessListener(addr, MemAccessEvent::MEM_READ) { }
|
||||
};
|
||||
|
||||
/**
|
||||
@ -366,9 +343,9 @@ public:
|
||||
class MemWriteListener : virtual public MemAccessListener {
|
||||
public:
|
||||
MemWriteListener()
|
||||
: MemAccessListener(MEM_READ) { }
|
||||
: MemAccessListener(MemAccessEvent::MEM_READ) { }
|
||||
MemWriteListener(address_t addr)
|
||||
: MemAccessListener(addr, MEM_WRITE) { }
|
||||
: MemAccessListener(addr, MemAccessEvent::MEM_WRITE) { }
|
||||
};
|
||||
|
||||
/**
|
||||
@ -377,23 +354,17 @@ public:
|
||||
*/
|
||||
class TroubleListener : virtual public BaseListener {
|
||||
private:
|
||||
/**
|
||||
* Specific guest system interrupt/trap number that actually
|
||||
* trigger the listener.
|
||||
*/
|
||||
int m_TriggerNumber;
|
||||
TroubleEvent m_Data; //!< event related data, e.g. trap number
|
||||
/**
|
||||
* Specific guest system interrupt/trap numbers to watch,
|
||||
* or ANY_INTERRUPT/ANY_TRAP.
|
||||
*/
|
||||
std::vector<unsigned> m_WatchNumbers;
|
||||
public:
|
||||
TroubleListener() : m_TriggerNumber (-1) { }
|
||||
TroubleListener(unsigned troubleNumber)
|
||||
: m_TriggerNumber(-1)
|
||||
{ addWatchNumber(troubleNumber); }
|
||||
TroubleListener() { }
|
||||
TroubleListener(unsigned troubleNumber) { 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
|
||||
* @return \c true if number is added to the list \c false if the number
|
||||
* was already in the list
|
||||
@ -401,14 +372,14 @@ public:
|
||||
bool addWatchNumber(unsigned troubleNumber);
|
||||
/**
|
||||
* Remove an interrupt/trap-number which is in the list of observed
|
||||
* numbers
|
||||
* numbers.
|
||||
* @param troubleNumber number of an interrupt or trap
|
||||
* @return \c true if the number was found and removed \c false if the
|
||||
* number was not in the list
|
||||
*/
|
||||
bool removeWatchNumber(unsigned troubleNum);
|
||||
/**
|
||||
* Returns the list of observed numbers
|
||||
* Returns the list of observed numbers.
|
||||
* @return a copy of the list which contains all observed numbers
|
||||
*/
|
||||
std::vector<unsigned> getWatchNumbers() { return m_WatchNumbers; }
|
||||
@ -420,13 +391,12 @@ public:
|
||||
* Sets the specific interrupt-/trap-number that actually triggered
|
||||
* the listener. Should not be used by experiment code.
|
||||
*/
|
||||
void setTriggerNumber(unsigned troubleNum)
|
||||
{ m_TriggerNumber = troubleNum; }
|
||||
void setTriggerNumber(unsigned troubleNum) { m_Data.setTriggerNumber(troubleNum); }
|
||||
/**
|
||||
* Returns the specific interrupt-/trap-number that actually triggered
|
||||
* the listener.
|
||||
*/
|
||||
unsigned getTriggerNumber() { return m_TriggerNumber; }
|
||||
unsigned getTriggerNumber() const { return m_Data.getTriggerNumber(); }
|
||||
};
|
||||
|
||||
/**
|
||||
@ -435,19 +405,18 @@ public:
|
||||
*/
|
||||
class InterruptListener : virtual public TroubleListener {
|
||||
private:
|
||||
bool m_IsNMI; //!< non maskable interrupt flag
|
||||
InterruptEvent m_Data; //!< event related data, e.g. NMI flag
|
||||
public:
|
||||
InterruptListener() : m_IsNMI(false) { }
|
||||
InterruptListener(unsigned interrupt) : m_IsNMI(false)
|
||||
{ addWatchNumber(interrupt); }
|
||||
InterruptListener() { }
|
||||
InterruptListener(unsigned interrupt) { addWatchNumber(interrupt); }
|
||||
/**
|
||||
* Returns \c true if the interrupt is non maskable, \c false otherwise.
|
||||
*/
|
||||
bool isNMI() { return m_IsNMI; }
|
||||
bool isNMI() { return m_Data.isNMI(); }
|
||||
/**
|
||||
* Sets the interrupt type (non maskable or not).
|
||||
*/
|
||||
void setNMI(bool enabled) { m_IsNMI = enabled; }
|
||||
void setNMI(bool enabled) { m_Data.setNMI(enabled); }
|
||||
};
|
||||
|
||||
/**
|
||||
@ -464,28 +433,30 @@ public:
|
||||
* \class GuestListener
|
||||
* Used to receive data from the guest system.
|
||||
*/
|
||||
// FIXME: This is not a "clean design" ... IOPortListener looks much like a copy of this class.
|
||||
// Additionaly, the port is fixed (at least in Bochs) but can be modified using setPort
|
||||
// (effectless for now).
|
||||
class GuestListener : virtual public BaseListener {
|
||||
private:
|
||||
char m_Data;
|
||||
unsigned m_Port;
|
||||
GuestEvent m_Data;
|
||||
public:
|
||||
GuestListener() : m_Data(0), m_Port(0) { }
|
||||
GuestListener() { }
|
||||
/**
|
||||
* Returns the data, transmitted by the guest system.
|
||||
*/
|
||||
char getData() const { return m_Data; }
|
||||
char getData() const { return m_Data.getData(); }
|
||||
/**
|
||||
* Sets the data which had been transmitted by the guest system.
|
||||
*/
|
||||
void setData(char data) { m_Data = data; }
|
||||
void setData(char data) { m_Data.setData(data); }
|
||||
/**
|
||||
* Returns the data length, transmitted by the guest system.
|
||||
*/
|
||||
unsigned getPort() const { return m_Port; }
|
||||
unsigned getPort() const { return m_Data.getPort(); }
|
||||
/**
|
||||
* Sets the data length which had been transmitted by the guest system.
|
||||
*/
|
||||
void setPort(unsigned port) { m_Port = port; }
|
||||
void setPort(unsigned port) { m_Data.setPort(port); }
|
||||
};
|
||||
|
||||
/**
|
||||
@ -494,27 +465,27 @@ public:
|
||||
*/
|
||||
class IOPortListener : virtual public BaseListener {
|
||||
private:
|
||||
unsigned char m_Data;
|
||||
IOPortEvent m_Data;
|
||||
unsigned m_Port;
|
||||
bool m_Out;
|
||||
public:
|
||||
/**
|
||||
* Initialises an IOPortListener
|
||||
*
|
||||
* @param port the port the listener ist listening on
|
||||
* @param port the port the listener is listening on
|
||||
* @param out Defines the direction of the listener.
|
||||
* \arg \c true Output on the given port is captured.
|
||||
* \arg \c false Input on the given port is captured.
|
||||
*/
|
||||
IOPortListener(unsigned port, bool out) : m_Data(0), m_Port(port), m_Out(out) { }
|
||||
IOPortListener(unsigned port, bool out) : m_Port(port), m_Out(out) { }
|
||||
/**
|
||||
* Returns the data sent to the specified port
|
||||
*/
|
||||
unsigned char getData() const { return m_Data; }
|
||||
unsigned char getData() const { return m_Data.getData(); }
|
||||
/**
|
||||
* Sets the data which had been transmitted.
|
||||
*/
|
||||
void setData(unsigned char data) { m_Data = data; }
|
||||
void setData(unsigned char data) { m_Data.setData(data); }
|
||||
/**
|
||||
* Retrieves the port which this listener is bound to.
|
||||
*/
|
||||
@ -528,13 +499,14 @@ public:
|
||||
* @param p The port number an I/O listener occured on
|
||||
* @param out True if the communication was outbound, false otherwise
|
||||
*/
|
||||
bool isMatching(unsigned p, bool out) const { return ( out = isOutListener() && p == getPort()); }
|
||||
bool isMatching(unsigned p, bool out) const { return out = isOutListener() && p == getPort(); }
|
||||
/**
|
||||
* Tells you if this listener is capturing outbound communication (inbound if false)
|
||||
*/
|
||||
bool isOutListener() const { return m_Out; }
|
||||
/**
|
||||
* Change the listener direction.
|
||||
* @param out direction flag
|
||||
* \arg \c true Output on the given port is captured.
|
||||
* \arg \c false Input on the given port is captured.
|
||||
*/
|
||||
@ -547,56 +519,52 @@ public:
|
||||
*/
|
||||
class JumpListener : virtual public BaseListener {
|
||||
private:
|
||||
unsigned m_Opcode;
|
||||
bool m_FlagTriggered;
|
||||
JumpEvent m_Data;
|
||||
public:
|
||||
/**
|
||||
* Constructs a new listener object.
|
||||
* @param parent the parent object
|
||||
* @param opcode the opcode of the jump-instruction to be observed
|
||||
* or ANY_INSTR to match all jump-instructions
|
||||
* or \c ANY_INSTR to match all jump-instructions
|
||||
*/
|
||||
JumpListener(unsigned opcode = ANY_INSTR)
|
||||
: m_Opcode(opcode), m_FlagTriggered(false) { }
|
||||
JumpListener(unsigned opcode = ANY_INSTR) : m_Data(opcode) { }
|
||||
/**
|
||||
* Retrieves the opcode of the jump-instruction.
|
||||
*/
|
||||
unsigned getOpcode() const { return m_Opcode; }
|
||||
unsigned getOpcode() const { return m_Data.getTriggerOpcode(); }
|
||||
/**
|
||||
* Returns \c true, if the listener was triggered due to specific register
|
||||
* content, \c false otherwise.
|
||||
*/
|
||||
bool isRegisterTriggered() { return !m_FlagTriggered; }
|
||||
bool isRegisterTriggered() const { return m_Data.isRegisterTriggered(); }
|
||||
/**
|
||||
* Returns \c true, of the listener was triggered due to specific FLAG
|
||||
* state, \c false otherwise. This is the common case.
|
||||
*/
|
||||
bool isFlagTriggered() { return m_FlagTriggered; }
|
||||
bool isFlagTriggered() const { return m_Data.isFlagTriggered(); }
|
||||
/**
|
||||
* Sets the requestet jump-instruction opcode.
|
||||
*/
|
||||
void setOpcode(unsigned oc) { oc = m_Opcode; }
|
||||
void setOpcode(unsigned oc) { m_Data.setTriggerOpcode(oc); }
|
||||
/**
|
||||
* Sets the trigger flag.
|
||||
*/
|
||||
void setFlagTriggered(bool flagTriggered) { m_FlagTriggered = flagTriggered; }
|
||||
void setFlagTriggered(bool flagTriggered) { m_Data.setFlagTriggered(flagTriggered); }
|
||||
};
|
||||
|
||||
/**
|
||||
* \class GenericTimerListener
|
||||
* This listener type is used to create timeouts within in an experiment.
|
||||
*
|
||||
* Depending on your simulator backend, a concrete class needs to be derived
|
||||
* from \c GenericTimerListener. \c onListenerAddition should be used to register and
|
||||
* \c onListenerDeletion to unregister the timer. \c onListenerTrigger can be used to
|
||||
* re-register the timer if a repetitive timer is requested and the back-
|
||||
* end doesn't support such timer types natively.
|
||||
* Depending on your simulator backend, a concrete class needs to be derived from
|
||||
* \c GenericTimerListener. \c onAddition should be used to register and \c onDeletion
|
||||
* to unregister the timer. \c onTrigger can be used to re-register the timer if a
|
||||
* repetitive timer is requested and the back-end doesn't support such timer types
|
||||
* natively.
|
||||
*/
|
||||
class GenericTimerListener : public BaseListener {
|
||||
protected:
|
||||
unsigned m_Timeout; //!< timeout interval in milliseconds
|
||||
timer_id_t m_Id; //!< internal timer id (sim-specific)
|
||||
bool m_Once; //!< \c true, if the timer should be triggered only once, \c false otherwise
|
||||
GenericTimerEvent m_Data;
|
||||
public:
|
||||
/**
|
||||
* Creates a new timer listener. This can be used to implement a timeout-
|
||||
@ -605,19 +573,18 @@ public:
|
||||
* @param timeout the time intervall in milliseconds (ms)
|
||||
* @see SimulatorController::addListener
|
||||
*/
|
||||
GenericTimerListener(unsigned timeout)
|
||||
: m_Timeout(timeout), m_Id(-1) { }
|
||||
GenericTimerListener(unsigned timeout) : m_Timeout(timeout) { }
|
||||
~GenericTimerListener() { }
|
||||
/**
|
||||
* Retrieves the internal timer id. Maybe useful for debug output.
|
||||
* @return the timer id
|
||||
*/
|
||||
timer_id_t getId() const { return m_Id; }
|
||||
timer_id_t getId() const { return m_Data.getId(); }
|
||||
/**
|
||||
* Sets the internal timer id. This should not be used by the experiment.
|
||||
* @param id the new timer id, given by the underlying simulator-backend
|
||||
*/
|
||||
void setId(timer_id_t id) { m_Id = id; }
|
||||
void setId(timer_id_t id) { m_Data.setId(id); }
|
||||
/**
|
||||
* Retrieves the timer's timeout value.
|
||||
* @return the timout in milliseconds
|
||||
|
||||
@ -1,9 +0,0 @@
|
||||
#include <cstdlib>
|
||||
|
||||
#include "Memory.hpp"
|
||||
|
||||
namespace fail {
|
||||
|
||||
const guest_address_t ADDR_INV = 0;
|
||||
|
||||
}
|
||||
12
src/core/sal/SALConfig.cc
Normal file
12
src/core/sal/SALConfig.cc
Normal file
@ -0,0 +1,12 @@
|
||||
#include "SALConfig.hpp"
|
||||
|
||||
namespace fail {
|
||||
|
||||
const address_t ADDR_INV = static_cast<address_t> (0);
|
||||
const address_t ANY_ADDR = static_cast<address_t> (-1);
|
||||
const unsigned ANY_INSTR = static_cast<unsigned> (-1);
|
||||
const unsigned ANY_TRAP = static_cast<unsigned> (-1);
|
||||
const unsigned ANY_INTERRUPT = static_cast<unsigned> (-1);
|
||||
const timer_id_t INVALID_TIMER = static_cast<timer_id_t> (-1);
|
||||
|
||||
} // end-of-namespace: fail
|
||||
@ -24,7 +24,22 @@ typedef uint32_t regwidth_t; //!< type of register width [bits]
|
||||
typedef register_data_t regdata_t; //!< type of register data
|
||||
typedef timer_t timer_id_t; //!< type of timer IDs
|
||||
|
||||
extern const address_t ADDR_INV; //!< invalid address flag (defined in Memory.cc)
|
||||
// The following flags are defined in SALConfig.cc.
|
||||
|
||||
// FIXME: The flags should be initialized based on simulator-specific values!
|
||||
|
||||
//! invalid address flag (e.g. for memory address ptrs)
|
||||
extern const address_t ADDR_INV;
|
||||
//! address wildcard (e.g. for breakpoint listeners)
|
||||
extern const address_t ANY_ADDR;
|
||||
//! instruction wildcard (e.g. for jump listeners)
|
||||
extern const unsigned ANY_INSTR;
|
||||
//! trap wildcard
|
||||
extern const unsigned ANY_TRAP;
|
||||
//! interrupt wildcard
|
||||
extern const unsigned ANY_INTERRUPT;
|
||||
//! invalid timer id (e.g. for timer listeners)
|
||||
extern const timer_id_t INVALID_TIMER;
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
|
||||
@ -75,9 +75,9 @@ void SimulatorController::onMemoryAccess(address_t addr, size_t len,
|
||||
bool is_write, address_t instrPtr)
|
||||
{
|
||||
// FIXME: Improve performance!
|
||||
MemAccessListener::accessType_t accesstype =
|
||||
is_write ? MemAccessListener::MEM_WRITE
|
||||
: MemAccessListener::MEM_READ;
|
||||
MemAccessEvent::access_type_t accesstype =
|
||||
is_write ? MemAccessEvent::MEM_WRITE
|
||||
: MemAccessEvent::MEM_READ;
|
||||
|
||||
ListenerManager::iterator it = m_LstList.begin();
|
||||
while (it != m_LstList.end()) { // check for active events
|
||||
|
||||
Reference in New Issue
Block a user