mspbsldump/src/main.c

326 lines
7.2 KiB
C

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <msp430.h>
#include "compiler.h"
void stdio_msp_init(void); // stdio_msp.c
static void setup_clocks(void) {
CSCTL0_H = CSKEY_H;
CSCTL1 = DCOFSEL_0/*3*/ | DCORSEL;
CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;
CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1;
CSCTL0_H = 0;
}
static void setup_io(void) {
WDTCTL = WDTPW | WDTHOLD; // Stop WDT
// Configure GPIO
P2SEL0 &= ~(BIT0 | BIT1); // port 2.[01] to eUSCI_A0
P2SEL1 |= BIT0 | BIT1;
P1OUT &= ~(BIT0|BIT1|BIT2|BIT3); // P1.[0-3]: status LED and LA trigger debug stuff
P1DIR |= (BIT0|BIT1|BIT2|BIT3);
PM5CTL0 &= ~LOCKLPM5; // Disable the GPIO power-on default high-impedance mode
// to activate previously configured port settings
}
// ---
__attribute__((__persistent__)) // put in FRAM (BSL clears RAM)
static uint32_t regbak[16]={0};
__attribute__((__persistent__))
static uint8_t stackbak[16]={0};
extern uint16_t curticks, curticks_;
__attribute__((__persistent__, __used__))
uint16_t curticks = 1;
__attribute__((__persistent__, __used__))
uint16_t curticks_ = 1;
extern uint16_t done_irq;
__attribute__((__persistent__, __used__))
uint16_t done_irq = 0;
extern uint16_t curaddr;
__attribute__((__persistent__, __used__))
uint16_t curaddr = 0x1000;
/*extern uint16_t traceaddr;
__attribute__((__persistent__))
uint16_t traceaddr = 0x1000; // changeme*/
typedef void (*bsl_fn)(void);
#define START_HARD 1/*36000*/
/*#define START_SOFT 36990*/
#define END_CYC 0xffffu
/*#define SKIP_CYC_OFF 5*/
// DUMP_MODE == 0 => insn trace mode
#define DUMP_MODE 1
#define DUMP_CYC_OFF 14
#define DUMP_ADDR_START 0x1000
#define DUMP_ADDR_END 0x1800
void do_trace(void);
__attribute__((__no_inline__)) void do_trace(void) {
// TODO: chain 2 timers for 32 bit tick number
// TODO: continue instead of restarting?
// ^: mightn't be possible: instruction exec restarts after irq
// init timer TA0
__bic_SR_register(GIE);
#if DUMP_MODE
//traceaddr = 0x1002;
TA1CCR0 = DUMP_CYC_OFF;
#else
#ifdef SKIP_CYC_OFF
if (curticks > SKIP_CYC_OFF) {
done_irq = 0;
TA1CCR0 = SKIP_CYC_OFF;
curticks_ = curticks - SKIP_CYC_OFF /*+ 2*/;
} else
#endif
{
done_irq = 1;
TA1CCR0 = curticks;
}
#endif
//TA1CCTL0 |= CCIFG;
//TA1CCTL0 &= ~(CCIE|CCIFG);
TA1CCTL0 = CCIE;
// exec bsl
asm volatile(
"mov.a #(__stack-8), sp\n"
"mov.w #0xaaaa, r4\n"
"mov.w #0xaaaa, r5\n"
"mov.w #0xaaaa, r6\n"
"mov.w #0xaaaa, r7\n"
"mov.w #0xaaaa, r8\n"
"mov.w #0xaaaa, r9\n"
"mov.w #0xaaaa, r10\n"
"mov.w #0xaaaa, r11\n"
"mov.w #0x0002, r12\n"
"mov.w #0xdead, r13\n"
"mov.w #0xbeef, r14\n"
"mov.w #0xaaaa, r15\n"
#if DUMP_MODE
// extra 0x1002 magic
"mov.w curaddr, sp\n"
#endif
//TA1CTL = TASSEL__SMCLK | ID__1 | MC__UP | TACLR | TAIE;
"mov.w #0x0216, TA1CTL\n"
"eint\n"
"call #0x1002\n" // CHANGEME (address to trace insn flow of)
/*"nop\n"
"nop\n"
"nop\n"
"nop\n"
"nop\n"
"nop\n"
//"mov.w #0x1337, r8\n"
"dint\nnop\n"
"add.w #-1, r4\n"
"add.w #1, r5\n"
"add.w #2, r6\n"
"add.w #4, r7\n"
"add.w #8, r8\n"
"add.w #-1, r4\n"
"add.w #1, r5\n"
"add.w #2, r6\n"
"add.w #4, r7\n"
"add.w #8, r8\n"
"add.w #-1, r4\n"
"add.w #1, r5\n"
"add.w #2, r6\n"
"add.w #4, r7\n"
"add.w #8, r8\n"
"add.w #-1, r4\n"
"add.w #1, r5\n"
"add.w #2, r6\n"
"add.w #4, r7\n"
"add.w #8, r8\n"
"1: jmp 1b\n"*/
);
//while (1) ;
__builtin_unreachable();
}
void do_collect(uint16_t* sp);
__attribute__((__used__, __no_inline__))
void do_collect(uint16_t* sp) {
//P1OUT=0;
TA1CTL &= ~(uint16_t)(TAIE|MC__UP);
// 0x1bc2/4 and 0x1bd6/8 contain a bic #GIE, sr instruction! these should be 2 bytes in size
/*if (pc16 == 0x1bc2 || pc16 == 0x1bc4 || pc16 == 0x1bd6 || pc16 == 0x1bd8) {
sp[24] |=
}*/
// 0x1b96 does a jump to ???? (probably from a memory location?)
#if DUMP_MODE
uint16_t v1 = sp[2*(12-4)];
uint16_t v2 = sp[2*(13-4)];
if (!(curaddr & 0xf)) {
iprintf("%04x: ", curaddr);
}
iprintf("%02x %02x %02x %02x ",
v1 & 0xff, (v1 >> 8) & 0xff,
v2 & 0xff, (v2 >> 8) & 0xff
);
if ((curaddr & 0xf) == 0xc) {
iprintf("\r\n");
}
#else
#ifdef START_SOFT
if (curticks < START_SOFT) goto next_iter;
#endif
uint16_t sr = sp[24];
uint32_t pc = sp[25];
//uint16_t pc16 = pc;
// general purpose registers
for (int i = 0; i < 12; ++i) {
uint32_t v = sp[(i*2)+0] | ((uint32_t)sp[(i*2)+1] << 16);
regbak[i+4] = v;
}
pc |= ((uint32_t)(sr & 0xf000) << (16-12));
sr &= 0xfff;
sp = sp + 26;
regbak[0] = pc;
regbak[1] = sp;
regbak[2] = sr;
regbak[3] = 0; // cg
memcpy(stackbak, sp, 16);
// pc=r0 sp=r1 sr=r2 ; gp: r4-r15
iprintf("- %u\r\n", curticks);
iprintf("%05lx %05lx %03lx\r\n", regbak[0], regbak[1], regbak[2]);
iprintf("%05lx %05lx %05lx %05lx %05lx %05lx %05lx %05lx %05lx %05lx %05lx %05lx\r\n",
regbak[ 4], regbak[ 5], regbak[ 6], regbak[ 7], regbak[ 8], regbak[ 9],
regbak[10], regbak[11], regbak[12], regbak[13], regbak[14], regbak[15]);
iprintf("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\r\n",
stackbak[0], stackbak[1], stackbak[2], stackbak[3],
stackbak[4], stackbak[5], stackbak[6], stackbak[7],
stackbak[8], stackbak[9], stackbak[10], stackbak[11],
stackbak[12], stackbak[13], stackbak[14], stackbak[15]);
//fflush(stdout);
#endif
next_iter:
#if DUMP_MODE
if (curaddr == DUMP_ADDR_END) while(1); // start of info mem
curaddr += 4;
#else
if (curticks == END_CYC) while(1);
++curticks;
#endif
do_trace();
__builtin_unreachable();
}
__attribute__((__interrupt__(TIMER1_A0_VECTOR), __naked__))
void Timer_A1_ISR(void) {
asm volatile(
".extern do_collect\n"
".extern done_irq\n"
".extern curticks\n"
//"bis #0x3, P1OUT\n"
#if DUMP_MODE
// get a stack we can do stuff with
// (sp is currently in bsl space)
"mov.a #(__stack-8), sp\n"
#endif
#if !DUMP_MODE && defined(SKIP_CYC_OFF)
// do some hackery
"cmp.w #0, done_irq\n"
"jne .Lregular\n"
//"add.w #4, P1OUT\n"
// skip pc forward by 4
"add.w #4, 2(sp)\n"
// set/force GIE in sr
"bis.w #8, 0(sp)\n"
// done it now
"mov.w #1, done_irq\n"
// set timer counter for next IRQ for trace
"mov.w curticks_, TA1CCR0\n"
// clear TAIE, TAIFG, MC
"bic.w #0x0033, TA1CTL\n"
// clear irq flag, enable compare irq
"mov.w #16, TA1CCTL0\n"
// restart timer
"mov.w #0x0216, TA1CTL\n"
// continue as usual
"reti\n"
#endif
".Lregular:\n"
//"add.w #8, P1OUT\n"
"pushm.a #12, r15\n"
"mov.a sp, r12\n"
"call #do_collect\n"
"popm.a #12, r15\n"
"reti\n"
);
}
__attribute__((__interrupt__(UNMI_VECTOR)))
void NMI_ISR(void) {
SFRIFG1 &= ~NMIIE;
SYSUNIV = 0;
++P1OUT;
}
int main(void) {
setup_io();
setup_clocks();
stdio_msp_init();
//SFRIE1 = NMIIE;
//SFRRPCR = SYSRSTRE__ENABLE | SYSRSTUP__PULLUP | SYSNMIIES__FALLING | SYSNMI__NMI;
memset(regbak, 0, sizeof regbak);
__bis_SR_register(GIE); // enable irq
#if DUMP_MODE
curticks = DUMP_CYC_OFF;
curaddr = DUMP_ADDR_START;
#else
curticks = START_HARD;
#endif
/*uint8_t zarea[8];
memcpy(zarea, (void*)0x1000, 8);
iprintf("zarea: %02x %02x %02x %02x %02x %02x %02x %02x\r\n",
zarea[0], zarea[1], zarea[2], zarea[3],
zarea[4], zarea[5], zarea[6], zarea[7]
);*/
puts("hello world!\r\n");
done_irq = 0;
do_trace();
__builtin_unreachable();
}