Skip to content

Commit

Permalink
Implemented basic MSP430 GDB proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
sysprogs committed Sep 1, 2012
0 parents commit aae9135
Show file tree
Hide file tree
Showing 25 changed files with 5,186 additions and 0 deletions.
258 changes: 258 additions & 0 deletions GDBTarget.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
#include "stdafx.h"
#include "GDBTarget.h"
#include "MSP430Util.h"

using namespace GDBServerFoundation;
using namespace MSP430Proxy;

#define REPORT_AND_RETURN(msg, result) { ReportLastMSP430Error(msg); return result; }

bool MSP430Proxy::MSP430GDBTarget::Initialize( const char *pPortName )
{
if (m_bClosePending)
return m_bValid;

LONG version = 0;
if (MSP430_Initialize((char *)pPortName, &version) != STATUS_OK)
REPORT_AND_RETURN("Cannot initialize MSP430.DLL", false);
m_bClosePending = true;

if (MSP430_VCC(3333) != STATUS_OK)
REPORT_AND_RETURN("Cannot enable Vcc", false);

if (MSP430_Identify((char *)&m_DeviceInfo, sizeof(m_DeviceInfo), DEVICE_UNKNOWN) != STATUS_OK)
REPORT_AND_RETURN("Cannot identify the MSP430 device", false);

if (MSP430_Reset(ALL_RESETS, FALSE, FALSE) != STATUS_OK)
REPORT_AND_RETURN("Cannot reset the MSP430 device", false);

m_UsedBreakpoints.resize(m_DeviceInfo.nBreakpoints);

m_bValid = true;
return true;
}

MSP430Proxy::MSP430GDBTarget::~MSP430GDBTarget()
{
if (m_bClosePending)
MSP430_Close(FALSE);
}

bool MSP430Proxy::MSP430GDBTarget::WaitForJTAGEvent()
{
for (;;)
{
LONG state = 0;
if (MSP430_State(&state, m_BreakInPending, NULL) != STATUS_OK)
REPORT_AND_RETURN("Cannot query device state", false);
if (state != RUNNING)
{
m_BreakInPending = false;
return true;
}
}
}

GDBServerFoundation::GDBStatus MSP430Proxy::MSP430GDBTarget::ExecuteRemoteCommand( const std::string &command, std::string &output )
{
if (command == "help")
{
output = "Supported stub commands:\n\
\tmon help - Display this message\n\
\tmon erase - Erase the FLASH memory\n";
return kGDBSuccess;
}
else if (command == "erase")
{
if (MSP430_Erase(ERASE_MAIN, m_DeviceInfo.mainStart, m_DeviceInfo.mainEnd - m_DeviceInfo.mainStart) != STATUS_OK)
{
output = "Cannot erase FLASH: ";
output += GetLastMSP430Error();
output += "\n";
}
else
output = "Flash memory erased. Run \"load\" to program your binary.\n";

return kGDBSuccess;
}
else
return kGDBNotSupported;
}

GDBServerFoundation::GDBStatus MSP430Proxy::MSP430GDBTarget::GetEmbeddedMemoryRegions( std::vector<EmbeddedMemoryRegion> &regions )
{
if (m_DeviceInfo.mainStart || m_DeviceInfo.mainEnd)
regions.push_back(EmbeddedMemoryRegion(mtFLASH, m_DeviceInfo.mainStart, m_DeviceInfo.mainEnd - m_DeviceInfo.mainStart + 1));
if (m_DeviceInfo.ramStart || m_DeviceInfo.ramEnd)
regions.push_back(EmbeddedMemoryRegion(mtRAM, m_DeviceInfo.ramStart, m_DeviceInfo.ramEnd- m_DeviceInfo.ramStart + 1));
if (m_DeviceInfo.ram2Start || m_DeviceInfo.ram2End)
regions.push_back(EmbeddedMemoryRegion(mtRAM, m_DeviceInfo.ram2Start, m_DeviceInfo.ram2End- m_DeviceInfo.ram2Start + 1));
return kGDBSuccess;
}

