diff --git a/.gitignore b/.gitignore index 879f3ee4..63fe4245 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ *.o +*.lo *.a +*.la *.d *.acc *.pb.h @@ -10,6 +12,7 @@ Makefile build build-* +.deps simulators/bochs/autom4te.cache/ simulators/bochs/bochs @@ -35,3 +38,19 @@ simulators/gem5/.hg simulators/gem5/m5out/ src/core/sal/gem5/SConscript + +debuggers/openocd/config.h +debuggers/openocd/config.log +debuggers/openocd/config.status +debuggers/openocd/jimtcl/configure.gnu.bak +debuggers/openocd/libtool +debuggers/openocd/openocd_wrapper.hpp +debuggers/openocd/src/.libs/ +debuggers/openocd/src/helper/bin2char +debuggers/openocd/src/jtag/minidriver_imp.h +debuggers/openocd/src/openocd +debuggers/openocd/src/startup.tcl +debuggers/openocd/src/startup_tcl.c +debuggers/openocd/src/target/xscale_debug.h +debuggers/openocd/stamp-h1 + diff --git a/cmake/FindFTDI.cmake b/cmake/FindFTDI.cmake new file mode 100644 index 00000000..8b831a0f --- /dev/null +++ b/cmake/FindFTDI.cmake @@ -0,0 +1,22 @@ +# Find FTDI library +# Defines: +# FTDI_FOUND +# FTDI_INCLUDE_DIR +# FTDI_LIBRARY +# + +FIND_PATH(FTDI_INCLUDE_DIR ftdi.h) + +FIND_LIBRARY(FTDI_LIBRARY NAMES ftdi + PATHS /usr/lib /usr/local/lib + ENV LIBRARY_PATH # PATH and LIB will also work + ENV LD_LIBRARY_PATH +) + +# handle the QUIETLY and REQUIRED arguments and set FTDI_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(FTDI DEFAULT_MSG FTDI_LIBRARY FTDI_INCLUDE_DIR) + +MARK_AS_ADVANCED(FTDI_INCLUDE_DIR FTDI_LIBRARY) +unset(FTDI_DIR CACHE) diff --git a/cmake/panda.cmake b/cmake/panda.cmake new file mode 100644 index 00000000..959b56b5 --- /dev/null +++ b/cmake/panda.cmake @@ -0,0 +1,49 @@ +if(BUILD_PANDA) + + message(STATUS "[${PROJECT_NAME}] Building Pandaboard variant ...") + SET(VARIANT panda) + + find_package(FTDI REQUIRED) + set(openocd_library_dependencies ${openocd_library_dependencies} ${FTDI_LIBRARY}) + + # FIXME: some libraries still need to be located the "cmake way" + set(openocd_library_dependencies ${openocd_library_dependencies} -ldl) + + set(openocd_src_dir ${PROJECT_SOURCE_DIR}/debuggers/openocd) + set(openocd_configure_params --enable-ft2232_libftdi --disable-werror CACHE STRING "OpenOCD default configure parameters") + + # Use cmake's external project feature to build openocd library + include(ExternalProject) + ExternalProject_Add( + libfailopenocd_external + SOURCE_DIR ${openocd_src_dir} + CONFIGURE_COMMAND ${openocd_src_dir}/configure ${openocd_configure_params} + BUILD_COMMAND $(MAKE) -C ${openocd_src_dir} + ## Put install command here, to prevent cmake calling make install + INSTALL_COMMAND ${CMAKE_COMMAND} -E echo "[${PROJECT_NAME}] Built openocd library" + BUILD_IN_SOURCE 1 + ) + + # make sure aspects don't fail to match in entry.cc + #include_directories(${PROJECT_SOURCE_DIR}/src/core ${CMAKE_BINARY_DIR}/src/core) + # an executable needs at least one source file, so we hand over an empty .cc file to make cmake happy. + + add_executable(fail-client ${openocd_src_dir}/openocd_wrapper.cc) + target_link_libraries(fail-client ${openocd_src_dir}/src/.libs/libopenocd.a ${openocd_src_dir}/jimtcl/libjim.a fail ${openocd_library_dependencies}) + add_dependencies(fail-client libfailopenocd_external) + + #copy the conf-files to build directory + file(COPY ${openocd_src_dir}/tcl/ DESTINATION oocd_conf/ PATTERN openocd EXCLUDE) + get_filename_component(OOCD_CONF_FILES_PATH ${CMAKE_BINARY_DIR}/oocd_conf/ REALPATH) + + configure_file(${openocd_src_dir}/openocd.cfg openocd.cfg COPYONLY) + + get_filename_component(OOCD_CONF_FILE_PATH ${CMAKE_BINARY_DIR}/openocd.cfg REALPATH) + configure_file(${openocd_src_dir}/openocd_wrapper.hpp.in + ${openocd_src_dir}/openocd_wrapper.hpp) + include_directories(${openocd_src_dir}) + + # /FIXME + install(TARGETS fail-client RUNTIME DESTINATION bin) + +endif(BUILD_PANDA) diff --git a/src/core/sal/panda/PandaArmCPU.cc b/src/core/sal/panda/PandaArmCPU.cc new file mode 100644 index 00000000..30be2dfd --- /dev/null +++ b/src/core/sal/panda/PandaArmCPU.cc @@ -0,0 +1,23 @@ +#include "PandaArmCPU.hpp" + +#include "openocd_wrapper.hpp" + +namespace fail { + +regdata_t PandaArmCPU::getRegisterContent(const Register* reg) const +{ + regdata_t data; + + // ToDo: ID-translation + oocdw_read_reg(reg->getId(), ARM_REGS_CORE, &data); + + return data; +} + +void PandaArmCPU::setRegisterContent(const Register* reg, regdata_t value) +{ + // ToDo: ID-translation + oocdw_write_reg(reg->getId(), ARM_REGS_CORE, value); +} + +} // end-of-namespace: fail diff --git a/src/core/sal/panda/PandaArmCPU.hpp b/src/core/sal/panda/PandaArmCPU.hpp new file mode 100644 index 00000000..216feacb --- /dev/null +++ b/src/core/sal/panda/PandaArmCPU.hpp @@ -0,0 +1,71 @@ +#ifndef __PANDA_ARM_CPU_HPP__ + #define __PANDA_ARM_CPU_HPP__ + +#include "../arm/ArmArchitecture.hpp" +#include "../arm/ArmCPUState.hpp" + +namespace fail { + +/** + * \class PandaArmCPU + * + * \c PandaArmCPU is the concrete CPU implementation for the TI Pandaboard ES. It + * implements the CPU interfaces \c ArmArchitecture and \c ArmCPUState. + * \c ArmArchitecture refers to architectural information (e.g. register \a count) + * while \c ArmCPUState encapsulates the CPU state (e.g. register \a content). + */ +class PandaArmCPU : public ArmArchitecture, public ArmCPUState { +private: + unsigned int m_Id; //!< the unique ID of this CPU +public: + /** + * Creates a new gem5 CPU for ARM based targets. + * @param id the unique ID of the CPU to be created (the first CPU0 has ID 0) + * @param system the gem5 system object + */ + PandaArmCPU(unsigned int id) : m_Id(id) { } + + virtual ~PandaArmCPU() {} + /** + * Retrieves the register content from the current Pandaboard CPU. + * @param reg the destination register whose content should be retrieved + * @return the content of register \c reg + */ + regdata_t getRegisterContent(const Register* reg) const; + /** + * Sets the register content for the \a current Pandaboard CPU. + * @param reg the (initialized) register object whose content should be set + * @param value the new content of the register \c reg + */ + void setRegisterContent(const Register* reg, regdata_t value); + /** + * Retrieves the current instruction pointer (IP aka program counter, PC for short) + * for the current CPU \c this. + * @return the current instruction ptr address + */ + address_t getInstructionPointer() const { return getRegisterContent(getRegister(RI_IP)); } + /** + * Retrieves the current stack pointer for the current CPU \c this. + * @return the current stack ptr address + */ + address_t getStackPointer() const { return getRegisterContent(getRegister(RI_SP)); } + /** + * Retrieves the link register (return address when a function returns) for + * the current CPU \c this. See + * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211h/ch02s08s01.html + * for further information. + * @return the current link register address + */ + address_t getLinkRegister() const { return getRegisterContent(getRegister(RI_LR)); } + /** + * Returns the ID of the current CPU. + * @return the unique ID of \c this CPU object + */ + unsigned int getId() const { return m_Id; } +}; + +typedef PandaArmCPU ConcreteCPU; //!< the concrete CPU type for Pandaboard (ARM) + +} // end-of-namespace: fail + +#endif // __PANDA_ARM_CPU_HPP__ diff --git a/src/core/sal/panda/PandaBreakpoints.ah b/src/core/sal/panda/PandaBreakpoints.ah new file mode 100644 index 00000000..7a7d968f --- /dev/null +++ b/src/core/sal/panda/PandaBreakpoints.ah @@ -0,0 +1,74 @@ +#ifndef __PANDA_BREAKPOINTS_AH__ + #define __PANDA_BREAKPOINTS_AH__ + +#include "config/FailConfig.hpp" +#include "config/VariantConfig.hpp" + +#if defined(BUILD_PANDA) && defined(CONFIG_EVENT_BREAKPOINTS) + +#include "../SALInst.hpp" +#include "../../../debuggers/openocd/openocd_wrapper.hpp" + +aspect PandaBreakpoints +{ + advice "fail::BPSingleListener" : slice class + { + public: + bool onAddition() + { + // Setup Breakpoint on Pandaboard + struct halt_condition hc; + if (m_WatchInstrPtr == ANY_ADDR) { + hc.type = HALT_TYPE_SINGLESTEP; + } else { + hc.type = HALT_TYPE_BP; + } + hc.address = m_WatchInstrPtr; + hc.addr_len= 4; // Thumb? => 2 + oocdw_set_halt_condition(&hc); + return true; + } + + void onDeletion() + { + // Delete Breakpoint on Pandaboard + struct halt_condition hc; + if (m_WatchInstrPtr == ANY_ADDR) { + hc.type = HALT_TYPE_SINGLESTEP; + } else { + hc.type = HALT_TYPE_BP; + } + hc.type = HALT_TYPE_BP; + hc.address = m_WatchInstrPtr; + hc.addr_len= 4; // Thumb? => 2 + oocdw_delete_halt_condition(&hc); + } + }; + +#if defined(CONFIG_EVENT_BREAKPOINTS_RANGE) + #error Range Breakpoints not yet implemented for Pandaboard + + advice "fail::BPRangeListener" : slice class + { + public: + bool onAddition() + { + // Calculate address range + address_t range = m_WatchEndAddr - m_WatchStartAddr; // range / sizeof(address_t) ??! + + // ToDo: Setup MMU to watch address range + } + + void onDeletion() + { + // Calculate address range + address_t range = m_WatchEndAddr - m_WatchStartAddr; // range / sizeof(address_t) ??! + + // ToDo: Setup MMU to no longer watch address range + } + }; +#endif // CONFIG_EVENT_BREAKPOINTS_RANGE +}; + +#endif // BUILD_PANDA && CONFIG_EVENT_BREAKPOINTS +#endif // __PANDA_BREAKPOINTS_AH__ diff --git a/src/core/sal/panda/PandaConfig.hpp b/src/core/sal/panda/PandaConfig.hpp new file mode 100644 index 00000000..1d9b299d --- /dev/null +++ b/src/core/sal/panda/PandaConfig.hpp @@ -0,0 +1,18 @@ +/** + * \file PandaConfig.hpp + * \brief Type definitions and configuration settings for + * the Pandaboard. + */ + +#ifndef __PANDA_CONFIG_HPP__ + #define __PANDA_CONFIG_HPP__ + +namespace fail { + typedef uint32_t host_address_t; //!< the host memory address type + typedef uint32_t guest_address_t; //!< the guest memory address type + typedef uint32_t register_data_t; //!< register data type (32 bit) + typedef int timer_t; //!< type of timer IDs + +} // end-of-namespace: fail + +#endif // __PANDA_CONFIG_HPP__ diff --git a/src/core/sal/panda/PandaController.cc b/src/core/sal/panda/PandaController.cc new file mode 100644 index 00000000..1f89ced8 --- /dev/null +++ b/src/core/sal/panda/PandaController.cc @@ -0,0 +1,116 @@ +#include + +#include "PandaController.hpp" +#include "PandaMemory.hpp" +#include "../SALInst.hpp" +#include "../Listener.hpp" + +#include "openocd_wrapper.hpp" + +#if defined(CONFIG_FIRE_INTERRUPTS) + #error Firing intterupts not implemented for Pandaboard +#endif + +#if defined(CONFIG_SR_REBOOT) || defined(CONFIG_SR_RESTORE) || defined(CONFIG_SR_SAVE) + #error Save/Restore is not yet implemented for Pandaboard +#endif + +namespace fail { + + +PandaController::PandaController() + : SimulatorController(new PandaMemoryManager()), m_CurrFlow(NULL) +{ + // ToDo: Multiple CPUs? => for (unsigned i = 0; i < BX_SMP_PROCESSORS; i++) + addCPU(new ConcreteCPU(0)); +} + +PandaController::~PandaController() +{ + delete m_Mem; + std::vector::iterator it = m_CPUs.begin(); + while (it != m_CPUs.end()) { + delete *it; + it = m_CPUs.erase(it); + } +} + +void PandaController::onTimerTrigger(void* thisPtr) +{ + // FIXME: The timer logic can be modified to use only one timer in Bochs. + // (For now, this suffices.) + TimerListener* pli = static_cast(thisPtr); + // Check for a matching TimerListener. (In fact, we are only + // interessted in the iterator pointing at pli.) + ListenerManager::iterator it = std::find(simulator.m_LstList.begin(), + simulator.m_LstList.end(), pli); + // TODO: This has O(|m_LstList|) time complexity. We can further improve this + // by creating a method such that makeActive(pli) works as well, + // reducing the time complexity to O(1). + simulator.m_LstList.makeActive(it); + simulator.m_LstList.triggerActiveListeners(); +} + +void PandaController::onIOPort(ConcreteCPU* cpu, unsigned char data, unsigned port, bool out) { + // Check for active IOPortListeners: + ListenerManager::iterator it = m_LstList.begin(); + while (it != m_LstList.end()) { + BaseListener* pLi = *it; + IOPortListener* pIOPt = dynamic_cast(pLi); + if (pIOPt != NULL && pIOPt->isMatching(port, out)) { + pIOPt->setData(data); + pIOPt->setTriggerCPU(cpu); + it = m_LstList.makeActive(it); + // "it" has already been set to the next element (by calling + // makeActive()): + continue; // -> skip iterator increment + } + it++; + } + m_LstList.triggerActiveListeners(); +} + +bool PandaController::save(const std::string& path) +{ + // ToDo (PORT): Save + + /*int stat; + + stat = mkdir(path.c_str(), 0777); + if (!(stat == 0 || errno == EEXIST)) { + return false; + // std::cout << "[FAIL] Can not create target-directory to save!" << std::endl; + // TODO: (Non-)Verbose-Mode? Log-level? Maybe better: use return value to indicate failure? + }*/ + + return true; +} + +void PandaController::restore(const std::string& path) +{ + clearListeners(); + /*restore_bochs_request = true; + BX_CPU(0)->async_event |= 1; + sr_path = path;*/ + + // ToDo (PORT): Restore +} + +void PandaController::reboot() +{ + clearListeners(); + + oocdw_reboot(); +} + +void PandaController::terminate(int exCode) +{ + oocdw_finish(); + /* + * Resume to let OpenOCD terminate properly + */ + m_Flows.resume(); + SimulatorController::terminate(exCode); +} + +} // end-of-namespace: fail diff --git a/src/core/sal/panda/PandaController.hpp b/src/core/sal/panda/PandaController.hpp new file mode 100644 index 00000000..8d4ee6a5 --- /dev/null +++ b/src/core/sal/panda/PandaController.hpp @@ -0,0 +1,95 @@ +#ifndef __PANDA_CONTROLLER_HPP__ + #define __PANDA_CONTROLLER_HPP__ + +#include +#include +#include +#include +#include + +#include "../SimulatorController.hpp" + +struct command_context; + +namespace fail { + +class ExperimentFlow; + + +struct target; + +/** + * \class PandaController + * Pandaboard-specific implementation of a SimulatorController. + */ +class PandaController : public SimulatorController { +private: + ExperimentFlow* m_CurrFlow; //!< Stores the current flow for save/restore-operations +public: + /** + * Initialize the controller, i.e., add the number of simulated CPUs. + */ + PandaController(); + ~PandaController(); + /* ******************************************************************** + * Standard Listener Handler API: + * ********************************************************************/ + /** + * I/O port communication handler. This method is called (from + * the IOPortCom aspect) every time when pandaboard performs a port I/O operation. + * @param cpu the CPU that caused the IO port access + * @param data the data transmitted + * @param port the port it was transmitted on + * @param out \c true if the I/O traffic has been outbound, \c false otherwise + */ + void onIOPort(ConcreteCPU* cpu, unsigned char data, unsigned port, bool out); + /** + * Internal handler for TimerListeners. This method is called when a previously + * registered (openocd-wrapper) timer triggers. It searches for the provided + * TimerListener object within the ListenerManager and fires such an event + * by calling \c triggerActiveListeners(). + * @param thisPtr a pointer to the TimerListener-object triggered + */ + void onTimerTrigger(void *thisPtr); + /* ******************************************************************** + * Simulator Controller & Access API: + * ********************************************************************/ + /** + * Save device state. + * @param path Location to store state information + * @return \c true if the state has been successfully saved, \c false otherwise + */ + bool save(const std::string& path); + /** + * Restore device state. Clears all Listeners. + * @param path Location to previously saved state information + */ + void restore(const std::string& path); + /** + * Reboot pandaboard. Clears all Listeners. + */ + void reboot(); + /** + * Fire an interrupt. + * @param irq Interrupt to be fired + */ + //void fireInterrupt(unsigned irq); + + virtual simtime_t getTimerTicks() { + // return bx_pc_system.time_ticks(); + // ToDo (PORT) + return 0; + } + virtual simtime_t getTimerTicksPerSecond() { + // return bx_pc_system.time_ticks() / bx_pc_system.time_usec() * 1000000; /* imprecise hack */ + // ToDo (PORT) + return 0; + } + + // Overloading super method to terminate OpenOCD properly + void terminate(int exCode = EXIT_SUCCESS); +}; + +} // end-of-namespace: fail + +#endif // __PANDA_CONTROLLER_HPP__ diff --git a/src/core/sal/panda/PandaListener.cc b/src/core/sal/panda/PandaListener.cc new file mode 100644 index 00000000..6a79cbb7 --- /dev/null +++ b/src/core/sal/panda/PandaListener.cc @@ -0,0 +1,11 @@ +#include "PandaListener.hpp" +#include "../SALInst.hpp" + +namespace fail { + +void onTimerTrigger(void* thisPtr) +{ + simulator.onTimerTrigger(thisPtr); +} + +} // end-of-namespace: fail diff --git a/src/core/sal/panda/PandaListener.hpp b/src/core/sal/panda/PandaListener.hpp new file mode 100644 index 00000000..9ca38599 --- /dev/null +++ b/src/core/sal/panda/PandaListener.hpp @@ -0,0 +1,13 @@ +#ifndef __PANDA_LISTENER_HPP__ + #define __PANDA_LISTENER_HPP__ + +namespace fail { + +/** + * Global internal handler for (Pandaboard) TimerListeners. + */ +void onTimerTrigger(void *thisPtr); + +} // end-of-namespace: fail + +#endif // __PANDA_LISTENER_HPP__ diff --git a/src/core/sal/panda/PandaMemory.hpp b/src/core/sal/panda/PandaMemory.hpp new file mode 100644 index 00000000..51542b03 --- /dev/null +++ b/src/core/sal/panda/PandaMemory.hpp @@ -0,0 +1,114 @@ +#ifndef __PANDA_MEMORY_HPP__ + #define __PANDA_MEMORY_HPP__ + +#include "../Memory.hpp" + +#include "openocd_wrapper.hpp" + +namespace fail { + +/** + * \class PandaMemoryManager + * Represents a concrete implemenation of the abstract + * MemoryManager to provide access to the memory pool + * of the pandaboard. + */ +class PandaMemoryManager : public MemoryManager { +public: + /** + * Constructs a new MemoryManager object and initializes + * it's attributes appropriately. + */ + PandaMemoryManager() : MemoryManager() { } + /** + * Retrieves the size of the available simulated memory. + * @return the size of the memory pool in bytes + */ + size_t getPoolSize() const + { + //ToDo (PORT): Get pool size from ELF file? + return 0xFFFFFFFF; + } + /** + * Retrieves the starting address of the host memory. This is the + * first valid address in memory. + * @return the starting address + */ + host_address_t getStartAddr() const + { + //ToDo Get Start address from ELF file!? + return 0; + } + + /** + * Retrieves the byte at address \a addr in the memory. + * @param addr The guest address where the byte is located. + * The address is expected to be valid. + * @return the byte at \a addr + */ + byte_t getByte(guest_address_t addr) + { + // ToDo: Address translation + /* host_address_t haddr = guestToHost(addr); + assert(haddr != (host_address_t)ADDR_INV && "FATAL ERROR: Invalid guest address provided!"); + return static_cast(*reinterpret_cast(haddr));*/ + + uint8_t buf [1]; + + oocdw_read_from_memory(addr, 1, 1, buf); + + return buf[0]; + } + + /** + * Retrieves \a cnt bytes at address \a addr from the memory. + * @param addr The guest address where the bytes are located. + * The address is expected to be valid. + * @param cnt The number of bytes to be retrieved. \a addr + \a cnt + * is expected to not exceed the memory limit. + * @param dest Pointer to destination buffer to copy the data to. + */ + void getBytes(guest_address_t addr, size_t cnt, void *dest) + { + // ToDo: Address translation + /* host_address_t haddr = guestToHost(addr); + assert(haddr != (host_address_t)ADDR_INV && "FATAL ERROR: Invalid guest address provided!"); + return static_cast(*reinterpret_cast(haddr));*/ + + uint8_t *d = static_cast(dest); + + oocdw_read_from_memory(addr, 1, cnt, d); + } + + /** + * Writes the byte \a data to memory. + * @param addr The guest address to write. + * The address is expected to be valid. + * @param data The new byte to write + */ + void setByte(guest_address_t addr, byte_t data) + { + oocdw_write_to_memory(addr, 1, 1, &data, false); + } + + /** + * Copies data to memory. + * @param addr The guest address to write. + * The address is expected to be valid. + * @param cnt The number of bytes to be retrieved. \a addr + \a cnt + * is expected to not exceed the memory limit. + * @param src Pointer to data to be copied. + */ + void setBytes(guest_address_t addr, size_t cnt, void const *src) + { + // ToDo (PORT): This works, but may be slower than writing a whole block + uint8_t const *s = static_cast(src); + + // ToDo: Check Endianess? + oocdw_write_to_memory(addr, 1, cnt, s, false); + } +}; + +} // end-of-namespace: fail + +#endif // __PANDA_MEMORY_HPP__ diff --git a/src/core/sal/panda/PandaTimer.ah b/src/core/sal/panda/PandaTimer.ah new file mode 100644 index 00000000..ff54278f --- /dev/null +++ b/src/core/sal/panda/PandaTimer.ah @@ -0,0 +1,50 @@ +#ifndef __PANDA_TIMER_AH__ + #define __PANDA_TIMER_AH__ + +#include "config/VariantConfig.hpp" +#include "config/FailConfig.hpp" + +#if defined(BUILD_PANDA) + +#include "../../../debuggers/openocd/openocd_wrapper.hpp" +#include "PandaListener.hpp" + +aspect PandaTimer { + advice "fail::TimerListener" : slice class { + public: + bool onAddition() + { + // Register the timer listener in the Bochs simulator: + timer_id_t id = m_registerTimer(this); + if (id == -1) { + setId(INVALID_TIMER); + return false; // unable to register the timer (error in Bochs' function call) + } + setId(id); + return true; + } + void onDeletion() + { + // Unregister the time listener: + m_unregisterTimer(this); + } + private: + timer_id_t m_registerTimer(TimerListener* pev) + { + assert(pev != NULL && "FATAL ERROR: TimerListener object ptr cannot be NULL!"); + return static_cast( + oocdw_register_timer(pev, fail::onTimerTrigger, + pev->getTimeout() /*timeout in microseconds*/, + true /*start immediately*/, "Fail*: PandaController"/*name*/)); + } + bool m_unregisterTimer(TimerListener* pev) + { + assert(pev != NULL && "FATAL ERROR: TimerListener object ptr cannot be NULL!"); + oocdw_deactivate_timer(static_cast(pev->getId())); + return oocdw_unregisterTimer(static_cast(pev->getId())); + } + }; +}; + +#endif // BUILD_PANDA && CONFIG_EVENT_BREAKPOINTS +#endif // __PANDA_LISTENER_AH__ diff --git a/src/core/sal/panda/PandaWatchpoints.ah b/src/core/sal/panda/PandaWatchpoints.ah new file mode 100644 index 00000000..6c622d00 --- /dev/null +++ b/src/core/sal/panda/PandaWatchpoints.ah @@ -0,0 +1,61 @@ +#ifndef __PANDA_WATCHPOINTS_AH__ + #define __PANDA_WATCHPOINTS_AH__ + +#include "config/FailConfig.hpp" +#include "config/VariantConfig.hpp" + +#if defined(BUILD_PANDA) && defined(CONFIG_EVENT_MEMREAD) && defined(CONFIG_EVENT_MEMWRITE) + +#include "../SALInst.hpp" +#include "../../../debuggers/openocd/openocd_wrapper.hpp" + +aspect PandaWatchpoints +{ + advice "fail::MemAccessListener" : slice class + { + int m_t32access; + public: + bool onAddition() + { + // Setup Watchpoint on Pandaboard + struct halt_condition hc; + + switch(m_WatchType) { + case MemAccessEvent::MEM_READ: hc.type = HALT_TYPE_WP_READ; break; + case MemAccessEvent::MEM_WRITE: hc.type = HALT_TYPE_WP_WRITE; break; + case MemAccessEvent::MEM_READWRITE: hc.type = HALT_TYPE_WP_READWRITE; break; + default: return false; + } + + hc.address = m_WatchAddr; + hc.addr_len = m_WatchWidth; + + oocdw_set_halt_condition(&hc); + + return true; + } + + void onDeletion() + { + // Remove Watchpoint from Pandaboard + struct halt_condition hc; + + switch(m_WatchType) { + case MemAccessEvent::MEM_READ: hc.type = HALT_TYPE_WP_READ; break; + case MemAccessEvent::MEM_WRITE: hc.type = HALT_TYPE_WP_WRITE; break; + case MemAccessEvent::MEM_READWRITE: hc.type = HALT_TYPE_WP_READWRITE; break; + default: return; // ToDo: Error handling + } + + hc.address = m_WatchAddr; + hc.addr_len = m_WatchWidth; + + // ToDo: Error handling + oocdw_delete_halt_condition(&hc); + } + }; + +}; + +#endif // BUILD_PANDA && CONFIG_EVENT_MEMREAD && CONFIG_EVENT_MEMWRITE +#endif // __PANDA_WATCHPOINTS_AH__