; This is designed to be serial-line downloaded to cdcode. ; ; Our memory map: ; ; [8c000000,8c010000) Stack (r15 set by cdcode) ; [8c010000,8c01????) cdcode ; [8c020000,8c02????) Us ; This code is heavy on the magic numbers. All the other BBA-driving ; code I've found is equally so. :-( .include "regs.s" .include "maple-bits.s" . = 0x8c020000 .sz any .pr any SETS.L #main,r0 jmp @r0 nop SETCONST ; Our "data segment". ; Nothing here at present. ; The only things startup.s sets up that cdcode hasn't already done for ; us are (1) fpscr and (2) clearing bss. We don't have bss because we ; aren't linked by a conventional linker, and we don't use floating ; point so we don't care about fpscr. We do, however, need to set up ; the VBR. We also save r10-r14 against returning to cdcode. .align 2 main: mov.l r14,@-r15 mov.l r13,@-r15 mov.l r12,@-r15 mov.l r11,@-r15 mov.l r10,@-r15 ldc r14,gbr stc sr,r1 SETS.L #~[SR_FD|SR_RB|SR_BL],r2 and r2,r1 ldc r1,sr ; Note that r0-r7 may have just changed if we switched banks. mov #0,r1 lds r1,fpscr .sz 0 .pr 0 SETS.L #intvec,r0 ldc r0,vbr ; Real code begins here. ; Make sure all interrupts are blocked. stc sr,r0 or #0xf0,r0 ldc r0,sr ; Set up the PCI bridge. bsr init_gapspci nop bsr putchar mov #13,r1 bsr putchar mov #10,r1 lds r11,pr rts nop GAPSPCI_BRIDGE_2_constant: .ascii "GAPSPCI_BRIDGE_2" .align 2 init_gapspci: SETS.L #0xa05f688c,r9 SETS.L #0xa1001400,r8 SETS.L #0xa1001600,r7 ; This loop is most of what NetBSD and libronin call G2_LOCK(). ; All G2_LOCK() does that this doesn't is disable interrupts. 1: mov.l @r9,r0 tst #32,r0 bf 1b ; Check the GAPSPCI_BRIDGE_2 constant. SETS.L #GAPSPCI_BRIDGE_2_constant,r2 mov r8,r3 SETS.L #16,r4 1: mov.b @r2+,r0 mov.b @r3+,r1 cmp/eq r0,r1 bf initfail_nomagic dt r4 bf 1b ; GAPSPCI_BRIDGE2 is there. ; I assume this is some kind of magic "please init" value. SETS.L #0x5a14a501,r0 mov r8,r1 add #0x18,r1 mov.l r0,@r1 ; Why 1000000? Because that's what libronin and NetBSD do. :( SETS.L #1000000,r0 1: dt r0 bf 1b ; I assume this is some kind of "init completed OK" check. ; The "not responding" description of failure is from NetBSD. mov.l @r1,r0 cmp/eq #1,r0 bf initfail_noresp ; Offsets 20, 24, 14, and 34 are unknown to me. ; NetBSD field member names imply 28 is a DMA base address ; register and 2c is a DMA area end pointer. SETS.L #0x01840000,r0 SETS.L #0x01000000,r1 mov.l r1,@(0x20,r8) mov.l r1,@(0x24,r8) mov.l r0,@(0x28,r8) SETS.L #0x01848000,r0 mov.l r0,@(0x2c,r8) SETS.L #1,r0 mov.l r0,@(0x14,r8) mov.l r0,@(0x34,r8) ; In libronin, these are all opaque magic numbers. NetBSD has ; a bus_space_map call that implies a1001600 is PCI ; configuration space and thus these are PCI registers. Based ; on NetBSD's dev/pci/pcireg.h and the libronin code, I've ; commented this code with guesses as to what's what. ; 0x06 - PCI status (top half of command/status at 0x04) ; 0xf900 - Turn on PARITY_DETECT, SPECIAL_ERROR, MASTER_ABORT, ; MASTER_TARGET_ABORT, TARGET_TARGET_ABORT, and PARITY_ERROR. ; Set DEVSEL_MASK to DEVSEL_FAST and turn off ; BACKTOBACK_SUPPORT, UDF_SUPPORT, 66MHZ_SUPPORT and ; CAPLIST_SUPPORT. (All names from NetBSD.) The 0x000f bits ; have no definitions in dev/pci/pcireg.h. ; The reason I think this is the _top_ half, not the _bottom_ ; half, of the PCI register is twofold: (1) PCI tends to come ; from a peecee perspective, which means little-endian, and ; (2) in view of the NetBSD names for the bits, the code makes ; a lot more sense this way than with the halves swapped. SETS.W #0xf900,r0 mov.w r0,@(0x06,r7) ; Not sure. ROM mapping register maybe? (PCI_MAPREG_ROM) SETS.L #0,r0 mov.l r0,@(0x30,r7) ; Interrupt line? (Low byte of PCI_INTERRUPT_REG) mov r7,r1 add #0x3c,r1 mov.b r0,@r1 ; LAT timer, whatever that is? ; (Second-low byte of PCI_BHLC_REG) mov #0xf0,r0 mov.b r0,@(0x0d,r7) ; Set MEM_ENABLE and MASTER_ENABLE in PCI command (low half of ; command/status - see above) mov.w @(0x04,r7),r0 or #0x06,r0 mov.w r0,@(0x04,r7) ; Not sure. More mapping stuff? (PCI_MAPREG_PCB_END) SETS.L #0x01000000,r1 mov.l r1,@(0x14,r7) ; Don't know _what_ this is. mov r7,r1 add #0x50,r1 mov.b @r1,r0 tst #1,r0 bf failmsg_dunno ; It all looks good. rts nop failmsg_nomagic: .asciz "PCI bridge magic string not found"(13,10) failmsg_noresp: .asciz "PCI bridge not responding"(13,10) failmsg_dunno: .asciz "PCI bridge not working (offset 0x50)"(13,10) .align 2 initfail_nomagic: SETS.L #failmsg_nomagic,r1 bra putstr nop initfail_noresp: SETS.L #failmsg_noresp,r1 bra putstr nop initfail_dunno: SETS.L #failmsg_dunno,r1 bra putstr nop SETCONST printhex8: mov #8,r0 printhexN: mov.l r4,@-r15 mov r0,r4 add #-8,r0 neg r0,r0 SHLL #2,r0 shld r0,r1 mov.l r3,@-r15 mov.l r2,@-r15 sts.l pr,@-r15 mova 9f,r0 mov r0,r3 mov r1,r2 1: mov r2,r0 SHLR #28,r0 SHLL #4,r2 add r3,r0 bsr putchar mov.b @r0,r1 dt r4 bf 1b lds.l @r15+,pr mov.l @r15+,r2 mov.l @r15+,r3 rts mov.l @r15+,r4 .align 4 9: .ascii "0123456789abcdef" .align 2 putchar2: sts.l pr,@-r15 bsr putchar mov.l r1,@-r15 mov.l @r15+,r1 lds.l @r15+,pr putchar: 1: mov.w @(SCFDR2-SCIF_BASE,gbr),r0 SHXR #SCFDR2_TX_SHIFT,r0 and #SCFDR2_TX_MASK,r0 cmp/eq #16,r0 bt 1b mov r1,r0 mov.b r0,@(SCFTDR2-SCIF_BASE,gbr) 1: mov.w @(SCFDR2-SCIF_BASE,gbr),r0 SHXR #SCFDR2_TX_SHIFT,r0 tst #SCFDR2_TX_MASK,r0 bf 1b rts nop putstr: 1: mov.w @(SCFDR2-SCIF_BASE,gbr),r0 SHXR #SCFDR2_TX_SHIFT,r0 and #SCFDR2_TX_MASK,r0 cmp/eq #16,r0 bt 1b mov.b @r1+,r0 tst r0,r0 bt 1f bra 1b mov.b r0,@(SCFTDR2-SCIF_BASE,gbr) 1: ; don't bother waiting for drain here; we do a putchar call, ; which will drain everything, after all putstr calls and ; before anything for which it matters. rts nop nbgetchar: mov.w @(SCFDR2-SCIF_BASE,gbr),r0 SHXR #SCFDR2_RX_SHIFT,r0,r1 tst #SCFDR2_RX_MASK,r0 bt 1f mov.b @(SCFRDR2-SCIF_BASE,gbr),r0 extu.b r0,r1 mov.w @(SCLSR2-SCIF_BASE,gbr),r0 mov #0,r0 mov.w r0,@(SCLSR2-SCIF_BASE,gbr) rts mov r1,r0 1: rts mov #-1,r0 SETCONST ; Not sure we actually need to align the VBR; the only reason I ; have to suspect we might is that it's the kind of thing I've ; seen relatively often before - interrupt/trap vector tables ; often need to be aligned, not infrequently to a remarkably ; strict boundary. I see no indication in the manuals that ; the SH requires _any_ alignment, but it's easy to do and ; definitely won't hurt anything. (No explicit indication, ; that is. It is implicit in the execution of code at ; VBR+0x100, VBR+0x400, and VBR+0x600 that VBR must be even.) .align 0x10000 ; Exception handling consists of: ; - Save PC and SR in SPC and SSR ; - Set SR bit BL to 1 (block exceptions/interrupts) ; - Set SR bit MD to 1 (privileged mode) ; - Set SR bit RB to 1 (r0-r7 bank 1) ; - Write code to EXPEVT or INTEVT ; - Set PC to vector addr, resume execution intvec = . . = intvec + 0x100 SETS.L #0x100,r2 SETS.L #EXPEVT,r0 mov.l @r0,r3 SETS.L #INTEVT,r0 SETS.L #regdump,r1 jmp @r1 mov.l @r0,r4 SETCONST . = intvec + 0x400 SETS.L #0x400,r2 SETS.L #EXPEVT,r0 mov.l @r0,r3 SETS.L #INTEVT,r0 SETS.L #regdump,r1 jmp @r1 mov.l @r0,r4 SETCONST . = intvec + 0x600 SETS.L #0x600,r2 SETS.L #EXPEVT,r0 mov.l @r0,r3 SETS.L #INTEVT,r0 SETS.L #regdump,r1 jmp @r1 mov.l @r0,r4 SETCONST . = intvec + 0x1000 crash_msg_0: .asciz (13,10,10)"FATAL TRAP"(13,10)"R0 " crash_msg_1: .asciz " R1 " crash_msg_2: .asciz " R2 " crash_msg_3: .asciz " R3 " crash_msg_4: .asciz (13,10)"R4 " crash_msg_5: .asciz " R5 " crash_msg_6: .asciz " R6 " crash_msg_7: .asciz " R7 " crash_msg_8: .asciz (13,10)"R8 " crash_msg_9: .asciz " R9 " crash_msg_10: .asciz " R10 " crash_msg_11: .asciz " R11 " crash_msg_12: .asciz (13,10)"R12 " crash_msg_13: .asciz " R13 " crash_msg_14: .asciz " R14 " crash_msg_15: .asciz " R15 " crash_msg_gbr: .asciz (13,10)"GBR " crash_msg_sr: .asciz " SR " crash_msg_pc: .asciz " PC " crash_msg_mach: .asciz (13,10)"MACH" crash_msg_macl: .asciz " MACL" crash_msg_pr: .asciz " PR " crash_msg_vec: .asciz (13,10)"vector" crash_msg_expevt: .asciz " EXPEVT" crash_msg_intevt: .asciz " INTEVT" crash_msg_done: .asciz (13,10) crash_msg_equal: .asciz " = " .align 4 crash_msgs: .long crash_msg_0 .long crash_msg_1 .long crash_msg_2 .long crash_msg_3 .long crash_msg_4 .long crash_msg_5 .long crash_msg_6 .long crash_msg_7 .long crash_msg_8 .long crash_msg_9 .long crash_msg_10 .long crash_msg_11 .long crash_msg_12 .long crash_msg_13 .long crash_msg_14 .long crash_msg_15 .long crash_msg_gbr .long crash_msg_sr .long crash_msg_pc .long crash_msg_mach .long crash_msg_macl .long crash_msg_pr .long crash_msg_vec .long crash_msg_expevt .long crash_msg_intevt .long 0 .align 2 regdump: mov r15,r5 SETS.L #intstacktop,r15 mov.l r4,@-r15 mov.l r3,@-r15 mov.l r2,@-r15 sts.l pr,@-r15 sts.l macl,@-r15 sts.l mach,@-r15 stc.l spc,@-r15 stc.l ssr,@-r15 stc.l gbr,@-r15 mov.l r5,@-r15 mov.l r14,@-r15 mov.l r13,@-r15 mov.l r12,@-r15 mov.l r11,@-r15 mov.l r10,@-r15 mov.l r9,@-r15 mov.l r8,@-r15 stc.l r7_bank,@-r15 stc.l r6_bank,@-r15 stc.l r5_bank,@-r15 stc.l r4_bank,@-r15 stc.l r3_bank,@-r15 stc.l r2_bank,@-r15 stc.l r1_bank,@-r15 stc.l r0_bank,@-r15 SETS.L #SCIF_BASE,r14 SETS.L #crash_msgs,r9 SETS.L #putstr,r8 SETS.L #printhex8,r7 SETS.L #putchar,r6 1: mov.l @r9+,r1 tst r1,r1 bt 1f jsr @r8 nop SETS.L #crash_msg_equal,r1 jsr @r8 nop jsr @r7 mov.l @r15+,r1 bra 1b nop 1: SETS.L #crash_msg_done,r1 jsr @r8 nop jsr @r6 mov #0,r1 SETS.L #0xa0000000,r0 ; hard-reset vector jmp @r0 nop SETCONST .align 4 .space 0x1000 intstacktop = .