GDBServerFoundation::GDBStatus MSP430GDBTarget::GetLastStopRecord( TargetStopRecord *pRec )
{
pRec->Reason = kSignalReceived;
pRec->Extension.SignalNumber = SIGTRAP;
return kGDBSuccess;
}

GDBServerFoundation::GDBStatus MSP430GDBTarget::ResumeAndWait( int threadID )
{
if (MSP430_Run(RUN_TO_BREAKPOINT, FALSE) != STATUS_OK)
REPORT_AND_RETURN("Cannot resume device", kGDBUnknownError);

if (!WaitForJTAGEvent())
return kGDBUnknownError;
return kGDBSuccess;
}

GDBServerFoundation::GDBStatus MSP430GDBTarget::Step( int threadID )
{
if (MSP430_Run(SINGLE_STEP, FALSE) != STATUS_OK)
REPORT_AND_RETURN("Cannot perform single stepping", kGDBUnknownError);

if (!WaitForJTAGEvent())
return kGDBUnknownError;

return kGDBSuccess;
}

GDBServerFoundation::GDBStatus MSP430GDBTarget::SendBreakInRequestAsync()
{
m_BreakInPending = true;
return kGDBSuccess;
}

GDBServerFoundation::GDBStatus MSP430GDBTarget::ReadFrameRelatedRegisters( int threadID, TargetRegisterValues &registers )
{
LONG rawRegs[16];
if (MSP430_Read_Registers(rawRegs, MASKREG(PC) | MASKREG(SP)) != STATUS_OK)
REPORT_AND_RETURN("Cannot read frame-related registers", kGDBUnknownError);

registers[PC] = RegisterValue(rawRegs[PC], 2);
registers[SP] = RegisterValue(rawRegs[SP], 2);

return kGDBSuccess;
}

GDBServerFoundation::GDBStatus MSP430GDBTarget::ReadTargetRegisters( int threadID, TargetRegisterValues &registers )
{
LONG rawRegs[16];
if (MSP430_Read_Registers(rawRegs, ALL_REGS) != STATUS_OK)
REPORT_AND_RETURN("Cannot read device registers", kGDBUnknownError);

for (size_t i = 0; i < __countof(rawRegs); i++)
registers[i] = RegisterValue(rawRegs[i], 16);

return kGDBSuccess;
}

GDBServerFoundation::GDBStatus MSP430GDBTarget::WriteTargetRegisters( int threadID, const TargetRegisterValues &registers )
{
LONG rawRegs[16];
int mask = 0;

for (size_t i = 0; i < 16; i++)
if (registers[i].Valid)
{
mask |= MASKREG(i);
rawRegs[i] = registers[i].ToUInt32();
}

if (MSP430_Write_Registers(rawRegs, mask) != STATUS_OK)
REPORT_AND_RETURN("Cannot write device registers", kGDBUnknownError);

return kGDBSuccess;
}

GDBServerFoundation::GDBStatus MSP430GDBTarget::ReadTargetMemory( ULONGLONG Address, void *pBuffer, size_t *pSizeInBytes )
{
if (MSP430_Read_Memory((LONG)Address, (char *)pBuffer, *pSizeInBytes) != STATUS_OK)
REPORT_AND_RETURN("Cannot read device memory", kGDBUnknownError);
return kGDBSuccess;
}

GDBServerFoundation::GDBStatus MSP430GDBTarget::WriteTargetMemory( ULONGLONG Address, const void *pBuffer, size_t sizeInBytes )
{
if (MSP430_Write_Memory((LONG)Address, (char *)pBuffer, sizeInBytes) != STATUS_OK)
REPORT_AND_RETURN("Cannot write device memory", kGDBUnknownError);
return kGDBSuccess;
}

GDBServerFoundation::GDBStatus MSP430GDBTarget::GetDynamicLibraryList( std::vector<DynamicLibraryRecord> &libraries )
{
return kGDBNotSupported;
}

