# HG changeset patch # User Michael Spacefalcon # Date 1366179919 0 # Node ID a06573cacb6ebf3ef14b1655fb811b9d8ee612f0 # Parent a445735685bad1bd33fb4e043e8b7f42f7220fc2 boot ROM re: trying to understand the code that runs after '<' received diff -r a445735685ba -r a06573cacb6e bootrom.disasm --- a/bootrom.disasm Tue Apr 16 20:56:31 2013 +0000 +++ b/bootrom.disasm Wed Apr 17 06:25:19 2013 +0000 @@ -8,6 +8,20 @@ 18: ea200004 b 0x800030 1c: ea200004 b 0x800034 +; The following routine (starting at 0x20) is used to transfer control +; to nCS0 application images that are designed to work with no internal +; boot ROM "in the way", i.e., images identified by a 1 in the 0x2000 word. +; The present routine is copied to the internal RAM and executed there. +; +; The routine itself takes one argument in R0 and uses it to set the +; nIBOOT override bits in the FFFF:FB10 register. If R0==1, bits <9:8> +; of this register are set to 11, putting nCS0 at address 0. If R0==0, +; the bits are set to 01, putting the internal ROM at 0. Otherwise, +; the bits are set to 00, restoring the nIBOOT pin configuration. +; (In actual operation the argument passed to this function is the word +; from 0x2000, so it's equal to 1.) Then the routine causes the +; watchdog timer to go off, resetting the ARM. + 20: e24dd004 sub sp, sp, #4 ; 0x4 24: e59f20b8 ldr r2, =0xFFFFFB10 ; via 0xe4 28: e1d2c0b0 ldrh r12, [r2] @@ -58,9 +72,10 @@ dc: e28dd004 add sp, sp, #4 ; 0x4 e0: e12fff1e bx lr -; literal pool +; literal pool for the above routine e4: fffffb10 e8: 000080f5 +; end of the code copied to the internal RAM for booting type 1 images ec: e92d4010 stmdb sp!, {r4, lr} f0: e59fcd0c ldr r12, [pc, #3340] ; 0xe04 @@ -72,7 +87,7 @@ 108: e5d0c000 ldrb r12, [r0] 10c: e31c0040 tst r12, #64 ; 0x40 110: 0afffffc beq 0x108 - 114: eb000513 bl 0x1568 + 114: eb000513 bl 0x1568 ; IND_CALL 118: eafffffe b 0x118 11c: e3a0c004 mov r12, #4 ; 0x4 @@ -1002,16 +1017,23 @@ eec: e10600bc strh r0, [r6, -r12] ef0: e8bd8070 ldmia sp!, {r4, r5, r6, pc} +; The routine at 0xef4 gets called from main() after a '<' character +; has been received and autoboot thereby interrupted in the +; autoboot-enabled flash state. + ef4: e92d4070 stmdb sp!, {r4, r5, r6, lr} - ef8: e59fc3e4 ldr r12, [pc, #996] ; 0x12e4 + ef8: e59fc3e4 ldr r12, =0xFFFFF900 ; via 0x12e4 efc: e1dc40b0 ldrh r4, [r12] - f00: e59f33d0 ldr r3, [pc, #976] ; 0x12d8 +; original value of FFFF:F900 saved in R4 +; now set it to FF22, just like the 0xe2c init routine did + f00: e59f33d0 ldr r3, =0xFFFFFD00 ; via 0x12d8 f04: e3a05b01 mov r5, #1024 ; 0x400 f08: e3a0c801 mov r12, #65536 ; 0x10000 f0c: e24cc0de sub r12, r12, #222 ; 0xde f10: e103c0b5 strh r12, [r3, -r5] - f14: e59f63c0 ldr r6, [pc, #960] ; 0x12dc - f18: e59fc3c0 ldr r12, [pc, #960] ; 0x12e0 +; write 0x2002 to FFFF:9800, again just like 0xe2c did + f14: e59f63c0 ldr r6, =0xFFFF9800 ; via 0x12dc + f18: e59fc3c0 ldr r12, =0x2002 ; via 0x12e0 f1c: e1c6c0b0 strh r12, [r6] f20: e1b05f8c movs r5, r12, lsl #31 f24: 1afffffd bne 0xf20 @@ -1051,9 +1073,34 @@ fac: e10340bc strh r4, [r3, -r12] fb0: e8bd8070 ldmia sp!, {r4, r5, r6, pc} +; Routine 0xfb4 gets called from main() where the boot code is giving +; the UARTs a chance to interrupt the autoboot process before transferring +; control to the nCS0 image. +; +; Arguments: both R0 and R1 point to byte variables acting as additional +; function outputs. +; +; If a '<' character is received on either UART, the function returns +; without further fuss. If nothing was received on either UART, it +; also returns without further fuss. However, if the "wrong" byte value +; was received on either UART, the function flips the VCLKOUT_DIV2 bit +; in the FFFF:FD02 register - it is the boot code's way of figuring out +; whether the input clock is 13 or 26 MHz. +; +; Return values: +; In R0: 1 if '<' received, 0 otherwise +; In *R0: UART ID if '<' received, FF otherwise +; In *R1: final state of the 800534 byte variable +; +; The latter variable records the state of the divide-by-2. On the first +; try, the divide-by-2 is enabled, and the variable contains 0. When this +; function disables the /2, the variable is set to 1. It keeps toggling +; back and forth as wrong bytes come in. + fb4: e3a0c0ff mov r12, #255 ; 0xff fb8: e5c0c000 strb r12, [r0] - fbc: e59fc324 ldr r12, [pc, #804] ; 0x12e8 +; check the MODEM UART first + fbc: e59fc324 ldr r12, =0xFFFF5000 ; via 0x12e8 fc0: e5dc2805 ldrb r2, [r12, #2053] fc4: e1b02f82 movs r2, r2, lsl #31 fc8: 1a000001 bne 0xfd4 @@ -1063,6 +1110,9 @@ fd8: e352003c cmp r2, #60 ; 0x3c fdc: 0a000024 beq 0x1074 fe0: e3a02001 mov r2, #1 ; 0x1 +; Control gets here if no '<' was received on the MODEM UART. +; R2 contains 1 if some other byte value was received, or 0 if nothing. +; Now check the IrDA UART. fe4: e5dc3005 ldrb r3, [r12, #5] fe8: e1b03f83 movs r3, r3, lsl #31 fec: 1a000002 bne 0xffc @@ -1072,13 +1122,14 @@ ffc: e5dcc000 ldrb r12, [r12] 1000: e35c003c cmp r12, #60 ; 0x3c 1004: 0a000017 beq 0x1068 - 1008: e59fc2dc ldr r12, [pc, #732] ; 0x12ec +; control gets here if the "wrong" byte value was received on either UART + 1008: e59fc2dc ldr r12, =0x800534 ; via 0x12ec 100c: e5dc0000 ldrb r0, [r12] 1010: e3500000 cmp r0, #0 ; 0x0 1014: 1a000008 bne 0x103c 1018: e3a00001 mov r0, #1 ; 0x1 101c: e5cc0000 strb r0, [r12] - 1020: e59f02c8 ldr r0, [pc, #712] ; 0x12f0 + 1020: e59f02c8 ldr r0, =0xFFFFFD02 ; via 0x12f0 1024: e1d0c0b0 ldrh r12, [r0] 1028: e20c20bf and r2, r12, #191 ; 0xbf 102c: e20cccff and r12, r12, #65280 ; 0xff00 @@ -1087,22 +1138,23 @@ 1038: ea000005 b 0x1054 103c: e3a00000 mov r0, #0 ; 0x0 1040: e5cc0000 strb r0, [r12] - 1044: e59fc2a4 ldr r12, [pc, #676] ; 0x12f0 + 1044: e59fc2a4 ldr r12, =0xFFFFFD02 ; via 0x12f0 1048: e1dc00b0 ldrh r0, [r12] 104c: e3800040 orr r0, r0, #64 ; 0x40 1050: e1cc00b0 strh r0, [r12] - 1054: e59fc290 ldr r12, [pc, #656] ; 0x12ec + 1054: e59fc290 ldr r12, =0x800534 ; via 0x12ec 1058: e5dcc000 ldrb r12, [r12] 105c: e5c1c000 strb r12, [r1] 1060: e3a00000 mov r0, #0 ; 0x0 1064: e12fff1e bx lr - +; control gets here if a '<' character was received on the IrDA UART 1068: e3a0c001 mov r12, #1 ; 0x1 106c: e5c0c000 strb r12, [r0] 1070: ea000001 b 0x107c +; control gets here if a '<' character was received on the MODEM UART 1074: e3a0c000 mov r12, #0 ; 0x0 1078: e5c0c000 strb r12, [r0] - 107c: e59fc268 ldr r12, [pc, #616] ; 0x12ec + 107c: e59fc268 ldr r12, =0x800534 ; via 0x12ec 1080: e5dcc000 ldrb r12, [r12] 1084: e5c1c000 strb r12, [r1] 1088: e3a00001 mov r0, #1 ; 0x1 @@ -1248,7 +1300,9 @@ 1240: e59f10b0 ldr r1, =0x800524 ; via 0x12f8 1244: e2415004 sub r5, r1, #4 ; 0x4 1248: e59f40b0 ldr r4, =0x373C ; via 0x1300 +; the retry count loaded into R4 is 14140 in decimal 124c: e1a00005 mov r0, r5 +; call made with R0=0x800520, R1=0x800524 1250: ebffff57 bl 0xfb4 1254: e3500000 cmp r0, #0 ; 0x0 1258: 1a000001 bne 0x1264 @@ -1300,9 +1354,16 @@ 12fc: 00800104 1300: 0000373c +; Routine 0x1304: emit a character string through a UART +; +; Arguments: +: R0: pointer to the string +; R1: number of characters (bytes) to transmit +; R2: UART ID (0=MODEM, 1=IrDA) + 1304: e3510000 cmp r1, #0 ; 0x0 1308: 012fff1e bxeq lr - 130c: e59fc178 ldr r12, [pc, #376] ; 0x148c + 130c: e59fc178 ldr r12, =0x1FCC ; via 0x148c 1310: e79cc102 ldr r12, [r12, r2, lsl #2] 1314: e28c3005 add r3, r12, #5 ; 0x5 1318: e5d32000 ldrb r2, [r3] @@ -1375,7 +1436,12 @@ 13d0: 1affffed bne 0x138c 13d4: e8bd8ff0 ldmia sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc} - 13d8: e59fc0ac ldr r12, [pc, #172] ; 0x148c +; The following routine switches a UART to a different baud rate. +; Arguments: +; R0: baud rate index from the table at 0x1FD4 +; R1: UART ID (0=MODEM, 1=IrDA) + + 13d8: e59fc0ac ldr r12, =0x1FCC ; via 0x148c 13dc: e79c2101 ldr r2, [r12, r1, lsl #2] 13e0: e282c005 add r12, r2, #5 ; 0x5 13e4: e5dc1000 ldrb r1, [r12] @@ -1385,7 +1451,7 @@ 13f4: e5dc1000 ldrb r1, [r12] 13f8: e3811080 orr r1, r1, #128 ; 0x80 13fc: e5cc1000 strb r1, [r12] - 1400: e59f108c ldr r1, [pc, #140] ; 0x1494 + 1400: e59f108c ldr r1, =0x1FD4 ; via 0x1494 1404: e7d13080 ldrb r3, [r1, r0, lsl #1] 1408: e5c23001 strb r3, [r2, #1] 140c: e0810080 add r0, r1, r0, lsl #1 @@ -1396,16 +1462,25 @@ 1420: e5cc0000 strb r0, [r12] 1424: e12fff1e bx lr +; 0x1428 - UART read Rx character routine +; +; Arguments: +; R0: UART ID (0=MODEM, 1=IrDA) +; R1: poll repeat count, 0 means wait forever +; R2: pointer to buffer where the received booty is stored +; +; Return value: 1 if a character was received, 0 otherwise + 1428: e3510000 cmp r1, #0 ; 0x0 142c: 1a000006 bne 0x144c - 1430: e59fc054 ldr r12, [pc, #84] ; 0x148c + 1430: e59fc054 ldr r12, =0x1FCC ; via 0x148c 1434: e79cc100 ldr r12, [r12, r0, lsl #2] 1438: e28c1005 add r1, r12, #5 ; 0x5 143c: e5d10000 ldrb r0, [r1] 1440: e1b00f80 movs r0, r0, lsl #31 1444: 0afffffc beq 0x143c 1448: ea000009 b 0x1474 - 144c: e59fc038 ldr r12, [pc, #56] ; 0x148c + 144c: e59fc038 ldr r12, =0x1FCC ; via 0x148c 1450: e79cc100 ldr r12, [r12, r0, lsl #2] 1454: e28c3005 add r3, r12, #5 ; 0x5 1458: e5d30000 ldrb r0, [r3] @@ -1521,6 +1596,11 @@ 1588: eafffffe b 0x1588 +; This routine effects the transfer of control to the flash (nCS0) +; application image of the type indicated by the argument in R0. +; The latter argument is the word read from 0x2000. +; R1 contains the word read from 0x2004. + 158c: e92d4010 stmdb sp!, {r4, lr} 1590: e1a04000 mov r4, r0 1594: e1b0c0a4 movs r12, r4, lsr #1 @@ -1539,7 +1619,7 @@ 15c8: e38ccc01 orr r12, r12, #256 ; 0x100 15cc: e1c0c0b0 strh r12, [r0] 15d0: e1a04001 mov r4, r1 - 15d4: ebffffe3 bl 0x1568 + 15d4: ebffffe3 bl 0x1568 ; IND_CALL 15d8: e8bd8010 ldmia sp!, {r4, pc} 15dc: e3540001 cmp r4, #1 ; 0x1 15e0: 18bd8010 ldmneia sp!, {r4, pc} @@ -1555,10 +1635,20 @@ 1600: fffffb10 1604: 00800038 +; This routine computes a simple word-wise (16 bits at a time) sum of +; the present internal boot ROM code (ignoring carry-outs), and returns +; it in R0. The upper 16 bits of the R0 return value will always be 0. +; +; If the argument in R0 equals 1, a call to the 0xe2c memmap/clock init +; function is made first, with the same arguments as at the beginning +; of main(). + 1608: e92d4000 stmdb sp!, {lr} 160c: e24dd008 sub sp, sp, #8 ; 0x8 1610: e3500001 cmp r0, #1 ; 0x1 1614: 1a000006 bne 0x1634 +; 0xe2c routine is called with the same arguments as at the beginning +; of main() 1618: e3a0c002 mov r12, #2 ; 0x2 161c: e5cdc000 strb r12, [sp] 1620: e3a00004 mov r0, #4 ; 0x4 @@ -1789,10 +1879,13 @@ ; base addresses of the two UARTs 1fcc: ffff5800 1fd0: ffff5000 -; ??? - 1fd4: 0e000700 cdpeq 7, 0, cr0, cr0, cr0, {0} - 1fd8: 1c001500 cfstr32ne mvfx1, [r0] - 1fdc: 00002a00 andeq r2, r0, r0, lsl #20 +; UART baud rates + 1fd4: 0700 ; /7 (115200?) + 1fd6: 0e00 ; /14 (57600?) + 1fd8: 1500 ; /21 (38400?) + 1fda: 1c00 ; /28 (28800?) + 1fdc: 2a00 ; /42 (19200?) + 1fde: 0000 ; These ldr-jump instructions get copied to the 7 internal RAM words ; starting at 0x80001C. They have the effect of defining the preceding diff -r a445735685ba -r a06573cacb6e bootrom.notes --- a/bootrom.notes Tue Apr 16 20:56:31 2013 +0000 +++ b/bootrom.notes Wed Apr 17 06:25:19 2013 +0000 @@ -37,11 +37,19 @@ 80001C 7 words: hard vectors: the physical vector locations in the ROM contain branch instructions to these 7 RAM addresses - +800038: The helper routine for transferring control to type 1 flash images + is copied to and run here. +800100: the last word of the above routine 800104: word initialized to 0x0001D4C0 800108: byte initialized to 0x01 -800534: byte initialized to 0x00 +800520: byte variable filled every time the 0xfb4 routine is called + holds the ID of the UART on which '<' came in, or FF if none +800524: byte variable filled every time the 0xfb4 routine is called + filled with a copy of 800534 + +800534: byte initialized to 0x00, then may be set to 1 by the 0xfb4 + routine if it selects /1 clock mode. 8005C0: appears to be the intended low address (bottom) of the stack 80074C: top of the stack (initial value loaded into SP)