diff --git a/MSP430EEMTarget.cpp b/MSP430EEMTarget.cpp index 98cb67a..c70bb8b 100644 --- a/MSP430EEMTarget.cpp +++ b/MSP430EEMTarget.cpp @@ -41,6 +41,7 @@ bool MSP430Proxy::MSP430EEMTarget::Initialize(const GlobalSettings &settings) return false; m_BreakpointPolicy = settings.SoftBreakPolicy; + m_BreakpointInstruction = settings.BreakpointInstruction; MESSAGE_ID msgs = {0,}; msgs.uiMsgIdSingleStep = WMX_SINGLESTEP; @@ -71,12 +72,18 @@ bool MSP430Proxy::MSP430EEMTarget::Initialize(const GlobalSettings &settings) bkpt.lMask = 0xffff; if (MSP430_EEM_SetBreakpoint(&m_SoftwareBreakpointWrapperHandle, &bkpt) != STATUS_OK) REPORT_AND_RETURN("Cannot create a MDB breakpoint for handling software breakpoints", false); + if (m_bVerbose) + printf("Registered software breakpoint support. Breakpoint instruction: 0x%x; meta-breakpoint handle: %d\n", m_BreakpointInstruction, m_SoftwareBreakpointWrapperHandle); m_HardwareBreakpointsUsed++; } else + { m_SoftwareBreakpointWrapperHandle = -1; + if (m_bVerbose) + printf("Warning: Software breakpoints disabled by configuration\n"); + } - m_pBreakpointManager = new SoftwareBreakpointManager(m_DeviceInfo.mainStart, m_DeviceInfo.mainEnd, settings.BreakpointInstruction, settings.InstantBreakpointCleanup); + m_pBreakpointManager = new SoftwareBreakpointManager(m_DeviceInfo.mainStart, m_DeviceInfo.mainEnd, settings.BreakpointInstruction, settings.InstantBreakpointCleanup, settings.Verbose); return true; } @@ -91,17 +98,24 @@ MSP430Proxy::MSP430EEMTarget::~MSP430EEMTarget() memset(&bkpt, 0, sizeof(bkpt)); bkpt.bpMode = BP_CLEAR; - MSP430_EEM_SetBreakpoint(&m_SoftwareBreakpointWrapperHandle, &bkpt); + STATUS_T status = MSP430_EEM_SetBreakpoint(&m_SoftwareBreakpointWrapperHandle, &bkpt); + if (m_bVerbose) + printf("Unregistering software breakpoint support => %d, bpHandle = %d\n", status, m_SoftwareBreakpointWrapperHandle); } } void MSP430Proxy::MSP430EEMTarget::EEMNotificationHandler( MSP430_MSG wMsg, WPARAM wParam, LPARAM lParam ) { + if (m_bVerbose) + printf("EEM notification: 0x%x\n", wMsg); + switch(wMsg) { case WMX_BREKAPOINT: case WMX_SINGLESTEP: case WMX_STOPPED: + if (m_bVerbose) + printf("Target stop detected\n"); m_LastStopEvent = wMsg; m_TargetStopped.Set(); break; @@ -118,6 +132,8 @@ bool MSP430Proxy::MSP430EEMTarget::WaitForJTAGEvent() { for (;;) { + if (m_bVerbose) + printf("Waiting for the target to stop (EEM event will be generated)...\n"); m_TargetStopped.Wait(); bool breakIn = m_BreakInPending; @@ -128,6 +144,9 @@ bool MSP430Proxy::MSP430EEMTarget::WaitForJTAGEvent() if (MSP430_Read_Register(®PC, PC) != STATUS_OK) REPORT_AND_RETURN("Cannot read PC register", false); + if (m_bVerbose) + printf("Target stopped, PC = 0x%x\n", regPC); + SoftwareBreakpointManager::BreakpointState bpState = m_pBreakpointManager->GetBreakpointState(regPC - 2); if (m_RAMBreakpoints.IsBreakpointPresent((USHORT)regPC - 2)) bpState = SoftwareBreakpointManager::BreakpointActive; @@ -136,6 +155,9 @@ bool MSP430Proxy::MSP430EEMTarget::WaitForJTAGEvent() { case SoftwareBreakpointManager::BreakpointActive: case SoftwareBreakpointManager::BreakpointInactive: + if (m_bVerbose) + printf("Found a software breakpoint at PC = 0x%X\n", regPC - 2); + regPC -= 2; if (regPC == m_BreakpointAddrOfLastResumeOp) @@ -144,6 +166,8 @@ bool MSP430Proxy::MSP430EEMTarget::WaitForJTAGEvent() //We don't want to stop indefinitely here. if (m_LastResumeMode != SINGLE_STEP) { + if (m_bVerbose) + printf("Resuming execution after a software breakpoint\n"); if (!DoResumeTarget(m_LastResumeMode)) return false; continue; @@ -156,6 +180,9 @@ bool MSP430Proxy::MSP430EEMTarget::WaitForJTAGEvent() if (bpState == SoftwareBreakpointManager::BreakpointInactive && m_LastResumeMode != SINGLE_STEP && !breakIn) { + if (m_bVerbose) + printf("Breakpoint at PC = 0x%X is inactive. Skipping...\n", regPC); + //Skip the breakpoint if (!DoResumeTarget(m_LastResumeMode)) return false; @@ -269,14 +296,27 @@ bool MSP430Proxy::MSP430EEMTarget::DoResumeTarget( RUN_MODES_t mode ) printf("ERROR: Cannot commit software breakpoints\n"); return false; } - return __super::DoResumeTarget(mode); + + if (!__super::DoResumeTarget(mode)) + return false; + + if (m_BreakInPending) + { + if (m_bVerbose) + printf("Break-in request already pending when resuming the target. Re-sending break-in request to MSP430.DLL.\n"); + SendBreakInRequestAsync(); + } + return true; } GDBServerFoundation::GDBStatus MSP430Proxy::MSP430EEMTarget::SendBreakInRequestAsync() { - LONG state; + LONG state = 0; m_BreakInPending = true; - if (MSP430_State(&state, TRUE, NULL) != STATUS_OK) + STATUS_T status = MSP430_State(&state, TRUE, NULL); + if (m_bVerbose) + printf("Break-in request: MSP430_State() => %d, state = %d\n", status, state); + if (status != STATUS_OK) REPORT_AND_RETURN("Cannot stop device", kGDBNotSupported); return kGDBSuccess; } @@ -318,6 +358,9 @@ GDBServerFoundation::GDBStatus MSP430Proxy::MSP430EEMTarget::DoCreateCodeBreakpo if (MSP430_EEM_SetBreakpoint(&bpHandle, &bkpt) != STATUS_OK) REPORT_AND_RETURN("Cannot set an EEM breakpoint", kGDBUnknownError); + if (m_bVerbose) + printf("Created a hardware breakpoint #%d at 0x%x\n", bpHandle, (ULONG)Address); + m_HardwareBreakpointsUsed++; C_ASSERT(sizeof(bpHandle) == 2); @@ -340,6 +383,9 @@ GDBServerFoundation::GDBStatus MSP430Proxy::MSP430EEMTarget::DoCreateCodeBreakpo unsigned short insn; if (MSP430_Read_Memory(addr, (char *)&insn, 2) != STATUS_OK) REPORT_AND_RETURN("Cannot set a software breakpoint in RAM", kGDBUnknownError); + + if (m_bVerbose) + printf("Setting a RAM breakpoint at 0x%x. Previous instruction is 0x%x\n", addr, insn); *pCookie = MAKE_BP_COOKIE(kBpCookieTypeSoftwareRAM, insn); @@ -371,8 +417,11 @@ GDBServerFoundation::GDBStatus MSP430Proxy::MSP430EEMTarget::DoRemoveCodeBreakpo if (MSP430_EEM_SetBreakpoint(&bpHandle, &bkpt) != STATUS_OK) REPORT_AND_RETURN("Cannot remove an EEM breakpoint", kGDBUnknownError); - if(hardware) - m_HardwareBreakpointsUsed--; + + if (m_bVerbose) + printf("Removed a hardware breakpoint #%d at 0x%x\n", (WORD)(Cookie & kBpCookieDataMask), (ULONG)Address); + + m_HardwareBreakpointsUsed--; return kGDBSuccess; } else @@ -382,6 +431,9 @@ GDBServerFoundation::GDBStatus MSP430Proxy::MSP430EEMTarget::DoRemoveCodeBreakpo ASSERT((Cookie & kBpCookieTypeMask) == kBpCookieTypeSoftwareRAM); unsigned short originalINSN = (unsigned short)(Cookie & kBpCookieDataMask); + if (m_bVerbose) + printf("Deleting SRAM breakpoint at 0x%x. Restoring original instruction of 0x%x.\n", (ULONG)Address, originalINSN); + if (MSP430_Write_Memory(Address & ~1, (char *)&originalINSN, 2) != STATUS_OK) REPORT_AND_RETURN("Cannot remove a software breakpoint from RAM", kGDBUnknownError); diff --git a/MSP430Target.cpp b/MSP430Target.cpp index 0e910cd..1d00a6c 100644 --- a/MSP430Target.cpp +++ b/MSP430Target.cpp @@ -13,11 +13,63 @@ bool MSP430Proxy::MSP430GDBTarget::Initialize(const GlobalSettings &settings) if (m_bClosePending) return m_bValid; + m_bVerbose = settings.Verbose; + LONG version = 0; if (MSP430_Initialize((char *)settings.PortName, &version) != STATUS_OK) REPORT_AND_RETURN("Cannot initialize MSP430.DLL", false); m_bClosePending = true; + switch(settings.Interface) + { + case Jtag: + if (m_bVerbose) + printf("Selecting JTAG interface...\n"); + if (MSP430_Configure(INTERFACE_MODE, JTAG_IF) != STATUS_OK) + REPORT_AND_RETURN("Cannot select JTAG interface", false); + break; + case SpyBiWare: + if (m_bVerbose) + printf("Selecting Spy-bi-Wire interface...\n"); + if (MSP430_Configure(INTERFACE_MODE, SPYBIWIRE_IF) != STATUS_OK) + REPORT_AND_RETURN("Cannot select Spy-bi-Wire interface", false); + break; + case JtagOverSpyBiWare: + if (m_bVerbose) + printf("Selecting JTAG-over-Spy-bi-Wire interface...\n"); + if (MSP430_Configure(INTERFACE_MODE, SPYBIWIREJTAG_IF) != STATUS_OK) + REPORT_AND_RETURN("Cannot select JTAG-over-Spy-bi-Wire interface", false); + break; + case AutomaticInterface: + if (m_bVerbose) + printf("Selecting auto interface...\n"); + if (MSP430_Configure(INTERFACE_MODE, AUTOMATIC_IF) != STATUS_OK) + REPORT_AND_RETURN("Cannot select auto interface", false); + break; + } + + switch(settings.InterfaceSpeed) + { + case Slow: + if (m_bVerbose) + printf("Setting interface speed to slow...\n"); + if (MSP430_Configure(SET_INTERFACE_SPEED, SLOW) != STATUS_OK) + REPORT_AND_RETURN("Cannot set interface speed", false); + break; + case Medium: + if (m_bVerbose) + printf("Setting interface speed to medium...\n"); + if (MSP430_Configure(SET_INTERFACE_SPEED, MEDIUM) != STATUS_OK) + REPORT_AND_RETURN("Cannot set interface speed", false); + break; + case Fast: + if (m_bVerbose) + printf("Setting interface speed to fast...\n"); + if (MSP430_Configure(SET_INTERFACE_SPEED, FAST) != STATUS_OK) + REPORT_AND_RETURN("Cannot set interface speed", false); + break; + } + if (MSP430_VCC(settings.Voltage) != STATUS_OK) REPORT_AND_RETURN("Cannot enable Vcc", false); @@ -68,11 +120,23 @@ MSP430Proxy::MSP430GDBTarget::~MSP430GDBTarget() bool MSP430Proxy::MSP430GDBTarget::WaitForJTAGEvent() { + LONGLONG lastReportTime = {0,}; for (;;) { LONG state = 0; if (MSP430_State(&state, m_BreakInPending, NULL) != STATUS_OK) REPORT_AND_RETURN("Cannot query device state", false); + + if (m_bVerbose) + { + LONGLONG currentTime = {0,}; + GetSystemTimeAsFileTime(reinterpret_cast(¤tTime)); + if ((currentTime - lastReportTime) > (3000000)) //300ms + { + printf("MSP430_State() => %d, break-in %s\n", state, m_BreakInPending ? "requested" : "not requested"); + } + } + if (state != RUNNING) { m_BreakInPending = false; @@ -206,6 +270,10 @@ GDBServerFoundation::GDBStatus MSP430GDBTarget::ReadTargetMemory( ULONGLONG Addr _snprintf(szMsg, _TRUNCATE, "Cannot read %d memory bytes at 0x%I64X", readSize, Address); REPORT_AND_RETURN(szMsg, kGDBUnknownError); } + + if (m_bVerbose) + printf("MSP430_Read_Memory(0x%x, %d) => success\n", (LONG)Address, *pSizeInBytes); + return kGDBSuccess; } @@ -248,13 +316,13 @@ GDBServerFoundation::GDBStatus MSP430GDBTarget::Terminate() GDBServerFoundation::GDBStatus MSP430GDBTarget::CreateBreakpoint( BreakpointType type, ULONGLONG Address, unsigned kind, OUT INT_PTR *pCookie ) { printf("Warning! Breakpoints are no longer supported in non-EEM mode.\n"); - return kGDBUnknownError; + return kGDBUnknownError; } GDBServerFoundation::GDBStatus MSP430GDBTarget::RemoveBreakpoint( BreakpointType type, ULONGLONG Address, INT_PTR Cookie ) { printf("Warning! Breakpoints are no longer supported in non-EEM mode.\n"); - return kGDBUnknownError; + return kGDBUnknownError; } GDBServerFoundation::GDBStatus MSP430Proxy::MSP430GDBTarget::EraseFLASH( ULONGLONG addr, size_t length ) @@ -290,7 +358,11 @@ void MSP430Proxy::MSP430GDBTarget::ReportLastMSP430Error( const char *pHint ) bool MSP430Proxy::MSP430GDBTarget::DoResumeTarget( RUN_MODES_t mode ) { - if (MSP430_Run(mode, FALSE) != STATUS_OK) + STATUS_T status = MSP430_Run(mode, FALSE); + if (m_bVerbose) + printf("MSP430_Run(%d) => %d\n", mode, status); + + if (status != STATUS_OK) REPORT_AND_RETURN("Cannot resume device", false); return true; diff --git a/MSP430Target.h b/MSP430Target.h index 8b476fa..c678da3 100644 --- a/MSP430Target.h +++ b/MSP430Target.h @@ -22,6 +22,7 @@ namespace MSP430Proxy { protected: DEVICE_T m_DeviceInfo; + bool m_bVerbose; private: bool m_bClosePending, m_bValid; @@ -41,6 +42,7 @@ namespace MSP430Proxy MSP430GDBTarget() : m_bClosePending(false) , m_bValid(false) + , m_bVerbose(false) , m_BreakInPending(false) , m_bFLASHErased(false) , m_bFLASHCommandsUsed(false) diff --git a/SoftwareBreakpointManager.cpp b/SoftwareBreakpointManager.cpp index 5f668d9..2fa85e6 100644 --- a/SoftwareBreakpointManager.cpp +++ b/SoftwareBreakpointManager.cpp @@ -5,12 +5,13 @@ using namespace MSP430Proxy; -MSP430Proxy::SoftwareBreakpointManager::SoftwareBreakpointManager( unsigned flashStart, unsigned flashEnd, unsigned short breakInstruction, bool instantCleanup ) +MSP430Proxy::SoftwareBreakpointManager::SoftwareBreakpointManager( unsigned flashStart, unsigned flashEnd, unsigned short breakInstruction, bool instantCleanup, bool verbose ) : m_FlashStart(flashStart) , m_FlashEnd(flashEnd) , m_FlashSize(flashEnd - flashStart + 1) , m_BreakInstruction(breakInstruction) , m_bInstantCleanup(instantCleanup) + , m_bVerbose(verbose) { ASSERT(!(m_FlashSize & 1)); size_t segmentCount = (m_FlashSize + MAIN_SEGMENT_SIZE - 1) / MAIN_SEGMENT_SIZE; @@ -121,6 +122,8 @@ bool MSP430Proxy::SoftwareBreakpointManager::CommitBreakpoints() m_Segments[i].BpState[j] = NoBreakpoint; data[j] = m_Segments[i].OriginalInstructions[j]; eraseNeeded = true; + if (m_bVerbose) + printf("Restoring original FLASH instruction at 0x%x\n", segBase + j * 2); break; case BreakpointPending: m_Segments[i].BpState[j] = BreakpointActive; @@ -129,6 +132,9 @@ bool MSP430Proxy::SoftwareBreakpointManager::CommitBreakpoints() if ((data[j] & m_BreakInstruction) != m_BreakInstruction) eraseNeeded = true; + if (m_bVerbose) + printf("Inserting a FLASH breakpoint at 0x%x, sector erase %s\n", segBase + j * 2, eraseNeeded ? "pending" : "not pending"); + data[j] = m_BreakInstruction; break; } diff --git a/SoftwareBreakpointManager.h b/SoftwareBreakpointManager.h index 87403cb..203e809 100644 --- a/SoftwareBreakpointManager.h +++ b/SoftwareBreakpointManager.h @@ -56,6 +56,7 @@ namespace MSP430Proxy unsigned short m_BreakInstruction; bool m_bInstantCleanup; + bool m_bVerbose; struct TranslatedAddr { @@ -100,7 +101,7 @@ namespace MSP430Proxy to set another breakpoint. \remarks The size of the FLASH erase block is assumed to be a constant of 512 bytes. */ - SoftwareBreakpointManager(unsigned flashStart, unsigned flashEnd, unsigned short breakInstruction, bool instantCleanup); + SoftwareBreakpointManager(unsigned flashStart, unsigned flashEnd, unsigned short breakInstruction, bool instantCleanup, bool verbose); }; } diff --git a/msp430-gdbproxy.cpp b/msp430-gdbproxy.cpp index 6719233..32bec00 100644 --- a/msp430-gdbproxy.cpp +++ b/msp430-gdbproxy.cpp @@ -114,6 +114,9 @@ All options are optional:\n\ --keepalive - Keep running after GDB disconnects, wait for next connection\n\ --autoerase - Erase FLASH when debugging is started\n\ --nohint - Do not show the 'how to start debugging' message\n\ + --verbose - Enable verbose diagnostic output\n\ + --iface=jtag/sbw/sbwjtag/auto - Specify connection interface\n\ + --ifacespeed=slow/medium/fast - Specify interface speed\n\ "); } @@ -141,6 +144,8 @@ void ParseOptions(int argc, char* argv[], GlobalSettings &settings) settings.EnableEEMMode = false; else if (arg == "keepbp") settings.InstantBreakpointCleanup = false; + else if (arg == "verbose") + settings.Verbose = true; else if (arg == "bp_insn") { if (strlen(val) < 3 || _memicmp(val, "0x", 2)) @@ -175,6 +180,30 @@ void ParseOptions(int argc, char* argv[], GlobalSettings &settings) settings.AutoErase = true; else if (arg == "nohint") settings.NoHint = true; + else if (arg =="iface") + { + if (!val) + continue; + if (!strcmp(val, "jtag")) + settings.Interface = Jtag; + else if (!strcmp(val, "sbw")) + settings.Interface = SpyBiWare; + else if (!strcmp(val, "sbwjtag")) + settings.Interface = JtagOverSpyBiWare; + else if (!strcmp(val, "auto")) + settings.Interface = AutomaticInterface; + } + else if (arg =="ifacespeed") + { + if (!val) + continue; + if (!strcmp(val, "fast")) + settings.InterfaceSpeed = Fast; + else if (!strcmp(val, "medium")) + settings.InterfaceSpeed = Medium; + else if (!strcmp(val, "slow")) + settings.InterfaceSpeed = Slow; + } } } @@ -193,13 +222,18 @@ int main(int argc, char* argv[]) LONG version = 0; STATUS_T status = MSP430_Initialize((char *)settings.PortName, &version); + if (settings.Verbose) + printf("MSP430_Initialize(%s) => status = %d, version = %d\n", settings.PortName, status, version); + if (status != STATUS_OK) { printf("Cannot initalize MSP430.DLL on port %s:\n\t%s\n", settings.PortName, GetLastMSP430Error()); printf("\nRun msp430-gdbproxy --help for usage instructions.\n"); return 1; } - MSP430_Close(FALSE); + + status = MSP430_Close(FALSE); + printf("MSP430_Close() returned %d\n", status); GDBServer srv(new MSP430StubFactory(settings)); ActionStatus st = srv.Start(settings.ListenPort); @@ -209,7 +243,7 @@ int main(int argc, char* argv[]) return 1; } - printf("msp430-gdbproxy++ v1.01 [http://gnutoolchains.com/msp430/gdbproxy]\nSuccessfully initialized MSP430.DLL on %s\nListening on port %d.\n", settings.PortName, settings.ListenPort); + printf("msp430-gdbproxy++ v1.3 [http://gnutoolchains.com/msp430/gdbproxy]\nSuccessfully initialized MSP430.DLL on %s\nListening on port %d.\n", settings.PortName, settings.ListenPort); if (!settings.NoHint) { printf("\nRun \"msp430-gdbproxy --help\" to learn about command line options.\n\ diff --git a/settings.h b/settings.h index a7e9b78..66aafed 100644 --- a/settings.h +++ b/settings.h @@ -9,6 +9,23 @@ namespace MSP430Proxy SoftwareOnly, }; + enum HardwareInterface + { + UnspecifiedInterface, + Jtag, + SpyBiWare, + JtagOverSpyBiWare, + AutomaticInterface, + }; + + enum HardwareInterfaceSpeed + { + UnspecifiedSpeed, + Fast, + Medium, + Slow + }; + struct GlobalSettings { bool EnableEEMMode; @@ -21,6 +38,9 @@ namespace MSP430Proxy bool SingleSessionOnly; bool AutoErase; bool NoHint; + bool Verbose; + HardwareInterface Interface; + HardwareInterfaceSpeed InterfaceSpeed; GlobalSettings() { @@ -34,6 +54,9 @@ namespace MSP430Proxy SingleSessionOnly = true; AutoErase = false; NoHint = false; + Verbose = false; + Interface = UnspecifiedInterface; + InterfaceSpeed = UnspecifiedSpeed; } }; } \ No newline at end of file