T32: FailT32 support for Cortex-M3

Currently working:
 - Connect/Disconnect, Read CPU info
 - CMM Script generation and T32 startup via cmake (make runt32)
 - Read/Write Register, Read Program Pointer
 - Read/Write Memory
 - Single Breakpoint
 - Setting Memory Breakpoint

TODO:
 - Fix mock aspect for T32_GetRam.
 - Fix Thumb2 bit in function addresses from ELFReader
 - Evaluate memory breakpoint hit
This commit is contained in:
Martin Hoffmann
2013-02-28 16:09:01 +01:00
parent 5481cbfd39
commit 3501050548
13 changed files with 170 additions and 26 deletions

View File

@ -1,5 +1,11 @@
# T32 remote specific configuration options
OPTION( T32_MOCK_API "Intercept remote calls to T32 for debugging" OFF)
include_directories(include)
set(T32_PORTNUM 20000 CACHE PATH "TCP Port number for remote access.")
set(T32_PACKLEN 1024 CACHE INTERNAL "TCP Packet size, max. 1024")
configure_file( include/t32config.hpp.in ${CMAKE_BINARY_DIR}/include/t32config.hpp)
include_directories(include ${CMAKE_BINARY_DIR}/include)
include_directories(${CMAKE_BINARY_DIR}/src/core)

View File

@ -1,11 +1,36 @@
## Setup T32 target architecture for startup scripts
if(EXISTS $ENV{T32SYS})
SET(T32_SYS $ENV{T32SYS})
message(STATUS "[FAIL*] T32 base directory: T32SYS=${T32_SYS}")
else()
message(FATAL_ERROR "Please set env variable T32SYS to a valid T32 installation base directory.")
endif()
if(EXISTS $ENV{FAIL_ELF_PATH})
SET(T32_ELF_PATH $ENV{FAIL_ELF_PATH})
message(STATUS "[FAIL*] T32 ELF under test: ${T32_ELF_PATH}")
else()
message(FATAL_ERROR "Please set the FAIL_ELF_PATH enviroment variable to the binary under test.")
endif()
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/cmm)
configure_file(config.t32.usb.in ${PROJECT_BINARY_DIR}/cmm/config.t32.usb)
configure_file(t32.cmm ${PROJECT_BINARY_DIR}/cmm/t32.cmm COPYONLY)
set(T32_ARCHITECTURE armm3 CACHE PATH "Setup target architecture for default cmm scripts (currently only armm3)")
message(STATUS "[FAIL*] T32 Architecture: ${T32_ARCHITECTURE}")
set(T32_EXE "${T32_SYS}/bin/pc_linux/" CACHE INTERNAL "") # TODO: set pc_linux64 for 64 bit systems
add_subdirectory(${T32_ARCHITECTURE})
message(STATUS "[FAIL*] T32 CPU name: ${T32_CPUNAME}")
message(STATUS "[FAIL*] T32 Architecture: ${T32_ARCHITECTURE}")
message(STATUS "[FAIL*] T32 CPU name: ${T32_CPUNAME}")
message(STATUS "[FAIL*] T32 Executable: ${T32_EXE}")
add_custom_target(runt32
COMMAND T32CONFIG=${PROJECT_BINARY_DIR}/cmm/config.t32.usb ${T32_EXE} &
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/cmm"
COMMENT "Starting Lauterbach."
)

View File

