fail: add support for pandaboard
Change-Id: I1525c9b36d58bf53ad238a553d914f183f983bba
This commit is contained in:
19
.gitignore
vendored
19
.gitignore
vendored
@ -1,5 +1,7 @@
|
|||||||
*.o
|
*.o
|
||||||
|
*.lo
|
||||||
*.a
|
*.a
|
||||||
|
*.la
|
||||||
*.d
|
*.d
|
||||||
*.acc
|
*.acc
|
||||||
*.pb.h
|
*.pb.h
|
||||||
@ -10,6 +12,7 @@
|
|||||||
Makefile
|
Makefile
|
||||||
build
|
build
|
||||||
build-*
|
build-*
|
||||||
|
.deps
|
||||||
|
|
||||||
simulators/bochs/autom4te.cache/
|
simulators/bochs/autom4te.cache/
|
||||||
simulators/bochs/bochs
|
simulators/bochs/bochs
|
||||||
@ -35,3 +38,19 @@ simulators/gem5/.hg
|
|||||||
simulators/gem5/m5out/
|
simulators/gem5/m5out/
|
||||||
|
|
||||||
src/core/sal/gem5/SConscript
|
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
|
||||||
|
|
||||||
|
|||||||
22
cmake/FindFTDI.cmake
Normal file
22
cmake/FindFTDI.cmake
Normal file
@ -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)
|
||||||
49
cmake/panda.cmake
Normal file
49
cmake/panda.cmake
Normal file
@ -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)
|
||||||
23
src/core/sal/panda/PandaArmCPU.cc
Normal file
23
src/core/sal/panda/PandaArmCPU.cc
Normal file
@ -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
|
||||||
71
src/core/sal/panda/PandaArmCPU.hpp
Normal file
71
src/core/sal/panda/PandaArmCPU.hpp
Normal file
@ -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__
|
||||||
74
src/core/sal/panda/PandaBreakpoints.ah
Normal file
74
src/core/sal/panda/PandaBreakpoints.ah
Normal file
@ -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__
|
||||||
18
src/core/sal/panda/PandaConfig.hpp
Normal file
18
src/core/sal/panda/PandaConfig.hpp
Normal file
@ -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__
|
||||||
116
src/core/sal/panda/PandaController.cc
Normal file
116
src/core/sal/panda/PandaController.cc
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#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<ConcreteCPU*>::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<TimerListener*>(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<IOPortListener*>(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
|
||||||
95
src/core/sal/panda/PandaController.hpp
Normal file
95
src/core/sal/panda/PandaController.hpp
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#ifndef __PANDA_CONTROLLER_HPP__
|
||||||
|
#define __PANDA_CONTROLLER_HPP__
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#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__
|
||||||
11
src/core/sal/panda/PandaListener.cc
Normal file
11
src/core/sal/panda/PandaListener.cc
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#include "PandaListener.hpp"
|
||||||
|
#include "../SALInst.hpp"
|
||||||
|
|
||||||
|
namespace fail {
|
||||||
|
|
||||||
|
void onTimerTrigger(void* thisPtr)
|
||||||
|
{
|
||||||
|
simulator.onTimerTrigger(thisPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end-of-namespace: fail
|
||||||
13
src/core/sal/panda/PandaListener.hpp
Normal file
13
src/core/sal/panda/PandaListener.hpp
Normal file
@ -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__
|
||||||
114
src/core/sal/panda/PandaMemory.hpp
Normal file
114
src/core/sal/panda/PandaMemory.hpp
Normal file
@ -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<byte_t>(*reinterpret_cast<Bit8u*>(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<byte_t>(*reinterpret_cast<Bit8u*>(haddr));*/
|
||||||
|
|
||||||
|
uint8_t *d = static_cast<uint8_t *>(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<uint8_t const *>(src);
|
||||||
|
|
||||||
|
// ToDo: Check Endianess?
|
||||||
|
oocdw_write_to_memory(addr, 1, cnt, s, false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end-of-namespace: fail
|
||||||
|
|
||||||
|
#endif // __PANDA_MEMORY_HPP__
|
||||||
50
src/core/sal/panda/PandaTimer.ah
Normal file
50
src/core/sal/panda/PandaTimer.ah
Normal file
@ -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<timer_id_t>(
|
||||||
|
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<unsigned>(pev->getId()));
|
||||||
|
return oocdw_unregisterTimer(static_cast<unsigned>(pev->getId()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BUILD_PANDA && CONFIG_EVENT_BREAKPOINTS
|
||||||
|
#endif // __PANDA_LISTENER_AH__
|
||||||
61
src/core/sal/panda/PandaWatchpoints.ah
Normal file
61
src/core/sal/panda/PandaWatchpoints.ah
Normal file
@ -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__
|
||||||
Reference in New Issue
Block a user