GDBServerFoundation::GDBStatus MSP430GDBTarget::GetThreadList( std::vector<ThreadRecord> &threads )
{
return kGDBNotSupported;
}

GDBServerFoundation::GDBStatus MSP430GDBTarget::SetThreadModeForNextCont( int threadID, DebugThreadMode mode, OUT bool *pNeedRestoreCall, IN OUT INT_PTR *pRestoreCookie )
{
return kGDBNotSupported;
}

GDBServerFoundation::GDBStatus MSP430GDBTarget::Terminate()
{
return kGDBNotSupported;
}

GDBServerFoundation::GDBStatus MSP430GDBTarget::CreateBreakpoint( BreakpointType type, ULONGLONG Address, unsigned kind, OUT INT_PTR *pCookie )
{
if (type != bptHardwareBreakpoint)
return kGDBNotSupported;

for (size_t i = 0; i < m_UsedBreakpoints.size(); i++)
if (!m_UsedBreakpoints[i])
{
if (MSP430_Breakpoint(i, (LONG)Address) != STATUS_OK)
REPORT_AND_RETURN("Cannot set a hardware breakpoint", kGDBUnknownError);
m_UsedBreakpoints[i] = true;
*pCookie = i;
return kGDBSuccess;
}

return kGDBUnknownError;
}

GDBServerFoundation::GDBStatus MSP430GDBTarget::RemoveBreakpoint( BreakpointType type, ULONGLONG Address, INT_PTR Cookie )
{
if (type != bptHardwareBreakpoint)
return kGDBNotSupported;

size_t i = (size_t)Cookie;
MSP430_Clear_Breakpoint(i);
m_UsedBreakpoints[i] = false;

return kGDBSuccess;
}

GDBServerFoundation::GDBStatus MSP430Proxy::MSP430GDBTarget::EraseFLASH( ULONGLONG addr, size_t length )
{
if (MSP430_Erase(ERASE_MAIN, (LONG)addr, length) != STATUS_OK)
REPORT_AND_RETURN("Cannot erase FLASH memory", kGDBUnknownError);
return kGDBSuccess;
}

GDBServerFoundation::GDBStatus MSP430Proxy::MSP430GDBTarget::WriteFLASH( ULONGLONG addr, const void *pBuffer, size_t length )
{
if (MSP430_Write_Memory((LONG)addr, (char *)pBuffer, length) != STATUS_OK)
REPORT_AND_RETURN("Cannot program FLASH memory", kGDBUnknownError);
return kGDBSuccess;
}

GDBServerFoundation::GDBStatus MSP430Proxy::MSP430GDBTarget::CommitFLASHWrite()
{
return kGDBSuccess;
}

void MSP430Proxy::MSP430GDBTarget::ReportLastMSP430Error( const char *pHint )
{
if (pHint)
printf("%s: %s\n", pHint, GetLastMSP430Error());
else
printf("%s\n", GetLastMSP430Error());
}
77 changes: 77 additions & 0 deletions GDBTarget.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#pragma once
#include "../../GDBServerFoundation/GDBServer.h"
#include "../../GDBServerFoundation/GDBStub.h"
#include "../../GDBServerFoundation/IGDBTarget.h"
#include <MSP430_Debug.h>

#include "registers-msp430.h"
#include <vector>

