m3dev

cortex m3 debug tools -- superceded by mdebug
git clone http://frotz.net/git/m3dev.git
Log | Files | Refs | README | LICENSE

main.c (7060B)


      1 /* main.c
      2  *
      3  * Copyright 2011 Brian Swetland <swetland@frotz.net>
      4  * 
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 #include <fw/types.h>
     19 #include <fw/lib.h>
     20 #include <fw/io.h>
     21 
     22 #include <arch/hardware.h>
     23 #include <arch/cpu.h>
     24 #include <arch/interrupts.h>
     25 
     26 #include <protocol/rswdp.h>
     27 #include "swdp.h"
     28 
     29 extern u32 gpio_led0;
     30 extern u32 gpio_led1;
     31 extern u32 gpio_led2;
     32 extern u32 gpio_led3;
     33 extern u32 gpio_reset_n;
     34 
     35 unsigned swdp_trace = 0;
     36 
     37 void reboot_bootloader(void) {
     38 	usb_stop();
     39 	writel(0x12345678, GPREG0);
     40 	writel(0xA5A50000, GPREG1);
     41 	reboot();
     42 }
     43 
     44 #define DEBUG_MAX 52
     45 static struct {
     46 	u32 txn;
     47 	u32 cmd;
     48 	u8 data[DEBUG_MAX];
     49 } pmsg = {
     50 	.txn = RSWD_TXN_ASYNC,
     51 	.cmd = RSWD_MSG(CMD_DEBUG_PRINT, 0, DEBUG_MAX/4),
     52 };
     53 static unsigned poff = 0;
     54 
     55 void flushu(void) {
     56 	while (poff < DEBUG_MAX)
     57 		pmsg.data[poff++] = 0;
     58 	usb_xmit(&pmsg, sizeof(pmsg));
     59 	poff = 0;
     60 }
     61 
     62 void _putu(unsigned c) {
     63 	pmsg.data[poff++] = c;
     64 	if (poff == DEBUG_MAX)
     65 		flushu();
     66 }
     67 
     68 void printu(const char *fmt, ...) {
     69 	va_list ap;
     70 	va_start(ap, fmt);
     71 	vprintx(_putu, fmt, ap);
     72 	va_end(ap);
     73 	if (poff)
     74 		flushu();
     75 }
     76 
     77 static u8 optable[16] = {
     78 	[OP_RD | OP_DP | OP_X0] = RD_IDCODE,
     79 	[OP_RD | OP_DP | OP_X4] = RD_DPCTRL,
     80 	[OP_RD | OP_DP | OP_X8] = RD_RESEND,
     81 	[OP_RD | OP_DP | OP_XC] = RD_BUFFER,
     82 	[OP_WR | OP_DP | OP_X0] = WR_ABORT,
     83 	[OP_WR | OP_DP | OP_X4] = WR_DPCTRL,
     84 	[OP_WR | OP_DP | OP_X8] = WR_SELECT,
     85 	[OP_WR | OP_DP | OP_XC] = WR_BUFFER,
     86 	[OP_RD | OP_AP | OP_X0] = RD_AP0,
     87 	[OP_RD | OP_AP | OP_X4] = RD_AP1,
     88 	[OP_RD | OP_AP | OP_X8] = RD_AP2,
     89 	[OP_RD | OP_AP | OP_XC] = RD_AP3,
     90 	[OP_WR | OP_AP | OP_X0] = WR_AP0,
     91 	[OP_WR | OP_AP | OP_X4] = WR_AP1,
     92 	[OP_WR | OP_AP | OP_X8] = WR_AP2,
     93 	[OP_WR | OP_AP | OP_XC] = WR_AP3,
     94 };
     95 
     96 /* TODO bounds checking -- we trust the host far too much */
     97 void process_txn(u32 txnid, u32 *rx, int rxc, u32 *tx) {
     98 	unsigned msg, op, n;
     99 	unsigned txc = 1;
    100 	unsigned count = 0;
    101 	unsigned status = 0;
    102 	void (*func)(void) = 0;
    103 
    104 	tx[0] = txnid;
    105 
    106 	while (rxc-- > 0) {
    107 		count++;
    108 		msg = *rx++;
    109 		op = RSWD_MSG_OP(msg);
    110 		n = RSWD_MSG_ARG(msg);
    111 #if CONFIG_M3DEBUG_TRACE
    112 		printx("> %b %b %h <\n", RSWD_MSG_CMD(msg), op, n);
    113 #endif
    114 		switch (RSWD_MSG_CMD(msg)) {
    115 		case CMD_NULL:
    116 			continue;
    117 		case CMD_SWD_WRITE:
    118 			while (n-- > 0) {
    119 				rxc--;
    120 				if (swdp_write(optable[op], *rx++)) {
    121 					status = 3;
    122 					goto done;
    123 				}
    124 			}
    125 			continue;
    126 		case CMD_SWD_READ:
    127 			tx[txc++] = RSWD_MSG(CMD_SWD_DATA, 0, n); 
    128 			while (n-- > 0) {
    129 				if (swdp_read(optable[op], tx + txc)) {
    130 					txc++;
    131 					while (n-- > 0)
    132 						tx[txc++] = 0xfefefefe;
    133 					status = 3;
    134 					goto done;
    135 				}
    136 				txc++;
    137 			}
    138 			continue;
    139 		case CMD_SWD_DISCARD:
    140 			while (n-- > 0) {
    141 				u32 tmp;
    142 				if (swdp_read(optable[op], &tmp)) {
    143 					status = 3;
    144 					goto done;
    145 				}
    146 			}
    147 			continue;
    148 		case CMD_ATTACH:
    149 			swdp_reset();
    150 			continue;
    151 		case CMD_RESET:
    152 			if (n == 0) {
    153 				/* deassert RESET */
    154 				gpio_cfg_dir(gpio_reset_n, GPIO_CFG_IN);
    155 			} else {
    156 				/* assert RESET */
    157 				gpio_cfg_dir(gpio_reset_n, GPIO_CFG_OUT);
    158 				gpio_clr(gpio_reset_n);
    159 			}
    160 			continue;
    161 		case CMD_DOWNLOAD: {
    162 			u32 *addr = (void*) *rx++;
    163 			rxc--;
    164 			while (n) {
    165 				*addr++ = *rx++;
    166 				rxc--;
    167 			}
    168 			continue;
    169 		}
    170 		case CMD_EXECUTE:
    171 			func = (void*) *rx++;
    172 			rxc--;
    173 			continue;
    174 		case CMD_TRACE:
    175 			swdp_trace = op;
    176 			continue;
    177 		case CMD_BOOTLOADER:
    178 			func = reboot_bootloader;
    179 			continue;
    180 		case CMD_SET_CLOCK:
    181 			n = ssp0_set_clock(n);
    182 			printu("swdp clock is now 0x%x KHz\n", n);
    183 			continue;
    184 		default:
    185 			printx("unknown command %b\n", RSWD_MSG_CMD(msg));
    186 			status = 1;
    187 			goto done;
    188 		}
    189 	}
    190 
    191 done:
    192 	tx[txc++] = RSWD_MSG(CMD_STATUS, status, count);
    193 
    194 	/* if we're about to send an even multiple of the packet size
    195 	 * (64), add a NULL op on the end to create a short packet at
    196 	 * the end.
    197 	 */
    198 	if ((txc & 0xf) == 0)
    199 		tx[txc++] = RSWD_MSG(CMD_NULL, 0, 0);
    200 
    201 #if CONFIG_M3DEBUG_TRACE
    202 	printx("[ send %x words ]\n", txc);
    203 	for (n = 0; n < txc; n+=4) {
    204 		printx("%x %x %x %x\n",
    205 			tx[n], tx[n+1], tx[n+2], tx[n+3]);
    206 	}
    207 #endif
    208 	usb_xmit(tx, txc * 4);
    209 
    210 	if (func) {
    211 		for (n = 0; n < 1000000; n++) asm("nop");
    212 		func();
    213 		for (;;) ;
    214 	}	
    215 }
    216 
    217 static u32 rxbuffer[512];
    218 static u32 txbuffer[512+1];
    219 
    220 #if CONFIG_M3DEBUG_SERIAL_IFC
    221 extern void _start(void);
    222 
    223 static void ep2_rx_full_cb(void)
    224 {
    225 	int i;
    226 
    227 	static char buf[64];
    228 	int len = usb_ep2_read(buf, sizeof(buf));
    229 	for (i = 0; i < len; i++) {
    230 		serial_putc(buf[i]);
    231 	}
    232 }
    233 
    234 static char outbuf[64];
    235 static volatile int outbufpos = 0;
    236 static volatile int ep2_tx_active = 0;
    237 
    238 static void queue_ep2_tx(void)
    239 {
    240 	if (outbufpos > 0 && !ep2_tx_active) {
    241 		ep2_tx_active = 1;
    242 		int oldbufpos = outbufpos;
    243 		outbufpos = 0;
    244 
    245 		// side effect of this routine is enabling interrupts
    246 		usb_ep2_write(outbuf, oldbufpos);
    247 	}
    248 }
    249 
    250 static void ep2_tx_empty_cb(void)
    251 {
    252 //	printx("tx empty\n");
    253 	disable_interrupts();
    254 
    255 	ep2_tx_active = 0;
    256 	queue_ep2_tx();
    257 
    258 	enable_interrupts();
    259 }
    260 
    261 static void serial_async_cb(char c)
    262 {
    263 	if (outbufpos >= sizeof(outbuf))
    264 		return;
    265 
    266 	disable_interrupts();
    267 
    268 	outbuf[outbufpos++] = c;
    269 
    270 //	serial_putc(c);
    271 	queue_ep2_tx();
    272 
    273 	enable_interrupts();
    274 }
    275 #endif
    276 
    277 int main() {
    278 	int rxc;
    279 
    280 	board_init();
    281 
    282 #if CONFIG_M3DEBUG_SERIAL_IFC
    283 #ifndef CONFIG_USB_2ND_IFC
    284 #error CONFIG_M3DEBUG_SERIAL_IFC requires CONFIG_USB_2ND_IFC
    285 #endif
    286 #ifndef CONFIG_USB_USE_IRQS
    287 #error CONFIG_M3DEBUG_SERIAL_IFC requires CONFIG_USB_USE_IRQS
    288 #endif
    289 	irq_set_base((unsigned) _start);
    290 	enable_interrupts();
    291 #endif
    292 
    293 	serial_init(48000000, 115200);
    294 	ssp0_init();
    295 
    296 #if CONFIG_M3DEBUG_TRACE
    297 	printx("[ rswdp agent v0.9 ]\n");
    298 	printx("[ built " __DATE__ " " __TIME__ " ]\n");
    299 #endif
    300 
    301 #if CONFIG_M3DEBUG_SERIAL_IFC
    302 	usb_init(0x18d1, 0xdb04, "m3dev", "super-m3debug");
    303 
    304 	usb_ep2_rx_full_cb = &ep2_rx_full_cb;
    305 	usb_ep2_tx_empty_cb = &ep2_tx_empty_cb;
    306 	usb_unmask_ep2_rx_full();
    307 	usb_unmask_ep2_tx_empty();
    308 
    309 	serial_start_async_rx(&serial_async_cb);
    310 	irq_enable(v_uart);
    311 #else
    312 	usb_init(0x18d1, 0xdb03, "m3dev", "m3debug");
    313 #endif
    314 
    315 	for (;;) {
    316 		gpio_clr(gpio_led0);
    317 		rxc = usb_recv(rxbuffer, sizeof(rxbuffer));
    318 		gpio_set(gpio_led0);
    319 
    320 #if CONFIG_M3DEBUG_TRACE
    321 		int n;
    322 		printx("[ recv %x words ]\n", rxc/4);
    323 		for (n = 0; n < (rxc/4); n+=4) {
    324 			printx("%x %x %x %x\n",
    325 				rxbuffer[n], rxbuffer[n+1], rxbuffer[n+2], rxbuffer[n+3]);
    326 		}
    327 #endif
    328 
    329 		if ((rxc < 4) || (rxc & 3)) {
    330 			printx("error, runt frame, or strange frame... %x\n", rxc);
    331 			continue;
    332 		}
    333 
    334 		rxc = rxc / 4;
    335 
    336 		if ((rxbuffer[0] & 0xFFFF0000) != 0xAA770000) {
    337 			printx("invalid frame %x\n", rxbuffer[0]);
    338 			continue;
    339 		}
    340 
    341 		process_txn(rxbuffer[0], rxbuffer + 1, rxc - 1, txbuffer);
    342 	}
    343 }