|
| 1 | +#include <nds/asminc.h> |
| 2 | + |
| 3 | +#define ITCM_foo_base 0x00000004 |
| 4 | + |
| 5 | +.align 4 |
| 6 | +.arm |
| 7 | + |
| 8 | +@ Writes a new value to the ARM9 SCFG_CLK. |
| 9 | +@ Must be called from ITCM. |
| 10 | +@ Must wait 8 clock cycles after changing the value before returning. |
| 11 | +@ https://problemkaputt.de/gbatek.htm#dsicontrolregistersscfg |
| 12 | +@ Not what I experimentally observed, but better safe than sorry... |
| 13 | +@ void _arm9_write_to_scfg_clk(uint16_t new_val); |
| 14 | +BEGIN_ASM_FUNC _arm9_write_to_scfg_clk |
| 15 | + mov r1, #0x04000000 |
| 16 | + add r1, #0x4000 |
| 17 | + strh r0,[r1, #4] |
| 18 | + @ Wait 8 clock cycles... Could be done in a better way. |
| 19 | + mov r0, #8 |
| 20 | + wait_loop: |
| 21 | + subs r0, r0, #1 |
| 22 | + bne wait_loop |
| 23 | + bx lr |
| 24 | + |
| 25 | +_arm9_write_to_scfg_clk_end: |
| 26 | + |
| 27 | +bx_r1_caller: |
| 28 | + bx r1 |
| 29 | + |
| 30 | +@ Writes a new value to the ARM9 SCFG_CLK. |
| 31 | +@ Copies the right function to ITCM and calls it. |
| 32 | +@ void arm9_write_to_scfg_clk(uint16_t new_val); |
| 33 | +BEGIN_ASM_FUNC arm9_write_to_scfg_clk |
| 34 | + push {r4, lr} |
| 35 | + |
| 36 | + mrc p15, 0, r3, c1, c0, 0 @ Store current Control Register |
| 37 | + push {r3} |
| 38 | + ldr r2,=#0x00041000 @ Enable ITCM back |
| 39 | + orr r3, r3, r2 |
| 40 | + mvn r2, #1 @ Disabe MMU/PU |
| 41 | + and r3, r3, r2 |
| 42 | + mcr p15, 0, r3, c1, c0, 0 @ Update Control Register |
| 43 | + |
| 44 | + mov r3, #3 |
| 45 | + mcr p15, 0, r3, c5, c0, 3 @ Enable RW IAccess |
| 46 | + |
| 47 | + mov r1, #ITCM_foo_base @ ITCM foo_base |
| 48 | + ldr r2,=_arm9_write_to_scfg_clk |
| 49 | + ldr r3,=_arm9_write_to_scfg_clk_end-_arm9_write_to_scfg_clk |
| 50 | + itcm_copy_loop: |
| 51 | + ldr r4,[r2, #0] |
| 52 | + str r4,[r1, #0] |
| 53 | + add r1, #4 |
| 54 | + add r2, #4 |
| 55 | + subs r3, r3, #4 |
| 56 | + bne itcm_copy_loop |
| 57 | + mov r1, #ITCM_foo_base @ ITCM foo_base |
| 58 | + @ Call _arm9_write_to_scfg_clk |
| 59 | + bl bx_r1_caller |
| 60 | + |
| 61 | + @ Clear back the ITCM |
| 62 | + mov r0, #0 |
| 63 | + mov r1, #0x00000000 @ ITCM |
| 64 | + ldr r3,=#0x00008000 @ Wipe ITCM back |
| 65 | + itcm_clear_loop: |
| 66 | + str r0,[r1, #0] |
| 67 | + add r1, #4 |
| 68 | + subs r3, r3, #4 |
| 69 | + bne itcm_clear_loop |
| 70 | + |
| 71 | + mov r3, #0 |
| 72 | + mcr p15, 0, r3, c7, c5, 0 @ Flush ICache |
| 73 | + mcr p15, 0, r3, c5, c0, 3 @ Disable IAccess |
| 74 | + |
| 75 | + pop {r3} |
| 76 | + mcr p15, 0, r3, c1, c0, 0 @ Restore old Control Register |
| 77 | + |
| 78 | + pop {r4, pc} |
0 commit comments