Skip to content

Commit

Permalink
on-chip software debugger support (#26)
Browse files Browse the repository at this point in the history
* Rebase dbg branch after float merge

* Make it compile against codal master
  • Loading branch information
mmoskal authored and pelikhan committed Oct 13, 2017
1 parent 3e346dd commit 151eb85
Show file tree
Hide file tree
Showing 8 changed files with 191 additions and 40 deletions.
5 changes: 5 additions & 0 deletions libs/base/core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -859,8 +859,13 @@ void mapSetRef(RefMap *map, unsigned key, TValue val) {
// Debugger
//

// This is only to be called once at the beginning of lambda function
//%
void *getGlobalsPtr() {
#ifdef DEVICE_GROUP_ID_USER
fiber_set_group(DEVICE_GROUP_ID_USER);
#endif

return globals;
}

Expand Down
10 changes: 9 additions & 1 deletion libs/base/pxt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,6 @@ void error(ERROR code, int subcode) {

uint16_t *bytecode;
TValue *globals;
int numGlobals;

unsigned *allocate(uint16_t sz) {
unsigned *arr = new unsigned[sz];
Expand Down Expand Up @@ -531,6 +530,15 @@ void exec_binary(unsigned *pc) {
bytecode = *((uint16_t **)pc++); // the actual bytecode is here
globals = (TValue *)allocate(getNumGlobals());

if (*HF2_DBG_MAGIC_PTR == HF2_DBG_MAGIC_START) {
*HF2_DBG_MAGIC_PTR = 0;
// this will cause alignment fault at the first breakpoint
globals[0] = (TValue)1;
} else {
// can be any valid address, best in RAM for speed
globals[0] = (TValue)&globals;
}

// just compare the first word
// TODO
checkStr(((uint32_t *)bytecode)[0] == 0x923B8E70 && (unsigned)templateHash() == *pc,
Expand Down
176 changes: 142 additions & 34 deletions libs/core/hf2.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
#define UF2_DEFINE_HANDOVER 1
#include "hf2.h"
#include "pxt.h"
#include "uf2format.h"
#include "CodalDmesg.h"

static void *stackCopy;
static uint32_t stackSize;
//#define LOG DMESG
#define LOG(...) ((void)0)

#if CONFIG_ENABLED(DEVICE_USB)
//#define LOG DMESG
#define LOG(...) ((void)0)

static volatile bool resume = false;

using namespace codal;

Expand Down Expand Up @@ -86,8 +90,7 @@ int HF2::sendSerial(const void *data, int size, int isError)
// Recieve HF2 message
// Does not block. Will store intermediate data in pkt.
// `serial` flag is cleared if we got a command message.
int HF2::recv()
{
int HF2::recv() {
uint8_t buf[64];
int len = out->read(buf, sizeof(buf));
if (len <= 0)
Expand All @@ -101,8 +104,7 @@ int HF2::recv()
memcpy(pkt.buf + pkt.size, buf + 1, size);
pkt.size += size;
tag &= HF2_FLAG_MASK;
if (tag != HF2_FLAG_CMDPKT_BODY)
{
if (tag != HF2_FLAG_CMDPKT_BODY) {
if (tag == HF2_FLAG_CMDPKT_LAST)
pkt.serial = 0;
else if (tag == HF2_FLAG_SERIAL_OUT)
Expand All @@ -119,24 +121,19 @@ int HF2::recv()
// Send HF2 message.
// Use command message when flag == HF2_FLAG_CMDPKT_LAST
// Use serial stdout for HF2_FLAG_SERIAL_OUT and stderr for HF2_FLAG_SERIAL_ERR.
int HF2::send(const void *data, int size, int flag0)
{
int HF2::send(const void *data, int size, int flag0) {
uint8_t buf[64];
const uint8_t *ptr = (const uint8_t *)data;

if (!CodalUSB::usbInstance->isInitialised())
return -1;

for (;;)
{
for (;;) {
int s = 63;
int flag = flag0;
if (size <= 63)
{
if (size <= 63) {
s = size;
}
else
{
} else {
if (flag == HF2_FLAG_CMDPKT_LAST)
flag = HF2_FLAG_CMDPKT_BODY;
}
Expand All @@ -152,24 +149,19 @@ int HF2::send(const void *data, int size, int flag0)
return 0;
}

int HF2::sendResponse(int size)
{
int HF2::sendResponse(int size) {
return send(pkt.buf, 4 + size, HF2_FLAG_CMDPKT_LAST);
}

int HF2::sendResponseWithData(const void *data, int size)
{
int HF2::sendResponseWithData(const void *data, int size) {
int res;

if (size <= (int)sizeof(pkt.buf) - 4)
{
if (size <= (int)sizeof(pkt.buf) - 4) {
__disable_irq();
memcpy(pkt.resp.data8, data, size);
__enable_irq();
res = sendResponse(size);
}
else
{
} else {
__disable_irq();
send(pkt.buf, 4, HF2_FLAG_CMDPKT_BODY);
res = send(data, size, HF2_FLAG_CMDPKT_LAST);
Expand All @@ -179,8 +171,7 @@ int HF2::sendResponseWithData(const void *data, int size)
return res;
}

static void copy_words(void *dst0, const void *src0, uint32_t n_words)
{
static void copy_words(void *dst0, const void *src0, uint32_t n_words) {
uint32_t *dst = (uint32_t *)dst0;
const uint32_t *src = (const uint32_t *)src0;
while (n_words--)
Expand All @@ -199,8 +190,7 @@ int HF2::endpointRequest()

uint32_t tmp;

if (pkt.serial)
{
if (pkt.serial) {
// TODO raise some event?
return 0;
}
Expand All @@ -217,8 +207,7 @@ int HF2::endpointRequest()

#define checkDataSize(str, add) usb_assert(sz == 8 + (int)sizeof(cmd->str) + (int)(add))

switch (cmdId)
{
switch (cmdId) {
case HF2_CMD_INFO:
return sendResponseWithData(uf2_info(), strlen(uf2_info()));

Expand All @@ -229,8 +218,14 @@ int HF2::endpointRequest()
resp->bininfo.max_message_size = sizeof(pkt.buf);
return sendResponse(sizeof(resp->bininfo));

case HF2_DBG_RESTART:
*HF2_DBG_MAGIC_PTR = HF2_DBG_MAGIC_START;
target_reset();
break;

case HF2_CMD_RESET_INTO_APP:
*DBL_TAP_PTR = DBL_TAP_MAGIC_QUICK_BOOT;
// fall-through
case HF2_CMD_RESET_INTO_BOOTLOADER:
target_reset();
break;
Expand Down Expand Up @@ -261,6 +256,22 @@ int HF2::endpointRequest()
break;
#endif

case HF2_DBG_GET_GLOBAL_STATE: {
HF2_GLOBAL_STATE_Result gstate = {
.num_globals = (uint32_t)getNumGlobals(), //
.globals_addr = (uint32_t)globals,
};
return sendResponseWithData(&gstate, sizeof(gstate));
}

case HF2_DBG_RESUME:
globals[0] = (TValue)cmd->data32[0];
resume = true;
return sendResponse(0);

case HF2_DBG_GET_STACK:
return sendResponseWithData(stackCopy, stackSize);

default:
// command not understood
resp->status16 = HF2_STATUS_INVALID_CMD;
Expand All @@ -270,8 +281,105 @@ int HF2::endpointRequest()
return sendResponse(0);
}

HF2::HF2() : USBHID()
{
}
HF2::HF2() : USBHID() {}

struct ExceptionContext {
uint32_t excReturn; // 0xFFFFFFF9
uint32_t r0;
uint32_t r1;
uint32_t r2;
uint32_t r3;
uint32_t r12;
uint32_t lr;
uint32_t faultInstrAddr;
uint32_t psr;
};

struct Paused_Data {
uint32_t pc;
};
static Paused_Data pausedData;

void bkptPaused() {

// waiting for https://github.com/lancaster-university/codal/pull/14
#ifdef DEVICE_GROUP_ID_USER
// the loop below counts as "system" task, and we don't want to pause ourselves
fiber_set_group(DEVICE_GROUP_ID_SYSTEM);
// pause everyone else
fiber_pause_group(DEVICE_GROUP_ID_USER);
#endif

while (!resume) {
// DMESG("BKPT");
hf2.pkt.resp.eventId = HF2_EV_DBG_PAUSED;
hf2.sendResponseWithData(&pausedData, sizeof(pausedData));
// TODO use an event
for (int i = 0; i < 20; ++i) {
if (resume)
break;
fiber_sleep(50);
}
}

if (stackCopy) {
free(stackCopy);
stackCopy = NULL;
}

#ifdef DEVICE_GROUP_ID_USER
fiber_resume_group(DEVICE_GROUP_ID_USER);
// go back to user mode
fiber_set_group(DEVICE_GROUP_ID_USER);
#endif

resume = false;
}

extern "C" void handleHardFault(ExceptionContext *ectx) {
auto instr = (uint16_t *)ectx->faultInstrAddr;

DMESG("FLT %p", instr);

if (ectx->faultInstrAddr & 0x80000000) {
ectx->faultInstrAddr &= ~0x80000000;
// switch to step-over mode
globals[0] = (TValue)3;
return;
}

DMESG("BB %p %p %p lr=%p r0=%p", instr[-1], instr[0], instr[1], ectx->lr, ectx->r0);

if (instr[0] == 0x6840) {
// ldr r0, [r0, #4] -- entry breakpoint
ectx->faultInstrAddr += 2;
// we're being ask for step-over mode
if (ectx->r0 == 3) {
// switch to debugger-attached-no-stepping mode
globals[0] = (TValue)0;
ectx->lr |= 0x80000000;
}
return;
}

if (instr[0] == 0x6800) {
// ldr r0, [r0, #0]
ectx->lr = ectx->faultInstrAddr + 3; // next instruction + thumb mode
pausedData.pc = ectx->faultInstrAddr + 2;
void *ssp = (void *)(ectx + 1);
stackSize = CORTEX_M0_STACK_BASE - (uint32_t)ssp;
if (stackCopy)
free(stackCopy);
stackCopy = malloc(stackSize);
memcpy(stackCopy, ssp, stackSize);
ectx->faultInstrAddr = ((uint32_t)(&bkptPaused) & (~1U));
return;
}

while (1) {
}
}

extern "C" void HardFault_Handler(void) {
asm("push {lr}; mov r0, sp; bl handleHardFault; pop {pc}");
}
2 changes: 1 addition & 1 deletion libs/core/hf2.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ typedef struct

class HF2 : public codal::USBHID
{
public:
HF2_Buffer pkt;
int sendResponse(int size);
int send(const void *data, int size, int flag);
int recv();
int sendResponseWithData(const void *data, int size);

public:
HF2();
virtual int endpointRequest();
virtual int stdRequest(UsbEndpointIn &ctrl, USBSetup& setup);
Expand Down
20 changes: 20 additions & 0 deletions libs/core/hf2dbg.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#ifndef HF2DBG_H
#define HF2DBG_H 1

// we use a location at the top of the stack to store a magic value
// which causes us to stop at the very first break point in the program
#define HF2_DBG_MAGIC_PTR ((uint32_t *)(CORTEX_M0_STACK_BASE - (DEVICE_STACK_SIZE - 4)))
#define HF2_DBG_MAGIC_START 0xf0ebac7f

#define HF2_DBG_GET_GLOBAL_STATE 0x53fc66e0
struct HF2_GLOBAL_STATE_Result {
uint32_t num_globals;
uint32_t globals_addr;
};

#define HF2_DBG_RESTART 0x1120bd93
#define HF2_DBG_RESUME 0x27a55931
#define HF2_EV_DBG_PAUSED 0x3692f9fd
#define HF2_DBG_GET_STACK 0x70901510

#endif
1 change: 1 addition & 0 deletions libs/core/pxt.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ using namespace codal;
#include "pins.h"
#include "devpins.h"
#include "hf2.h"
#include "hf2dbg.h"

#define PAGE_SIZE 256

Expand Down
1 change: 1 addition & 0 deletions libs/core/pxt.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"enums.d.ts",
"hf2.cpp",
"hf2.h",
"hf2dbg.h",
"uf2format.h",
"uf2hid.h",
"ns.ts",
Expand Down
16 changes: 12 additions & 4 deletions libs/core/uf2hid.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,17 +73,25 @@ typedef struct {
struct HF2_WRITE_WORDS_Command write_words;
struct HF2_READ_WORDS_Command read_words;
struct HF2_CHKSUM_PAGES_Command chksum_pages;
uint8_t data8[0];
uint16_t data16[0];
uint32_t data32[0];
};
} HF2_Command;

typedef struct {
uint16_t tag;
union {
uint32_t eventId;
struct {
uint8_t status;
uint8_t status_info;
uint16_t tag;
union {
struct {
uint8_t status;
uint8_t status_info;
};
uint16_t status16;
};
};
uint16_t status16;
};
union {
struct HF2_BININFO_Result bininfo;
Expand Down

0 comments on commit 151eb85

Please sign in to comment.