diff --git a/src/core/sal/CMakeLists.txt b/src/core/sal/CMakeLists.txt index caccca89..79be3fcc 100644 --- a/src/core/sal/CMakeLists.txt +++ b/src/core/sal/CMakeLists.txt @@ -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 diff --git a/src/core/sal/Event.hpp b/src/core/sal/Event.hpp new file mode 100644 index 00000000..b1e60ad9 --- /dev/null +++ b/src/core/sal/Event.hpp @@ -0,0 +1,329 @@ +#ifndef __EVENT_HPP__ + #define __EVENT_HPP__ + +#include +#include +#include +#include +#include +#include + +#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__ diff --git a/src/core/sal/Listener.cc b/src/core/sal/Listener.cc index 4af22919..80d8de41 100644 --- a/src/core/sal/Listener.cc +++ b/src/core/sal/Listener.cc @@ -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; diff --git a/src/core/sal/Listener.hpp b/src/core/sal/Listener.hpp index 1b057dfc..7a38def2 100644 --- a/src/core/sal/Listener.hpp +++ b/src/core/sal/Listener.hpp @@ -9,19 +9,15 @@ #include #include "SALConfig.hpp" +#include "Event.hpp" namespace fail { class ExperimentFlow; -//! address wildcard (e.g. for BPListeners) -const address_t ANY_ADDR = static_cast(-1); -//! instruction wildcard -const unsigned ANY_INSTR = static_cast(-1); -//! trap wildcard -const unsigned ANY_TRAP = static_cast(-1); -//! interrupt wildcard -const unsigned ANY_INTERRUPT = static_cast(-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 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 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 diff --git a/src/core/sal/Memory.cc b/src/core/sal/Memory.cc deleted file mode 100644 index 275455b4..00000000 --- a/src/core/sal/Memory.cc +++ /dev/null @@ -1,9 +0,0 @@ -#include - -#include "Memory.hpp" - -namespace fail { - -const guest_address_t ADDR_INV = 0; - -} diff --git a/src/core/sal/SALConfig.cc b/src/core/sal/SALConfig.cc new file mode 100644 index 00000000..a164ccbc --- /dev/null +++ b/src/core/sal/SALConfig.cc @@ -0,0 +1,12 @@ +#include "SALConfig.hpp" + +namespace fail { + +const address_t ADDR_INV = static_cast (0); +const address_t ANY_ADDR = static_cast (-1); +const unsigned ANY_INSTR = static_cast (-1); +const unsigned ANY_TRAP = static_cast (-1); +const unsigned ANY_INTERRUPT = static_cast (-1); +const timer_id_t INVALID_TIMER = static_cast (-1); + +} // end-of-namespace: fail diff --git a/src/core/sal/SALConfig.hpp b/src/core/sal/SALConfig.hpp index e3f17a29..14cae5b8 100644 --- a/src/core/sal/SALConfig.hpp +++ b/src/core/sal/SALConfig.hpp @@ -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 diff --git a/src/core/sal/SimulatorController.cc b/src/core/sal/SimulatorController.cc index c97634e5..719d3a3e 100644 --- a/src/core/sal/SimulatorController.cc +++ b/src/core/sal/SimulatorController.cc @@ -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