diff options
author | YamaArashi <shadow962@live.com> | 2016-01-23 12:25:42 -0800 |
---|---|---|
committer | YamaArashi <shadow962@live.com> | 2016-01-23 12:25:42 -0800 |
commit | 1362b60f3467f0894d55e82f3294980b6373021d (patch) | |
tree | c53b76333cbb099df9e12dfe7ebfc56bd258b707 /asm/libgcnmultiboot.s |
Initial commit
Diffstat (limited to 'asm/libgcnmultiboot.s')
-rw-r--r-- | asm/libgcnmultiboot.s | 539 |
1 files changed, 539 insertions, 0 deletions
diff --git a/asm/libgcnmultiboot.s b/asm/libgcnmultiboot.s new file mode 100644 index 000000000..7827180e0 --- /dev/null +++ b/asm/libgcnmultiboot.s @@ -0,0 +1,539 @@ +; This library can be used to download and execute a multi-boot image from +; a GameCube using the JOY Bus protocol over the link cable. + + .set GCMB_STRUCT_BASE_DEST_PTR, 0x20 + .set GCMB_STRUCT_CUR_DEST_PTR, 0x24 + .set GCMB_STRUCT_SERIAL_INTR_HANDLER, 0x28 + + thumb_func_start GameCubeMultiBoot_Hash +GameCubeMultiBoot_Hash: ; 81DCB38 + push {r4,lr} + ldr r4, pool_HashVal + eors r3, r1 + movs r2, 0x20 + +$loop: + lsrs r3, 1 + bcc $skipEor + + eors r3, r4 + +$skipEor: + subs r2, 0x1 + bne $loop + + pop {r4,pc} + thumb_func_end GameCubeMultiBoot_Hash + + thumb_func_start GameCubeMultiBoot_Main +; void GameCubeMultiBoot_Main(struct GameCubeMultiBoot *mb); +GameCubeMultiBoot_Main: ; 81DCB4C + ldr r1, [r0, GCMB_STRUCT_SERIAL_INTR_HANDLER] + cmp r1, 0 + beq _081DCB72 + ldrb r1, [r0, 0x1] + adds r1, 0x1 + strb r1, [r0, 0x1] + ldrb r1, [r0, 0x2] + cmp r1, 0x2 + beq _081DCBBC + ldr r3, pool_InterruptRegs + ldrh r2, [r3, OFFSET_REG_IME - 0x200] + movs r1, 0 + strh r1, [r3, OFFSET_REG_IME - 0x200] + ldrb r1, [r0] + cmp r1, 0xA + bgt _081DCB70 + adds r1, 0x1 + strb r1, [r0] +_081DCB70: + strh r2, [r3, OFFSET_REG_IME - 0x200] +_081DCB72: + bcs GameCubeMultiBoot_Init + ldrb r1, [r0, 0x2] + cmp r1, 0 + bne _081DCBBE + ldr r1, [r0, GCMB_STRUCT_CUR_DEST_PTR] + ldr r2, [r0, GCMB_STRUCT_BASE_DEST_PTR] + subs r1, r2 + beq _081DCC3E + cmp r1, 0xA0 + bcc _081DCC3E + push {r4-r6} + movs r1, 0x98 + adds r2, RomHeaderNintendoLogo - RomBase + ldr r4, pool_NintendoLogo +_081DCB8E: + ldm r2!, {r5} + ldm r4!, {r6} + cmp r5, r6 + bne _081DCBA4 + subs r1, 0x4 + bne _081DCB8E + ldm r2!, {r5} + ldm r4!, {r6} + eors r5, r6 + lsrs r5, 8 + str r2, [r0, GCMB_STRUCT_BASE_DEST_PTR] +_081DCBA4: + pop {r4-r6} + bne GameCubeMultiBoot_Init + movs r1, 0x1 + strb r1, [r0, 0x2] + ldr r1, [r0, 0x4] + ldr r2, [r0, 0x8] + eors r1, r2 + str r1, [r0, 0x18] + ldr r2, pool_Kawa + muls r1, r2 + adds r1, 0x1 + str r1, [r0, 0x14] +_081DCBBC: + bx lr +_081DCBBE: + ldr r1, [r0, GCMB_STRUCT_CUR_DEST_PTR] + mov r12, r1 + ldr r3, [r0, 0x18] + push {r4-r7} + ldr r4, [r0, GCMB_STRUCT_BASE_DEST_PTR] + ldr r5, pool_Kawa + ldr r6, [r0, 0x14] + ldr r7, pool_HashVal +_081DCBCE: + cmp r4, r12 + bcs _081DCBEE + ldr r1, [r4] + eors r1, r6 + adds r1, r3 + stm r4!, {r1} + eors r3, r1 + movs r2, 0x20 +_081DCBDE: + lsrs r3, 1 + bcc _081DCBE4 + eors r3, r7 +_081DCBE4: + subs r2, 0x1 + bne _081DCBDE + muls r6, r5 + adds r6, 0x1 + b _081DCBCE +_081DCBEE: + str r4, [r0, GCMB_STRUCT_BASE_DEST_PTR] + str r6, [r0, 0x14] + pop {r4-r7} + str r3, [r0, 0x18] + ldrh r1, [r0, 0x12] + cmp r1, 0 + bne _081DCC3E + ldr r1, [r0, GCMB_STRUCT_CUR_DEST_PTR] + ldr r2, [r0, GCMB_STRUCT_BASE_DEST_PTR] + cmp r1, r2 + bne _081DCC3E + ldr r1, [r0, 0xC] + cmp r1, 0 + beq _081DCC28 + ldrh r1, [r0, 0x10] + cmp r1, 0 + beq _081DCBBC + mov r12, lr + movs r1, 0xBB + ldr r3, [r0, 0xC] + bl GameCubeMultiBoot_Hash + ldrh r1, [r0, 0x10] + mov lr, r12 + subs r1, r3 + bne GameCubeMultiBoot_Init + movs r1, 0x2 + strb r1, [r0, 0x2] + bx lr +_081DCC28: + mov r12, lr + ldrb r1, [r0, 0x3] + lsls r1, 24 + subs r1, 0x1 + str r1, [r0, 0xC] + bl GameCubeMultiBoot_Hash + lsls r3, 8 + adds r3, 0xFF + str r3, [r0, 0x1C] + bx r12 +_081DCC3E: + bx lr + thumb_func_end GameCubeMultiBoot_Main + + .align 2, 0 + +pool_HashVal: .4byte 0xa1c1 + +pool_Kawa: .ascii "Kawa" ; name of BIOS developer + +pool_NintendoLogo: .4byte RomHeaderNintendoLogo + + thumb_func_start GameCubeMultiBoot_ExecuteProgram +; void GameCubeMultiBoot_ExecuteProgram(struct GameCubeMultiBoot *mb); +GameCubeMultiBoot_ExecuteProgram: ; 81DCC4C + ldrb r1, [r0, 0x2] + cmp r1, 0x2 + bne $unableToExecute + ldr r3, pool_InterruptRegs + movs r1, 0 + strh r1, [r3, OFFSET_REG_IME - 0x200] + ldr r1, pool_MultiBootLoadAddr + adds r1, 0xC0 + bx r1 +$unableToExecute: + bx lr + thumb_func_end GameCubeMultiBoot_ExecuteProgram + + thumb_func_start GameCubeMultiBoot_Init +; void GameCubeMultiBoot_Init(struct GameCubeMultiBoot *mb); +GameCubeMultiBoot_Init: ; 81DCC60 + ldr r3, pool_InterruptRegs + +; Save IME register. + ldrh r2, [r3, OFFSET_REG_IME - 0x200] + +; Disable interrupts. + movs r1, 0 + strh r1, [r3, OFFSET_REG_IME - 0x200] + +; Set the handler to the "Stop" routine. +; Unless the first command that is received is a device reset command, the +; "Stop" routine will be executed and no further commands will be processed. + adr r3, GcMbIntrHandler_Stop + str r3, [r0, GCMB_STRUCT_SERIAL_INTR_HANDLER] + + ldrb r3, [r0, 0x3] + push {r3} + ldrb r3, [r0, 0x1] + push {r0,r3} + + adds r3, r0, 0 + adds r3, GCMB_STRUCT_BASE_DEST_PTR + +; clear all but the last 3 fields of the struct +$clearStructLoop: + stm r0!, {r1} + cmp r0, r3 + blo $clearStructLoop + + pop {r0,r3} + lsrs r3, 1 + strb r3, [r0, 0x3] + pop {r3} + strb r3, [r0, 0x1] + + ldr r3, pool_SerialRegs + +; Turn off JOY Bus mode. + lsls r0, r3, 10 + strh r0, [r3, OFFSET_REG_RCNT - 0x120] + +; Turn on JOY Bus mode. + movs r0, 0xC0 + lsls r0, 8 + strh r0, [r3, OFFSET_REG_RCNT - 0x120] + +; Init JOY Bus registers. + movs r0, 0x47 + strh r0, [r3, OFFSET_REG_JOYCNT - 0x120] + strh r1, [r3, OFFSET_REG_JOYSTAT - 0x120] + + ldr r3, pool_InterruptRegs + +; Acknowledge serial interrupt. + movs r0, INTR_FLAG_SERIAL + strh r0, [r3, OFFSET_REG_IF - 0x200] + +; Enable serial interrupt. + ldrh r1, [r3, OFFSET_REG_IE - 0x200] + orrs r1, r0 + strh r1, [r3, OFFSET_REG_IE - 0x200] + +; Restore IME register. + strh r2, [r3, OFFSET_REG_IME - 0x200] + + bx lr + thumb_func_end GameCubeMultiBoot_Init + + non_word_aligned_thumb_func_start GameCubeMultiBoot_HandleSerialInterrupt +; void GameCubeMultiBoot_HandleSerialInterrupt(struct GameCubeMultiBoot *mb); +GameCubeMultiBoot_HandleSerialInterrupt: ; 81DCCAA + ldr r3, pool_SerialRegs + +; Acknowledge reset/receive/send flags. + ldrh r1, [r3, OFFSET_REG_JOYCNT - 0x120] + strh r1, [r3, OFFSET_REG_JOYCNT - 0x120] + + movs r2, 0 + strb r2, [r0] + + ldr r2, [r0, GCMB_STRUCT_SERIAL_INTR_HANDLER] + cmp r2, 0 + beq GameCubeMultiBoot_HandleSerialInterruptDone + + lsrs r1, 1 ; was a device reset command received? + bcs GameCubeMultiBoot_BeginHandshake ; branch if so + + mov pc, r2 + + .align 2, 0 + +; Zero the status and the interrupt handler pointer. +; Commands from the GameCube will not be processed after this is executed +; unless GameCubeMultiBoot_Init() is called again. +GcMbIntrHandler_Stop: + movs r2, 0 + strh r2, [r3, OFFSET_REG_JOYSTAT - 0x120] + +GameCubeMultiBoot_SetInterruptHandler: + str r2, [r0, GCMB_STRUCT_SERIAL_INTR_HANDLER] + +GameCubeMultiBoot_ReadVCount: + ldr r3, pool_RegDispstat + ldrh r1, [r3, OFFSET_REG_VCOUNT - OFFSET_REG_DISPSTAT] + strb r1, [r0, 0x3] + +GameCubeMultiBoot_HandleSerialInterruptDone: + bx lr + +GameCubeMultiBoot_BeginHandshake: + ldr r1, [r3, OFFSET_REG_JOY_RECV - 0x120] + ldr r1, pool_RubyUSAGameCode + str r1, [r3, OFFSET_REG_JOY_TRANS - 0x120] + movs r1, 0x10 + strh r1, [r3, OFFSET_REG_JOYSTAT - 0x120] + ldrb r1, [r0, 0x3] + strb r1, [r0, 0x9] + ldrb r1, [r0, 0x2] + cmp r1, 0 + bne GcMbIntrHandler_Stop + ldr r1, pool_MultiBootLoadAddr + str r1, [r0, GCMB_STRUCT_BASE_DEST_PTR] + str r1, [r0, GCMB_STRUCT_CUR_DEST_PTR] + adr r2, GcMbIntrHandler_CheckGameCodeSent + b GameCubeMultiBoot_SetInterruptHandler + + .align 2, 0 + +GcMbIntrHandler_CheckGameCodeSent: ; 81DCCEC + lsls r1, 31 + bcc GcMbIntrHandler_Stop ; stop if send failed + bmi GameCubeMultiBoot_CheckHandshakeResponse ; branch if receive is complete + +; If the response hasn't been fully received yet, +; check again upon the next interrupt. + adr r2, GcMbIntrHandler_CheckHandshakeResponse + b GameCubeMultiBoot_SetInterruptHandler + + .align 2, 0 + +GcMbIntrHandler_CheckHandshakeResponse: ; 81DCCF8 + lsrs r1, 1 ; is receive complete? + bcc GcMbIntrHandler_Stop ; stop if not + +GameCubeMultiBoot_CheckHandshakeResponse: + ldr r1, [r3, OFFSET_REG_JOY_RECV - 0x120] + ldr r2, pool_RubyUSAGameCode + cmp r1, r2 + bne GcMbIntrHandler_Stop ; stop if the GameCube didn't reply with the same game code + ldrb r1, [r0, 0x3] + strb r1, [r0, 0xB] + adr r2, GcMbIntrHandler_81DCD0C + b GameCubeMultiBoot_SetInterruptHandler + + .align 2, 0 + +GcMbIntrHandler_81DCD0C: ; 81DCD0C + lsrs r1, 1 ; is receive complete? + bcc GcMbIntrHandler_Stop ; branch if not + ldr r1, [r3, OFFSET_REG_JOY_RECV - 0x120] + lsrs r2, r1, 24 + cmp r2, 0xDD + bne GcMbIntrHandler_Stop + str r1, [r0, 0x4] + ldrb r1, [r0, 0x1] + strb r1, [r0, 0xA] + movs r2, 0 + movs r3, 0 + ldr r1, [r0, 0x8] + lsrs r1, 8 +_081DCD26: + lsrs r1, 1 + adcs r2, r3 + cmp r1, 0 + bne _081DCD26 + cmp r2, 0xE + bgt _081DCD38 + cmp r2, 0x7 + bge _081DCD3A + movs r1, 0xFF +_081DCD38: + strb r1, [r0, 0xA] +_081DCD3A: + ldr r1, [r0, 0x8] + adds r1, 0xEE + ldr r3, pool_SerialRegs + str r1, [r3, OFFSET_REG_JOY_TRANS - 0x120] + movs r1, 0x30 + strh r1, [r3, OFFSET_REG_JOYSTAT - 0x120] + adr r2, GcMbIntrHandler_81DCD4C + b GameCubeMultiBoot_SetInterruptHandler + + .align 2, 0 + +GcMbIntrHandler_81DCD4C: ; 81DCD4C + lsls r1, 31 + bcc GcMbIntrHandler_Stop ; stop if send failed + bmi _081DCD5C ; branch if receive is complete + adr r2, GcMbIntrHandler_81DCD58 + b GameCubeMultiBoot_SetInterruptHandler + + .align 2, 0 + +GcMbIntrHandler_81DCD58: ; 81DCD58 + lsrs r1, 1 ; is receive complete? + bcc GcMbIntrHandler_Stop ; branch if not +_081DCD5C: + ldr r1, [r3, OFFSET_REG_JOY_RECV - 0x120] + ldr r2, _081DCDFC + cmp r1, r2 + bhs GcMbIntrHandler_Stop + adds r1, 0x1 + adds r1, r1 + strh r1, [r0, 0x12] + ldrb r1, [r0, 0x2] + cmp r1, 0 +_081DCD6E: + bne GcMbIntrHandler_Stop + ldr r1, pool_MultiBootLoadAddr + str r1, [r0, GCMB_STRUCT_BASE_DEST_PTR] + str r1, [r0, GCMB_STRUCT_CUR_DEST_PTR] + adr r2, GcMbIntrHandler_81DCD7C + b GameCubeMultiBoot_SetInterruptHandler + + .align 2, 0 + +GcMbIntrHandler_81DCD7C: ; 81DCD7C + lsrs r1, 1 ; is receive complete? + bcc GcMbIntrHandler_Stop ; branch if not + ldr r2, [r0, GCMB_STRUCT_CUR_DEST_PTR] + movs r1, 0x4 + ands r1, r2 + adds r1, 0x8 + lsls r1, 2 + strh r1, [r3, OFFSET_REG_JOYSTAT - 0x120] + ldr r1, [r3, OFFSET_REG_JOY_RECV - 0x120] + stm r2!, {r1} + str r2, [r0, GCMB_STRUCT_CUR_DEST_PTR] + ldrh r1, [r0, 0x12] + subs r1, 0x1 + strh r1, [r0, 0x12] + bne GameCubeMultiBoot_ReadVCount + +_081DCD9A: + ldrb r1, [r0, 0x1] + lsls r1, 8 + adds r1, 0xCC + str r1, [r3, OFFSET_REG_JOY_TRANS - 0x120] + adr r2, _081DCDA8 + b GameCubeMultiBoot_SetInterruptHandler + + .align 2, 0 + +_081DCDA8: + lsls r1, 31 + +_081DCDAA: + bcc GcMbIntrHandler_Stop + ldr r1, [r0, 0x1C] + cmp r1, 0 + beq _081DCD9A + str r1, [r3, OFFSET_REG_JOY_TRANS - 0x120] + adr r2, GcMbIntrHandler_81DCDB8 + b GameCubeMultiBoot_SetInterruptHandler + + .align 2, 0 + +GcMbIntrHandler_81DCDB8: ; 81DCDB8 + lsls r1, 31 + bcc _081DCDAA ; branch if send failed + bmi _081DCDC8 ; branch if receive is complete + adr r2, GcMbIntrHandler_81DCDC4 + b GameCubeMultiBoot_SetInterruptHandler + + .align 2, 0 + +GcMbIntrHandler_81DCDC4: ; 81DCDC4 + lsrs r1, 1 ; is receive complete? + bcc _081DCDAA ; branch if not + +_081DCDC8: + ldr r1, [r3, OFFSET_REG_JOY_RECV - 0x120] + lsrs r2, r1, 24 + cmp r2, 0xBB + bne _081DCD6E + strh r1, [r0, 0x10] + adr r2, GcMbIntrHandler_81DCDD8 + b GameCubeMultiBoot_SetInterruptHandler + + .align 2, 0 + +GcMbIntrHandler_81DCDD8: ; 81DCDD8 + b GcMbIntrHandler_Stop + + thumb_func_end GameCubeMultiBoot_HandleSerialInterrupt + + non_word_aligned_thumb_func_start GameCubeMultiBoot_Quit +; void GameCubeMultiBoot_Quit(); +GameCubeMultiBoot_Quit: ; 81DCDDA + ldr r3, pool_InterruptRegs + +; Save IME register. + ldrh r2, [r3, OFFSET_REG_IME - 0x200] + +; Disable interrupts. + movs r1, 0 + strh r1, [r3, OFFSET_REG_IME - 0x200] + + ldr r3, pool_SerialRegs + +; Acknowledge all JOYCNT flags. + movs r0, 0x7 + strh r0, [r3, OFFSET_REG_JOYCNT - 0x120] + +; Turn off JOY Bus mode. + lsls r0, r3, 10 + strh r0, [r3, OFFSET_REG_RCNT - 0x120] ; store 0x8000 + + ldr r3, pool_InterruptRegs + +; Acknowledge serial interrupt. + movs r0, INTR_FLAG_SERIAL + strh r0, [r3, OFFSET_REG_IF - 0x200] + +; Disable serial interrupt. + ldrh r1, [r3, OFFSET_REG_IE - 0x200] + bics r1, r0 + strh r1, [r3, OFFSET_REG_IE - 0x200] + +; Restore IME register. + strh r2, [r3, OFFSET_REG_IME - 0x200] + + bx lr + thumb_func_end GameCubeMultiBoot_Quit + + .align 2, 0 + +_081DCDFC: .4byte 0x00004000 + +pool_InterruptRegs: .4byte REG_BASE + 0x200 + +pool_SerialRegs: .4byte REG_BASE + 0x120 + +pool_RegDispstat: .4byte REG_DISPSTAT + +pool_RubyUSAGameCode: .ascii "AXVE" + +pool_MultiBootLoadAddr: .4byte EWRAM_START |