diff --git a/.gitignore b/.gitignore index 67f13345..d0f38907 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,6 @@ # testing builds/ + +# Google Drive on OSX +Icon? diff --git a/platforms/m3/prc_v14/software/Makefile b/platforms/m3/prc_v14/software/Makefile index 5f3ad48e..42323d29 100644 --- a/platforms/m3/prc_v14/software/Makefile +++ b/platforms/m3/prc_v14/software/Makefile @@ -52,6 +52,7 @@ CXX := $(CROSS_COMPILE)-g++ LD := $(CROSS_COMPILE)-ld OBJDUMP := $(CROSS_COMPILE)-objdump OBJCOPY := $(CROSS_COMPILE)-objcopy +NM := $(CROSS_COMPILE)-nm ################################################################################ ## You should not need to edit this makefile beyond this point @@ -67,16 +68,23 @@ LIBS := $(subst .c,.o,$(wildcard libs/*.c)) LIBS += $(subst .s,.o,$(wildcard libs/*.s)) HEADERS := $(wildcard include/*.h) -DIRS := $(patsubst %/,%,$(filter-out libs/,$(filter-out include/,$(wildcard */)))) +GDB:= $(subst .c,.o,$(wildcard gdb/*.c)) +GDB+= $(subst .s,.o,$(wildcard gdb/*.s)) + +DIRS := $(patsubst %/,%,\ + $(filter-out libs/,\ + $(filter-out include/,\ + $(filter-out gdb/,\ + $(wildcard */))))) BINS := $(foreach var,$(DIRS),$(var)/$(var).bin) HEXS := $(foreach var,$(DIRS),$(var)/$(var).hex) ELFS := $(foreach var,$(DIRS),$(var)/$(var).elf) -.PRECIOUS: $(LIBS) $(BINS) $(ELFS) +.PRECIOUS: $(LIBS) $(BINS) $(ELFS) $(GDB) .PHONY: all -all: $(HEXS) +all: $(GDB) $(HEXS) $(DIRS): $(MAKE) $@/$@.hex @@ -87,7 +95,7 @@ $(DIRS): #%.bin: $$(wildcard $$(dir $$*)*.c) -%.o: $(HEADERS) +%.o: $(HEADERS) %.hex: %.bin xxd -g1 -c1 $< | cut -d' ' -f2 > $@ @@ -98,11 +106,20 @@ $(DIRS): $(OBJCOPY) -O binary $< $@ # Mind the order here to align -T$^ -%.elf: libs/memmap $(LIBS) %.o - $(LD) $(LDFLAGS) -T$^ "$$(echo $$(arm-none-eabi-gcc -print-libgcc-file-name) | tr -d '\r')" -o $@ +# This will link in GDB support if you #include "gdb.h" in any of the c/s files +%.elf: COBJ=$(patsubst %.c,%.o,$(wildcard $(dir $@)*.c)) +%.elf: SOBJ=$(patsubst %.s,%.o,$(wildcard $(dir $@)*.s)) +%.elf: libs/memmap $(LIBS) $$(COBJ) $$(SOBJ) + @if [ -n "$$(echo $$( $(NM) $(filter-out $<,$^) | grep use_gdb))" ]; then \ + $(LD) $(LDFLAGS) -T$^ $(GDB) \ + "$$(echo $$( $(CC) -print-libgcc-file-name) | tr -d '\r')" -o $@ ;\ + else \ + $(LD) $(LDFLAGS) -T$^ \ + "$$(echo $$( $(CC) -print-libgcc-file-name) | tr -d '\r')" -o $@ ;\ + fi $(OBJDUMP) -Sd $@ > $*.asm -.PRECIOUS: %.elf +.PRECIOUS: %.elf %.o ########## @@ -113,6 +130,7 @@ clean: rm -f $(HEXS) rm -f $(LIBS) rm -f $(ELFS) + rm -f $(GDB) clean-%: rm -f $*/$*.bin $*/$*.hex diff --git a/platforms/m3/prc_v14/software/PRCv14_sleep_wakeup/PRCv14_sleep_wakeup.c b/platforms/m3/prc_v14/software/PRCv14_sleep_wakeup/PRCv14_sleep_wakeup.c index 1fba4f94..ed1dc142 100755 --- a/platforms/m3/prc_v14/software/PRCv14_sleep_wakeup/PRCv14_sleep_wakeup.c +++ b/platforms/m3/prc_v14/software/PRCv14_sleep_wakeup/PRCv14_sleep_wakeup.c @@ -8,6 +8,8 @@ #include "PRCv14_RF.h" #include "mbus.h" +#include "gdb.h" + // uncomment this for debug mbus message // #define DEBUG_MBUS_MSG #define DEBUG_MBUS_MSG_1 @@ -57,7 +59,7 @@ void handler_ext_int_5(void) __attribute__ ((interrupt ("IRQ"))); void handler_ext_int_6(void) __attribute__ ((interrupt ("IRQ"))); void handler_ext_int_7(void) __attribute__ ((interrupt ("IRQ"))); void handler_ext_int_8(void) __attribute__ ((interrupt ("IRQ"))); -void handler_ext_int_9(void) __attribute__ ((interrupt ("IRQ"))); +//void handler_ext_int_9(void) __attribute__ ((interrupt ("IRQ"))); void handler_ext_int_10(void) __attribute__ ((interrupt ("IRQ"))); void handler_ext_int_11(void) __attribute__ ((interrupt ("IRQ"))); void handler_ext_int_12(void) __attribute__ ((interrupt ("IRQ"))); @@ -73,7 +75,7 @@ void handler_ext_int_5(void) { *NVIC_ICPR = (0x1 << 5); mbus_msg_flag = 0x13; } void handler_ext_int_6(void) { *NVIC_ICPR = (0x1 << 6); mbus_msg_flag = 0x14; } // REG4 void handler_ext_int_7(void) { *NVIC_ICPR = (0x1 << 7); mbus_msg_flag = 0x15; } // REG5 void handler_ext_int_8(void) { *NVIC_ICPR = (0x1 << 8); mbus_msg_flag = 0x16; } // REG6 -void handler_ext_int_9(void) { *NVIC_ICPR = (0x1 << 9); mbus_msg_flag = 0x17; } // REG7 +//void handler_ext_int_9(void) { *NVIC_ICPR = (0x1 << 9); mbus_msg_flag = 0x17; } // REG7 void handler_ext_int_10(void) { *NVIC_ICPR = (0x1 << 10); } // MEM WR void handler_ext_int_11(void) { *NVIC_ICPR = (0x1 << 11); } // MBUS_RX void handler_ext_int_12(void) { *NVIC_ICPR = (0x1 << 12); } // MBUS_TX diff --git a/platforms/m3/prc_v14/software/gdb/_gdb.s b/platforms/m3/prc_v14/software/gdb/_gdb.s new file mode 100644 index 00000000..b48dd205 --- /dev/null +++ b/platforms/m3/prc_v14/software/gdb/_gdb.s @@ -0,0 +1,233 @@ +/* + * + * GDB Hooks for GDBoverMBUS support + * + * This works by co-opting the service routine call (svc) + * as well as Interrupt #9 (handler_ext_int_9) + * + * + * + * Andrew Lukefahr + * lukefahr@indiana.edu + * + * Much of this is borrowed from: + * - https://github.com/adamheinrich/os.h/blob/master/src/os_pendsv_handler.s + * - The Definitive Guide to ARM Cortex-M0 and Cortex-M0+ Processors Section 10.7.1 + */ + +.syntax unified +.cpu cortex-m0 +.fpu softvfp + +.thumb + + +/* + * + * use the software trap handler as a soft-Breakpoint + * + */ +.global handler_svcall +.type handler_svcall, %function +handler_svcall: + + + /* + * Exception frame saved by the NVIC hardware onto stack: + * +------+ + * | | <- SP before interrupt (orig. SP) + * | xPSR | + * | PC | + * | LR | + * | R12 | + * | R3 | + * | R2 | + * | R1 | + * | R0 | <- SP after entering interrupt (orig. SP + 32 bytes) + * +------+ + */ + + /* + * Registers saved by the software (PendSV_Handler): + * +------+ + * | R7 | + * | R6 | + * | R5 | + * | R4 | + * | R11 | + * | R10 | + * | R9 | + * | R8 | <- Saved SP (orig. SP + 64 bytes) + * +------+ + */ + /* we can push r4-r7 directly, r8-r11 we have to move into a lower + * register first, then store it */ + push {r4,r5,r6,r7} + mov r4, r8 + mov r5, r9 + mov r6, r10 + mov r7, r11 + push {r4,r5,r6,r7} + + /* + * Finally save the (recalculated) origional stack pointer and + * the Special LR is saved by the software (PendSV_Handler): + * +------+ + * | SP | this is the origional (pre-svc) sp value + * |ISR_LR| <- Saved SP (orig. SP + 72 bytes) + * +------+ + */ + mov r1, sp + subs r1, #68 //back to origional sp before svc + push {r1} + push {lr} + + /* Now we can call the C svc_handler + * adapted from 'the_definitive_guide_to_arm_cortex_m0_and_cortex_m0+_processors' + */ + + /* make the stack pointer the first argument to the C svc_handler + * but first we need to figure out which stack we're using + * and we can do that by testing the special LR + */ + movs r0, #4 + mov r1, LR // SPECIAL LR + tst r0, r1 + beq stacking_used_MSP + + stacking_used_PSP: + mrs r0, PSP // first parameter - stacking was using PSP + b handler_svcall_2 + + stacking_used_MSP: + mrs r0, MSP // first parameter - stacking was using MSP + + handler_svcall_2: + /* ok, now we can actually call the c svc_handler */ + ldr r2, =_gdb_break // branch to C handler + blx r2 + + /* pop the Special LR */ + pop {r1} + + /* pop the dummy SP */ + pop {r4} + + /* pop r8-r11 */ + pop {r4,r5,r6,r7} + mov r8, r4 + mov r9, r5 + mov r10, r6 + mov r11, r7 + + /* pop r4-r7 */ + pop {r4,r5,r6,r7} + + /* and return from SVC */ + bx r1 + +/* + * + * use the MBUS Reg #7 (IRQ#9) Interrupt as a soft-Halt + * + */ + +.global handler_ext_int_9 /* 25 External Interrupt(9) */ +.type handler_ext_int_9, %function +handler_ext_int_9: + + + /* + * Exception frame saved by the NVIC hardware onto stack: + * +------+ + * | | <- SP before interrupt (orig. SP) + * | xPSR | + * | PC | + * | LR | + * | R12 | + * | R3 | + * | R2 | + * | R1 | + * | R0 | <- SP after entering interrupt (orig. SP + 32 bytes) + * +------+ + */ + + /* + * Registers saved by the software (PendSV_Handler): + * +------+ + * | R7 | + * | R6 | + * | R5 | + * | R4 | + * | R11 | + * | R10 | + * | R9 | + * | R8 | <- Saved SP (orig. SP + 64 bytes) + * +------+ + */ + /* we can push r4-r7 directly, r8-r11 we have to move into a lower + * register first, then store it */ + push {r4,r5,r6,r7} + mov r4, r8 + mov r5, r9 + mov r6, r10 + mov r7, r11 + push {r4,r5,r6,r7} + + /* + * Finally save the (recalculated) origional stack pointer and + * the Special LR is saved by the software (PendSV_Handler): + * +------+ + * | SP | this is the origional (pre-svc) sp value + * |ISR_LR| <- Saved SP (orig. SP + 72 bytes) + * +------+ + */ + mov r1, sp + subs r1, #68 //back to origional sp before svc + push {r1} + push {lr} + + /* Now we can call the C svc_handler + * adapted from 'the_definitive_guide_to_arm_cortex_m0_and_cortex_m0+_processors' + */ + + /* make the stack pointer the first argument to the C svc_handler + * but first we need to figure out which stack we're using + * and we can do that by testing the special LR + */ + movs r0, #4 + mov r1, LR // SPECIAL LR + tst r0, r1 + beq irq9_stacking_used_MSP + + irq9_stacking_used_PSP: + mrs r0, PSP // first parameter - stacking was using PSP + b handler_ext_int_9_2 + + irq9_stacking_used_MSP: + mrs r0, MSP // first parameter - stacking was using MSP + + handler_ext_int_9_2: + /* ok, now we can actually call the c svc_handler */ + ldr r2, =_gdb_halt // branch to C handler + blx r2 + + /* pop the Special LR */ + pop {r1} + + /* pop the dummy SP */ + pop {r4} + + /* pop r8-r11 */ + pop {r4,r5,r6,r7} + mov r8, r4 + mov r9, r5 + mov r10, r6 + mov r11, r7 + + /* pop r4-r7 */ + pop {r4,r5,r6,r7} + + /* and return from SVC */ + bx r1 + diff --git a/platforms/m3/prc_v14/software/gdb/gdb.c b/platforms/m3/prc_v14/software/gdb/gdb.c new file mode 100644 index 00000000..5e0d52ae --- /dev/null +++ b/platforms/m3/prc_v14/software/gdb/gdb.c @@ -0,0 +1,166 @@ +/* + * + * GDB Hooks for GDBoverMBUS support + * + * This works by co-opting the service routine call (svc) + * as well as Interrupt #9 (handler_ext_int_9) + * + * + * + * Andrew Lukefahr + * lukefahr@indiana.edu + * + * Much of this is borrowed from: + * - https://github.com/adamheinrich/os.h/blob/master/src/os_pendsv_handler.s + * - The Definitive Guide to ARM Cortex-M0 and Cortex-M0+ Processors Section 10.7.1 + */ + +#include +#include + +#include "PRCv14.h" + +/* this struct is used by the assembley-level file 'gdb.s' + * and must stay in this specific order + */ +struct svc_args +{ + //yes this is a wired order, and yes it needs to be this way + uint32_t isr_lr; + uint32_t sp; //pre-svc sp + uint32_t r8; + uint32_t r9; + uint32_t r10; + uint32_t r11; + uint32_t r4; + uint32_t r5; + uint32_t r6; + uint32_t r7; + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r12; + uint32_t lr; + uint32_t pc; + uint32_t xPSR; +} ; //18 regs in total + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * + * + * PROTOTYPES + * + * + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + + +/** + * High-level (C) function called in response to a software-break + * which is implimented as 'svc 01' (0xdf01) + * + * @regs: a copy of the processor registers as the existed pre-software break + * + */ +void _gdb_break( struct svc_args * regs) + __attribute__ ((noinline,used)); + +/** + * High-level (C) function called in reponse to a "halt" interrupt + * (this is overriding handler_ext_int_9) + * + * @regs: a copy of the processor registers as the existed pre-halt + */ +void _gdb_halt( struct svc_args * regs) + __attribute__ ((noinline,used)); + +/** + * writes a 32-bit message over MBUS + * + * This is duplicated to allow us to debug the 'regular' mbus_write32 function + * could be inlined depending on compiler + * + * @addr the mbus address to write to + * @data the 32-bit data to be written + */ +uint32_t _gdb_mbus_write_message32(uint32_t addr, uint32_t data) + __attribute__ ((used)); + + + + + + + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * + * + * IMPLIMENTATIONS + * + * + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +void _gdb_halt( struct svc_args * regs) +{ + volatile uint32_t break_flag = 0x0; + + //disable watchdogs (CPU + MBUS) + disable_timerwd(); + *MBCWD_RESET = 1; + + //broadcast the address of the flag + _gdb_mbus_write_message32( 0xe0, (uint32_t) &break_flag); + // and the starting address of the registers + _gdb_mbus_write_message32( 0xe0, (uint32_t) regs); + + //loop until GDB signals + while (break_flag != 0x1) {} + + // oh-right, this is actually IRQ-9 + //maybe we should clear the interrupt flag + *NVIC_ICPR = (0x1 << 9); + + config_timerwd( *TIMERWD_CNT); + *MBCWD_RESET = 0; +} + + + +void _gdb_break( struct svc_args * regs) +{ + //disable watchdogs (CPU + MBUS) + disable_timerwd(); + *MBCWD_RESET = 1; + + + //this wasn't a "real" instruction so backup one instruction + regs->pc -= 2; + + volatile uint32_t break_flag = 0x0; + + //broadcast the address of the flag + _gdb_mbus_write_message32( 0xe0, (uint32_t) &break_flag); + // and the starting address of the registers + _gdb_mbus_write_message32( 0xe0, (uint32_t) regs); + + //loop until GDB signals + while (break_flag != 0x1) {} + + config_timerwd( *TIMERWD_CNT); + *MBCWD_RESET = 0; + +} + +//so we can soft-step into mbus_write_message32 +uint32_t _gdb_mbus_write_message32(uint32_t addr, uint32_t data) { + uint32_t mbus_addr = 0xA0003000 | (addr << 4); + *((volatile uint32_t *) mbus_addr) = data; + return 1; +} + diff --git a/platforms/m3/prc_v14/software/include/gdb.h b/platforms/m3/prc_v14/software/include/gdb.h new file mode 100644 index 00000000..96150800 --- /dev/null +++ b/platforms/m3/prc_v14/software/include/gdb.h @@ -0,0 +1,7 @@ +#ifndef __GDB_H__ +#define __GDB_H__ + +// This is WAY into GNU GCC only... +int use_gdb __attribute__ ((visibility ("hidden"))); + +#endif diff --git a/platforms/m3/prc_v14/software/include/mbus.h b/platforms/m3/prc_v14/software/include/mbus.h index a4960d8c..f4fd337e 100755 --- a/platforms/m3/prc_v14/software/include/mbus.h +++ b/platforms/m3/prc_v14/software/include/mbus.h @@ -159,7 +159,6 @@ void mbus_remote_register_write( * @param remote_reg_addr The register to read on the remote * @param local_reg_addr The register to save the value to on this node */ -inline void mbus_remote_register_read( uint8_t remote_prefix, uint8_t remote_reg_addr, diff --git a/platforms/m3/prc_v14/software/libs/mbus.c b/platforms/m3/prc_v14/software/libs/mbus.c index 422d65c9..71d4552e 100755 --- a/platforms/m3/prc_v14/software/libs/mbus.c +++ b/platforms/m3/prc_v14/software/libs/mbus.c @@ -110,7 +110,6 @@ void mbus_remote_register_write( mbus_write_message(address, &data, 1); } -inline void mbus_remote_register_read( uint8_t remote_prefix, uint8_t remote_reg_addr,