@ -1,9 +1,15 @@
### Configure cmm Scripts for ARM Cortex-M3
if(EXISTS $ENV{T32SYS})
SET(T32_SYS $ENV{T32SYS})
else(EXISTS $ENV{KESOROOTPATH})
message(FATAL_ERROR "Please set env variable T32SYS to valid T32 installation base directory.")
endif(EXISTS $ENV{T32SYS})
set(T32_EXE "${T32_EXE}/t32marm" CACHE INTERNAL "")
set(T32_CPUNAME STM32F103RG CACHE PATH "CPU name for SYSTEM.CPU call. (e.g. STM32F103RG)")
configure_file(armm3cfg.cmm.in ${PROJECT_BINARY_DIR}/cmm/armm3cfg.cmm)
configure_file(init.cmm ${PROJECT_BINARY_DIR}/cmm/init.cmm COPYONLY)
configure_file(loadelf.cmm ${PROJECT_BINARY_DIR}/cmm/loadelf.cmm COPYONLY)
configure_file(t32term.cmm ${PROJECT_BINARY_DIR}/cmm/t32term.cmm COPYONLY)

View File

@ -0,0 +1,58 @@
;
;please refer the installation guide for more information
;about your configuration
;
;
;uncomment the following 3 lines if you don't use already environment variables
;changes to the actual directory names are necessary
;OS=
;SYS=/opt/t32
;TMP=/usr/tmp
;
;uncomment the following 4 lines if you use PowerTrace, PowerNexus or PowerDebugEthernet
;with onhost driver executable (t32m*) via ethernet interface
;the nodename is only the default name, please replace it with the actual node name
;PBI=
;NET
;NODE=t32
;PACKLEN=1024
;uncomment the following 2 lines if you use PowerTrace, PowerNexus, PowerDebugEthernet or
;PowerDebugInterface USB with onhost driver executable (t32m*) via USB interface
;please refer the installation manual (file icd_quick_installation.pdf) about more details
;concerning USB driver installation
PBI=
USB
;
;uncomment the following 3 lines if you use an ICE or PodbusEthernetController
;with standard hostdriver executable (t32cde) via ethernet interface
;the nodename is only the default name, please replace it with the actual node name
;LINK=NET
;NODE=t32
;PACKLEN=1024
;uncomment the following 1 lines if you use SCSI interface (ICE)
;LINK=SCSI
;uncomment the following 3 lines if you want to use TRACE32 fonts
;SCREEN=
;FONT=DEC
;FONT=SMALL
;uncomment the following 2 lines if you want to use TRACE32 bitmap fonts
;SCREEN=
;FONTMODE=3
;uncomment the following 2 lines if you use OPENWINDOWS
;SCREEN=
;WMGR=OW16
;uncomment the following 2 lines if you use MOTIF
;SCREEN=
;WMGR=MOTIF16
RCL=NETASSIST
PACKLEN=1024
PORT=@T32_PORTNUM@

View File

@ -1,10 +1,10 @@
;===== Cortex-M3 Lauterbach initialisation ====
&appimage="OS.ENV(FAIL_ELF_PATH)"
&appimage=OS.ENV(FAIL_ELF_PATH)
DO init.cmm
VAr.Frame /LOCALS /CALLER
;VAr.Frame /LOCALS /CALLER
REGISTER /SPOTLIGHT
Data.ListAsm
;Data.ListAsm

View File