namespace MSP430Proxy
{
using namespace GDBServerFoundation;

class MSP430GDBTarget : public ISyncGDBTarget, public IFLASHProgrammer
{
private:
bool m_bClosePending, m_bValid;
DEVICE_T m_DeviceInfo;
std::vector<bool> m_UsedBreakpoints;

bool m_BreakInPending;

private:
bool WaitForJTAGEvent();
void ReportLastMSP430Error(const char *pHint);

public:
MSP430GDBTarget()
: m_bClosePending(false)
, m_bValid(false)
, m_BreakInPending(false)
{
}

~MSP430GDBTarget();

bool Initialize(const char *pPortName);

virtual GDBStatus GetLastStopRecord(TargetStopRecord *pRec);
virtual GDBStatus ResumeAndWait(int threadID);
virtual GDBStatus Step(int threadID);
virtual GDBStatus SendBreakInRequestAsync();

virtual const PlatformRegisterList *GetRegisterList()
{
return &GDBServerFoundation::MSP430::RegisterList;
}

public: //Register accessing API
virtual GDBStatus ReadFrameRelatedRegisters(int threadID, TargetRegisterValues &registers);
virtual GDBStatus ReadTargetRegisters(int threadID, TargetRegisterValues &registers);
virtual GDBStatus WriteTargetRegisters(int threadID, const TargetRegisterValues &registers);

public: //Memory accessing API
virtual GDBStatus ReadTargetMemory(ULONGLONG Address, void *pBuffer, size_t *pSizeInBytes);
virtual GDBStatus WriteTargetMemory(ULONGLONG Address, const void *pBuffer, size_t sizeInBytes);

public: //Optional methods, can be left unimplemented
virtual GDBStatus GetDynamicLibraryList(std::vector<DynamicLibraryRecord> &libraries);
virtual GDBStatus GetThreadList(std::vector<ThreadRecord> &threads);
virtual GDBStatus SetThreadModeForNextCont(int threadID, DebugThreadMode mode, OUT bool *pNeedRestoreCall, IN OUT INT_PTR *pRestoreCookie);
virtual GDBStatus Terminate();

virtual GDBStatus CreateBreakpoint(BreakpointType type, ULONGLONG Address, unsigned kind, OUT INT_PTR *pCookie);
virtual GDBStatus RemoveBreakpoint(BreakpointType type, ULONGLONG Address, INT_PTR Cookie);

virtual GDBStatus ExecuteRemoteCommand(const std::string &command, std::string &output);

virtual IFLASHProgrammer *GetFLASHProgrammer() {return this;}

public:
virtual GDBStatus GetEmbeddedMemoryRegions(std::vector<EmbeddedMemoryRegion> &regions);
virtual GDBStatus EraseFLASH(ULONGLONG addr, size_t length);
virtual GDBStatus WriteFLASH(ULONGLONG addr, const void *pBuffer, size_t length);
virtual GDBStatus CommitFLASHWrite();
};
}
2 changes: 2 additions & 0 deletions MSP430Util.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#include "stdafx.h"
#include "MSP430Util.h"
7 changes: 7 additions & 0 deletions MSP430Util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#pragma once
#include <MSP430.h>

static const char *GetLastMSP430Error()
{
return MSP430_Error_String(MSP430_Error_Number());
}
40 changes: 40 additions & 0 deletions ReadMe.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
========================================================================
CONSOLE APPLICATION : msp430-gdbproxy Project Overview
========================================================================

AppWizard has created this msp430-gdbproxy application for you.

This file contains a summary of what you will find in each of the files that
make up your msp430-gdbproxy application.


msp430-gdbproxy.vcxproj
This is the main project file for VC++ projects generated using an Application Wizard.
It contains information about the version of Visual C++ that generated the file, and
information about the platforms, configurations, and project features selected with the
Application Wizard.

msp430-gdbproxy.vcxproj.filters
This is the filters file for VC++ projects generated using an Application Wizard.
It contains information about the association between the files in your project
and the filters. This association is used in the IDE to show grouping of files with
similar extensions under a specific node (for e.g. ".cpp" files are associated with the
"Source Files" filter).

msp430-gdbproxy.cpp
This is the main application source file.

/////////////////////////////////////////////////////////////////////////////
Other standard files:

StdAfx.h, StdAfx.cpp
These files are used to build a precompiled header (PCH) file
named msp430-gdbproxy.pch and a precompiled types file named StdAfx.obj.

/////////////////////////////////////////////////////////////////////////////
Other notes:

AppWizard uses "TODO:" comments to indicate parts of the source code you
should add to or customize.

/////////////////////////////////////////////////////////////////////////////
Loading

0 comments on commit aae9135

Please sign in to comment.