@ -6,6 +6,7 @@
#include <vector>
#include "sal/SALInst.hpp"
#include "t32config.hpp"
namespace fail {
@ -16,7 +17,7 @@ namespace fail {
*/
class T32Connector {
public:
T32Connector() : m_hostname("localhost"), m_port("20010"), m_packetlength("1024"), m_log("T32", false), m_connection_established(false) { };
T32Connector() : m_hostname("localhost"), m_port(T32_PORTNUM), m_packetlength(T32_PACKLEN), m_log("T32", false), m_connection_established(false) { };
T32Connector(const char* hostname, const char* port, const char* packlen) : m_hostname(hostname), m_port(port),
m_packetlength(packlen), m_log("T32", false), m_connection_established(false) { };
@ -48,6 +49,9 @@ namespace fail {
bool isBigEndian(void) const { return !m_littleendian; };
bool isLittleEndian(void) const { return m_littleendian; };
void showDataRegions(void) const { showMemoryRegions(m_data_memory_map); };
void showProgramRegions(void) const { showMemoryRegions(m_program_memory_map); };
private:
const char* m_hostname; //!< The hostname of the T32 device
const char* m_port; //!< The port to connect as configure in config.t32. Here we use strings, as required by the API
@ -57,7 +61,8 @@ namespace fail {
std::string m_cpustring;
typedef std::vector< std::pair< address_t, address_t > > memory_map_t;
typedef std::pair< address_t, address_t > region_t;
typedef std::vector< region_t > memory_map_t;
memory_map_t m_data_memory_map;
memory_map_t m_program_memory_map;
@ -78,6 +83,7 @@ namespace fail {
enum MemoryDiscoverCommand_t { DISCOVER_PROGRAM_RAM = 2, DISCOVER_DATA_RAM = 1, DISCOVER_END = 0, };
void discoverMemory(int discovertype, memory_map_t & map);
void showMemoryRegions(const memory_map_t & map) const;
};
} // end-of-namespace fail

View File

@ -0,0 +1,8 @@
#ifndef __T32CONFIG_HPP__
#define __T32CONFIG_HPP__
#define T32_PORTNUM "@T32_PORTNUM@"
#define T32_PACKLEN "@T32_PACKLEN@"
#endif

View File

@ -14,27 +14,34 @@ T32Connector::~T32Connector() {
bool T32Connector::startup(){
// Setup connection to Lauterbach
m_log << "Remote connection: " << m_hostname << ":" << m_port << " - Packet length: " << m_packetlength << std::endl;
T32_Config("NODE=", m_hostname);
T32_Config("PACKLEN=", m_packetlength);
T32_Config("PORT=", m_port);
T32_Config("NODE=", m_hostname);
T32_Config("PACKLEN=", m_packetlength);
T32_Config("PORT=", m_port);
m_log << "Init." << std::endl;
if(!err(T32_Init()) ) { return false; }
if(!err(T32_Init()) ) { return false; }
m_log << "Attach." << std::endl;
if(!err(T32_Attach(T32_DEV_ICD)) ) { return false; }
if(!err(T32_Attach(T32_DEV_ICD)) ) { return false; }
word tmp, fpu, endian;
char* cpuname[128];
char * cpuname;
//if(!err(T32_GetCpuInfo( reinterpret_cast<char**>(&m_cpustring), &fpu, &endian, &tmp))) { return false; }
if(!err(T32_GetCpuInfo( reinterpret_cast<char**>(&cpuname), &fpu, &endian, &tmp))) { return false; }
if(!err(T32_GetCpuInfo( (&cpuname), &fpu, &endian, &tmp))) { return false; }
m_littleendian = (endian != 0);
m_cpustring = reinterpret_cast<const char*>(cpuname);
m_log << "Attached to: " << m_cpustring << (isBigEndian() == true ? " (BIG-endian)" : " (little-endian)") << std::endl;
m_log << "Attached to: " << m_cpustring << std::endl;
// discoverMemory(DISCOVER_PROGRAM_RAM, m_program_memory_map);
// discoverMemory(DISCOVER_DATA_RAM, m_data_memory_map);
// discoverMemory(DISCOVER_PROGRAM_RAM, m_program_memory_map);
// discoverMemory(DISCOVER_DATA_RAM, m_data_memory_map);
if(m_data_memory_map.size() > 0) {
showDataRegions();
}
if(m_program_memory_map.size() > 0) {
showProgramRegions();
}
m_connection_established = true;
// TODO send init script.
@ -44,7 +51,9 @@ bool T32Connector::startup(){
void T32Connector::discoverMemory(int access, memory_map_t& map) {
dword pstart = 0, pend;
word paccess;
int c = 1;
do {
std::cout << "Discovering Memory Regions: " << c++ << std::endl;
paccess = access;
err(T32_GetRam(&pstart, &pend, &paccess));
if(paccess != DISCOVER_END){
@ -66,6 +75,14 @@ int T32Connector::getState() const {
}
void T32Connector::showMemoryRegions(const memory_map_t& map) const {
for(int i = 0; i < map.size(); i++){
std::cout << "[" << i << "] 0x" << std::hex << map[i].first << " - 0x" << std::hex << map[i].second << std::endl;
}
}
/* Default T32 error handler */
bool T32Connector::err(int errornum) const {
if(errornum != 0){

View File

@ -78,7 +78,10 @@ int main(int argc, char** argv){
}
// Initialize T32
t32.startup();
if(t32.startup() == false){
cout << "Could not connect to Lauterbach :(" << endl;
return -1;
}
// Let the SimulatorController do the dirty work.

View File

@ -6,6 +6,7 @@
#cmakedefine BUILD_OVP
#cmakedefine BUILD_QEMU
#cmakedefine BUILD_T32
#cmakedefine T32_MOCK_API
#cmakedefine BUILD_X86
#cmakedefine BUILD_ARM

View File

@ -22,6 +22,7 @@ regdata_t T32ArmCPU::getRegisterContent(Register* reg) const
return m_regbuffer[reg->getIndex()];
} else {
/// TODO Error handling!
std::cout << "could not read register :(" << std::endl;
}
}
return 0; // we should not come here.
@ -31,12 +32,15 @@ void T32ArmCPU::setRegisterContent(Register* reg, regdata_t value)
{
uint64_t mask = (1 << reg->getIndex());
// set value to be set by T32:
m_regbuffer[reg->getIndex()] = value;
if(mask){
if( T32_WriteRegister(static_cast<dword>(mask & lower), static_cast<dword>(mask >> 32), m_regbuffer) == 0 ){
// No error, return value.
return;
} else {
/// TODO Error handling!
std::cout << "could not write register :(" << std::endl;
}
}
}

View File

@ -2,12 +2,15 @@
#define __T32MOCK_AH__
#include <iostream>
#include "config/VariantConfig.hpp"
#if defined(BUILD_T32) // && defined(T32MOCK)
#if defined(BUILD_T32) && defined(T32_MOCK_API)
#warning "T32 remote calls are intercepted by T32Mock aspect!"
/* Mock aspect for testing without T32 HW attached. */
aspect T32Mock
{
// TODO: Let T32_GetRam's third parameter set to 0.
advice call("% T32_% (...)") : around ()
{
std::cout << "[T32 MOCK] " << JoinPoint::signature() << " (";
@ -21,6 +24,5 @@ aspect T32Mock
*tjp->result() = 0;
}
};
#endif // BUILD_T32 && CONFIG_EVENT_BREAKPOINTS
#endif // __T32MOCK_AH__

View File

@ -26,13 +26,21 @@ bool VEZSExperiment::run()
m_log << "Instruction Pointer: 0x" << hex << simulator.getCPU(0).getInstructionPointer() << endl;
// Test register access
Register* reg = simulator.getCPU(0).getRegister(RI_R1);
m_log << "Register R2: 0x" << hex << simulator.getCPU(0).getRegisterContent(reg) << endl;
reg = simulator.getCPU(0).getRegister(RI_R2);
m_log << "Register R1: 0x" << hex << simulator.getCPU(0).getRegisterContent(reg) << endl;
reg = simulator.getCPU(0).getRegister(RI_R2);
m_log << "Register R2: 0x" << hex << simulator.getCPU(0).getRegisterContent(reg) << endl;
simulator.getCPU(0).setRegisterContent(reg, 0x23);
reg = simulator.getCPU(0).getRegister(RI_R3);
m_log << "Register R3: 0x" << hex << simulator.getCPU(0).getRegisterContent(reg) << endl;
simulator.terminate();
// STOP HERE
// Test Memory access
address_t targetaddress = 0x12345678;
MemoryManager& mm = simulator.getMemoryManager();