├── src7 ├── inc.cpp ├── entry.s ├── inc.h ├── tests │ ├── tests.h │ ├── initialstate.cpp │ ├── ipcfifo_irq.cpp │ ├── ipcsync.cpp │ └── ipcfifo.cpp └── framework │ ├── main.s │ ├── waitloop.cpp │ └── rw.cpp ├── rockwrestler.nds ├── src9 ├── entry.s ├── framework │ ├── time.s │ ├── font.s │ ├── cp15.s │ ├── interwork.s │ ├── menu.s │ ├── rw.cpp │ ├── main.s │ ├── font.bin │ └── menu.cpp ├── tests │ ├── tests.h │ ├── ipcfifo_irq.cpp │ ├── ipcsync.cpp │ ├── sqrt.cpp │ ├── armv4.s │ ├── ipcfifo.cpp │ ├── initialstate.cpp │ ├── vramcnt.cpp │ ├── tcm.cpp │ ├── wramcnt.cpp │ ├── division.cpp │ └── armv5.s ├── inc.cpp └── inc.h ├── linker7.ld ├── linker9.ld ├── time.py ├── common ├── common.cpp ├── common.s └── common.h ├── README.md └── 7.txt /src7/inc.cpp: -------------------------------------------------------------------------------- 1 | // empty 2 | -------------------------------------------------------------------------------- /rockwrestler.nds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RockPolish/rockwrestler/HEAD/rockwrestler.nds -------------------------------------------------------------------------------- /src7/entry.s: -------------------------------------------------------------------------------- 1 | .text 2 | .global _start, main 3 | 4 | main: 5 | _start: 6 | b arm7_main 7 | -------------------------------------------------------------------------------- /src9/entry.s: -------------------------------------------------------------------------------- 1 | .text 2 | .global _start, main 3 | 4 | main: 5 | _start: 6 | b arm9_main 7 | -------------------------------------------------------------------------------- /src7/inc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../common/common.h" 3 | 4 | // non-IO registers 5 | volatile voidfncptr* const IRQHANDLER = (voidfncptr*)0x380FFFC; 6 | 7 | -------------------------------------------------------------------------------- /src7/tests/tests.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void arm7_ipcfifo_test(); 4 | void arm7_ipcsync_test(); 5 | void arm7_ipcfifo_irq_test(); 6 | void arm7_rwmode(); 7 | 8 | -------------------------------------------------------------------------------- /src9/framework/time.s: -------------------------------------------------------------------------------- 1 | @ this file is generated automatically by time.py 2 | .text 3 | .arm 4 | .align 2 5 | .global txt_buildtime 6 | txt_buildtime: .asciz "BUILT 02/04/2023 22:05:00" 7 | -------------------------------------------------------------------------------- /linker7.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") 2 | OUTPUT_ARCH(arm) 3 | ENTRY(main) 4 | 5 | MEMORY 6 | { 7 | rom : ORIGIN = 0x03800100, LENGTH = 0x10000 - 0x200 8 | } 9 | 10 | SECTIONS 11 | { 12 | .text : { *(.text*) *(.bss*) } > rom /* honestly not sure how this file works, but it works */ 13 | } 14 | -------------------------------------------------------------------------------- /linker9.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") 2 | OUTPUT_ARCH(arm) 3 | ENTRY(main) 4 | 5 | MEMORY 6 | { 7 | rom : ORIGIN = 0x02000100, LENGTH = 0x300000 /* 4 MB - 256 bytes - some stuff at the end.. this probably does not matter much? */ 8 | } 9 | 10 | SECTIONS 11 | { 12 | .text : { *(.text*) *(.bss*) } > rom /* honestly not sure how this file works, but it works */ 13 | } 14 | -------------------------------------------------------------------------------- /time.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | if __name__ == "__main__": 4 | s = "BUILT "+datetime.datetime.now().strftime("%d/%m/%Y %H:%M:%S") 5 | f = open("src9/framework/time.s", "w") 6 | f.write("@ this file is generated automatically by time.py\n") 7 | f.write(".text\n") 8 | f.write(".arm\n") 9 | f.write(".align 2\n") 10 | f.write(".global txt_buildtime\n") 11 | f.write("txt_buildtime: .asciz \"" + s + "\"\n") 12 | f.close() 13 | -------------------------------------------------------------------------------- /src9/framework/font.s: -------------------------------------------------------------------------------- 1 | .text 2 | .global font_start 3 | 4 | @ stored as 256-color 64 bytes/tile with first 8 bytes representing first horizontal line, next 8 bytes next line, ... 5 | @ are kinda in ascii format: first 16 tiles are copies of 0-9 and ABCDEF for easy hexadecimal printing 6 | @ next 16 tiles are some special symbols 7 | @ then normal ASCII characters. font could be compressed but is not for simplicity 8 | .align 2 9 | font_start: .incbin "src9/framework/font.bin" 10 | -------------------------------------------------------------------------------- /common/common.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | // enable/disable trace on my emulator - disable_trace is called by the ARM7 after a test, by the ARM9 when failing a test 4 | // it may be useful to enable the trace as a test starts and then look at the last few instructions before the test fails, 5 | // as the trace is automatically disabled when failing 6 | // these addresses are in the GBA cartridge range, writing to them does nothing 7 | 8 | extern "C" void enable_trace() 9 | { 10 | *((vu32*)0x8004400) = 0x8004400; 11 | } 12 | 13 | extern "C" void disable_trace() 14 | { 15 | *((vu32*)0x8005500) = 0x8005500; 16 | } 17 | -------------------------------------------------------------------------------- /common/common.s: -------------------------------------------------------------------------------- 1 | .arm 2 | .align 2 3 | .text 4 | .global wait_busy, l_EIC, l_DIC, call_fncptr 5 | 6 | wait_busy: 7 | subs r0, #1 8 | bne wait_busy 9 | bx r14 10 | 11 | l_EIC: 12 | @ clear "interrupt disable" flag in CPSR 13 | mrs r3, cpsr 14 | bic r3, #1 << 7 15 | msr cpsr_c, r3 16 | bx r14 17 | 18 | l_DIC: 19 | @ set "interrupt disable" flag in CPSR 20 | mrs r3, cpsr 21 | orr r3, #1 << 7 22 | msr cpsr_c, r3 23 | bx r14 24 | 25 | @ calling this function with a function pointer as opposed to calling it directly in C++ ensures that the compiler does not generate blx 26 | call_fncptr: 27 | bx r0 28 | -------------------------------------------------------------------------------- /src9/framework/cp15.s: -------------------------------------------------------------------------------- 1 | .text 2 | .arm 3 | .global cp15_get_controlreg, cp15_set_controlreg, cp15_get_DTCMcontrol, cp15_set_DTCMcontrol, cp15_get_ITCMcontrol, cp15_set_ITCMcontrol 4 | .align 2 5 | 6 | cp15_get_controlreg: 7 | mrc p15, #0, r0, c1, c0, #0 @ C1,C0,0 8 | bx r14 9 | 10 | cp15_set_controlreg: 11 | mcr p15, #0, r0, c1, c0, #0 @ C1,C0,0 12 | bx r14 13 | 14 | cp15_get_DTCMcontrol: 15 | mrc p15, #0, r0, c9, c1, #0 @ C9,C1,0 16 | bx r14 17 | 18 | cp15_set_DTCMcontrol: 19 | mcr p15, #0, r0, c9, c1, #0 @ C9,C1,0 20 | bx r14 21 | 22 | cp15_get_ITCMcontrol: 23 | mrc p15, #0, r0, c9, c1, #1 @ C9,C1,1 24 | bx r14 25 | 26 | cp15_set_ITCMcontrol: 27 | mcr p15, #0, r0, c9, c1, #1 @ C9,C1,1 28 | bx r14 29 | -------------------------------------------------------------------------------- /src9/framework/interwork.s: -------------------------------------------------------------------------------- 1 | .text 2 | .arm 3 | .align 2 4 | .global test_cpu_state, test_cpu_state_thumb 5 | 6 | @ call this function (from thumb or ARM, set r14 properly) and this function will return 7 | @ whether it was called in ARM or thumb state (r7 = 1 for ARM, r7 = 2 for thumb) 8 | @ note: load the address of test_cpu_state_thumb (ARM) in r6 before jumping here 9 | @ value of r4 may be changed 10 | @ useful for testing if things like blx, ldr r15, [...], pop {r15} ... are properly changing state in ARMv5 11 | 12 | test_cpu_state: 13 | .hword 0x4730 @ bx r6 in thumb: jump to test_cpu_state_thumb 14 | .hword 0xE3A0 @ these two halfwords: mov r4, #0xC00000 in ARM 15 | @ if we reach this part: we are in ARM mode 16 | @ set r7 to 1 and return 17 | mov r7, #1 18 | bx r14 19 | 20 | test_cpu_state_thumb: 21 | @ set r7 to 2 and return 22 | mov r7, #2 23 | bx r14 24 | 25 | 26 | @ 0100 01Op H1H2 Rs/Hs Rd/Hd - branch to Rs is possible (opcode 3) 27 | @ 0100 0111 0 0 110 000 branches to r6 28 | -------------------------------------------------------------------------------- /src9/tests/tests.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // ARMv4 4 | extern "C" void run_tests_armv4_conditioncodes(); 5 | 6 | // ARMv5 7 | extern "C" void run_tests_armv5_clz(); 8 | extern "C" void run_tests_armv5_qadd_qsub(); 9 | extern "C" void run_tests_armv5_qdadd_qdsub(); 10 | extern "C" void run_tests_armv5_SMLAxy(); 11 | extern "C" void run_tests_armv5_SMULxy(); 12 | extern "C" void run_tests_armv5_SMLAWy(); 13 | extern "C" void run_tests_armv5_SMULWy(); 14 | extern "C" void run_tests_armv5_SMLALxy(); 15 | extern "C" void run_tests_armv5_blx(); 16 | extern "C" void run_tests_armv5_ldrpopr15(); 17 | extern "C" void run_tests_armv5_ldm_stm(); 18 | 19 | // IPC 20 | void run_tests_ipcsync(); 21 | void run_tests_ipcfifo(); 22 | void run_tests_ipcfifo_irq(); 23 | 24 | // DS maths 25 | void run_tests_ds_maths_sqrt_32(); 26 | void run_tests_ds_maths_sqrt_64(); 27 | void run_tests_ds_maths_div_32_32(); 28 | void run_tests_ds_maths_div_64_32(); 29 | void run_tests_ds_maths_div_64_64(); 30 | 31 | // memory control 32 | void run_tests_vramcnt(); 33 | void run_tests_wramcnt(); 34 | void run_tests_tcm(); 35 | 36 | // initial state 37 | void run_tests_initialstate_ipc_irq_cpsr(); 38 | void run_tests_initialstate_cp15(); 39 | -------------------------------------------------------------------------------- /src7/tests/initialstate.cpp: -------------------------------------------------------------------------------- 1 | #include "../inc.h" 2 | 3 | extern u32 val_CPSR; 4 | 5 | extern "C" void test_initialstate() 6 | { 7 | l_DIC(); 8 | // get some values of registers at boot time, store these at start of main RAM (4 MB) where ARM9 can read them freely 9 | vu32* result_base = (vu32*)0x2000004; // skip first word 10 | result_base[0] = REG_IPCSYNC; 11 | result_base[1] = REG_IPCFIFOCNT; 12 | // enable FIFO + clear error bit 13 | REG_IPCFIFOCNT = (1 << 15) | (1 << 14); 14 | // count how many values are in the queue (this also clears the queue) 15 | int FIFO_length = 0; 16 | while (!(REG_IPCFIFOCNT & (1 << 8))) // as long as the FIFO is not empty 17 | { 18 | vu32 FIFO_val = REG_IPCFIFORECV; 19 | FIFO_length++; 20 | if (FIFO_length > 20) 21 | { 22 | // IPCFIFO maybe unimplemented, shouldn't keep looping here forever 23 | FIFO_length = 0xFFFF; 24 | break; 25 | } 26 | } 27 | result_base[2] = FIFO_length; 28 | result_base[3] = REG_IME; 29 | result_base[4] = REG_IE; 30 | result_base[5] = REG_IF; 31 | REG_IME = 0; 32 | REG_IE = 0; 33 | REG_IF = 0xFFFFFFFF; // acknowledge all 34 | 35 | result_base[6] = val_CPSR; 36 | } 37 | -------------------------------------------------------------------------------- /src7/framework/main.s: -------------------------------------------------------------------------------- 1 | .text 2 | .arm 3 | .align 2 4 | .global arm7_main 5 | 6 | .global val_CPSR 7 | val_CPSR: .word 0 8 | 9 | arm7_main: 10 | @ some initial values.. 11 | mrs r0, cpsr 12 | str r0, val_CPSR 13 | 14 | 15 | @ init stack pointers 16 | bl init_stackpointers 17 | 18 | @ call "initial state" test which stores some results in main RAM where ARM9 can also access it 19 | bl test_initialstate 20 | 21 | 22 | arm7_main_post_inittest: 23 | @ just reset stack 24 | bl init_stackpointers 25 | 26 | @ call C++ main loop function 27 | bl arm7_waitloop 28 | 29 | @ disable interrupts 30 | ldr r0, =0x4000208 31 | mov r1, #0 32 | str r1, [r0] 33 | 34 | bl disable_trace @ useful to automatically disable trace when a test fails (enable it before ofc) 35 | b arm7_main_post_inittest 36 | 37 | 38 | 39 | init_stackpointers: 40 | @ set irq and user mode stack pointer 41 | mrs r3, cpsr @ old CPSR 42 | mov r4, r3 43 | bic r3, r3, #0x1F 44 | orr r3, r3, #0x12 @ IRQ 45 | msr cpsr_c, r3 46 | ldr r13, =0x380FF00 @ ARM7-WRAM +64 KB, minus a little bit so we don't overwrite the magic word at the end of WRAM 47 | 48 | msr cpsr_c, r4 49 | ldr r13, =0x380F000 50 | bx r14 51 | -------------------------------------------------------------------------------- /src9/framework/menu.s: -------------------------------------------------------------------------------- 1 | .text 2 | .arm 3 | .align 2 4 | .global fail_test, timeout_test, timeout_rw 5 | 6 | @ after failing a test: wait until B is pressed and then released 7 | wait_b_released: 8 | ldr r0, =0x4000130 9 | ldrh r1, [r0] 10 | tst r1, #1 << 1 @ B 11 | bne wait_b_released 12 | wait_b_released2: 13 | ldrh r1, [r0] 14 | tst r1, #1 << 1 15 | beq wait_b_released2 16 | 17 | b main_post_init 18 | 19 | @ these are called as functions but do not return (the test failed anyway) 20 | @ -> show that the test failed, then reset back to the menu 21 | @ r0 contains the number of the test that failed (for fail_test, timeout_test) 22 | fail_test: 23 | push {r0} 24 | bl disable_trace 25 | ldr r0, =txt_fail 26 | mov r1, #5 27 | pop {r2} 28 | bl cpp_fail_test 29 | b wait_b_released 30 | 31 | timeout_test: 32 | push {r0} 33 | bl disable_trace 34 | ldr r0, =txt_timeout 35 | mov r1, #8 36 | pop {r2} 37 | bl cpp_fail_test 38 | b wait_b_released 39 | 40 | timeout_rw: 41 | bl disable_trace 42 | ldr r0, =txt_timeout_rw 43 | mov r1, #12 44 | mov r2, #-1 45 | bl cpp_fail_test 46 | b wait_b_released 47 | 48 | 49 | txt_fail: .asciz "FAIL " 50 | txt_timeout: .asciz "TIMEOUT " 51 | txt_timeout_rw: .asciz "TIMEOUT R/W " 52 | -------------------------------------------------------------------------------- /src7/tests/ipcfifo_irq.cpp: -------------------------------------------------------------------------------- 1 | // tests IPCFIFO interrupts 2 | #include "../inc.h" 3 | 4 | volatile int magic; 5 | 6 | static void irqhandler() 7 | { 8 | REG_IF = 1 << 17; // acknowledge interrupt 9 | magic = 89; 10 | } 11 | 12 | void arm7_ipcfifo_irq_test() 13 | { 14 | // first, wait a bit 15 | wait_busy(65536); 16 | 17 | // now send word with IPCFIFO: ARM7 has "receive not empty" IRQ enabled 18 | REG_IPCFIFOCNT = (1 << 2) | (1 << 3) | (1 << 15); // "send fifo empty IRQ" + flush FIFO + enable 19 | // -> we'll wake up when ARM9 reads our message 20 | *IRQHANDLER = &irqhandler; 21 | REG_IF = 1 << 17; 22 | REG_IE = 1 << 17; 23 | REG_IME = 1; 24 | l_EIC(); 25 | 26 | // initialize magic value before sending the value to avoid race conditions 27 | magic = 41; 28 | 29 | // send 0x8100 30 | REG_IPCFIFOSEND = 0x8100; 31 | 32 | // wait possibly a long time.. don't want to test tight synchronization 33 | int timeout = 65536 * 16; 34 | while (magic != 89) 35 | { 36 | if (--timeout == 0) 37 | { 38 | return; 39 | } 40 | } 41 | 42 | // need to tell ARM9 that our interrupt arrived 43 | REG_IPCFIFOCNT = (1 << 3) | (1 << 15); 44 | wait_busy(8192); 45 | 46 | REG_IPCFIFOSEND = 0xA50; 47 | REG_IME = 0; 48 | } 49 | -------------------------------------------------------------------------------- /src7/tests/ipcsync.cpp: -------------------------------------------------------------------------------- 1 | // tests IPCSYNC + interrupts 2 | #include "../inc.h" 3 | 4 | static volatile int magic; 5 | 6 | static void irqhandler() 7 | { 8 | // set magic to 123 if we received a 0 9 | REG_IF = 1 << 16; // acknowledge interrupt 10 | if ((REG_IPCSYNC & 0xF) != 9) return; 11 | 12 | magic = 0x69; 13 | REG_IPCSYNC = 11 << 8; // send 11 14 | // wait a bit 15 | wait_busy(8192); 16 | 17 | // send 0 with IRQ 18 | REG_IPCSYNC = 1 << 13; 19 | } 20 | 21 | bool wait_ipcsync_value(int value) 22 | { 23 | int timeout = 4096; 24 | while ((REG_IPCSYNC & 0xF) != value) 25 | { 26 | if (--timeout == 0) 27 | { 28 | return false; 29 | } 30 | } 31 | return true; 32 | } 33 | 34 | void arm7_ipcsync_test() 35 | { 36 | // send 4 37 | REG_IPCSYNC = 4 << 8; 38 | 39 | // wait for 5 40 | if (!wait_ipcsync_value(5)) return; 41 | 42 | magic = 11; 43 | // send 7, enable IRQ 44 | *IRQHANDLER = &irqhandler; 45 | REG_IF = 1 << 16; 46 | REG_IE = 1 << 16; 47 | REG_IME = 1; 48 | l_EIC(); 49 | REG_IPCSYNC = (7 << 8) | (1 << 14); 50 | 51 | int timeout = 65536; 52 | while (magic != 0x69) 53 | { 54 | if (--timeout == 0) 55 | { 56 | return; 57 | } 58 | } 59 | 60 | REG_IME = 0; 61 | } 62 | -------------------------------------------------------------------------------- /src7/tests/ipcfifo.cpp: -------------------------------------------------------------------------------- 1 | // tests IPCFIFO 2 | #include "../inc.h" 3 | 4 | void arm7_ipcfifo_test() 5 | { 6 | // send 0x12345678 7 | REG_IPCFIFOSEND = 0x12345678; 8 | 9 | wait_busy(4096); 10 | 11 | // we want to have received 3 words 12 | // if any check here doesn't pass: reset ARM7. ARM9 will be waiting for a response, if it doesn't get it, it's a fail 13 | if (!(REG_IPCFIFOCNT & 1)) return; // send empty = 1 14 | if (REG_IPCFIFOCNT & (1 << 1)) return; // send full = 0 15 | if (REG_IPCFIFOCNT & (1 << 8)) return; // receive empty = 0 16 | if (REG_IPCFIFOCNT & (1 << 9)) return; // receive full = 0 17 | if (REG_IPCFIFOCNT & (1 << 14)) return; // error = 0 18 | 19 | u32 w1 = REG_IPCFIFORECV; 20 | u32 w2 = REG_IPCFIFORECV; 21 | u32 w3 = REG_IPCFIFORECV; 22 | 23 | if (!(REG_IPCFIFOCNT & 1)) return; // send empty = 1 24 | if (REG_IPCFIFOCNT & (1 << 1)) return; // send full = 0 25 | if (!(REG_IPCFIFOCNT & (1 << 8))) return; // receive empty = 1 26 | if (REG_IPCFIFOCNT & (1 << 9)) return; // receive full = 0 27 | if (REG_IPCFIFOCNT & (1 << 14)) return; // error = 0 28 | 29 | // + check to see if the words are correct 30 | if (w1 != 0x1844CCAB) return; 31 | if (w2 != 0xB914A201) return; 32 | if (w3 != 0x1844CCAC) return; 33 | 34 | // send 16 values so that the queue is full 35 | for(int i = 0; i < 16; i++) 36 | { 37 | REG_IPCFIFOSEND = 0x11000000 + i; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src7/framework/waitloop.cpp: -------------------------------------------------------------------------------- 1 | #include "../inc.h" 2 | #include "../tests/tests.h" 3 | 4 | // return from this function after a test: resets ARM7, just goes back into this loop but with stack, ... reset 5 | extern "C" void arm7_waitloop() 6 | { 7 | wait_busy(1 << 18); // wait a little bit so that ARM9 has definitely set IPCSYNC to 0 8 | REG_IPCSYNC = 0; 9 | REG_IPCFIFOCNT = 1 << 15; // enable FIFO 10 | 11 | // keep polling IPCSYNC to see if ARM9 wants us to start a test 12 | while (true) 13 | { 14 | int ipcsync_val = REG_IPCSYNC & 0xF; 15 | switch (ipcsync_val) 16 | { 17 | // heartbeat 18 | case 1: 19 | { 20 | REG_IPCSYNC = 1 << 8; 21 | break; 22 | } 23 | case 2: 24 | { 25 | REG_IPCSYNC = 2 << 8; 26 | break; 27 | } 28 | 29 | // rw mode 30 | case 10: 31 | { 32 | arm7_rwmode(); 33 | return; 34 | } 35 | 36 | // IPC tests 37 | case 11: 38 | { 39 | arm7_ipcfifo_irq_test(); 40 | return; 41 | } 42 | 43 | case 12: 44 | { 45 | arm7_ipcfifo_test(); 46 | return; 47 | } 48 | 49 | case 13: 50 | { 51 | arm7_ipcsync_test(); 52 | return; 53 | } 54 | default: break; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src9/tests/ipcfifo_irq.cpp: -------------------------------------------------------------------------------- 1 | // tests IPCFIFO interrupts 2 | #include "../inc.h" 3 | 4 | static volatile int magic; 5 | 6 | static void irqhandler() 7 | { 8 | // set magic to 13 if we received 0x8100 9 | REG_IF = 1 << 18; // acknowledge interrupt 10 | if (REG_IPCFIFORECV == 0x8100) 11 | { 12 | magic = 13; 13 | } 14 | } 15 | 16 | 17 | void run_tests_ipcfifo_irq() 18 | { 19 | // enable receive not empty IRQ in IE (IE.18) + acknowledge it first (IF) 20 | REG_IF = 1 << 18; 21 | REG_IE = 1 << 18; 22 | 23 | // enable "receive not empty" in IPCFIFOCNT 24 | REG_IPCFIFOCNT = (1 << 10) | (1 << 15); // receive fifo not empty IRQ + enable fifo 25 | 26 | // set IRQ handler 27 | *IRQHANDLER = &irqhandler; 28 | 29 | // enable interrupts (IME and CPSR) 30 | REG_IME = 1; 31 | l_EIC(); 32 | 33 | // send 11 with IPCSYNC: this starts the test on ARM7 side, it will send to FIFO -> interrupt on our side 34 | magic = 88; 35 | REG_IPCSYNC = 11 << 8; 36 | 37 | int timeout = 65536*4; 38 | while (magic != 13) // IRQ handler changes magic to 13 if it read 0x8100 from FIFO 39 | { 40 | if (--timeout == 0) 41 | { 42 | timeout_test(0x000); 43 | } 44 | } 45 | 46 | REG_IPCSYNC = 0; // reset IPCSYNC 47 | 48 | REG_IME = 0; // disable interrupts 49 | // we read a word from the queue in our interrupt handler: ARM7 gets interrupt, will send 0xA50 50 | u32 read_from_fifo = read_from_IPCFIFO(0x001); 51 | 52 | if (read_from_fifo != 0xA50) fail_test(0x002); 53 | } 54 | -------------------------------------------------------------------------------- /src9/tests/ipcsync.cpp: -------------------------------------------------------------------------------- 1 | // tests IPCSYNC + interrupts 2 | #include "../inc.h" 3 | 4 | static volatile int magic; 5 | 6 | static void irqhandler() 7 | { 8 | // set magic to 123 if we received a 0 9 | REG_IF = 1 << 16; // acknowledge interrupt 10 | if ((REG_IPCSYNC & 0xF) == 0) 11 | { 12 | magic = 123; 13 | } 14 | } 15 | 16 | void wait_ipcsync_value(int value, int test_number) 17 | { 18 | int timeout = 16384; 19 | while ((REG_IPCSYNC & 0xF) != value) 20 | { 21 | if (--timeout == 0) 22 | { 23 | timeout_test(test_number); 24 | } 25 | } 26 | } 27 | 28 | void run_tests_ipcsync() 29 | { 30 | // send 13 31 | REG_IPCSYNC = 13 << 8; 32 | 33 | // wait to receive 4 34 | wait_ipcsync_value(4, 0x000); 35 | 36 | // send 5 37 | REG_IPCSYNC = 5 << 8; 38 | 39 | // receive 7 40 | wait_ipcsync_value(7, 0x001); 41 | 42 | // now with interrupts 43 | // "wait a bit" 44 | wait_busy(4096); 45 | 46 | // send 9 with interrupt 47 | REG_IPCSYNC = (9 << 8) | (1 << 13); 48 | 49 | // receive 11 50 | wait_ipcsync_value(11, 0x002); 51 | 52 | // now wait for ARM7 to send us interrupt 53 | magic = 77; 54 | REG_IPCSYNC = 1 << 14; // enable IRQ from remote CPU 55 | l_EIC(); 56 | *IRQHANDLER = &irqhandler; 57 | REG_IF = 1 << 16; // clear bit in case it was still on 58 | REG_IE = 1 << 16; // enable IPCSYNC IRQ 59 | REG_IME = 1; 60 | 61 | int timeout = 65536; 62 | while (magic != 123) 63 | { 64 | if (--timeout == 0) 65 | { 66 | timeout_test(0x003); 67 | } 68 | } 69 | 70 | REG_IME = 0; 71 | REG_IPCSYNC = 0; 72 | } 73 | -------------------------------------------------------------------------------- /src9/tests/sqrt.cpp: -------------------------------------------------------------------------------- 1 | // tests NDS square root IO registers 2 | #include "../inc.h" 3 | 4 | struct SQRTtest 5 | { 6 | u32 lo, hi, res; 7 | }; 8 | 9 | const SQRTtest sqrt32_tests[] = { 10 | {0, 0, 0}, 11 | {1, 0, 1}, 12 | {3, 0, 1}, 13 | {4, 0, 2}, 14 | {5, 0, 2}, 15 | {143, 18, 11}, 16 | {144, -1, 12}, 17 | {145, 444, 12}, 18 | {1<<30, -33, 1<<15}, 19 | {4294836224, 555, 65534}, 20 | {4294836225, 555, 65535}, 21 | {4294836226, 555, 65535}, 22 | {4294967295, 555, 65535} 23 | }; 24 | 25 | const SQRTtest sqrt64_tests[] = { 26 | {0, 0, 0}, 27 | {1, 0, 1}, 28 | {3, 0, 1}, 29 | {4, 0, 2}, 30 | {5, 0, 2}, 31 | {143, 0, 11}, 32 | {144, 0, 12}, 33 | {145, 0, 12}, 34 | {1<<30, 0, 1<<15}, 35 | {4294836224, 0, 65534}, 36 | {4294836225, 0, 65535}, 37 | {4294836226, 0, 65535}, 38 | {4294967295, 0, 65535}, 39 | {0, 1, 65536}, 40 | {1, 1, 65536}, 41 | {0, 2, 92681}, 42 | {1111, 2, 92681}, 43 | {999999, 2, 92687}, 44 | {0, 1<<28, 1<<30}, 45 | {1, 1<<28, 1<<30}, 46 | {-1, (1<<28)-1, (1<<30)-1}, 47 | {-1, -1, -1} 48 | }; 49 | 50 | 51 | 52 | 53 | void check_sqrt(const SQRTtest array[], int test_count) 54 | { 55 | for(int i = 0; i < test_count; i++) 56 | { 57 | REG_SQRTLO = array[i].lo; 58 | REG_SQRTHI = array[i].hi; 59 | 60 | wait_bit_value(i, SQRTCNT, 15, false); // wait for bit 15 = busy bit to be turned off 61 | 62 | u32 res = REG_SQRTRES; 63 | if (res != array[i].res) fail_test(i); 64 | } 65 | } 66 | 67 | void run_tests_ds_maths_sqrt_32() 68 | { 69 | REG_SQRTCNT = 0; // 32-bit mode 70 | check_sqrt(sqrt32_tests, 13); 71 | } 72 | 73 | void run_tests_ds_maths_sqrt_64() 74 | { 75 | REG_SQRTCNT = 1; // 64-bit mode 76 | check_sqrt(sqrt64_tests, 22); 77 | } 78 | -------------------------------------------------------------------------------- /src9/framework/rw.cpp: -------------------------------------------------------------------------------- 1 | // ARM7 rw mode: can then do ARM7_read_word(address) to receive the value at that address on the ARM7 side 2 | #include "../inc.h" 3 | 4 | // this function pretty much does everything: reading, writing, ... 5 | // do not call it directly, use the other 8 functions defined in this file 6 | u32 ARM7_rw_core(u32 address, int type, u32 value) 7 | { 8 | REG_IPCFIFOSEND = address | (type << 28); // transmit address + type in one go 9 | if ((type >= 4) && (type <= 6)) REG_IPCFIFOSEND = value; // also send value 10 | // wait for receive empty bit to be turned off 11 | int timeout = 8192; 12 | while (REG_IPCFIFOCNT & (1 << 8)) 13 | { 14 | if (--timeout == 0) 15 | { 16 | timeout_rw(); 17 | } 18 | } 19 | // return value we received (even when we write something: a value is returned to signal that the ARM7 has finished the write) 20 | return REG_IPCFIFORECV; 21 | } 22 | 23 | void ARM7_start_rw() 24 | { 25 | // clear IPCFIFO queue 26 | REG_IPCFIFOCNT = (1 << 3) | (1 << 15); // send fifo clear + enable send/receive fifo 27 | // send 10 with IPCSYNC to tell ARM7 to await our read/write commands 28 | REG_IPCSYNC = 10 << 8; 29 | 30 | // wait a bit 31 | wait_busy(4096); 32 | 33 | // send 0 with IPCSYNC so ARM7 doesn't immediately go back to read/write mode after we end the test 34 | REG_IPCSYNC = 0; 35 | } 36 | 37 | u32 ARM7_read_word(u32 address) 38 | { 39 | return ARM7_rw_core(address, 1, 0); 40 | } 41 | 42 | u16 ARM7_read_halfword(u32 address) 43 | { 44 | return ARM7_rw_core(address, 2, 0); 45 | } 46 | 47 | u8 ARM7_read_byte(u32 address) 48 | { 49 | return ARM7_rw_core(address, 3, 0); 50 | } 51 | 52 | void ARM7_write_word(u32 address, u32 value) 53 | { 54 | ARM7_rw_core(address, 4, value); 55 | } 56 | 57 | void ARM7_write_halfword(u32 address, u16 value) 58 | { 59 | ARM7_rw_core(address, 5, value); 60 | } 61 | 62 | void ARM7_write_byte(u32 address, u8 value) 63 | { 64 | ARM7_rw_core(address, 6, value); 65 | } 66 | 67 | void ARM7_end_rw() 68 | { 69 | ARM7_rw_core(0, 0, 0); 70 | } 71 | -------------------------------------------------------------------------------- /src9/tests/armv4.s: -------------------------------------------------------------------------------- 1 | .text 2 | .arm 3 | .align 2 4 | .global run_tests_armv4_conditioncodes 5 | 6 | @ load all 16 combinations of sign/zero/carry/overflow flags and test the 15 different condition codes 7 | @ fail test 0x0XY : condition code Y of flag combination X gave the wrong result (and is the first wrong result, only first is shown) 8 | 9 | cc_gt: @ S Z C V al le gt lt ge ls hi vc vs pl mi cc cs ne eq 10 | .hword 0x56AA @ 0 0 0 0 1 0 1 0 1 1 0 1 0 1 0 1 0 1 0 11 | .hword 0x6A6A @ 0 0 0 1 1 1 0 1 0 1 0 0 1 1 0 1 0 1 0 12 | .hword 0x55A6 @ 0 0 1 0 ... 13 | .hword 0x6966 14 | .hword 0x66A9 15 | .hword 0x6A69 16 | .hword 0x66A5 17 | .hword 0x6A65 18 | .hword 0x6A9A 19 | .hword 0x565A 20 | .hword 0x6996 21 | .hword 0x5556 22 | .hword 0x6A99 23 | .hword 0x6659 24 | .hword 0x6A95 25 | .hword 0x6655 26 | 27 | 28 | .align 2 29 | 30 | run_tests_armv4_conditioncodes: 31 | adr r0, cc_gt 32 | 33 | @ combination (sign/zero/carry/overflow and then 28 zero bits) 34 | mov r1, #0 35 | 36 | cc_loop: 37 | mov r2, #0 38 | msr cpsr_f, r1 39 | 40 | orreq r2, #0x1 41 | orrne r2, #0x2 42 | orrcs r2, #0x4 43 | orrcc r2, #0x8 44 | orrmi r2, #0x10 45 | orrpl r2, #0x20 46 | orrvs r2, #0x40 47 | orrvc r2, #0x80 48 | orrhi r2, #0x100 49 | orrls r2, #0x200 50 | orrge r2, #0x400 51 | orrlt r2, #0x800 52 | orrgt r2, #0x1000 53 | orrle r2, #0x2000 54 | orral r2, #0x4000 55 | 56 | ldrh r3, [r0], #2 @ load the expected value 57 | cmp r2, r3 58 | bne cc_find_error 59 | adds r1, #1 << 28 60 | bcc cc_loop 61 | bx r14 62 | 63 | 64 | cc_find_error: 65 | lsr r0, r1, #24 @ shift the 4 bits to be bit 4-7 of the test number 66 | @ r2 contains our value, r3 the ground truth: find the lowest bit in which r2 and r3 67 | @ are different, not gonna use clz to find the highest bit as it might not yet be implemented 68 | eor r2, r3 69 | mov r1, #0 70 | @ this loop won't be infinite because r2 ^ r3 != 0 71 | cc_errloop: 72 | lsrs r2, #1 73 | addcc r1, #1 74 | bcc cc_errloop 75 | 76 | @ r1 contains the bit number so which condition failed, add it to r0 and print it 77 | add r0, r1 78 | b fail_test 79 | -------------------------------------------------------------------------------- /src7/framework/rw.cpp: -------------------------------------------------------------------------------- 1 | // lets the ARM7 wait for requests by the ARM9 to read from an address + return the value, or write a value to an address 2 | #include "../inc.h" 3 | 4 | void arm7_rwmode() 5 | { 6 | // enable FIFO 7 | REG_IPCFIFOCNT = 1 << 15; 8 | 9 | while (true) 10 | { 11 | if (REG_IPCFIFOCNT & (1 << 8)) continue; // only continue if queue not empty 12 | // read word: upper nibble says what to do, other 28 bits say which address 13 | u32 fifo_val = REG_IPCFIFORECV; 14 | int type = fifo_val >> 28; 15 | void* ptr = (void*)(fifo_val & 0x0FFFFFFF); 16 | if ((type >= 4) && (type <= 6)) 17 | { 18 | // additionally wait for the value to be sent that we need to write 19 | // -> wait until receive empty bit is off 20 | while (REG_IPCFIFOCNT & (1 << 8)) { } 21 | } 22 | switch (type) 23 | { 24 | case 0: 25 | { 26 | // end rw mode: write a value as ARM9 is waiting for response 27 | REG_IPCFIFOSEND = 0; 28 | return; 29 | } 30 | case 1: 31 | { 32 | // read word 33 | REG_IPCFIFOSEND = *((vu32*)ptr); 34 | break; 35 | } 36 | case 2: 37 | { 38 | // read halfword 39 | REG_IPCFIFOSEND = *((vu16*)ptr); 40 | break; 41 | } 42 | case 3: 43 | { 44 | // read byte 45 | REG_IPCFIFOSEND = *((vu8*)ptr); 46 | break; 47 | } 48 | case 4: 49 | { 50 | // write word 51 | *((vu32*)ptr) = REG_IPCFIFORECV; 52 | REG_IPCFIFOSEND = 0; 53 | break; 54 | } 55 | case 5: 56 | { 57 | // write halfword 58 | *((vu16*)ptr) = REG_IPCFIFORECV; 59 | REG_IPCFIFOSEND = 0; 60 | break; 61 | } 62 | case 6: 63 | { 64 | // write byte 65 | *((vu8*)ptr) = REG_IPCFIFORECV; 66 | REG_IPCFIFOSEND = 0; 67 | break; 68 | } 69 | default: 70 | { 71 | // also end mode 72 | REG_IPCFIFOSEND = 0; 73 | return; 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src9/inc.cpp: -------------------------------------------------------------------------------- 1 | #include "inc.h" 2 | 3 | u32 read_from_IPCFIFO(int test_number) 4 | { 5 | // wait until bit 8 (receive empty) is off 6 | wait_bit_value(test_number, IPCFIFOCNT, 8, false); 7 | // then read one value 8 | return REG_IPCFIFORECV; 9 | } 10 | 11 | extern "C" void init_iostate() 12 | { 13 | // set CP15 control register: disables PU, enables ITCM/DTCM 14 | // also disables data (bit 2) + instruction (bit 12) cache 15 | cp15_set_controlreg(0x00052078); 16 | 17 | REG_POWCNT1 = 0x8003; // enable both LCDs, 2D engine A, + display swap 18 | REG_VRAMCNT_A = 0x80; // bank A in LCDC mode 19 | REG_DISPCNT = 0x20000; // VRAM display, block A 20 | 21 | // set DTCM location, + ITCM 22 | cp15_set_DTCMcontrol(0x0080000A); 23 | cp15_set_ITCMcontrol(0x0000000C); 24 | 25 | // disable IME 26 | REG_IME = 0; 27 | } 28 | 29 | void wait_vblank() 30 | { 31 | // wait for V-blank flag to be unset, then wait for it to be set 32 | while ((REG_DISPSTAT & 1) == 1) { } 33 | while ((REG_DISPSTAT & 1) == 0) { } 34 | } 35 | 36 | // leftover from calling this label in assembly 37 | extern "C" void l_resetIPCSYNC() 38 | { 39 | REG_IPCSYNC = 0; 40 | } 41 | 42 | // fill screen with light gray color 43 | void clear_screen() 44 | { 45 | for(int i = 0; i < 256*192/2; i++) 46 | { 47 | ((u32*)0x6800000)[i] = 0x56B556B5; 48 | } 49 | } 50 | 51 | // clear one 8x8 tile with a color 52 | // 0 <= x < 32, 0 <= y < 24 53 | void draw_cleartile(int x, int y, u16 col) 54 | { 55 | for(int j = 0; j < 8; j++) 56 | { 57 | for(int i = 0; i < 8; i++) 58 | { 59 | ((u16*)0x6800000)[(i + 8*x) + 256*(j + 8*y)] = col; 60 | } 61 | } 62 | } 63 | 64 | const u16 palette[] = { 65 | 0x0000, // (0, 0, 0) 66 | 0x294A, // (10, 10, 10) 67 | 0x56B5, // (21, 21, 21) 68 | 0x7FFF // (31, 31, 31) 69 | }; 70 | extern u8 font_start[]; // all tiles 71 | 72 | // draw one tile 73 | // 0 <= x < 32, 0 <= y < 24 74 | void draw_tile(int x, int y, int tile) 75 | { 76 | u8* tile_start = &font_start[64*tile]; 77 | 78 | for(int j = 0; j < 8; j++) 79 | { 80 | for(int i = 0; i < 8; i++) 81 | { 82 | u8 palette_index = tile_start[i + 8*j]; 83 | ((u16*)0x6800000)[(i + 8*x) + 256*(j + 8*y)] = palette[palette_index]; 84 | } 85 | } 86 | } 87 | 88 | // draw a string (\n .. not supported) 89 | // 0 <= x < 32, 0 <= y < 24 90 | void draw_string(int x, int y, const char* str) 91 | { 92 | while (*str) 93 | { 94 | char c = *(str++); 95 | draw_tile(x++, y, c); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /common/common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | // types 5 | typedef uint8_t u8; 6 | typedef uint16_t u16; 7 | typedef uint32_t u32; 8 | typedef uint64_t u64; 9 | typedef int8_t s8; 10 | typedef int16_t s16; 11 | typedef int32_t s32; 12 | typedef int64_t s64; 13 | 14 | typedef volatile u8 vu8; 15 | typedef volatile u16 vu16; 16 | typedef volatile u32 vu32; 17 | typedef volatile u64 vu64; 18 | typedef volatile s8 vs8; 19 | typedef volatile s16 vs16; 20 | typedef volatile s32 vs32; 21 | typedef volatile s64 vs64; 22 | 23 | typedef void (*voidfncptr)(); 24 | 25 | // asm functions 26 | extern "C" void wait_busy(int steps); 27 | extern "C" void l_EIC(); 28 | extern "C" void l_DIC(); 29 | extern "C" void call_fncptr(voidfncptr); 30 | 31 | // C++ functions called by asm 32 | extern "C" void enable_trace(); 33 | extern "C" void disable_trace(); 34 | 35 | //// IO registers 36 | // IPC 37 | vu16* const IPCSYNC = (vu16*)0x4000180; 38 | vu16* const IPCFIFOCNT = (vu16*)0x4000184; 39 | vu32* const IPCFIFOSEND = (vu32*)0x4000188; 40 | vu32* const IPCFIFORECV = (vu32*)0x4100000; 41 | 42 | #define REG_IPCSYNC (*IPCSYNC) 43 | #define REG_IPCFIFOCNT (*IPCFIFOCNT) 44 | #define REG_IPCFIFOSEND (*IPCFIFOSEND) 45 | #define REG_IPCFIFORECV (*IPCFIFORECV) 46 | 47 | // interrupts 48 | vu32* const IME = (vu32*)0x4000208; 49 | vu32* const IE = (vu32*)0x4000210; 50 | vu32* const IF = (vu32*)0x4000214; 51 | 52 | #define REG_IME (*IME) 53 | #define REG_IE (*IE) 54 | #define REG_IF (*IF) 55 | 56 | 57 | 58 | // memory region markers 59 | const u32 DTCM_START = 0x12345678; 60 | const u32 DTCM_END = 0x87654321; 61 | 62 | const u32 ITCM_START = 0x5A5B5C5D; 63 | const u32 ITCM_END = 0x6A6B6C6D; 64 | 65 | // shared WRAM (32 KB): two banks of 16 66 | const u32 SHWRAM_START1 = 0x1A2B3C4D; 67 | const u32 SHWRAM_END1 = 0x1F2F3F4F; 68 | const u32 SHWRAM_START2 = 0x2F3F4F5F; 69 | const u32 SHWRAM_END2 = 0x89ABCDEF; 70 | 71 | const u32 VRAM_A_START = 0xA1A2A3A4; 72 | const u32 VRAM_A_END = 0xA5A6A7A8; 73 | const u32 VRAM_B_START = 0xB1B2B3B4; 74 | const u32 VRAM_B_END = 0xB5B6B7B8; 75 | const u32 VRAM_C_START = 0xC1C2C3C4; 76 | const u32 VRAM_C_END = 0xC5C6C7C8; 77 | const u32 VRAM_D_START = 0xD1D2D3D4; 78 | const u32 VRAM_D_END = 0xD5D6D7D8; 79 | const u32 VRAM_E_START = 0xE1E2E3E4; 80 | const u32 VRAM_E_END = 0xE5E6E7E8; 81 | const u32 VRAM_F_START = 0xF1F2F3F4; 82 | const u32 VRAM_F_END = 0xF5F6F7F8; 83 | const u32 VRAM_G_START = 0xA0A2A3A4; 84 | const u32 VRAM_G_END = 0xA0A6A7A8; 85 | const u32 VRAM_H_START = 0xB0A2A3A4; 86 | const u32 VRAM_H_END = 0xB0A6A7A8; 87 | const u32 VRAM_I_START = 0xC0A2A3A4; 88 | const u32 VRAM_I_END = 0xC0A6A7A8; 89 | 90 | const u32 ARM7RAM_START = 0xC0DE5890; 91 | const u32 ARM7RAM_END = 0xDEADBEEF; 92 | -------------------------------------------------------------------------------- /src9/tests/ipcfifo.cpp: -------------------------------------------------------------------------------- 1 | // tests IPCFIFO (not entirely complete) 2 | #include "../inc.h" 3 | 4 | void run_tests_ipcfifo() 5 | { 6 | REG_IPCFIFOCNT = 1 << 15; // enable FIFO 7 | REG_IPCSYNC = 12 << 8; // tell ARM7 to start IPCFIFO test 8 | 9 | // ARM7 starts by sending 0x12345678 10 | if (read_from_IPCFIFO(0x000) != 0x12345678) fail_test(0x001); 11 | 12 | // write 0 to IPCSYNC 13 | REG_IPCSYNC = 0; 14 | 15 | if (!(REG_IPCFIFOCNT & 1)) fail_test(0x002); // send empty = 1 16 | if (REG_IPCFIFOCNT & (1 << 1)) fail_test(0x003); // send full = 0 17 | if (!(REG_IPCFIFOCNT & (1 << 8))) fail_test(0x004); // receive empty = 1 18 | if (REG_IPCFIFOCNT & (1 << 9)) fail_test(0x005); // receive full = 0 19 | if (REG_IPCFIFOCNT & (1 << 14)) fail_test(0x006); // error = 0 20 | 21 | // send three words 22 | REG_IPCFIFOSEND = 0x1844CCAB; 23 | REG_IPCFIFOSEND = 0xB914A201; 24 | REG_IPCFIFOSEND = 0x1844CCAC; 25 | 26 | // wait until "receive full" bit is on 27 | wait_bit_value(0x007, IPCFIFOCNT, 9, true); 28 | 29 | if (!(REG_IPCFIFOCNT & 1)) fail_test(0x008); // send empty = 1 30 | if (REG_IPCFIFOCNT & (1 << 1)) fail_test(0x009); // send full = 0 31 | if (REG_IPCFIFOCNT & (1 << 8)) fail_test(0x00A); // receive empty = 0 32 | if (REG_IPCFIFOCNT & (1 << 14)) fail_test(0x00B); // error = 0 33 | 34 | // read 16 words, make sure they match 35 | for(int i = 0; i < 16; i++) 36 | { 37 | u32 word = REG_IPCFIFORECV; 38 | if (word != (0x11000000 + i)) fail_test(0x010 + i); 39 | } 40 | 41 | if (!(REG_IPCFIFOCNT & 1)) fail_test(0x020); // send empty = 1 42 | if (REG_IPCFIFOCNT & (1 << 1)) fail_test(0x021); // send full = 0 43 | if (!(REG_IPCFIFOCNT & (1 << 8))) fail_test(0x022); // receive empty = 1 44 | if (REG_IPCFIFOCNT & (1 << 9)) fail_test(0x023); // receive full = 0 45 | if (REG_IPCFIFOCNT & (1 << 14)) fail_test(0x024); // error = 0 46 | 47 | // read from empty queue: should read value that was last read, and set error bit 48 | u32 word = REG_IPCFIFORECV; 49 | if (word != 0x1100000F) fail_test(0x025); // seems to fail on desmume/melonDS, passes on no$gba 50 | 51 | if (!(REG_IPCFIFOCNT & 1)) fail_test(0x026); // send empty = 1 52 | if (REG_IPCFIFOCNT & (1 << 1)) fail_test(0x027); // send full = 0 53 | if (!(REG_IPCFIFOCNT & (1 << 8))) fail_test(0x028); // receive empty = 1 54 | if (REG_IPCFIFOCNT & (1 << 9)) fail_test(0x029); // receive full = 0 55 | if (!(REG_IPCFIFOCNT & (1 << 14))) fail_test(0x02A); // error = 1 56 | 57 | // write 0 to error bit, should NOT turn it off 58 | REG_IPCFIFOCNT = REG_IPCFIFOCNT & ~(1 << 14); 59 | 60 | if (!(REG_IPCFIFOCNT & (1 << 14))) fail_test(0x02B); // error = 1 61 | 62 | // acknowledge it by writing a 1 63 | REG_IPCFIFOCNT = REG_IPCFIFOCNT; // don't optimize this out 64 | 65 | if (REG_IPCFIFOCNT & (1 << 14)) fail_test(0x02C); // error = 0 66 | 67 | REG_IPCSYNC = 0; 68 | } 69 | -------------------------------------------------------------------------------- /src9/framework/main.s: -------------------------------------------------------------------------------- 1 | .text 2 | .arm 3 | .align 2 4 | .global arm9_main, main_post_init, val_CPSR 5 | 6 | val_CPSR: .word 0 7 | 8 | .global val_cp15 @ just use the start as an array 9 | val_cp15: 10 | val_cp15_100: .word 0 11 | val_cp15_200: .word 0 12 | val_cp15_201: .word 0 13 | val_cp15_300: .word 0 14 | val_cp15_500: .word 0 15 | val_cp15_501: .word 0 16 | val_cp15_502: .word 0 17 | val_cp15_503: .word 0 18 | 19 | val_cp15_600: .word 0 20 | val_cp15_610: .word 0 21 | val_cp15_620: .word 0 22 | val_cp15_630: .word 0 23 | val_cp15_640: .word 0 24 | val_cp15_650: .word 0 25 | val_cp15_660: .word 0 26 | val_cp15_670: .word 0 27 | 28 | val_cp15_910: .word 0 29 | val_cp15_911: .word 0 30 | 31 | @ entry point 32 | arm9_main: 33 | mrs r0, cpsr 34 | str r0, val_CPSR 35 | 36 | mrc p15, #0, r0, c1, c0, #0 37 | str r0, val_cp15_100 38 | mrc p15, #0, r0, c2, c0, #0 39 | str r0, val_cp15_200 40 | mrc p15, #0, r0, c2, c0, #1 41 | str r0, val_cp15_201 42 | mrc p15, #0, r0, c3, c0, #0 43 | str r0, val_cp15_300 44 | mrc p15, #0, r0, c5, c0, #0 45 | str r0, val_cp15_500 46 | mrc p15, #0, r0, c5, c0, #1 47 | str r0, val_cp15_501 48 | mrc p15, #0, r0, c5, c0, #2 49 | str r0, val_cp15_502 50 | mrc p15, #0, r0, c5, c0, #3 51 | str r0, val_cp15_503 52 | 53 | mrc p15, #0, r0, c6, c0, #0 54 | str r0, val_cp15_600 55 | mrc p15, #0, r0, c6, c1, #0 56 | str r0, val_cp15_610 57 | mrc p15, #0, r0, c6, c2, #0 58 | str r0, val_cp15_620 59 | mrc p15, #0, r0, c6, c3, #0 60 | str r0, val_cp15_630 61 | mrc p15, #0, r0, c6, c4, #0 62 | str r0, val_cp15_640 63 | mrc p15, #0, r0, c6, c5, #0 64 | str r0, val_cp15_650 65 | mrc p15, #0, r0, c6, c6, #0 66 | str r0, val_cp15_660 67 | mrc p15, #0, r0, c6, c7, #0 68 | str r0, val_cp15_670 69 | 70 | mrc p15, #0, r0, c9, c1, #0 71 | str r0, val_cp15_910 72 | mrc p15, #0, r0, c9, c1, #1 73 | str r0, val_cp15_911 74 | 75 | bl init_stackpointers 76 | bl test_initialstate 77 | bl init_iostate 78 | bl l_resetIPCSYNC 79 | 80 | @ main loop 81 | main_post_init: 82 | bl init_stackpointers @ there's some jumps that aren't really function calls.. if we return to this from a test we just reset the stack 83 | bl cpp_menu 84 | @ cpp menu never returns, but just to be sure: infinite loop 85 | forever: 86 | b forever 87 | 88 | 89 | 90 | @ initialize the current r13 + IRQ r13 91 | init_stackpointers: 92 | mrs r3, cpsr @ save old CPSR 93 | mov r4, r3 94 | @ IRQ 95 | bic r3, r3, #0x1F 96 | orr r3, r3, #0x12 97 | msr cpsr_c, r3 98 | ldr r13, =stack_irq+4096 99 | @ change back to old mode 100 | msr cpsr_c, r4 101 | ldr r13, =stack_normal+4096 102 | bx r14 103 | 104 | 105 | .pool 106 | 107 | @ stacks are just put in RAM to avoid DTCM dependency 108 | stack_normal: 109 | .space 4096 110 | stack_irq: 111 | .space 4096 112 | 113 | -------------------------------------------------------------------------------- /src9/tests/initialstate.cpp: -------------------------------------------------------------------------------- 1 | #include "../inc.h" 2 | 3 | u16 val_IPCSYNC, val_IPCFIFOCNT, FIFO_length; 4 | u32 val_IME, val_IE, val_IF; 5 | 6 | vu32* const result_base = (vu32*)0x2000004; // where the ARM7 has written some results 7 | 8 | // function that is called once at the start, should store the results somewhere 9 | extern "C" void test_initialstate() 10 | { 11 | l_DIC(); 12 | // get some values of registers at boot time, store these in the global vars defined above, print them in run_tests_initialstate() 13 | val_IPCSYNC = REG_IPCSYNC; 14 | val_IPCFIFOCNT = REG_IPCFIFOCNT; 15 | 16 | // enable FIFO + clear error bit 17 | REG_IPCFIFOCNT = (1 << 15) | (1 << 14); 18 | // count how many values are in the queue (this also clears the queue) 19 | FIFO_length = 0; 20 | while (!(REG_IPCFIFOCNT & (1 << 8))) // as long as the FIFO is not empty 21 | { 22 | vu32 FIFO_val = REG_IPCFIFORECV; 23 | FIFO_length++; 24 | if (FIFO_length > 20) 25 | { 26 | // IPCFIFO maybe unimplemented, shouldn't keep looping here forever 27 | FIFO_length = 0xFFFF; 28 | break; 29 | } 30 | } 31 | val_IME = REG_IME; 32 | val_IE = REG_IE; 33 | val_IF = REG_IF; 34 | REG_IME = 0; 35 | REG_IE = 0; 36 | REG_IF = 0xFFFFFFFF; // acknowledge all 37 | } 38 | 39 | extern u32 val_CPSR; 40 | 41 | // function that prints the results 42 | void run_tests_initialstate_ipc_irq_cpsr() 43 | { 44 | draw_string(15, 1, "ARM7"); 45 | draw_string(24, 1, "ARM9"); 46 | 47 | draw_string(2, 3, "IPCSYNC"); 48 | draw_hex_value<4>(17, 3, result_base[0]); 49 | draw_hex_value<4>(26, 3, val_IPCSYNC); 50 | 51 | draw_string(2, 4, "IPCFIFOCNT"); 52 | draw_hex_value<4>(17, 4, result_base[1]); 53 | draw_hex_value<4>(26, 4, val_IPCFIFOCNT); 54 | 55 | draw_string(2, 5, "FIFO LEN"); 56 | draw_hex_value<4>(17, 5, result_base[2]); 57 | draw_hex_value<4>(26, 5, FIFO_length); 58 | 59 | draw_string(2, 7, "IME"); 60 | draw_hex_value<1>(20, 7, result_base[3]); 61 | draw_hex_value<1>(29, 7, val_IME); 62 | 63 | draw_string(2, 8, "IE"); 64 | draw_hex_value<8>(13, 8, result_base[4]); 65 | draw_hex_value<8>(22, 8, val_IE); 66 | 67 | draw_string(2, 9, "IF"); 68 | draw_hex_value<8>(13, 9, result_base[5]); 69 | draw_hex_value<8>(22, 9, val_IF); 70 | 71 | draw_string(2, 11, "CPSR"); 72 | draw_hex_value<8>(13, 11, result_base[6]); 73 | draw_hex_value<8>(22, 11, val_CPSR); 74 | } 75 | 76 | extern u32 val_cp15[]; 77 | 78 | void run_tests_initialstate_cp15() 79 | { 80 | const char* labels[] = { 81 | "C1,C0,0", 82 | "C2,C0,0", 83 | "C2,C0,1", 84 | "C3,C0,0", 85 | "C5,C0,0", 86 | "C5,C0,1", 87 | "C5,C0,2", 88 | "C5,C0,3", 89 | "C6,C0,0", 90 | "C6,C1,0", 91 | "C6,C2,0", 92 | "C6,C3,0", 93 | "C6,C4,0", 94 | "C6,C5,0", 95 | "C6,C6,0", 96 | "C6,C7,0", 97 | "C9,C1,0", 98 | "C9,C1,1" 99 | }; 100 | 101 | int j = 1; 102 | for(int i = 0; i < 18; i++) 103 | { 104 | draw_string(2, j, labels[i]); 105 | draw_hex_value<8>(10, j, val_cp15[i]); 106 | j++; 107 | if ((i == 3) | (i == 7) | (i == 15)) j++; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rockwrestler test ROM for NDS emulators 2 | Work in progress - aims to test all NDS features such as the IPC, memory control, interrupts, and so forth. You should first aim to boot and pass armwrestler to ensure that the ARM CPU is running relatively bug free. As armwrestler does not very thoroughly check some new ARMv5 features, tests for this are available too. More general ARMv4 CPU tests are also on their way. 3 | Rockwrestler uses the same LCDC mode as armwrestler to draw on the screen. 4 | 5 | Almost all code except CPU tests is written in C++. You can use the `objdump` files `7.txt` and `9.txt` to translate between addresses and C++ code (mind the name mangling). An advantage of writing it in C++ is that you can compile the ROM without optimizations, which might generate simpler code that is easier to run for a buggy ARM core. It is meant to be compiled to ARM. No "advanced" C++ features like exceptions and polymorphism are used. 6 | 7 | ## The tests 8 | On the top right, there's a green or red light next to ARM7. This indicates if the ARM7 is currently in its main loop where it awaits tests. If this light is red due to a failed test, the ARM7 may be stuck somewhere and so future tests involving it will certainly fail. If this light is red when booting the ROM, either `IPCSYNC` is not working which is used for this, or the ARM7 is stuck somewhere else. 9 | Use the source code to look up a failed test number to find out what test it is and why it failed. 10 | 11 | ### ARMv4 12 | These tests aim to complement armwrestler in testing general CPU instructions that are present in ARMv4. Tests in this category behave the same on both NDS CPUs but are run on the ARM9 for simplicity. In the future, tests may be added for edge cases that behave differently on both CPUs, these would then be in a different category. 13 | For now there is only one basic test here, the `condition codes` test which checks the ARM condition code field. 14 | 15 | 16 | ### ARMv5 17 | These tests written in assembly provide some testing of new instructions, as well as testing the improved ARM-thumb interworking. `clz`, `qadd`, `qsub`, `qdadd`, `qdsub`, `blx`, and the five new multiplies `SMULxy`, `SMLAxy`, `SMULWy`, `SMLAWy`, and `SMLALxy` are the new instructions it currently tests. It additionally tests to ensure that `ldr`, `ldm` (ARM) and `pop` (thumb) can switch the state bit when loading into `r15`, and includes some tests for LDM/STM edge cases. 18 | 19 | ### IPC 20 | - The `IPCSYNC` test tries out this feature, including interrupts on both CPUs. 21 | - `IPCFIFO` sends some words back and forth between the two CPUs. This includes checking cases like reading from an empty FIFO and acknowledging the error bit. 22 | - `IPCFIFO IRQ` tests the IPCFIFO's "send FIFO empty" and "receive FIFO not empty" IRQs. 23 | 24 | ### DS MATH 25 | These tests try out the NDS IO registers for calculating divisions and square roots. Only results are checked, the timings aren't checked. `SQRT 32` and `SQRT 64` test the square root on 32 and 64-bit numbers respectively, while `DIV 32/32`, `DIV 64/32`, and `DIV 64/64` test division where the first number represents the size of the numerator, and the second number the size of the denominator. 26 | ### Memory 27 | - `WRAMCNT` tests sharing (parts of) the 32 KB of shared WRAM with the ARM7. This test requires IPCSYNC and IPCFIFO to be implemented as this is used to communicate between the CPUs. 28 | - `VRAMCNT` tests allocating the different VRAM banks to different addresses, including allocating banks to the ARM7 to be used as WRAM . This test requires IPCSYNC and IPCFIFO to be implemented as this is used to communicate between the CPUs. 29 | - `TCM` tests the DTCM and ITCM, including load mode, and overlapping TCM with another memory region. 30 | ### Initial state 31 | Tests in this submenu are not actually doing a test, but rather printing values of certain IO registers, CP15 registers, and other values at startup. There are currently no correct/wrong values here. 32 | 33 | ## Contributing 34 | Anyone is welcome to help and to improve existing tests or add new tests. Send me a message on Discord (join the Emudev Discord server) for more information. 35 | 36 | ## Special thanks to 37 | - http://problemkaputt.de/gbatek.htm 38 | - https://github.com/StrikerX3 for helping me test on hardware and giving good feedback. 39 | - https://github.com/GhostRain0 for adding ARMv5 LDM/STM tests. 40 | - Many people that populate the NDS channel in the Emudev Discord server and discussed with me these tests, giving me feedback on how to improve them and which tests might be useful. 41 | 42 | -------------------------------------------------------------------------------- /src9/tests/vramcnt.cpp: -------------------------------------------------------------------------------- 1 | // tests VRAMCNT 2 | #include "../inc.h" 3 | 4 | void run_tests_vramcnt() 5 | { 6 | // tell ARM7 to await read/write commands 7 | ARM7_start_rw(); 8 | 9 | // first, set all 9 VRAM banks to LCDC mode and write a magic value to start/end 10 | REG_VRAMCNT_A = REG_VRAMCNT_B = REG_VRAMCNT_C = REG_VRAMCNT_D = REG_VRAMCNT_E = 0x80; 11 | REG_VRAMCNT_F = REG_VRAMCNT_G = REG_VRAMCNT_H = REG_VRAMCNT_I = 0x80; 12 | 13 | // bank size LCDC address range 14 | // A 128K 0 - 6800000h-681FFFFh 15 | // B 128K 0 - 6820000h-683FFFFh 16 | // C 128K 0 - 6840000h-685FFFFh 17 | // D 128K 0 - 6860000h-687FFFFh 18 | // E 64K 0 - 6880000h-688FFFFh 19 | // F 16K 0 - 6890000h-6893FFFh 20 | // G 16K 0 - 6894000h-6897FFFh 21 | // H 32K 0 - 6898000h-689FFFFh 22 | // I 16K 0 - 68A0000h-68A3FFFh 23 | *((vu32*)0x6800000) = VRAM_A_START; 24 | *((vu32*)0x681FFFC) = VRAM_A_END; 25 | *((vu32*)0x6820000) = VRAM_B_START; 26 | *((vu32*)0x683FFFC) = VRAM_B_END; 27 | *((vu32*)0x6840000) = VRAM_C_START; 28 | *((vu32*)0x685FFFC) = VRAM_C_END; 29 | *((vu32*)0x6860000) = VRAM_D_START; 30 | *((vu32*)0x687FFFC) = VRAM_D_END; 31 | // TODO E, F, G, H, I 32 | 33 | 34 | // try to read back those values 35 | if (*((vu32*)0x6800000) != VRAM_A_START) fail_test(0x000); 36 | if (*((vu32*)0x681FFFC) != VRAM_A_END) fail_test(0x001); 37 | if (*((vu32*)0x6820000) != VRAM_B_START) fail_test(0x002); 38 | if (*((vu32*)0x683FFFC) != VRAM_B_END) fail_test(0x003); 39 | if (*((vu32*)0x6840000) != VRAM_C_START) fail_test(0x004); 40 | if (*((vu32*)0x685FFFC) != VRAM_C_END) fail_test(0x005); 41 | if (*((vu32*)0x6860000) != VRAM_D_START) fail_test(0x006); 42 | if (*((vu32*)0x687FFFC) != VRAM_D_END) fail_test(0x007); 43 | 44 | // ARM7 does not have any VRAM at the start: make it read from its VRAMSTAT, should be 0 45 | if (ARM7_read_byte(0x4000240) != 0) fail_test(0x008); 46 | 47 | // give VRAM C to ARM7 with offset 0 as WRAM 48 | REG_VRAMCNT_C = 0x82; 49 | 50 | // ARM7 can now access it at 6000000h+(20000h*OFS.0), OFS = 0 51 | // + ARM7 VRAMSTAT (240h) should be 0x01 52 | if (ARM7_read_byte(0x4000240) != 1) fail_test(0x009); 53 | 54 | // read start/end 55 | if (ARM7_read_word(0x6000000) != VRAM_C_START) fail_test(0x00A); 56 | if (ARM7_read_word(0x601FFFC) != VRAM_C_END) fail_test(0x00B); 57 | 58 | // change offset to 1 59 | REG_VRAMCNT_C = 0x8A; 60 | 61 | // check VRAMSTAT, read start/end with 128 KB offset 62 | if (ARM7_read_byte(0x4000240) != 1) fail_test(0x00C); 63 | if (ARM7_read_word(0x6020000) != VRAM_C_START) fail_test(0x00D); 64 | if (ARM7_read_word(0x603FFFC) != VRAM_C_END) fail_test(0x00E); 65 | 66 | // take away bank C, give bank D 67 | REG_VRAMCNT_C = 0; // just disable it 68 | REG_VRAMCNT_D = 0x82; 69 | 70 | // check VRAMSTAT, read start/end 71 | if (ARM7_read_byte(0x4000240) != 2) fail_test(0x00F); 72 | if (ARM7_read_word(0x6000000) != VRAM_D_START) fail_test(0x010); 73 | if (ARM7_read_word(0x601FFFC) != VRAM_D_END) fail_test(0x011); 74 | 75 | // enable bank C with offset 1 76 | REG_VRAMCNT_C = 0x8A; 77 | 78 | // check VRAMSTAT, read start/end of both banks 79 | if (ARM7_read_byte(0x4000240) != 3) fail_test(0x012); 80 | if (ARM7_read_word(0x6000000) != VRAM_D_START) fail_test(0x013); 81 | if (ARM7_read_word(0x601FFFC) != VRAM_D_END) fail_test(0x014); 82 | if (ARM7_read_word(0x6020000) != VRAM_C_START) fail_test(0x015); 83 | if (ARM7_read_word(0x603FFFC) != VRAM_C_END) fail_test(0x016); 84 | 85 | // set bank A to MST = 1 (engine A BG), offset 0 86 | REG_VRAMCNT_A = 0x81; 87 | 88 | // 6000000h+(20000h*OFS) 89 | if (*((vu32*)0x6000000) != VRAM_A_START) fail_test(0x017); 90 | if (*((vu32*)0x601FFFC) != VRAM_A_END) fail_test(0x018); 91 | 92 | // bank D: MST = 1 (engine A BG), offset 1 93 | REG_VRAMCNT_D = 0x89; 94 | 95 | // 6000000h+(20000h*OFS) 96 | if (*((vu32*)0x6020000) != VRAM_D_START) fail_test(0x019); 97 | if (*((vu32*)0x603FFFC) != VRAM_D_END) fail_test(0x01A); 98 | 99 | 100 | // reset bank A to LCDC as we use it to draw the screen 101 | REG_VRAMCNT_A = 0x80; 102 | 103 | // tell ARM7 we're done 104 | ARM7_end_rw(); 105 | 106 | // TODO. exhaustively check all MST/OFS combinations per bank, check VRAM bank overlapping 107 | } 108 | -------------------------------------------------------------------------------- /src9/tests/tcm.cpp: -------------------------------------------------------------------------------- 1 | // tests DTCM/ITCM 2 | #include "../inc.h" 3 | 4 | void run_tests_tcm() 5 | { 6 | u32 cp15control = cp15_get_controlreg(); 7 | cp15control |= 1 << 16; // enable DTCM 8 | cp15control &= ~(1 << 17); // disable DTCM load mode 9 | cp15_set_controlreg(cp15control); 10 | 11 | // put DTCM at 00 80 00 00, virtual size = 5 (512 bytes x 2^5 -> 16 KB) 12 | cp15_set_DTCMcontrol(0x0080000A); 13 | u32 masked_readback = cp15_get_DTCMcontrol() & 0xFFFFF03E; // only check relevant bits: 12-31 for region base, 1-5 for virtual size 14 | if (masked_readback != 0x0080000A) fail_test(0x000); 15 | 16 | // write magic value to start/end 17 | *((vu32*)0x00800000) = DTCM_START; 18 | *((vu32*)0x00803FFC) = DTCM_END; 19 | 20 | // try reading those 21 | if (*((vu32*)0x00800000) != DTCM_START) fail_test(0x001); 22 | if (*((vu32*)0x00803FFC) != DTCM_END) fail_test(0x002); 23 | 24 | // move DTCM to 00 60 00 00, set virtual size to 6 (32 KB, so mirrored!) 25 | cp15_set_DTCMcontrol(0x0060000C); 26 | 27 | // read start + mirrored start + end + mirrored end 28 | if (*((vu32*)0x00600000) != DTCM_START) fail_test(0x003); 29 | if (*((vu32*)0x00604000) != DTCM_START) fail_test(0x004); 30 | if (*((vu32*)0x00603FFC) != DTCM_END) fail_test(0x005); 31 | if (*((vu32*)0x00607FFC) != DTCM_END) fail_test(0x006); 32 | 33 | // move DTCM to 03 00 00 00 (shared WRAM) after writing magic values there 34 | REG_WRAMCNT = 0; // allocate all to ARM9 35 | 36 | *((vu32*)0x03000000) = SHWRAM_START1; 37 | *((vu32*)0x03007FFC) = SHWRAM_END2; 38 | 39 | cp15_set_DTCMcontrol(0x0300001A); // base: 0x03000000, virtual size 13 (-> 4 MB) 40 | // DTCM overlaps with WRAM: DTCM takes priority 41 | if (*((vu32*)0x03000000) != DTCM_START) fail_test(0x007); 42 | if (*((vu32*)0x033FFFFC) != DTCM_END) fail_test(0x008); // + 4 MB 43 | 44 | // now set virtual size to 4 (8 KB) -> read DTCM value from start, WRAM value from end 45 | cp15_set_DTCMcontrol(0x03000008); 46 | if (*((vu32*)0x03000000) != DTCM_START) fail_test(0x009); 47 | if (*((vu32*)0x03007FFC) != SHWRAM_END2) fail_test(0x00A); 48 | 49 | 50 | 51 | // enable DTCM load mode: reading should give WRAM values, while writing writes to DTCM 52 | cp15control = cp15_get_controlreg(); 53 | cp15control |= 1 << 17; // enable DTCM load mode 54 | cp15_set_controlreg(cp15control); 55 | 56 | // + virtual size to 32 KB, base at 0x03000000 still 57 | cp15_set_DTCMcontrol(0x0300000C); 58 | 59 | // read WRAM value from start/end 60 | if (*((vu32*)0x03000000) != SHWRAM_START1) fail_test(0x010); 61 | if (*((vu32*)0x03007FFC) != SHWRAM_END2) fail_test(0x011); 62 | 63 | // write new DTCM values 64 | *((vu32*)0x03000000) = DTCM_START + 1; 65 | *((vu32*)0x03007FFC) = DTCM_END + 1; 66 | 67 | // move DTCM back to 00 80 00 00 without load mode, read new DTCM values from there, and read old SHWRAM start 68 | cp15control = cp15_get_controlreg(); 69 | cp15control &= ~(1 << 17); // disable DTCM load mode 70 | cp15_set_controlreg(cp15control); 71 | cp15_set_DTCMcontrol(0x0080000A); // 0x00800000, 16 KB 72 | 73 | if (*((vu32*)0x00800000) != (DTCM_START + 1)) fail_test(0x012); 74 | if (*((vu32*)0x00803FFC) != (DTCM_END + 1)) fail_test(0x013); 75 | 76 | if (*((vu32*)0x03000000) != SHWRAM_START1) fail_test(0x014); // make sure load-mod write did not touch this value 77 | 78 | // ITCM: 32 KB, always locked at 0x00000000, but virtual size can be changed 79 | cp15control = cp15_get_controlreg(); 80 | cp15control |= 1 << 18; // enable ITCM 81 | cp15control &= ~(1 << 19); // disable ITCM load mode 82 | cp15_set_controlreg(cp15control); 83 | cp15_set_ITCMcontrol(0xC); // virtual size: 32 KB 84 | masked_readback = cp15_get_ITCMcontrol() & 0xFFFFF03E; // only check relevant bits: 12-31 for region base, 1-5 for virtual size 85 | if (masked_readback != 0xC) fail_test(0x020); 86 | 87 | *((vu32*)0x00000000) = ITCM_START; 88 | *((vu32*)0x00007FFC) = ITCM_END; 89 | 90 | // try reading 91 | if (*((vu32*)0x00000000) != ITCM_START) fail_test(0x021); 92 | if (*((vu32*)0x00007FFC) != ITCM_END) fail_test(0x022); 93 | 94 | // increase virtual size, read mirrors 95 | cp15_set_ITCMcontrol(0xE); // 64 KB 96 | if (*((vu32*)0x00008000) != ITCM_START) fail_test(0x023); 97 | if (*((vu32*)0x0000FFFC) != ITCM_END) fail_test(0x024); 98 | 99 | // TODO. ITCM load mode, let ITCM and DTCM overlap, let ITCM and other memory section overlap, ... 100 | 101 | 102 | // restore DTCM state, as other tests (with interrupts) rely on DTCM location being 00800000 103 | cp15_set_DTCMcontrol(0x0080000A); 104 | } 105 | -------------------------------------------------------------------------------- /src9/inc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../common/common.h" 3 | 4 | // asm functions 5 | extern "C" void fail_test(int test_number); 6 | extern "C" void timeout_test(int test_number); 7 | extern "C" void timeout_rw(); 8 | 9 | extern "C" u32 cp15_get_controlreg(); 10 | extern "C" void cp15_set_controlreg(u32 value); 11 | extern "C" u32 cp15_get_DTCMcontrol(); 12 | extern "C" void cp15_set_DTCMcontrol(u32 value); 13 | extern "C" u32 cp15_get_ITCMcontrol(); 14 | extern "C" void cp15_set_ITCMcontrol(u32 value); 15 | 16 | // C++ functions called from assembly 17 | extern "C" void l_resetIPCSYNC(); 18 | extern "C" void init_iostate(); 19 | 20 | // C++ functions 21 | void wait_vblank(); 22 | 23 | // drawing 24 | void clear_screen(); 25 | void draw_cleartile(int x, int y, u16 col); 26 | void draw_tile(int x, int y, int tile); 27 | void draw_string(int x, int y, const char* str); 28 | 29 | // rw 30 | void ARM7_start_rw(); 31 | u32 ARM7_read_word(u32 address); 32 | u16 ARM7_read_halfword(u32 address); 33 | u8 ARM7_read_byte(u32 address); 34 | void ARM7_write_word(u32 address, u32 value); 35 | void ARM7_write_halfword(u32 address, u16 value); 36 | void ARM7_write_byte(u32 address, u8 value); 37 | void ARM7_end_rw(); 38 | 39 | u32 read_from_IPCFIFO(int test_number); 40 | 41 | // wait for a certain bit to be set/unset in an IO register (or global var changed by interrupt) 42 | template 43 | void wait_bit_value(int test_number, volatile T* ptr, int bit_number, bool bit_value) 44 | { 45 | int timeout = 16384; 46 | while (((*ptr >> bit_number) & 1) != bit_value) 47 | { 48 | if (--timeout == 0) 49 | { 50 | timeout_test(test_number); 51 | } 52 | } 53 | } 54 | 55 | // draw a given value in hexadecimal, only the lowest N digits 56 | template 57 | void draw_hex_value(int x, int y, u32 value) 58 | { 59 | for(int i = 0; i < N; i++) 60 | { 61 | draw_tile(x+i, y, (value >> (4*(N-1-i))) & 0xF); 62 | } 63 | } 64 | 65 | // TODO add function to print in decimal 66 | 67 | 68 | // non-IO registers 69 | volatile voidfncptr* const IRQHANDLER = (voidfncptr*)0x00803FFC; 70 | 71 | //// IO registers 72 | vu32* const DISPCNT = (vu32*)0x4000000; 73 | vu16* const DISPSTAT = (vu16*)0x4000004; 74 | 75 | #define REG_DISPCNT (*DISPCNT) 76 | #define REG_DISPSTAT (*DISPSTAT) 77 | 78 | // keypad 79 | vu16* const KEYINPUT = (vu16*)0x4000130; 80 | 81 | #define REG_KEYINPUT (*KEYINPUT) 82 | const u16 KEY_A = 0; 83 | const u16 KEY_B = 1; 84 | const u16 KEY_SELECT = 2; 85 | const u16 KEY_START = 3; 86 | const u16 KEY_RIGHT = 4; 87 | const u16 KEY_LEFT = 5; 88 | const u16 KEY_UP = 6; 89 | const u16 KEY_DOWN = 7; 90 | const u16 KEY_R = 8; 91 | const u16 KEY_L = 9; 92 | 93 | const u16 KEY_MASK_A = 1; 94 | const u16 KEY_MASK_B = 2; 95 | const u16 KEY_MASK_SELECT = 4; 96 | const u16 KEY_MASK_START = 8; 97 | const u16 KEY_MASK_RIGHT = 16; 98 | const u16 KEY_MASK_LEFT = 32; 99 | const u16 KEY_MASK_UP = 64; 100 | const u16 KEY_MASK_DOWN = 128; 101 | const u16 KEY_MASK_R = 256; 102 | const u16 KEY_MASK_L = 512; 103 | 104 | // memory control 105 | vu8* const VRAMCNT_A = (vu8*)0x4000240; 106 | vu8* const VRAMCNT_B = (vu8*)0x4000241; 107 | vu8* const VRAMCNT_C = (vu8*)0x4000242; 108 | vu8* const VRAMCNT_D = (vu8*)0x4000243; 109 | vu8* const VRAMCNT_E = (vu8*)0x4000244; 110 | vu8* const VRAMCNT_F = (vu8*)0x4000245; 111 | vu8* const VRAMCNT_G = (vu8*)0x4000246; 112 | vu8* const WRAMCNT = (vu8*)0x4000247; 113 | vu8* const VRAMCNT_H = (vu8*)0x4000248; 114 | vu8* const VRAMCNT_I = (vu8*)0x4000249; 115 | 116 | #define REG_VRAMCNT_A (*VRAMCNT_A) 117 | #define REG_VRAMCNT_B (*VRAMCNT_B) 118 | #define REG_VRAMCNT_C (*VRAMCNT_C) 119 | #define REG_VRAMCNT_D (*VRAMCNT_D) 120 | #define REG_VRAMCNT_E (*VRAMCNT_E) 121 | #define REG_VRAMCNT_F (*VRAMCNT_F) 122 | #define REG_VRAMCNT_G (*VRAMCNT_G) 123 | #define REG_WRAMCNT (*WRAMCNT) 124 | #define REG_VRAMCNT_H (*VRAMCNT_H) 125 | #define REG_VRAMCNT_I (*VRAMCNT_I) 126 | 127 | // DIV 128 | vu16* const DIVCNT = (vu16*)0x4000280; 129 | vu32* const DIVNUMERLO = (vu32*)0x4000290; 130 | vu32* const DIVNUMERHI = (vu32*)0x4000294; 131 | vu32* const DIVDENOMLO = (vu32*)0x4000298; 132 | vu32* const DIVDENOMHI = (vu32*)0x400029C; 133 | vu32* const DIVRESLO = (vu32*)0x40002A0; 134 | vu32* const DIVRESHI = (vu32*)0x40002A4; 135 | vu32* const DIVREMLO = (vu32*)0x40002A8; 136 | vu32* const DIVREMHI = (vu32*)0x40002AC; 137 | 138 | #define REG_DIVCNT (*DIVCNT) 139 | #define REG_DIVNUMERLO (*DIVNUMERLO) 140 | #define REG_DIVNUMERHI (*DIVNUMERHI) 141 | #define REG_DIVDENOMLO (*DIVDENOMLO) 142 | #define REG_DIVDENOMHI (*DIVDENOMHI) 143 | #define REG_DIVRESLO (*DIVRESLO) 144 | #define REG_DIVRESHI (*DIVRESHI) 145 | #define REG_DIVREMLO (*DIVREMLO) 146 | #define REG_DIVREMHI (*DIVREMHI) 147 | 148 | // SQRT 149 | vu16* const SQRTCNT = (vu16*)0x40002B0; 150 | vu32* const SQRTRES = (vu32*)0x40002B4; 151 | vu32* const SQRTLO = (vu32*)0x40002B8; 152 | vu32* const SQRTHI = (vu32*)0x40002BC; 153 | 154 | #define REG_SQRTCNT (*SQRTCNT) 155 | #define REG_SQRTRES (*SQRTRES) 156 | #define REG_SQRTLO (*SQRTLO) 157 | #define REG_SQRTHI (*SQRTHI) 158 | 159 | // misc 160 | vu32* const POWCNT1 = (vu32*)0x4000304; 161 | 162 | #define REG_POWCNT1 (*POWCNT1) 163 | 164 | -------------------------------------------------------------------------------- /src9/tests/wramcnt.cpp: -------------------------------------------------------------------------------- 1 | // tests WRAMCNT/allocating the 32 KB memory block (partially) to ARM7 2 | #include "../inc.h" 3 | 4 | void run_tests_wramcnt() 5 | { 6 | // get ARM7 ready for read/write commands 7 | ARM7_start_rw(); 8 | 9 | // NDS9 - WRAMCNT - 0: 32 KB (ARM9) 10 | // 1: second half (ARM9), first half (ARM7) 11 | // 2: first half (ARM9), second half (ARM7) 12 | // 3: 32 KB (ARM7) 13 | // deallocation: ARM9: undefined (3******) 14 | // ARM7: area is 03000000-037FFFFF, not allocated -> mirror of ARM7-WRAM (03800000-03FFFFFF) 15 | 16 | // allocate all to ARM9 17 | REG_WRAMCNT = 0; 18 | 19 | // write magic values at start/end of each 16 KB section 20 | *((vu32*)0x3000000) = SHWRAM_START1; 21 | *((vu32*)0x3003FFC) = SHWRAM_END1; 22 | *((vu32*)0x3004000) = SHWRAM_START2; 23 | *((vu32*)0x3007FFC) = SHWRAM_END2; 24 | 25 | // try to read it back 26 | if (*((vu32*)0x3000000) != SHWRAM_START1) fail_test(0x000); 27 | if (*((vu32*)0x3003FFC) != SHWRAM_END1) fail_test(0x001); 28 | if (*((vu32*)0x3004000) != SHWRAM_START2) fail_test(0x002); 29 | if (*((vu32*)0x3007FFC) != SHWRAM_END2) fail_test(0x003); 30 | // + from a mirror 31 | if (*((vu32*)0x3020000) != SHWRAM_START1) fail_test(0x004); 32 | if (*((vu32*)0x3023FFC) != SHWRAM_END1) fail_test(0x005); 33 | if (*((vu32*)0x3024000) != SHWRAM_START2) fail_test(0x006); 34 | if (*((vu32*)0x3027FFC) != SHWRAM_END2) fail_test(0x007); 35 | 36 | // check ARM7 WRAMSTAT: should be 0 37 | if ((ARM7_read_byte(0x4000241) & 3) != 0) fail_test(0x008); 38 | 39 | // ARM7 should read mirrors of its own WRAM in this area 40 | // first, make it write start/end value to its own 64 KB WRAM 41 | ARM7_write_word(0x3800000, ARM7RAM_START); 42 | ARM7_write_word(0x380FFFC, ARM7RAM_END); 43 | 44 | // quickly check to make sure it was written to ARM7RAM correctly 45 | // should not be necessary as the ARM7 is running code from there 46 | // if the memory region isn't working, we would never have gotten this far 47 | if (ARM7_read_word(0x3800000) != ARM7RAM_START) fail_test(0x009); 48 | if (ARM7_read_word(0x380FFFC) != ARM7RAM_END) fail_test(0x00A); 49 | 50 | // now make ARM7 read from the shared WRAM region (03000000-037FFFFF) 51 | // should contain mirror of its own WRAM -> the magic values should be there 52 | if (ARM7_read_word(0x3000000) != ARM7RAM_START) fail_test(0x00B); 53 | if (ARM7_read_word(0x300FFFC) != ARM7RAM_END) fail_test(0x00C); 54 | // + read from mirror 55 | if (ARM7_read_word(0x3400000) != ARM7RAM_START) fail_test(0x00D); 56 | if (ARM7_read_word(0x340FFFC) != ARM7RAM_END) fail_test(0x00E); 57 | 58 | 59 | // switch to mode 1: we get second half, ARM7 gets first half 60 | REG_WRAMCNT = 1; 61 | 62 | // check WRAMSTAT 63 | if ((ARM7_read_byte(0x4000241) & 3) != 1) fail_test(0x00F); 64 | 65 | // make sure we can read the second half anywhere 66 | if (*((vu32*)0x3000000) != SHWRAM_START2) fail_test(0x010); 67 | if (*((vu32*)0x3003FFC) != SHWRAM_END2) fail_test(0x011); 68 | if (*((vu32*)0x304C000) != SHWRAM_START2) fail_test(0x012); 69 | if (*((vu32*)0x304FFFC) != SHWRAM_END2) fail_test(0x013); 70 | 71 | // and ARM7 should be able to read the first half 72 | if (ARM7_read_word(0x3000000) != SHWRAM_START1) fail_test(0x014); 73 | if (ARM7_read_word(0x3003FFC) != SHWRAM_END1) fail_test(0x015); 74 | if (ARM7_read_word(0x300C000) != SHWRAM_START1) fail_test(0x016); 75 | if (ARM7_read_word(0x300FFFC) != SHWRAM_END1) fail_test(0x017); 76 | 77 | 78 | // switch to mode 2: we get first half, ARM7 gets second half 79 | REG_WRAMCNT = 2; 80 | 81 | // check WRAMSTAT 82 | if ((ARM7_read_byte(0x4000241) & 3) != 2) fail_test(0x018); 83 | 84 | // make sure we can read the first half anywhere 85 | if (*((vu32*)0x3000000) != SHWRAM_START1) fail_test(0x019); 86 | if (*((vu32*)0x3003FFC) != SHWRAM_END1) fail_test(0x01A); 87 | if (*((vu32*)0x304C000) != SHWRAM_START1) fail_test(0x01B); 88 | if (*((vu32*)0x304FFFC) != SHWRAM_END1) fail_test(0x01C); 89 | 90 | // and ARM7 should be able to read the second half 91 | if (ARM7_read_word(0x3000000) != SHWRAM_START2) fail_test(0x01D); 92 | if (ARM7_read_word(0x3003FFC) != SHWRAM_END2) fail_test(0x01E); 93 | if (ARM7_read_word(0x300C000) != SHWRAM_START2) fail_test(0x01F); 94 | if (ARM7_read_word(0x300FFFC) != SHWRAM_END2) fail_test(0x020); 95 | 96 | 97 | // switch to mod 3: ARM7 gets everything 98 | REG_WRAMCNT = 3; 99 | 100 | // check WRAMSTAT 101 | if ((ARM7_read_byte(0x4000241) & 3) != 3) fail_test(0x021); 102 | 103 | // ensure ARM7 can read it from anywhere 104 | if (ARM7_read_word(0x3000000) != SHWRAM_START1) fail_test(0x022); 105 | if (ARM7_read_word(0x3003FFC) != SHWRAM_END1) fail_test(0x023); 106 | if (ARM7_read_word(0x300C000) != SHWRAM_START2) fail_test(0x024); 107 | if (ARM7_read_word(0x300FFFC) != SHWRAM_END2) fail_test(0x025); 108 | // + from a mirror 109 | if (ARM7_read_word(0x3110000) != SHWRAM_START1) fail_test(0x026); 110 | if (ARM7_read_word(0x3223FFC) != SHWRAM_END1) fail_test(0x027); 111 | if (ARM7_read_word(0x333C000) != SHWRAM_START2) fail_test(0x028); 112 | if (ARM7_read_word(0x344FFFC) != SHWRAM_END2) fail_test(0x029); 113 | 114 | 115 | // tell ARM7 we're done 116 | ARM7_end_rw(); 117 | } 118 | -------------------------------------------------------------------------------- /src9/framework/font.bin: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /src9/tests/division.cpp: -------------------------------------------------------------------------------- 1 | // tests NDS division IO registers 2 | #include "../inc.h" 3 | 4 | struct DIVtest 5 | { 6 | u32 numLo, numHi, denomLo, denomHi, resLo, resHi, remLo, remHi; 7 | bool divby0errorbit; 8 | }; 9 | 10 | // very unstructured test cases 11 | const DIVtest div32_32_tests[] = { 12 | {67, 0, 10, 0, 6, 0, 7, 0, false}, // @ 67 , 10 -> 6, 7 13 | {31463, 0, 456, 0, 68, 0, 455, 0, false}, 14 | {31464, 0, 456, 0, 69, 0, 0, 0, false}, 15 | {31465, 0, 456, 0, 69, 0, 1, 0, false}, 16 | 17 | { -140, 44, 18, 1, -7, -1, -14, -1, false}, // -140 , 18 -> -7, -14 (-140/18 = -7.77** -> -7, -140 - 18*(-7) = -14) 18 | { -809, 123, 18, 188, -44, -1, -17, -1, false}, 19 | { -810, -123, 18, 11, -45, -1, 0, 0, false}, 20 | { -811, 0, 18, -51, -45, -1, -1, -1, false}, 21 | 22 | { 817, -5, -10, -5, -81, -1, 7, 0, false}, 23 | { 810, -5, -10, -5, -81, -1, 0, 0, false}, 24 | { 811, -6, -10, 531, -81, -1, 1, 0, false}, 25 | { 809, 5, -10, 252, -80, -1, 9, 0, false}, 26 | 27 | { -54, 244, -10, 428, 5, 0, -4, -1, false}, 28 | { -59, 244, -10, 428, 5, 0, -9, -1, false}, 29 | { -60, 244, -10, 428, 6, 0, 0, 0, false}, 30 | { -61, 244, -10, 428, 6, 0, -1, -1, false}, 31 | 32 | { 188, 0, 1, 0, 188, 0, 0, 0, false}, 33 | { -123, 0, 1, 0, -123, -1, 0, 0, false}, 34 | { 614, 0, -1, 0, -614, -1, 0, 0, false}, 35 | { -555, 0, -1, 0, 555, 0, 0, 0, false}, 36 | 37 | { 0x80000000, 0, -1, 0, 0x80000000, 0, 0, 0, false}, // overflow (-MAX/-1 -> -MAX instead of MAX, not sign extended) 38 | { 123, 0, 0, 555, -1, 0, 123, 0, false}, // div by 0: res also sign extended incorrectly 39 | { -123, 0, 0, 555, 1, -1, -123, -1, false}, // ' 40 | { 0, 0, 0, 555, -1, 0, 0, 0, false}, 41 | { 456, 0, 0, 0, -1, 0, 456, 0, true}, // 64-bit denom = 0: error bit 42 | { -456, 0, 0, 0, 1, -1, -456, -1, true}, // ' 43 | { 0, 0, 0, 0, -1, 0, 0, 0, true} // ' 44 | }; 45 | 46 | const DIVtest div64_32_tests[] = { 47 | { 3433982045 , 1495661067 , 236509398 , 2881185925 , 1391126937 , 6 , 48106103 , 0 , false}, 48 | { 2154647668 , 3521289250 , 425590710 , 3127514378 , 782146911 , 4294967294 , 3932474858 , 4294967295 , false}, 49 | { 1922168281 , 1858073932 , 120466744 , 3903510642 , 1820883341 , 15 , 84121089 , 0 , false}, 50 | { 2205423745 , 1140703687 , 1341204594 , 3681089015 , 3652899083 , 0 , 759056795 , 0 , false}, 51 | { 3178427586 , 166340665 , 2977347259 , 3917866833 , 3752756569 , 4294967295 , 1176782527 , 0 , false}, 52 | { 3642771976 , 2744890040 , 3689984914 , 1961992904 , 2414569531 , 2 , 4205680482 , 4294967295 , false}, 53 | { 2953990472 , 228525878 , 595492953 , 3003833644 , 1648233065 , 0 , 144585415 , 0 , false}, 54 | { 4122067872 , 2331242851 , 3841153440 , 3927033522 , 1405134676 , 4 , 4267768608 , 4294967295 , false}, 55 | { 1298567073 , 541382732 , 442302378 , 2613613729 , 962117552 , 1 , 239531201 , 0 , false}, 56 | { 409708380 , 978081371 , 2832999784 , 2915952732 , 1421560420 , 4294967295 , 212138684 , 0 , false}, 57 | { 1930979202 , 1105853070 , 3119598546 , 578578769 , 254020341 , 4294967295 , 447521672 , 0 , false}, 58 | { 16225604 , 2021597761 , 1519863446 , 54293766 , 1417846109 , 1 , 1099756230 , 0 , false}, 59 | { 3966856588 , 3456041294 , 1659113464 , 4073113242 , 2123229307 , 4294967295 , 3737977188 , 4294967295 , false}, 60 | { 2503201751 , 3761051594 , 4111858164 , 1880989876 , 3933473996 , 2 , 4117312871 , 4294967295 , false}, 61 | { 3497809569 , 2352592527 , 1310362933 , 265449947 , 2223426585 , 4294967294 , 3382726772 , 4294967295 , false}, 62 | { 179874632 , 3182602627 , 302931460 , 626862639 , 1408744342 , 4294967292 , 4123306224 , 4294967295 , false}, 63 | 64 | { 0, 0x80000000, -1, 0, 0, 0x80000000, 0, 0, false}, // overflow (-MAX/-1 -> -MAX instead of MAX) 65 | { 123, 6, 0, 0x555, -1, -1, 123, 6, false}, // div by 0: res sign extended correctly 66 | { -123, -8, 0, 0x555, 1, 0, -123, -8, false}, // ' 67 | { 0, 0, 0, 0x555, -1, -1, 0, 0, false}, 68 | { 456, 6, 0, 0, -1, -1, 456, 6, true}, // 64-bit denom = 0: error bit 69 | { -456, -8, 0, 0, 1, 0, -456, -8, true}, // ' 70 | { 0, 0, 0, 0, -1, -1, 0, 0, true} // ' 71 | }; 72 | 73 | const DIVtest div64_64_tests[] = { 74 | { 1811435369 , 2899071174 , 378838206 , 1972369566 , 0 , 0 , 1811435369 , 2899071174 , false}, 75 | { 3561088202 , 2795612862 , 2670550186 , 1972501369 , 0 , 0 , 3561088202 , 2795612862 , false}, 76 | { 3544901067 , 876673192 , 95990780 , 0 , 570756327 , 9 , 88386919 , 0 , false}, 77 | { 3297557998 , 60728899 , 1831216766 , 1559128996 , 0 , 0 , 3297557998 , 60728899 , false}, 78 | { 3830564669 , 1873812420 , 3924560227 , 2604699052 , 4294967295 , 4294967295 , 3460157600 , 183544177 , false}, 79 | { 1045560126 , 865902829 , 4206723589 , 1021554562 , 0 , 0 , 1045560126 , 865902829 , false}, 80 | { 335827131 , 894068399 , 1504592406 , 26560618 , 33 , 0 , 2223885285 , 17567993 , false}, 81 | { 2206612439 , 2104078770 , 1144569821 , 1841111763 , 1 , 0 , 1062042618 , 262967007 , false}, 82 | { 2672951752 , 2052516775 , 641911416 , 1967816049 , 1 , 0 , 2031040336 , 84700726 , false}, 83 | { 402058462 , 2425767789 , 3651716241 , 1878602569 , 0 , 0 , 402058462 , 2425767789 , false}, 84 | { 2018647722 , 3185867357 , 1924563228 , 677692115 , 4294967295 , 4294967295 , 3943210950 , 3863559472 , false}, 85 | { 737594227 , 1343895311 , 3045244374 , 96026225 , 13 , 0 , 4099090325 , 95554376 , false}, 86 | { 2732658177 , 3839563371 , 3060215123 , 512049618 , 0 , 0 , 2732658177 , 3839563371 , false}, 87 | { 1699776401 , 961636287 , 516156236 , 0 , 3706866484 , 1 , 29194273 , 0 , false}, 88 | { 1464896284 , 2465942470 , 1950357861 , 0 , 267192719 , 4294967295 , 3105672881 , 4294967295 , false}, 89 | { 1884637257 , 3069229139 , 2129770961 , 3165750172 , 1 , 0 , 4049833592 , 4198446262 , false}, 90 | 91 | { 0, 0x80000000, -1, -1, 0, 0x80000000, 0, 0, false}, // overflow (-MAX/-1 -> -MAX instead of MAX) 92 | { 456, 6, 0, 0, -1, -1, 456, 6, true}, // 64-bit denom = 0: error bit 93 | { -456, -8, 0, 0, 1, 0, -456, -8, true}, // ' 94 | { 0, 0, 0, 0, -1, -1, 0, 0, true} // ' 95 | }; 96 | 97 | void check_div(const DIVtest array[], int test_count) 98 | { 99 | for(int i = 0; i < test_count; i++) 100 | { 101 | REG_DIVNUMERLO = array[i].numLo; 102 | REG_DIVNUMERHI = array[i].numHi; 103 | REG_DIVDENOMLO = array[i].denomLo; 104 | REG_DIVDENOMHI = array[i].denomHi; 105 | 106 | wait_bit_value(i, DIVCNT, 15, false); // wait for bit 15 = busy bit to be turned off 107 | 108 | u32 fail = 0; 109 | fail |= (array[i].resLo != REG_DIVRESLO); 110 | fail |= (array[i].resHi != REG_DIVRESHI) << 1; 111 | fail |= (array[i].remLo != REG_DIVREMLO) << 2; 112 | fail |= (array[i].remHi != REG_DIVREMHI) << 3; 113 | fail |= (array[i].divby0errorbit != ((REG_DIVCNT >> 14) & 1)) << 4; 114 | if (fail) fail_test(i); 115 | } 116 | } 117 | 118 | void run_tests_ds_maths_div_32_32() 119 | { 120 | REG_DIVCNT = 0; // 32/32 121 | check_div(div32_32_tests, 27); 122 | } 123 | 124 | void run_tests_ds_maths_div_64_32() 125 | { 126 | REG_DIVCNT = 1; // 64/32 127 | check_div(div64_32_tests, 23); 128 | } 129 | 130 | void run_tests_ds_maths_div_64_64() 131 | { 132 | REG_DIVCNT = 2; // 64/64 133 | check_div(div64_64_tests, 20); 134 | } 135 | -------------------------------------------------------------------------------- /src9/framework/menu.cpp: -------------------------------------------------------------------------------- 1 | #include "../inc.h" 2 | #include "../tests/tests.h" 3 | 4 | extern const char txt_buildtime[]; 5 | 6 | struct MenuEntry 7 | { 8 | const char* text; 9 | void* ptr; 10 | int type; // 0: test, 1: submenu, 2: function that just prints some stuff (don't print OK afterwards, just wait for B button) 11 | }; 12 | 13 | class Menu 14 | { 15 | public: 16 | const MenuEntry* entries; 17 | const char* title; 18 | const Menu* parent; 19 | 20 | int get_entry_count() const 21 | { 22 | int count = 0; 23 | const MenuEntry* p = entries; 24 | while ((p++)->text != nullptr) count++; 25 | return count; 26 | } 27 | 28 | void draw() const 29 | { 30 | // draw title, buttons 31 | clear_screen(); 32 | draw_string(3, 0, title); 33 | 34 | for(int i = 0; i < get_entry_count(); i++) 35 | { 36 | draw_string(2, 2+i, entries[i].text); 37 | } 38 | 39 | // only in main menu: draw disclaimer + build time 40 | if (parent == nullptr) 41 | { 42 | draw_string(3, 21, " WIP CONTACT: ROCKPOLISH"); 43 | draw_string(3, 22, " MAY STILL CONTAIN BUGS "); 44 | draw_string(3, 23, txt_buildtime); 45 | } 46 | } 47 | }; 48 | 49 | 50 | 51 | 52 | extern const Menu menu_main, menu_armv4, menu_armv5, menu_ipc, menu_dsmath, menu_memory, menu_initialstate; 53 | 54 | const MenuEntry menu_main_entries[] = { 55 | {"ARMv4", (void*)&menu_armv4, 1}, 56 | {"ARMv5", (void*)&menu_armv5, 1}, 57 | {"IPC", (void*)&menu_ipc, 1}, 58 | {"DS MATH", (void*)&menu_dsmath, 1}, 59 | {"MEMORY", (void*)&menu_memory, 1}, 60 | {"INITIAL STATE", (void*)&menu_initialstate, 1}, 61 | {nullptr, nullptr, 0} 62 | }; 63 | 64 | const MenuEntry menu_armv4_entries[] = { 65 | {"CONDITION CODES", (void*)&run_tests_armv4_conditioncodes, 0}, 66 | {nullptr, nullptr, 0} 67 | }; 68 | 69 | const MenuEntry menu_armv5_entries[] = { 70 | {"CLZ", (void*)&run_tests_armv5_clz, 0}, 71 | {"QADD, QSUB", (void*)&run_tests_armv5_qadd_qsub, 0}, 72 | {"QDADD, QDSUB", (void*)&run_tests_armv5_qdadd_qdsub, 0}, 73 | {"SMULxy", (void*)&run_tests_armv5_SMULxy, 0}, 74 | {"SMLAxy", (void*)&run_tests_armv5_SMLAxy, 0}, 75 | {"SMULWy", (void*)&run_tests_armv5_SMULWy, 0}, 76 | {"SMLAWy", (void*)&run_tests_armv5_SMLAWy, 0}, 77 | {"SMLALxy", (void*)&run_tests_armv5_SMLALxy, 0}, 78 | {"BLX", (void*)&run_tests_armv5_blx, 0}, 79 | {"LDR r15, POP {r15}, LDM {r15}", (void*)&run_tests_armv5_ldrpopr15, 0}, 80 | {"LDM / STM", (void*)&run_tests_armv5_ldm_stm, 0}, 81 | {nullptr, nullptr, 0} 82 | }; 83 | 84 | 85 | const MenuEntry menu_ipc_entries[] = { 86 | {"IPCSYNC", (void*)&run_tests_ipcsync, 0}, 87 | {"IPCFIFO", (void*)&run_tests_ipcfifo, 0}, 88 | {"IPCFIFO IRQ", (void*)&run_tests_ipcfifo_irq, 0}, 89 | {nullptr, nullptr, 0} 90 | }; 91 | 92 | const MenuEntry menu_dsmath_entries[] = { 93 | {"SQRT 32", (void*)&run_tests_ds_maths_sqrt_32, 0}, 94 | {"SQRT 64", (void*)&run_tests_ds_maths_sqrt_64, 0}, 95 | {"DIV 32/32", (void*)&run_tests_ds_maths_div_32_32, 0}, 96 | {"DIV 64/32", (void*)&run_tests_ds_maths_div_64_32, 0}, 97 | {"DIV 64/64", (void*)&run_tests_ds_maths_div_64_64, 0}, 98 | {nullptr, nullptr, 0} 99 | }; 100 | 101 | const MenuEntry menu_memory_entries[] = { 102 | {"WRAM CNT", (void*)&run_tests_wramcnt, 0}, 103 | {"VRAM CNT", (void*)&run_tests_vramcnt, 0}, 104 | {"TCM", (void*)&run_tests_tcm, 0}, 105 | {nullptr, nullptr, 0} 106 | }; 107 | 108 | const MenuEntry menu_initialstate_entries[] = { 109 | {"IPC/IRQ/CPSR", (void*)&run_tests_initialstate_ipc_irq_cpsr, 2}, 110 | {"CP15", (void*)&run_tests_initialstate_cp15, 2}, 111 | {nullptr, nullptr, 0} 112 | }; 113 | 114 | const Menu menu_main = {menu_main_entries, "ROCKWRESTLER", nullptr}; 115 | const Menu menu_armv4 = {menu_armv4_entries, "ARMv4", &menu_main}; 116 | const Menu menu_armv5 = {menu_armv5_entries, "ARMv5", &menu_main}; 117 | const Menu menu_ipc = {menu_ipc_entries, "IPC TESTS", &menu_main}; 118 | const Menu menu_dsmath = {menu_dsmath_entries, "DS MATH", &menu_main}; 119 | const Menu menu_memory = {menu_memory_entries, "MEMORY CONTROL", &menu_main}; 120 | const Menu menu_initialstate = {menu_initialstate_entries, "INITIAL STATE", &menu_main}; 121 | 122 | const Menu* menu_selected = &menu_main; 123 | int menu_index = 0; 124 | 125 | extern "C" void cpp_menu() 126 | { 127 | menu_selected->draw(); 128 | 129 | // how many frames each key has been held, or 0 if currently released 130 | int key_times[16]; 131 | for(int i = 0; i < 16; i++) 132 | { 133 | key_times[i] = 0; 134 | } 135 | 136 | u16 keys_held = 0, keys_released = 0, keys_held_slow = 0; 137 | 138 | // heartbeat: test if ARM7 is properly in main loop, draw green or red square in top right corner 139 | int heartbeat_value = 1; 140 | int heartbeat_time = 0; // frames without response, > 5 -> ARM7 is maybe stuck somewhere (or not implemented, or no IPCSYNC) 141 | 142 | while (true) 143 | { 144 | wait_vblank(); 145 | u16 keys_held_prev = keys_held; 146 | keys_held = ~REG_KEYINPUT; 147 | // released: held previously, not held now 148 | keys_released = keys_held_prev & ~keys_held; 149 | // pressed: held now, not held previously 150 | u16 keys_pressed = keys_held & ~keys_held_prev; 151 | keys_held_slow = 0; // keys that are either pressed just now, or are being held for a bit, every n frames 152 | for(int i = 0; i < 16; i++) 153 | { 154 | if ((keys_held >> i) & 1) 155 | { 156 | key_times[i]++; 157 | if ((key_times[i] == 1) || ((key_times[i] > 30) && ((key_times[i] & 7) == 0))) keys_held_slow |= 1 << i; 158 | } 159 | else key_times[i] = 0; 160 | } 161 | 162 | if (keys_held_slow & KEY_MASK_UP) 163 | { 164 | draw_cleartile(1, 2+menu_index, 0x56B5); 165 | menu_index--; 166 | if (menu_index < 0) menu_index += menu_selected->get_entry_count(); 167 | } 168 | if (keys_held_slow & KEY_MASK_DOWN) 169 | { 170 | draw_cleartile(1, 2+menu_index, 0x56B5); 171 | menu_index++; 172 | if (menu_index >= menu_selected->get_entry_count()) menu_index -= menu_selected->get_entry_count(); 173 | } 174 | 175 | if (keys_pressed & KEY_MASK_A) 176 | { 177 | clear_screen(); 178 | 179 | const MenuEntry& entry = menu_selected->entries[menu_index]; 180 | if (entry.type == 0) 181 | { 182 | // test: ptr is a function pointer 183 | voidfncptr f = (voidfncptr)menu_selected->entries[menu_index].ptr; 184 | call_fncptr(f); // use call_fncptr so compiler doesn't generate blx 185 | // if we reach this: the test passed 186 | draw_string(0, 0, "OK"); 187 | 188 | // wait until B button is held 189 | while (REG_KEYINPUT & KEY_MASK_B) { } 190 | menu_selected->draw(); 191 | keys_held |= KEY_MASK_B; 192 | // make the B button pressed so that this B hold does not transfer to the next frame 193 | // to then be used to go to the previous menu 194 | } 195 | else if (entry.type == 1) 196 | { 197 | // submenu: ptr is a pointer to a new Menu 198 | menu_selected = (const Menu*)menu_selected->entries[menu_index].ptr; 199 | menu_index = 0; 200 | menu_selected->draw(); 201 | } 202 | else if (entry.type == 2) 203 | { 204 | // just execute the function and then redraw the menu, don't draw OK 205 | voidfncptr f = (voidfncptr)menu_selected->entries[menu_index].ptr; 206 | call_fncptr(f); 207 | 208 | while (REG_KEYINPUT & KEY_MASK_B) { } 209 | menu_selected->draw(); 210 | keys_held |= KEY_MASK_B; 211 | } 212 | } 213 | 214 | if (keys_pressed & KEY_MASK_B) 215 | { 216 | // go back to previous menu 217 | if (menu_selected->parent != nullptr) 218 | { 219 | const void* from = menu_selected; 220 | menu_selected = menu_selected->parent; 221 | // use "from" menu to set cursor correctly 222 | menu_index = 0; 223 | while (menu_selected->entries[menu_index].ptr != from) menu_index++; 224 | menu_selected->draw(); 225 | } 226 | } 227 | 228 | // draw cursor 229 | draw_tile(1, 2+menu_index, 0x16); 230 | 231 | // ARM7 heartbeat 232 | if ((REG_IPCSYNC & 0xF) == heartbeat_value) 233 | { 234 | heartbeat_value = 3-heartbeat_value; // alternate 1, 2, 1, 2, ... 235 | heartbeat_time = 0; 236 | } 237 | else heartbeat_time++; 238 | 239 | REG_IPCSYNC = heartbeat_value << 8; 240 | 241 | // top right: "ARM7" + green or red square 242 | draw_string(27, 0, "ARM7"); 243 | draw_cleartile(31, 0, (heartbeat_time > 5) ? 0x001F : 0x03E0); 244 | } 245 | } 246 | 247 | extern "C" void cpp_fail_test(const char* str, int offset, int number) 248 | { 249 | // make sure we are in the right VRAM mode etc 250 | init_iostate(); 251 | 252 | // draw the string (fail, timeout, ...) 253 | draw_string(0, 0, str); 254 | 255 | // + the number of the test that failed (3 hexadecimal digits) 256 | // timeout_rw doesn't give a test number (-1), so don't draw that 257 | if (number >= 0) draw_hex_value<3>(offset, 0, number); 258 | } 259 | -------------------------------------------------------------------------------- /7.txt: -------------------------------------------------------------------------------- 1 | 2 | arm7.o: file format elf32-littlearm 3 | 4 | 5 | Disassembly of section .text: 6 | 7 | 03800100 <_start>: 8 | 3800100: ea00006e b 38002c0 9 | 10 | 03800104 <_Z11arm7_rwmodev>: 11 | 3800104: e3a03902 mov r3, #32768 ; 0x8000 12 | 3800108: e92d4010 push {r4, r14} 13 | 380010c: e3a0c641 mov r12, #68157440 ; 0x4100000 14 | 3800110: e3a0e301 mov r14, #67108864 ; 0x4000000 15 | 3800114: e3a04000 mov r4, #0 16 | 3800118: e59f10e0 ldr r1, [pc, #224] ; 3800200 <_Z11arm7_rwmodev+0xfc> 17 | 380011c: e1c138b4 strh r3, [r1, #132] ; 0x84 18 | 3800120: e1d138b4 ldrh r3, [r1, #132] ; 0x84 19 | 3800124: e3130c01 tst r3, #256 ; 0x100 20 | 3800128: 1afffffc bne 3800120 <_Z11arm7_rwmodev+0x1c> 21 | 380012c: e59c3000 ldr r3, [r12] 22 | 3800130: e1a00e23 lsr r0, r3, #28 23 | 3800134: e2402004 sub r2, r0, #4 24 | 3800138: e3520002 cmp r2, #2 25 | 380013c: e3c3220f bic r2, r3, #-268435456 ; 0xf0000000 26 | 3800140: 9a000009 bls 380016c <_Z11arm7_rwmodev+0x68> 27 | 3800144: e3500006 cmp r0, #6 28 | 3800148: 979ff100 ldrls r15, [r15, r0, lsl #2] 29 | 380014c: ea000026 b 38001ec <_Z11arm7_rwmodev+0xe8> 30 | 3800150: 038001ec orreq r0, r0, #236, 2 ; 0x3b 31 | 3800154: 038001cc orreq r0, r0, #204, 2 ; 0x33 32 | 3800158: 038001c0 orreq r0, r0, #192, 2 ; 0x30 33 | 380015c: 038001b0 orreq r0, r0, #176, 2 ; 0x2c 34 | 3800160: 038001a0 orreq r0, r0, #160, 2 ; 0x28 35 | 3800164: 03800188 orreq r0, r0, #136, 2 ; 0x22 36 | 3800168: 038001d8 orreq r0, r0, #216, 2 ; 0x36 37 | 380016c: e1d138b4 ldrh r3, [r1, #132] ; 0x84 38 | 3800170: e3130c01 tst r3, #256 ; 0x100 39 | 3800174: 0afffff2 beq 3800144 <_Z11arm7_rwmodev+0x40> 40 | 3800178: e1d138b4 ldrh r3, [r1, #132] ; 0x84 41 | 380017c: e3130c01 tst r3, #256 ; 0x100 42 | 3800180: 1afffff9 bne 380016c <_Z11arm7_rwmodev+0x68> 43 | 3800184: eaffffee b 3800144 <_Z11arm7_rwmodev+0x40> 44 | 3800188: e59c3000 ldr r3, [r12] 45 | 380018c: e1a03803 lsl r3, r3, #16 46 | 3800190: e1a03823 lsr r3, r3, #16 47 | 3800194: e1c230b0 strh r3, [r2] 48 | 3800198: e58e4188 str r4, [r14, #392] ; 0x188 49 | 380019c: eaffffdf b 3800120 <_Z11arm7_rwmodev+0x1c> 50 | 38001a0: e59c3000 ldr r3, [r12] 51 | 38001a4: e5823000 str r3, [r2] 52 | 38001a8: e58e4188 str r4, [r14, #392] ; 0x188 53 | 38001ac: eaffffdb b 3800120 <_Z11arm7_rwmodev+0x1c> 54 | 38001b0: e5d23000 ldrb r3, [r2] 55 | 38001b4: e20330ff and r3, r3, #255 ; 0xff 56 | 38001b8: e58e3188 str r3, [r14, #392] ; 0x188 57 | 38001bc: eaffffd7 b 3800120 <_Z11arm7_rwmodev+0x1c> 58 | 38001c0: e1d230b0 ldrh r3, [r2] 59 | 38001c4: e58e3188 str r3, [r14, #392] ; 0x188 60 | 38001c8: eaffffd4 b 3800120 <_Z11arm7_rwmodev+0x1c> 61 | 38001cc: e5923000 ldr r3, [r2] 62 | 38001d0: e58e3188 str r3, [r14, #392] ; 0x188 63 | 38001d4: eaffffd1 b 3800120 <_Z11arm7_rwmodev+0x1c> 64 | 38001d8: e59c3000 ldr r3, [r12] 65 | 38001dc: e20330ff and r3, r3, #255 ; 0xff 66 | 38001e0: e5c23000 strb r3, [r2] 67 | 38001e4: e58e4188 str r4, [r14, #392] ; 0x188 68 | 38001e8: eaffffcc b 3800120 <_Z11arm7_rwmodev+0x1c> 69 | 38001ec: e3a03301 mov r3, #67108864 ; 0x4000000 70 | 38001f0: e3a02000 mov r2, #0 71 | 38001f4: e8bd4010 pop {r4, r14} 72 | 38001f8: e5832188 str r2, [r3, #392] ; 0x188 73 | 38001fc: e12fff1e bx r14 74 | 3800200: 04000100 streq r0, [r0], #-256 ; 0xffffff00 75 | 76 | 03800204 : 77 | 3800204: e3a00701 mov r0, #262144 ; 0x40000 78 | 3800208: e92d4010 push {r4, r14} 79 | 380020c: eb000145 bl 3800728 80 | 3800210: e3a01000 mov r1, #0 81 | 3800214: e3a03902 mov r3, #32768 ; 0x8000 82 | 3800218: e3a0cc02 mov r12, #512 ; 0x200 83 | 380021c: e3a00c01 mov r0, #256 ; 0x100 84 | 3800220: e59f2090 ldr r2, [pc, #144] ; 38002b8 85 | 3800224: e1c218b0 strh r1, [r2, #128] ; 0x80 86 | 3800228: e1c238b4 strh r3, [r2, #132] ; 0x84 87 | 380022c: e1d238b0 ldrh r3, [r2, #128] ; 0x80 88 | 3800230: e203300f and r3, r3, #15 89 | 3800234: e2433001 sub r3, r3, #1 90 | 3800238: e353000c cmp r3, #12 91 | 380023c: 979ff103 ldrls r15, [r15, r3, lsl #2] 92 | 3800240: eafffff9 b 380022c 93 | 3800244: 038002b0 orreq r0, r0, #176, 4 94 | 3800248: 038002a8 orreq r0, r0, #168, 4 ; 0x8000000a 95 | 380024c: 0380022c orreq r0, r0, #44, 4 ; 0xc0000002 96 | 3800250: 0380022c orreq r0, r0, #44, 4 ; 0xc0000002 97 | 3800254: 0380022c orreq r0, r0, #44, 4 ; 0xc0000002 98 | 3800258: 0380022c orreq r0, r0, #44, 4 ; 0xc0000002 99 | 380025c: 0380022c orreq r0, r0, #44, 4 ; 0xc0000002 100 | 3800260: 0380022c orreq r0, r0, #44, 4 ; 0xc0000002 101 | 3800264: 0380022c orreq r0, r0, #44, 4 ; 0xc0000002 102 | 3800268: 0380029c orreq r0, r0, #156, 4 ; 0xc0000009 103 | 380026c: 03800290 orreq r0, r0, #144, 4 104 | 3800270: 03800284 orreq r0, r0, #132, 4 ; 0x40000008 105 | 3800274: 03800278 orreq r0, r0, #120, 4 ; 0x80000007 106 | 3800278: eb0000f3 bl 380064c <_Z17arm7_ipcsync_testv> 107 | 380027c: e8bd4010 pop {r4, r14} 108 | 3800280: e12fff1e bx r14 109 | 3800284: eb000053 bl 38003d8 <_Z17arm7_ipcfifo_testv> 110 | 3800288: e8bd4010 pop {r4, r14} 111 | 380028c: e12fff1e bx r14 112 | 3800290: eb000099 bl 38004fc <_Z21arm7_ipcfifo_irq_testv> 113 | 3800294: e8bd4010 pop {r4, r14} 114 | 3800298: e12fff1e bx r14 115 | 380029c: ebffff98 bl 3800104 <_Z11arm7_rwmodev> 116 | 38002a0: e8bd4010 pop {r4, r14} 117 | 38002a4: e12fff1e bx r14 118 | 38002a8: e1c2c8b0 strh r12, [r2, #128] ; 0x80 119 | 38002ac: eaffffde b 380022c 120 | 38002b0: e1c208b0 strh r0, [r2, #128] ; 0x80 121 | 38002b4: eaffffdc b 380022c 122 | 38002b8: 04000100 streq r0, [r0], #-256 ; 0xffffff00 123 | 124 | 038002bc : 125 | 38002bc: 00000000 andeq r0, r0, r0 126 | 127 | 038002c0 : 128 | 38002c0: e10f0000 mrs r0, CPSR 129 | 38002c4: e50f0010 str r0, [pc, #-16] ; 38002bc 130 | 38002c8: eb000007 bl 38002ec 131 | 38002cc: eb000012 bl 380031c 132 | 133 | 038002d0 : 134 | 38002d0: eb000005 bl 38002ec 135 | 38002d4: ebffffca bl 3800204 136 | 38002d8: e59f0030 ldr r0, [pc, #48] ; 3800310 137 | 38002dc: e3a01000 mov r1, #0 138 | 38002e0: e5801000 str r1, [r0] 139 | 38002e4: eb000109 bl 3800710 140 | 38002e8: eafffff8 b 38002d0 141 | 142 | 038002ec : 143 | 38002ec: e10f3000 mrs r3, CPSR 144 | 38002f0: e1a04003 mov r4, r3 145 | 38002f4: e3c3301f bic r3, r3, #31 146 | 38002f8: e3833012 orr r3, r3, #18 147 | 38002fc: e121f003 msr CPSR_c, r3 148 | 3800300: e59fd00c ldr r13, [pc, #12] ; 3800314 149 | 3800304: e121f004 msr CPSR_c, r4 150 | 3800308: e59fd008 ldr r13, [pc, #8] ; 3800318 151 | 380030c: e12fff1e bx r14 152 | 3800310: 04000208 streq r0, [r0], #-520 ; 0xfffffdf8 153 | 3800314: 0380ff00 orreq r15, r0, #0, 30 154 | 3800318: 0380f000 orreq r15, r0, #0 155 | 156 | 0380031c : 157 | 380031c: e52de004 push {r14} ; (str r14, [r13, #-4]!) 158 | 3800320: e24dd00c sub r13, r13, #12 159 | 3800324: eb000106 bl 3800744 160 | 3800328: e3a0c402 mov r12, #33554432 ; 0x2000000 161 | 380032c: e3a0e903 mov r14, #49152 ; 0xc000 162 | 3800330: e59f1094 ldr r1, [pc, #148] ; 38003cc 163 | 3800334: e1d128b0 ldrh r2, [r1, #128] ; 0x80 164 | 3800338: e58c2004 str r2, [r12, #4] 165 | 380033c: e1d128b4 ldrh r2, [r1, #132] ; 0x84 166 | 3800340: e3a03000 mov r3, #0 167 | 3800344: e58c2008 str r2, [r12, #8] 168 | 3800348: e3a00641 mov r0, #68157440 ; 0x4100000 169 | 380034c: e1c1e8b4 strh r14, [r1, #132] ; 0x84 170 | 3800350: ea000004 b 3800368 171 | 3800354: e5902000 ldr r2, [r0] 172 | 3800358: e2833001 add r3, r3, #1 173 | 380035c: e3530015 cmp r3, #21 174 | 3800360: e58d2004 str r2, [r13, #4] 175 | 3800364: 0a000016 beq 38003c4 176 | 3800368: e1d128b4 ldrh r2, [r1, #132] ; 0x84 177 | 380036c: e3120c01 tst r2, #256 ; 0x100 178 | 3800370: 0afffff7 beq 3800354 179 | 3800374: e3a01402 mov r1, #33554432 ; 0x2000000 180 | 3800378: e3a02301 mov r2, #67108864 ; 0x4000000 181 | 380037c: e3a00000 mov r0, #0 182 | 3800380: e3e0e000 mvn r14, #0 183 | 3800384: e581300c str r3, [r1, #12] 184 | 3800388: e5923208 ldr r3, [r2, #520] ; 0x208 185 | 380038c: e5813010 str r3, [r1, #16] 186 | 3800390: e5923210 ldr r3, [r2, #528] ; 0x210 187 | 3800394: e5813014 str r3, [r1, #20] 188 | 3800398: e5923214 ldr r3, [r2, #532] ; 0x214 189 | 380039c: e59fc02c ldr r12, [pc, #44] ; 38003d0 190 | 38003a0: e5813018 str r3, [r1, #24] 191 | 38003a4: e5820208 str r0, [r2, #520] ; 0x208 192 | 38003a8: e5820210 str r0, [r2, #528] ; 0x210 193 | 38003ac: e582e214 str r14, [r2, #532] ; 0x214 194 | 38003b0: e59c3000 ldr r3, [r12] 195 | 38003b4: e581301c str r3, [r1, #28] 196 | 38003b8: e28dd00c add r13, r13, #12 197 | 38003bc: e49de004 pop {r14} ; (ldr r14, [r13], #4) 198 | 38003c0: e12fff1e bx r14 199 | 38003c4: e59f3008 ldr r3, [pc, #8] ; 38003d4 200 | 38003c8: eaffffe9 b 3800374 201 | 38003cc: 04000100 streq r0, [r0], #-256 ; 0xffffff00 202 | 38003d0: 038002bc orreq r0, r0, #188, 4 ; 0xc000000b 203 | 38003d4: 0000ffff strdeq r15, [r0], -r15 ; 204 | 205 | 038003d8 <_Z17arm7_ipcfifo_testv>: 206 | 38003d8: e3a03301 mov r3, #67108864 ; 0x4000000 207 | 38003dc: e59f20e4 ldr r2, [pc, #228] ; 38004c8 <_Z17arm7_ipcfifo_testv+0xf0> 208 | 38003e0: e92d4010 push {r4, r14} 209 | 38003e4: e3a00a01 mov r0, #4096 ; 0x1000 210 | 38003e8: e5832188 str r2, [r3, #392] ; 0x188 211 | 38003ec: eb0000cd bl 3800728 212 | 38003f0: e59f30d4 ldr r3, [pc, #212] ; 38004cc <_Z17arm7_ipcfifo_testv+0xf4> 213 | 38003f4: e1d328b4 ldrh r2, [r3, #132] ; 0x84 214 | 38003f8: e3120001 tst r2, #1 215 | 38003fc: 0a00002f beq 38004c0 <_Z17arm7_ipcfifo_testv+0xe8> 216 | 3800400: e1d328b4 ldrh r2, [r3, #132] ; 0x84 217 | 3800404: e3120002 tst r2, #2 218 | 3800408: 1a00002c bne 38004c0 <_Z17arm7_ipcfifo_testv+0xe8> 219 | 380040c: e1d328b4 ldrh r2, [r3, #132] ; 0x84 220 | 3800410: e3120c01 tst r2, #256 ; 0x100 221 | 3800414: 1a000029 bne 38004c0 <_Z17arm7_ipcfifo_testv+0xe8> 222 | 3800418: e1d328b4 ldrh r2, [r3, #132] ; 0x84 223 | 380041c: e3120c02 tst r2, #512 ; 0x200 224 | 3800420: 1a000026 bne 38004c0 <_Z17arm7_ipcfifo_testv+0xe8> 225 | 3800424: e1d328b4 ldrh r2, [r3, #132] ; 0x84 226 | 3800428: e3120901 tst r2, #16384 ; 0x4000 227 | 380042c: 1a000023 bne 38004c0 <_Z17arm7_ipcfifo_testv+0xe8> 228 | 3800430: e3a02641 mov r2, #68157440 ; 0x4100000 229 | 3800434: e592c000 ldr r12, [r2] 230 | 3800438: e5921000 ldr r1, [r2] 231 | 380043c: e5920000 ldr r0, [r2] 232 | 3800440: e1d328b4 ldrh r2, [r3, #132] ; 0x84 233 | 3800444: e3120001 tst r2, #1 234 | 3800448: 0a00001c beq 38004c0 <_Z17arm7_ipcfifo_testv+0xe8> 235 | 380044c: e1d328b4 ldrh r2, [r3, #132] ; 0x84 236 | 3800450: e3120002 tst r2, #2 237 | 3800454: 1a000019 bne 38004c0 <_Z17arm7_ipcfifo_testv+0xe8> 238 | 3800458: e1d328b4 ldrh r2, [r3, #132] ; 0x84 239 | 380045c: e3120c01 tst r2, #256 ; 0x100 240 | 3800460: 0a000016 beq 38004c0 <_Z17arm7_ipcfifo_testv+0xe8> 241 | 3800464: e1d328b4 ldrh r2, [r3, #132] ; 0x84 242 | 3800468: e3120c02 tst r2, #512 ; 0x200 243 | 380046c: 1a000013 bne 38004c0 <_Z17arm7_ipcfifo_testv+0xe8> 244 | 3800470: e59f2058 ldr r2, [pc, #88] ; 38004d0 <_Z17arm7_ipcfifo_testv+0xf8> 245 | 3800474: e59fe058 ldr r14, [pc, #88] ; 38004d4 <_Z17arm7_ipcfifo_testv+0xfc> 246 | 3800478: e15c0002 cmp r12, r2 247 | 380047c: 0151000e cmpeq r1, r14 248 | 3800480: 13a01001 movne r1, #1 249 | 3800484: 03a01000 moveq r1, #0 250 | 3800488: e2822001 add r2, r2, #1 251 | 380048c: e1500002 cmp r0, r2 252 | 3800490: 13811001 orrne r1, r1, #1 253 | 3800494: e1d338b4 ldrh r3, [r3, #132] ; 0x84 254 | 3800498: e1a03883 lsl r3, r3, #17 255 | 380049c: e1911fa3 orrs r1, r1, r3, lsr #31 256 | 38004a0: 1a000006 bne 38004c0 <_Z17arm7_ipcfifo_testv+0xe8> 257 | 38004a4: e3a03411 mov r3, #285212672 ; 0x11000000 258 | 38004a8: e3a01301 mov r1, #67108864 ; 0x4000000 259 | 38004ac: e59f2024 ldr r2, [pc, #36] ; 38004d8 <_Z17arm7_ipcfifo_testv+0x100> 260 | 38004b0: e5813188 str r3, [r1, #392] ; 0x188 261 | 38004b4: e2833001 add r3, r3, #1 262 | 38004b8: e1530002 cmp r3, r2 263 | 38004bc: 1afffffb bne 38004b0 <_Z17arm7_ipcfifo_testv+0xd8> 264 | 38004c0: e8bd4010 pop {r4, r14} 265 | 38004c4: e12fff1e bx r14 266 | 38004c8: 12345678 eorsne r5, r4, #120, 12 ; 0x7800000 267 | 38004cc: 04000100 streq r0, [r0], #-256 ; 0xffffff00 268 | 38004d0: 1844ccab stmdane r4, {r0, r1, r3, r5, r7, r10, r11, r14, r15}^ 269 | 38004d4: b914a201 ldmdblt r4, {r0, r9, r13, r15} 270 | 38004d8: 11000010 tstne r0, r0, lsl r0 271 | 272 | 038004dc <_ZL10irqhandlerv>: 273 | 38004dc: e3a01301 mov r1, #67108864 ; 0x4000000 274 | 38004e0: e3a00802 mov r0, #131072 ; 0x20000 275 | 38004e4: e3a02059 mov r2, #89 ; 0x59 276 | 38004e8: e59f3008 ldr r3, [pc, #8] ; 38004f8 <_ZL10irqhandlerv+0x1c> 277 | 38004ec: e5810214 str r0, [r1, #532] ; 0x214 278 | 38004f0: e5832000 str r2, [r3] 279 | 38004f4: e12fff1e bx r14 280 | 38004f8: 03800758 orreq r0, r0, #88, 14 ; 0x1600000 281 | 282 | 038004fc <_Z21arm7_ipcfifo_irq_testv>: 283 | 38004fc: e92d4010 push {r4, r14} 284 | 3800500: e3a00801 mov r0, #65536 ; 0x10000 285 | 3800504: eb000087 bl 3800728 286 | 3800508: e3a04301 mov r4, #67108864 ; 0x4000000 287 | 380050c: e3a03802 mov r3, #131072 ; 0x20000 288 | 3800510: e3a02001 mov r2, #1 289 | 3800514: e59f1080 ldr r1, [pc, #128] ; 380059c <_Z21arm7_ipcfifo_irq_testv+0xa0> 290 | 3800518: e59f0080 ldr r0, [pc, #128] ; 38005a0 <_Z21arm7_ipcfifo_irq_testv+0xa4> 291 | 380051c: e1c108b4 strh r0, [r1, #132] ; 0x84 292 | 3800520: e59f107c ldr r1, [pc, #124] ; 38005a4 <_Z21arm7_ipcfifo_irq_testv+0xa8> 293 | 3800524: e59f007c ldr r0, [pc, #124] ; 38005a8 <_Z21arm7_ipcfifo_irq_testv+0xac> 294 | 3800528: e5810ffc str r0, [r1, #4092] ; 0xffc 295 | 380052c: e5843214 str r3, [r4, #532] ; 0x214 296 | 3800530: e5843210 str r3, [r4, #528] ; 0x210 297 | 3800534: e5842208 str r2, [r4, #520] ; 0x208 298 | 3800538: eb00007d bl 3800734 299 | 380053c: e3a00029 mov r0, #41 ; 0x29 300 | 3800540: e3a02c81 mov r2, #33024 ; 0x8100 301 | 3800544: e59f1060 ldr r1, [pc, #96] ; 38005ac <_Z21arm7_ipcfifo_irq_testv+0xb0> 302 | 3800548: e3a03601 mov r3, #1048576 ; 0x100000 303 | 380054c: e5810000 str r0, [r1] 304 | 3800550: e5842188 str r2, [r4, #392] ; 0x188 305 | 3800554: ea000001 b 3800560 <_Z21arm7_ipcfifo_irq_testv+0x64> 306 | 3800558: e2533001 subs r3, r3, #1 307 | 380055c: 0a00000c beq 3800594 <_Z21arm7_ipcfifo_irq_testv+0x98> 308 | 3800560: e5912000 ldr r2, [r1] 309 | 3800564: e3520059 cmp r2, #89 ; 0x59 310 | 3800568: 1afffffa bne 3800558 <_Z21arm7_ipcfifo_irq_testv+0x5c> 311 | 380056c: e59f3028 ldr r3, [pc, #40] ; 380059c <_Z21arm7_ipcfifo_irq_testv+0xa0> 312 | 3800570: e59f2038 ldr r2, [pc, #56] ; 38005b0 <_Z21arm7_ipcfifo_irq_testv+0xb4> 313 | 3800574: e3a00a02 mov r0, #8192 ; 0x2000 314 | 3800578: e1c328b4 strh r2, [r3, #132] ; 0x84 315 | 380057c: eb000069 bl 3800728 316 | 3800580: e3a03301 mov r3, #67108864 ; 0x4000000 317 | 3800584: e3a01ea5 mov r1, #2640 ; 0xa50 318 | 3800588: e3a02000 mov r2, #0 319 | 380058c: e5831188 str r1, [r3, #392] ; 0x188 320 | 3800590: e5832208 str r2, [r3, #520] ; 0x208 321 | 3800594: e8bd4010 pop {r4, r14} 322 | 3800598: e12fff1e bx r14 323 | 380059c: 04000100 streq r0, [r0], #-256 ; 0xffffff00 324 | 38005a0: ffff800c ; instruction: 0xffff800c 325 | 38005a4: 0380f000 orreq r15, r0, #0 326 | 38005a8: 038004dc orreq r0, r0, #220, 8 ; 0xdc000000 327 | 38005ac: 03800758 orreq r0, r0, #88, 14 ; 0x1600000 328 | 38005b0: ffff8008 ; instruction: 0xffff8008 329 | 330 | 038005b4 <_ZL10irqhandlerv>: 331 | 38005b4: e3a03301 mov r3, #67108864 ; 0x4000000 332 | 38005b8: e3a02801 mov r2, #65536 ; 0x10000 333 | 38005bc: e92d4010 push {r4, r14} 334 | 38005c0: e59f4044 ldr r4, [pc, #68] ; 380060c <_ZL10irqhandlerv+0x58> 335 | 38005c4: e5832214 str r2, [r3, #532] ; 0x214 336 | 38005c8: e1d438b0 ldrh r3, [r4, #128] ; 0x80 337 | 38005cc: e203300f and r3, r3, #15 338 | 38005d0: e3530009 cmp r3, #9 339 | 38005d4: 0a000001 beq 38005e0 <_ZL10irqhandlerv+0x2c> 340 | 38005d8: e8bd4010 pop {r4, r14} 341 | 38005dc: e12fff1e bx r14 342 | 38005e0: e3a03c0b mov r3, #2816 ; 0xb00 343 | 38005e4: e3a01069 mov r1, #105 ; 0x69 344 | 38005e8: e59f2020 ldr r2, [pc, #32] ; 3800610 <_ZL10irqhandlerv+0x5c> 345 | 38005ec: e3a00a02 mov r0, #8192 ; 0x2000 346 | 38005f0: e5821000 str r1, [r2] 347 | 38005f4: e1c438b0 strh r3, [r4, #128] ; 0x80 348 | 38005f8: eb00004a bl 3800728 349 | 38005fc: e3a03a02 mov r3, #8192 ; 0x2000 350 | 3800600: e1c438b0 strh r3, [r4, #128] ; 0x80 351 | 3800604: e8bd4010 pop {r4, r14} 352 | 3800608: e12fff1e bx r14 353 | 380060c: 04000100 streq r0, [r0], #-256 ; 0xffffff00 354 | 3800610: 0380075c orreq r0, r0, #92, 14 ; 0x1700000 355 | 356 | 03800614 <_Z18wait_ipcsync_valuei>: 357 | 3800614: e3a02a01 mov r2, #4096 ; 0x1000 358 | 3800618: e59f1028 ldr r1, [pc, #40] ; 3800648 <_Z18wait_ipcsync_valuei+0x34> 359 | 380061c: ea000001 b 3800628 <_Z18wait_ipcsync_valuei+0x14> 360 | 3800620: e2522001 subs r2, r2, #1 361 | 3800624: 0a000005 beq 3800640 <_Z18wait_ipcsync_valuei+0x2c> 362 | 3800628: e1d138b0 ldrh r3, [r1, #128] ; 0x80 363 | 380062c: e203300f and r3, r3, #15 364 | 3800630: e1530000 cmp r3, r0 365 | 3800634: 1afffff9 bne 3800620 <_Z18wait_ipcsync_valuei+0xc> 366 | 3800638: e3a00001 mov r0, #1 367 | 380063c: e12fff1e bx r14 368 | 3800640: e1a00002 mov r0, r2 369 | 3800644: e12fff1e bx r14 370 | 3800648: 04000100 streq r0, [r0], #-256 ; 0xffffff00 371 | 372 | 0380064c <_Z17arm7_ipcsync_testv>: 373 | 380064c: e3a03b01 mov r3, #1024 ; 0x400 374 | 3800650: e92d4070 push {r4, r5, r6, r14} 375 | 3800654: e59f508c ldr r5, [pc, #140] ; 38006e8 <_Z17arm7_ipcsync_testv+0x9c> 376 | 3800658: e3a02a01 mov r2, #4096 ; 0x1000 377 | 380065c: e1c538b0 strh r3, [r5, #128] ; 0x80 378 | 3800660: ea000001 b 380066c <_Z17arm7_ipcsync_testv+0x20> 379 | 3800664: e2522001 subs r2, r2, #1 380 | 3800668: 0a00001c beq 38006e0 <_Z17arm7_ipcsync_testv+0x94> 381 | 380066c: e1d538b0 ldrh r3, [r5, #128] ; 0x80 382 | 3800670: e203300f and r3, r3, #15 383 | 3800674: e3530005 cmp r3, #5 384 | 3800678: 1afffff9 bne 3800664 <_Z17arm7_ipcsync_testv+0x18> 385 | 380067c: e3a03301 mov r3, #67108864 ; 0x4000000 386 | 3800680: e3a04801 mov r4, #65536 ; 0x10000 387 | 3800684: e3a02001 mov r2, #1 388 | 3800688: e3a0c00b mov r12, #11 389 | 380068c: e59f1058 ldr r1, [pc, #88] ; 38006ec <_Z17arm7_ipcsync_testv+0xa0> 390 | 3800690: e59f0058 ldr r0, [pc, #88] ; 38006f0 <_Z17arm7_ipcsync_testv+0xa4> 391 | 3800694: e59f6058 ldr r6, [pc, #88] ; 38006f4 <_Z17arm7_ipcsync_testv+0xa8> 392 | 3800698: e586c000 str r12, [r6] 393 | 380069c: e5810ffc str r0, [r1, #4092] ; 0xffc 394 | 38006a0: e5834214 str r4, [r3, #532] ; 0x214 395 | 38006a4: e5834210 str r4, [r3, #528] ; 0x210 396 | 38006a8: e5832208 str r2, [r3, #520] ; 0x208 397 | 38006ac: eb000020 bl 3800734 398 | 38006b0: e3a02c47 mov r2, #18176 ; 0x4700 399 | 38006b4: e1a03004 mov r3, r4 400 | 38006b8: e1c528b0 strh r2, [r5, #128] ; 0x80 401 | 38006bc: ea000001 b 38006c8 <_Z17arm7_ipcsync_testv+0x7c> 402 | 38006c0: e2533001 subs r3, r3, #1 403 | 38006c4: 0a000005 beq 38006e0 <_Z17arm7_ipcsync_testv+0x94> 404 | 38006c8: e5962000 ldr r2, [r6] 405 | 38006cc: e3520069 cmp r2, #105 ; 0x69 406 | 38006d0: 1afffffa bne 38006c0 <_Z17arm7_ipcsync_testv+0x74> 407 | 38006d4: e3a03301 mov r3, #67108864 ; 0x4000000 408 | 38006d8: e3a02000 mov r2, #0 409 | 38006dc: e5832208 str r2, [r3, #520] ; 0x208 410 | 38006e0: e8bd4070 pop {r4, r5, r6, r14} 411 | 38006e4: e12fff1e bx r14 412 | 38006e8: 04000100 streq r0, [r0], #-256 ; 0xffffff00 413 | 38006ec: 0380f000 orreq r15, r0, #0 414 | 38006f0: 038005b4 orreq r0, r0, #180, 10 ; 0x2d000000 415 | 38006f4: 0380075c orreq r0, r0, #92, 14 ; 0x1700000 416 | 417 | 038006f8 : 418 | 38006f8: e59f3008 ldr r3, [pc, #8] ; 3800708 419 | 38006fc: e59f2008 ldr r2, [pc, #8] ; 380070c 420 | 3800700: e5832400 str r2, [r3, #1024] ; 0x400 421 | 3800704: e12fff1e bx r14 422 | 3800708: 08004000 stmdaeq r0, {r14} 423 | 380070c: 08004400 stmdaeq r0, {r10, r14} 424 | 425 | 03800710 : 426 | 3800710: e59f3008 ldr r3, [pc, #8] ; 3800720 427 | 3800714: e59f2008 ldr r2, [pc, #8] ; 3800724 428 | 3800718: e5832500 str r2, [r3, #1280] ; 0x500 429 | 380071c: e12fff1e bx r14 430 | 3800720: 08005000 stmdaeq r0, {r12, r14} 431 | 3800724: 08005500 stmdaeq r0, {r8, r10, r12, r14} 432 | 433 | 03800728 : 434 | 3800728: e2500001 subs r0, r0, #1 435 | 380072c: 1afffffd bne 3800728 436 | 3800730: e12fff1e bx r14 437 | 438 | 03800734 : 439 | 3800734: e10f3000 mrs r3, CPSR 440 | 3800738: e3c33080 bic r3, r3, #128 ; 0x80 441 | 380073c: e121f003 msr CPSR_c, r3 442 | 3800740: e12fff1e bx r14 443 | 444 | 03800744 : 445 | 3800744: e10f3000 mrs r3, CPSR 446 | 3800748: e3833080 orr r3, r3, #128 ; 0x80 447 | 380074c: e121f003 msr CPSR_c, r3 448 | 3800750: e12fff1e bx r14 449 | 450 | 03800754 : 451 | 3800754: e12fff10 bx r0 452 | 453 | 03800758 : 454 | 3800758: 00000000 andeq r0, r0, r0 455 | 456 | 0380075c <_ZL5magic>: 457 | 380075c: 00000000 andeq r0, r0, r0 458 | 459 | Disassembly of section .ARM.attributes: 460 | 461 | 00000000 <.ARM.attributes>: 462 | 0: 00002541 andeq r2, r0, r1, asr #10 463 | 4: 61656100 cmnvs r5, r0, lsl #2 464 | 8: 01006962 tsteq r0, r2, ror #18 465 | c: 0000001b andeq r0, r0, r11, lsl r0 466 | 10: 00543405 subseq r3, r4, r5, lsl #8 467 | 14: 01080206 tsteq r8, r6, lsl #4 468 | 18: 04120109 ldreq r0, [r2], #-265 ; 0xfffffef7 469 | 1c: 01150114 tsteq r5, r4, lsl r1 470 | 20: 01180317 tsteq r8, r7, lsl r3 471 | 24: Address 0x0000000000000024 is out of bounds. 472 | 473 | 474 | Disassembly of section .comment: 475 | 476 | 00000000 <.comment>: 477 | 0: 3a434347 bcc 10d0d24 <_start-0x272f3dc> 478 | 4: 65642820 strbvs r2, [r4, #-2080]! ; 0xfffff7e0 479 | 8: 74696b76 strbtvc r6, [r9], #-2934 ; 0xfffff48a 480 | c: 204d5241 subcs r5, r13, r1, asr #4 481 | 10: 656c6572 strbvs r6, [r12, #-1394]! ; 0xfffffa8e 482 | 14: 20657361 rsbcs r7, r5, r1, ror #6 483 | 18: 20293635 eorcs r3, r9, r5, lsr r6 484 | 1c: 312e3131 ; instruction: 0x312e3131 485 | 20: Address 0x0000000000000020 is out of bounds. 486 | 487 | -------------------------------------------------------------------------------- /src9/tests/armv5.s: -------------------------------------------------------------------------------- 1 | .text 2 | .arm 3 | .align 2 4 | .global run_tests_armv5_clz 5 | .global run_tests_armv5_qadd_qsub, run_tests_armv5_qdadd_qdsub 6 | .global run_tests_armv5_SMLAxy, run_tests_armv5_SMULxy 7 | .global run_tests_armv5_SMLAWy, run_tests_armv5_SMULWy 8 | .global run_tests_armv5_SMLALxy 9 | .global run_tests_armv5_blx, run_tests_armv5_ldrpopr15 10 | .global run_tests_armv5_ldm_stm 11 | 12 | @ TODO. test ldrd, strd 13 | 14 | run_tests_armv5_clz: 15 | mov r0, #0x000 16 | mov r1, #0x80000000 17 | clz r2, r1 18 | cmp r2, #0 19 | bne fail_test 20 | 21 | mov r0, #0x001 22 | ldr r1, =0x0075ABCD 23 | clz r2, r1 24 | cmp r2, #9 25 | bne fail_test 26 | 27 | mov r0, #0x002 28 | mov r1, #1 29 | clz r2, r1 30 | cmp r2, #31 31 | bne fail_test 32 | 33 | mov r0, #0x003 34 | mov r1, #0 35 | clz r2, r1 36 | cmp r2, #32 37 | bne fail_test 38 | 39 | mov r0, #0x004 40 | ldr r1, =0x00004D33 41 | clz r1, r1 42 | cmp r1, #17 43 | bne fail_test 44 | 45 | mov r0, #0x005 46 | mov r1, #0x50000000 47 | clz r1, r1 48 | cmp r1, #1 49 | bne fail_test 50 | 51 | bx r14 52 | 53 | .ltorg 54 | 55 | run_tests_armv5_qadd_qsub: 56 | push {r4, r5} 57 | mov r4, #0 @ so we can do "msr cpsr_f, r4" to reset the Q flag 58 | msr cpsr_f, r4 @ clear Q flag 59 | 60 | mov r0, #0x000 61 | msr cpsr_f, r4 62 | mov r2, #2 63 | mov r3, #3 64 | qadd r1, r2, r3 @ 5, Q = 0 65 | cmp r1, #5 66 | bne fail_test 67 | mrs r5, cpsr 68 | tst r5, #1 << 27 69 | bne fail_test @ Q = 0 70 | 71 | mov r0, #0x001 72 | mov r2, #7 73 | mov r3, #-6 74 | qadd r1, r2, r3 @ 1, Q = 0 75 | cmp r1, #1 76 | bne fail_test 77 | mrs r5, cpsr 78 | tst r5, #1 << 27 79 | bne fail_test 80 | 81 | mov r0, #0x002 82 | mov r2, #-44 83 | mov r3, #-14 84 | qadd r1, r2, r3 @ -30, Q = 0 85 | cmp r1, #-58 86 | bne fail_test 87 | mrs r5, cpsr 88 | tst r5, #1 << 27 89 | bne fail_test 90 | 91 | mov r0, #0x003 92 | mov r2, #0x7FFFFFFF 93 | mov r3, #1 94 | qadd r1, r2, r3 @ still 7FFFFFFF, Q = 1 95 | cmp r1, r2 96 | bne fail_test 97 | mrs r5, cpsr 98 | tst r5, #1 << 27 99 | beq fail_test 100 | 101 | @ Q is still 1: test sticky behaviour 102 | mov r0, #0x004 103 | mov r2, #6 104 | mov r3, #7 105 | qadd r1, r2, r3 @ 13, Q is still 1 (not reset!) 106 | cmp r1, #13 107 | bne fail_test 108 | mrs r5, cpsr 109 | tst r5, #1 << 27 110 | beq fail_test 111 | msr cpsr_f, r4 112 | 113 | mov r0, #0x005 114 | mov r2, #0x7FFFFFFF 115 | mov r3, #-1 116 | qadd r1, r2, r3 @ 7FFFFFFE, Q = 0 117 | cmp r1, #0x7FFFFFFE 118 | bne fail_test 119 | mrs r5, cpsr 120 | tst r5, #1 << 27 121 | bne fail_test 122 | 123 | mov r0, #0x006 124 | mov r2, #0x80000000 125 | mov r3, #-1 126 | qadd r1, r2, r3 @ 80000000, Q = 1 127 | cmp r1, #0x80000000 128 | bne fail_test 129 | mrs r5, cpsr 130 | tst r5, #1 << 27 131 | beq fail_test 132 | msr cpsr_f, r4 133 | 134 | mov r0, #0x007 135 | mov r2, #0x80000000 136 | mov r3, #1 137 | qadd r1, r2, r3 @ 80000001, Q = 0 138 | cmp r1, #0x80000001 139 | bne fail_test 140 | mrs r5, cpsr 141 | tst r5, #1 << 27 142 | bne fail_test 143 | 144 | mov r0, #0x008 145 | mov r2, #0x7FFFFFFE 146 | mov r3, #1 147 | qadd r1, r2, r3 @ 7FFFFFFF, Q = 0 148 | cmp r1, #0x7FFFFFFF 149 | bne fail_test 150 | mrs r5, cpsr 151 | tst r5, #1 << 27 152 | bne fail_test 153 | 154 | mov r0, #0x009 155 | mov r2, #0x80000001 156 | mov r3, #-1 157 | qadd r1, r2, r3 @ 80000000, Q = 0 158 | cmp r1, #0x80000000 159 | bne fail_test 160 | mrs r5, cpsr 161 | tst r5, #1 << 27 162 | bne fail_test 163 | 164 | mov r0, #0x00A 165 | mov r2, #0x7FFFFFFF 166 | mov r3, #0x80000000 167 | qadd r1, r2, r3 @ FFFFFFFF, Q = 0 168 | cmp r1, #0xFFFFFFFF 169 | bne fail_test 170 | mrs r5, cpsr 171 | tst r5, #1 << 27 172 | bne fail_test 173 | 174 | 175 | mov r0, #0x010 176 | mov r2, #7 177 | mov r3, #11 178 | qsub r1, r2, r3 @ -4, Q = 0 179 | cmp r1, #-4 180 | bne fail_test 181 | mrs r5, cpsr 182 | tst r5, #1 << 27 183 | bne fail_test 184 | 185 | mov r0, #0x011 186 | mov r2, #0x7FFFFFFF 187 | mov r3, #0 188 | qsub r1, r2, r3 @ 0x7FFFFFFF, Q = 0 189 | cmp r1, r2 190 | bne fail_test 191 | mrs r5, cpsr 192 | tst r5, #1 << 27 193 | bne fail_test 194 | 195 | mov r0, #0x012 196 | mov r2, #0x7FFFFFFF 197 | mov r3, #-1 198 | qsub r1, r2, r3 @ 0x7FFFFFFF, Q = 1 199 | cmp r1, r2 200 | bne fail_test 201 | mrs r5, cpsr 202 | tst r5, #1 << 27 203 | beq fail_test 204 | msr cpsr_f, r4 205 | 206 | mov r0, #0x013 207 | mov r2, #0x7FFFFFFF 208 | mov r3, #1 209 | qsub r1, r2, r3 @ 0x7FFFFFFE, Q = 0 210 | cmp r1, #0x7FFFFFFE 211 | bne fail_test 212 | mrs r5, cpsr 213 | tst r5, #1 << 27 214 | bne fail_test 215 | 216 | mov r0, #0x014 217 | mov r2, #0x7FFFFFFE 218 | mov r3, #1 219 | qsub r1, r2, r3 @ 0x7FFFFFFD, Q = 0 220 | cmp r1, #0x7FFFFFFD 221 | bne fail_test 222 | mrs r5, cpsr 223 | tst r5, #1 << 27 224 | bne fail_test 225 | 226 | mov r0, #0x015 227 | mov r2, #0x7FFFFFFE 228 | mov r3, #-1 229 | qsub r1, r2, r3 @ 0x7FFFFFFF, Q = 0 230 | cmp r1, #0x7FFFFFFF 231 | bne fail_test 232 | mrs r5, cpsr 233 | tst r5, #1 << 27 234 | bne fail_test 235 | 236 | mov r0, #0x016 237 | mov r2, #0x7FFFFFFE 238 | mov r3, #-2 239 | qsub r1, r2, r3 @ 0x7FFFFFFF, Q = 1 240 | cmp r1, #0x7FFFFFFF 241 | bne fail_test 242 | mrs r5, cpsr 243 | tst r5, #1 << 27 244 | beq fail_test 245 | msr cpsr_f, r4 246 | 247 | mov r0, #0x017 248 | mov r2, #0x80000000 249 | mov r3, #0 250 | qsub r1, r2, r3 @ 0x80000000, Q = 0 251 | cmp r1, #0x80000000 252 | bne fail_test 253 | mrs r5, cpsr 254 | tst r5, #1 << 27 255 | bne fail_test 256 | 257 | mov r0, #0x018 258 | mov r2, #0x80000000 259 | mov r3, #-1 260 | qsub r1, r2, r3 @ 0x80000001, Q = 0 261 | cmp r1, #0x80000001 262 | bne fail_test 263 | mrs r5, cpsr 264 | tst r5, #1 << 27 265 | bne fail_test 266 | 267 | mov r0, #0x019 268 | mov r2, #0x80000000 269 | mov r3, #1 270 | qsub r1, r2, r3 @ 0x80000000, Q = 1 271 | cmp r1, #0x80000000 272 | bne fail_test 273 | mrs r5, cpsr 274 | tst r5, #1 << 27 275 | beq fail_test 276 | msr cpsr_f, r4 277 | 278 | mov r0, #0x01A 279 | mov r2, #214 280 | mov r3, #-11 281 | qsub r1, r2, r3 @ 225, Q = 0 282 | cmp r1, #225 283 | bne fail_test 284 | mrs r5, cpsr 285 | tst r5, #1 << 27 286 | bne fail_test 287 | 288 | pop {r4, r5} 289 | bx r14 290 | 291 | 292 | run_tests_armv5_qdadd_qdsub: 293 | push {r4, r5} 294 | mov r4, #0 295 | msr cpsr_f, r4 @ clear Q flag 296 | 297 | mov r0, #0x000 298 | mov r2, #106 299 | mov r3, #8 300 | qdadd r1, r2, r3 @ 122, Q = 0 301 | cmp r1, #122 302 | bne fail_test 303 | mrs r5, cpsr 304 | tst r5, #1 << 27 305 | bne fail_test 306 | 307 | mov r0, #0x001 308 | mov r2, #144 309 | mov r3, #-12 310 | qdadd r1, r2, r3 @ 120, Q = 0 311 | cmp r1, #120 312 | bne fail_test 313 | mrs r5, cpsr 314 | tst r5, #1 << 27 315 | bne fail_test 316 | 317 | mov r0, #0x002 318 | mov r2, #-11 319 | mov r3, #8 320 | qdadd r1, r2, r3 @ 5, Q = 0 321 | cmp r1, #5 322 | bne fail_test 323 | mrs r5, cpsr 324 | tst r5, #1 << 27 325 | bne fail_test 326 | 327 | mov r0, #0x003 328 | mov r2, #9 329 | mov r3, #-12 330 | qdadd r1, r2, r3 @ -15, Q = 0 331 | cmp r1, #-15 332 | bne fail_test 333 | mrs r5, cpsr 334 | tst r5, #1 << 27 335 | bne fail_test 336 | 337 | mov r0, #0x004 338 | ldr r2, =0x7FFFFFF8 @ can still add 7 without overflowing 339 | mov r3, #3 340 | qdadd r1, r2, r3 @ 7FFFFFFE, Q = 0 341 | ldr r5, =0x7FFFFFFE 342 | cmp r1, r5 343 | bne fail_test 344 | mrs r5, cpsr 345 | tst r5, #1 << 27 346 | bne fail_test 347 | 348 | mov r0, #0x005 349 | ldr r2, =0x7FFFFFF8 350 | mov r3, #4 351 | qdadd r1, r2, r3 @ 7FFFFFFF, Q = 1 352 | cmp r1, #0x7FFFFFFF 353 | bne fail_test 354 | mrs r5, cpsr 355 | tst r5, #1 << 27 356 | beq fail_test 357 | msr cpsr_f, r4 358 | 359 | mov r0, #0x006 360 | ldr r2, =0x7FFFFFF9 361 | mov r3, #3 362 | qdadd r1, r2, r3 @ 7FFFFFFF, Q = 0 363 | cmp r1, #0x7FFFFFFF 364 | bne fail_test 365 | mrs r5, cpsr 366 | tst r5, #1 << 27 367 | bne fail_test 368 | 369 | mov r0, #0x007 370 | mov r2, #0x80000005 @ can still subtract 5 without overflowing 371 | mov r3, #-2 372 | qdadd r1, r2, r3 @ 80000001, Q = 0 373 | cmp r1, #0x80000001 374 | bne fail_test 375 | mrs r5, cpsr 376 | tst r5, #1 << 27 377 | bne fail_test 378 | 379 | mov r0, #0x008 380 | mov r2, #0x80000005 381 | mov r3, #-3 382 | qdadd r1, r2, r3 @ 80000000, Q = 1 383 | cmp r1, #0x80000000 384 | bne fail_test 385 | mrs r5, cpsr 386 | tst r5, #1 << 27 387 | beq fail_test 388 | msr cpsr_f, r4 389 | 390 | mov r0, #0x009 391 | mov r2, #0x80000004 392 | mov r3, #-2 393 | qdadd r1, r2, r3 @ 80000000, Q = 0 394 | cmp r1, #0x80000000 395 | bne fail_test 396 | mrs r5, cpsr 397 | tst r5, #1 << 27 398 | bne fail_test 399 | 400 | @ + tests where doubling the second operand is already requiring clamping (and thus setting Q to 1) 401 | mov r0, #0x00A 402 | mov r2, #0x80000000 @ very small number 403 | mov r3, #0x7FFFFFFE @ very large number, only increases by 1 when doubling after clamping 404 | qdadd r1, r2, r3 @ -1, Q = 1 405 | cmp r1, #-1 406 | bne fail_test 407 | mrs r5, cpsr 408 | tst r5, #1 << 27 409 | beq fail_test 410 | msr cpsr_f, r4 411 | 412 | mov r0, #0x00B 413 | mov r2, #0x80000000 414 | mov r3, #0x3FFFFFFF @ can still be doubled without clamping 415 | qdadd r1, r2, r3 @ -2, Q = 0 416 | cmp r1, #-2 417 | bne fail_test 418 | mrs r5, cpsr 419 | tst r5, #1 << 27 420 | bne fail_test 421 | 422 | mov r0, #0x00C 423 | mov r2, #0x80000000 424 | mov r3, #0x40000000 @ can no longer be doubled without clamping 425 | qdadd r1, r2, r3 @ -1, Q = 1 426 | cmp r1, #-1 427 | bne fail_test 428 | mrs r5, cpsr 429 | tst r5, #1 << 27 430 | beq fail_test 431 | msr cpsr_f, r4 432 | 433 | mov r0, #0x00D 434 | mov r2, #0x7FFFFFFF @ large number 435 | mov r3, #0xC0000001 @ can be doubled 436 | qdadd r1, r2, r3 @ 1, Q = 0 437 | cmp r1, #1 438 | bne fail_test 439 | mrs r5, cpsr 440 | tst r5, #1 << 27 441 | bne fail_test 442 | 443 | mov r0, #0x00E 444 | mov r2, #0x7FFFFFFF @ large number 445 | mov r3, #0xC0000000 @ can be doubled but only barely (edge) 446 | qdadd r1, r2, r3 @ 1, Q = 0 447 | cmp r1, #-1 448 | bne fail_test 449 | mrs r5, cpsr 450 | tst r5, #1 << 27 451 | bne fail_test 452 | 453 | mov r0, #0x00F 454 | mov r2, #0x7FFFFFFF @ large number 455 | mov r3, #0xBFFFFFFF @ can no longer be doubled 456 | qdadd r1, r2, r3 @ 1, Q = 1 457 | cmp r1, #-1 458 | bne fail_test 459 | mrs r5, cpsr 460 | tst r5, #1 << 27 461 | beq fail_test 462 | msr cpsr_f, r4 463 | 464 | 465 | mov r0, #0x010 466 | mov r2, #106 467 | mov r3, #8 468 | qdsub r1, r2, r3 @ 90, Q = 0 469 | cmp r1, #90 470 | bne fail_test 471 | mrs r5, cpsr 472 | tst r5, #1 << 27 473 | bne fail_test 474 | 475 | mov r0, #0x011 476 | mov r2, #144 477 | mov r3, #-12 478 | qdsub r1, r2, r3 @ 168, Q = 0 479 | cmp r1, #168 480 | bne fail_test 481 | mrs r5, cpsr 482 | tst r5, #1 << 27 483 | bne fail_test 484 | 485 | mov r0, #0x012 486 | mov r2, #7 487 | mov r3, #58 488 | qdsub r1, r2, r3 @ -109, Q = 0 489 | cmp r1, #-109 490 | bne fail_test 491 | mrs r5, cpsr 492 | tst r5, #1 << 27 493 | bne fail_test 494 | 495 | mov r0, #0x013 496 | mov r2, #-18 497 | mov r3, #-12 498 | qdsub r1, r2, r3 @ 6, Q = 0 499 | cmp r1, #6 500 | bne fail_test 501 | mrs r5, cpsr 502 | tst r5, #1 << 27 503 | bne fail_test 504 | 505 | mov r0, #0x014 506 | ldr r2, =0x7FFFFFF8 @ can still add 7 507 | mov r3, #-3 508 | qdsub r1, r2, r3 @ 7FFFFFFE, Q = 0 509 | ldr r5, =0x7FFFFFFE 510 | cmp r1, r5 511 | bne fail_test 512 | mrs r5, cpsr 513 | tst r5, #1 << 27 514 | bne fail_test 515 | 516 | mov r0, #0x015 517 | ldr r2, =0x7FFFFFF8 518 | mov r3, #-4 519 | qdsub r1, r2, r3 @ 7FFFFFFF, Q = 1 520 | cmp r1, #0x7FFFFFFF 521 | bne fail_test 522 | mrs r5, cpsr 523 | tst r5, #1 << 27 524 | beq fail_test 525 | msr cpsr_f, r4 526 | 527 | mov r0, #0x016 528 | ldr r2, =0x7FFFFFF9 529 | mov r3, #-3 530 | qdsub r1, r2, r3 @ 7FFFFFFF, Q = 0 531 | cmp r1, #0x7FFFFFFF 532 | bne fail_test 533 | mrs r5, cpsr 534 | tst r5, #1 << 27 535 | bne fail_test 536 | 537 | mov r0, #0x017 538 | mov r2, #0x80000005 @ can still sub 5 539 | mov r3, #2 540 | qdsub r1, r2, r3 @ 80000001, Q = 0 541 | cmp r1, #0x80000001 542 | bne fail_test 543 | mrs r5, cpsr 544 | tst r5, #1 << 27 545 | bne fail_test 546 | 547 | mov r0, #0x018 548 | mov r2, #0x80000005 549 | mov r3, #3 550 | qdsub r1, r2, r3 @ 80000000, Q = 1 551 | cmp r1, #0x80000000 552 | bne fail_test 553 | mrs r5, cpsr 554 | tst r5, #1 << 27 555 | beq fail_test 556 | msr cpsr_f, r4 557 | 558 | mov r0, #0x019 559 | mov r2, #0x80000004 560 | mov r3, #2 561 | qdsub r1, r2, r3 @ 80000000, Q = 0 562 | cmp r1, #0x80000000 563 | bne fail_test 564 | mrs r5, cpsr 565 | tst r5, #1 << 27 566 | bne fail_test 567 | 568 | @ + tests where doubling the second operand is already requiring clamping (and thus setting Q to 1) 569 | mov r0, #0x01A 570 | mov r2, #0x7FFFFFFF 571 | mov r3, #0x7FFFFFFE 572 | qdsub r1, r2, r3 @ 0, Q = 1 573 | cmp r1, #0 574 | bne fail_test 575 | mrs r5, cpsr 576 | tst r5, #1 << 27 577 | beq fail_test 578 | msr cpsr_f, r4 579 | 580 | mov r0, #0x01B 581 | mov r2, #0x7FFFFFFF 582 | mov r3, #0x3FFFFFFF @ can still be doubled 583 | qdsub r1, r2, r3 @ -1, Q = 0 584 | cmp r1, #1 585 | bne fail_test 586 | mrs r5, cpsr 587 | tst r5, #1 << 27 588 | bne fail_test 589 | 590 | mov r0, #0x01C 591 | mov r2, #0x7FFFFFFF 592 | mov r3, #0x40000000 @ can't be doubled without clamping 593 | qdsub r1, r2, r3 @ 0, Q = 1 594 | cmp r1, #0 595 | bne fail_test 596 | mrs r5, cpsr 597 | tst r5, #1 << 27 598 | beq fail_test 599 | msr cpsr_f, r4 600 | 601 | mov r0, #0x01D 602 | mov r2, #0x80000000 603 | mov r3, #0xC0000001 @ can be doubled 604 | qdsub r1, r2, r3 @ -2, Q = 0 605 | cmp r1, #-2 606 | bne fail_test 607 | mrs r5, cpsr 608 | tst r5, #1 << 27 609 | bne fail_test 610 | 611 | mov r0, #0x01E 612 | mov r2, #0x80000000 613 | mov r3, #0xC0000000 @ edge case 614 | qdsub r1, r2, r3 @ 0, Q = 0 615 | cmp r1, #0 616 | bne fail_test 617 | mrs r5, cpsr 618 | tst r5, #1 << 27 619 | bne fail_test 620 | 621 | mov r0, #0x01F 622 | mov r2, #0x80000000 623 | mov r3, #0xBFFFFFFF @ can't be doubled without clamping 624 | qdsub r1, r2, r3 @ 0, Q = 1 625 | cmp r1, #0 626 | bne fail_test 627 | mrs r5, cpsr 628 | tst r5, #1 << 27 629 | beq fail_test 630 | msr cpsr_f, r4 631 | 632 | pop {r4, r5} 633 | bx r14 634 | 635 | 636 | run_tests_armv5_SMLAxy: 637 | push {r4, r5} 638 | mov r4, #0 @ to clear Q 639 | msr cpsr_f, r4 640 | 641 | mov r0, #0x000 642 | mov r2, #7 643 | mov r3, #10 644 | mov r5, #2 645 | smlabb r1, r2, r3, r5 @ 7*10 + 2 = 72 646 | cmp r1, #72 647 | bne fail_test 648 | mrs r5, cpsr 649 | tst r5, #1 << 27 650 | bne fail_test 651 | 652 | mov r0, #0x001 653 | mov r2, #-3 654 | mov r3, #11 655 | mov r5, #100 656 | smlabb r1, r2, r3, r5 @ -3*11 + 100 = 67 657 | cmp r1, #67 658 | bne fail_test 659 | mrs r5, cpsr 660 | tst r5, #1 << 27 661 | bne fail_test 662 | 663 | mov r0, #0x002 664 | mov r2, #16384 665 | mov r3, #2 666 | mov r5, #0 667 | smlabb r1, r2, r3, r5 @ 32768 668 | cmp r1, #32768 669 | bne fail_test 670 | mrs r5, cpsr 671 | tst r5, #1 << 27 672 | bne fail_test 673 | 674 | mov r0, #0x003 675 | mov r2, #65536 676 | sub r2, r2, #1 677 | mov r3, r2 678 | mov r5, #0 679 | smlabb r1, r2, r3, r5 @ 1 680 | cmp r1, #1 681 | bne fail_test 682 | mrs r5, cpsr 683 | tst r5, #1 << 27 684 | bne fail_test 685 | 686 | mov r0, #0x004 687 | mov r2, #1 688 | mov r3, #1 689 | mov r5, #0x7FFFFFFF 690 | smlabb r1, r2, r3, r5 @ 0x80000000, Q = 1 691 | cmp r1, #0x80000000 692 | bne fail_test 693 | mrs r5, cpsr 694 | tst r5, #1 << 27 695 | beq fail_test 696 | msr cpsr_f, r4 697 | 698 | mov r0, #0x005 699 | mov r2, #7 700 | mov r3, #0x40000 701 | mov r5, #-28 702 | smlabt r1, r2, r3, r5 703 | cmp r1, #0 704 | bne fail_test 705 | mrs r5, cpsr 706 | tst r5, #1 << 27 707 | bne fail_test 708 | 709 | mov r0, #0x006 710 | ldr r2, =0xFFFC1234 @ -4 (top halfword) 711 | mov r3, #57 712 | mov r5, #-1 713 | smlatb r1, r2, r3, r5 714 | cmp r1, #-229 715 | bne fail_test 716 | mrs r5, cpsr 717 | tst r5, #1 << 27 718 | bne fail_test 719 | 720 | mov r0, #0x007 721 | mov r2, #0x80000000 @ -32768 722 | mov r3, #0x7FFFFFFF @ 32767 723 | mov r5, #0 724 | smlatt r1, r2, r3, r5 725 | sub r1, r1, #0xC0000000 726 | cmp r1, #0x8000 727 | bne fail_test 728 | mrs r5, cpsr 729 | tst r5, #1 << 27 730 | bne fail_test 731 | 732 | mov r0, #0x008 733 | mov r2, #0x80000000 @ -32768 734 | mov r3, #0x7FFFFFFF @ 32767 735 | mov r5, #0x80000000 736 | smlatt r1, r2, r3, r5 737 | sub r1, r1, #0x40000000 738 | cmp r1, #0x8000 739 | bne fail_test 740 | mrs r5, cpsr 741 | tst r5, #1 << 27 742 | beq fail_test 743 | msr cpsr_f, r4 744 | 745 | @ + one test with same destination & accumulate register 746 | mov r0, #0x009 747 | mov r1, #100 748 | mov r2, #7 749 | mov r3, #-3 750 | smlabb r1, r2, r3, r1 @ 100 + 7*(-3) = 79 751 | cmp r1, #79 752 | bne fail_test 753 | 754 | pop {r4, r5} 755 | bx r14 756 | 757 | 758 | run_tests_armv5_SMULxy: 759 | @ clear Q flag 760 | mov r0, #0 761 | msr cpsr_f, r0 762 | 763 | mov r0, #0x000 764 | mov r2, #14 765 | mov r3, #5 766 | smulbb r1, r2, r3 767 | cmp r1, #70 768 | bne fail_test 769 | 770 | mov r0, #0x001 771 | mov r2, #-6 772 | mov r3, #104 773 | smulbb r1, r2, r3 774 | cmp r1, #-624 775 | bne fail_test 776 | 777 | mov r0, #0x002 778 | mov r2, #0xFFFFFFF0 779 | mov r3, #88 780 | smultb r1, r2, r3 781 | cmp r1, #-88 782 | bne fail_test 783 | 784 | mov r0, #0x003 785 | mov r2, #-14 786 | mov r3, #0x00050000 787 | add r3, r3, #0x830 788 | smulbt r1, r2, r3 789 | cmp r1, #-70 790 | bne fail_test 791 | 792 | mov r0, #0x004 @ check to make sure Q was not set: these can't cause overflow 793 | mrs r3, cpsr 794 | tst r3, #1 << 27 795 | bne fail_test 796 | 797 | bx r14 798 | 799 | 800 | run_tests_armv5_SMLAWy: 801 | push {r4, r5, r7} 802 | @ clear Q flag 803 | mov r4, #0 804 | msr cpsr_f, r4 805 | 806 | mov r0, #0x000 807 | mov r2, #47 808 | mov r3, #5 809 | mov r5, #-3 810 | smlawb r1, r2, r3, r5 @ wide r2, bottom of r3, (r2*half(r3)) >> 16 + Rn !! 811 | cmp r1, #-3 812 | bne fail_test 813 | mrs r5, cpsr 814 | tst r5, #1 << 27 815 | bne fail_test 816 | 817 | mov r0, #0x001 818 | mov r2, #0x90000 819 | mov r3, #-7 820 | mov r5, #2 821 | smlawb r1, r2, r3, r5 822 | cmp r1, #-61 823 | bne fail_test 824 | mrs r5, cpsr 825 | tst r5, #1 << 27 826 | bne fail_test 827 | 828 | mov r0, #0x002 829 | mov r2, #0x400 830 | mov r3, #0x500 831 | mov r5, #-1 832 | smlawb r1, r2, r3, r5 833 | cmp r1, #19 834 | bne fail_test 835 | mrs r5, cpsr 836 | tst r5, #1 << 27 837 | bne fail_test 838 | 839 | mov r0, #0x003 840 | mov r2, #0x4 841 | mov r3, #0x4000 842 | mov r5, #0x7FFFFFFF 843 | smlawb r1, r2, r3, r5 844 | cmp r1, #0x80000000 845 | bne fail_test 846 | mrs r5, cpsr 847 | tst r5, #1 << 27 848 | beq fail_test 849 | msr cpsr_f, r4 850 | 851 | mov r0, #0x004 852 | mov r2, #0x140000 853 | mov r3, #0xFFFEFFFF 854 | sub r3, r3, #0x0230 855 | mov r5, #-5 856 | smlawt r1, r2, r3, r5 @ -2 * 20 - 5 857 | cmp r1, #-45 858 | bne fail_test 859 | mrs r5, cpsr 860 | tst r5, #1 << 27 861 | bne fail_test 862 | 863 | mov r0, #0x005 864 | mov r2, #0x04D0 @ 1232 865 | mov r3, #0xC300 @ -15616 866 | mov r5, #0 867 | smlawb r1, r2, r3, r5 868 | ldr r7, =#-294 869 | cmp r1, r7 870 | bne fail_test 871 | mrs r5, cpsr 872 | tst r5, #1 << 27 873 | bne fail_test 874 | 875 | mov r0, #0x006 876 | mov r2, #4 877 | mov r3, #0x40000000 878 | mov r5, #0x7FFFFFFF 879 | smlawt r1, r2, r3, r5 880 | cmp r1, #0x80000000 881 | bne fail_test 882 | mrs r5, cpsr 883 | tst r5, #1 << 27 884 | beq fail_test 885 | msr cpsr_f, r4 886 | 887 | @ + one test with same destination & accumulate register 888 | mov r0, #0x007 889 | mov r1, #100 890 | mov r2, #7 << 16 891 | mov r3, #-3 892 | smlawb r1, r2, r3, r1 @ 100 + ((7 << 16)*(-3)) >> 16 = 79 893 | cmp r1, #79 894 | bne fail_test 895 | 896 | pop {r4, r5, r7} 897 | bx r14 898 | 899 | 900 | run_tests_armv5_SMULWy: 901 | push {r7} 902 | @ clear Q flag 903 | mov r0, #0 904 | msr cpsr_f, r0 905 | 906 | mov r0, #0x000 907 | mov r2, #15 908 | mov r3, #44 909 | smulwb r1, r2, r3 910 | cmp r1, #0 911 | bne fail_test 912 | 913 | mov r0, #0x001 914 | smulwt r1, r2, r3 915 | cmp r1, #0 916 | bne fail_test 917 | 918 | mov r0, #0x002 919 | mov r2, #188 920 | mov r3, #0x7700 921 | smulwb r1, r2, r3 922 | cmp r1, #87 923 | bne fail_test 924 | 925 | mov r0, #0x003 926 | mov r2, #-188 927 | smulwb r1, r2, r3 928 | cmp r1, #-88 929 | bne fail_test 930 | 931 | mov r0, #0x004 932 | mov r2, #-241 933 | mov r3, #-69 934 | mov r2, r2, lsl #11 935 | smulwb r1, r2, r3 936 | ldr r7, =519 937 | cmp r1, r7 938 | bne fail_test 939 | 940 | mov r0, #0x005 941 | mov r2, #0x51000 942 | add r2, r2, #0x9A 943 | mov r3, #0x4000000 944 | smulwt r1, r2, r3 945 | ldr r7, =5186 946 | cmp r1, r7 947 | bne fail_test 948 | 949 | mov r0, #0x006 @ check to make sure Q wasn't set 950 | mrs r7, cpsr 951 | tst r7, #1 << 27 952 | bne fail_test 953 | 954 | pop {r7} 955 | bx r14 956 | 957 | 958 | run_tests_armv5_SMLALxy: 959 | push {r4, r7} 960 | @ SMLALxy (RdLo RdHi Rm Rs) (RdHiLo += HalfRm * HalfRs) (doesn't set Q even though there can be overflow!!) 961 | @ result in r1 (lo) r2 (hi), Rm = r3, Rs = r4 962 | mov r0, #0x000 963 | mov r1, #0 964 | mov r2, #0 965 | mov r3, #7 966 | mov r4, #18 967 | smlalbb r1, r2, r3, r4 968 | cmp r1, #126 969 | bne fail_test 970 | cmp r2, #0 971 | bne fail_test 972 | 973 | mov r0, #0x001 974 | mov r1, #0 975 | mov r3, #-7 976 | smlalbb r1, r2, r3, r4 977 | cmp r1, #-126 978 | bne fail_test 979 | cmp r2, #0xFFFFFFFF 980 | bne fail_test 981 | 982 | mov r0, #0x002 983 | ldr r1, =0x12345678 984 | mov r2, r1 985 | mov r3, #0x4700 986 | mov r4, #0x06D0 987 | smlalbb r1, r2, r3, r4 988 | ldr r7, =337118840 989 | cmp r1, r7 990 | bne fail_test 991 | ldr r7, =0x12345678 992 | cmp r2, r7 993 | bne fail_test 994 | 995 | mov r0, #0x003 996 | mov r1, #0 997 | mov r2, #1 998 | mov r3, #0xFFFFFFFF 999 | sub r3, r3, #0x0C10 @ ? 1000 | mov r4, #7 1001 | smlaltb r1, r2, r3, r4 1002 | cmp r1, #-7 1003 | bne fail_test 1004 | cmp r2, #0 1005 | bne fail_test 1006 | 1007 | mov r0, #0x004 1008 | mov r1, #4000 1009 | mov r2, #8 1010 | mov r3, #-7 1011 | mov r4, #0x150000 1012 | smlalbt r1, r2, r3, r4 1013 | ldr r7, =3853 1014 | cmp r1, r7 1015 | bne fail_test 1016 | cmp r2, #8 1017 | bne fail_test 1018 | 1019 | mov r0, #0x005 @ make sure Q was not set 1020 | mrs r4, cpsr 1021 | tst r4, #1 << 27 1022 | bne fail_test 1023 | 1024 | pop {r4, r7} 1025 | bx r14 1026 | 1027 | 1028 | run_tests_armv5_blx: 1029 | push {r5-r7, r14} 1030 | @ blx tests 1031 | ldr r3, =fail_test @ so we can do 'bx r3' instead of 'b fail_test_t' in thumb: the second doesn't work, it's too far away 1032 | ldr r5, =test_cpu_state @ we will branch to this address and it will return whether the branch ended in ARM or thumb (r7 = 1 or 2) 1033 | ldr r6, =test_cpu_state_thumb @ required for it to work 1034 | 1035 | @@ two sanity checks 1036 | @ use bx with lowest bit set to 0, must be ARM 1037 | mov r0, #0x000 1038 | bic r1, r5, #1 @ make sure bottom bit is cleared 1039 | mov r14, r15 @ set r14 to address of the instruction after the "bx r4" 1040 | bx r1 1041 | cmp r7, #1 1042 | bne fail_test 1043 | 1044 | @ same but with lowest bit set to 1, must be thumb 1045 | mov r0, #0x001 1046 | orr r1, r5, #1 1047 | mov r14, r15 1048 | bx r1 1049 | cmp r7, #2 1050 | bne fail_test 1051 | 1052 | @@ blx reg 1053 | mov r0, #0x002 1054 | bic r1, r5, #1 1055 | blx r1 1056 | cmp r7, #1 1057 | bne fail_test 1058 | 1059 | mov r0, #0x003 1060 | orr r1, r5, #1 1061 | blx r1 1062 | cmp r7, #2 1063 | bne fail_test 1064 | 1065 | @ blx with offset (always changes from arm to thumb) 1066 | mov r0, #0x004 1067 | blx test_cpu_state 1068 | cmp r7, #2 1069 | bne fail_test 1070 | 1071 | @@ now change to thumb mode and test those blx 1072 | add r1, r15, #1 1073 | bx r1 1074 | 1075 | .thumb 1076 | @ register blx 1077 | mov r0, #0x005 1078 | lsr r1, r5, #1 @ clear bit 0 1079 | lsl r1, r1, #1 @ 1080 | blx r1 1081 | cmp r7, #1 1082 | beq skip1 1083 | bx r3 1084 | skip1: 1085 | mov r0, #0x006 1086 | mov r1, #1 @ set bit 0 1087 | orr r1, r5 @ 1088 | blx r1 1089 | cmp r7, #2 1090 | beq skip2 1091 | bx r3 1092 | skip2: 1093 | @ blx with offset (two 16-bit instructions) (always changes from thumb to arm) 1094 | mov r0, #0x007 1095 | blx test_cpu_state 1096 | cmp r7, #1 1097 | beq skip3 1098 | bx r3 1099 | skip3: 1100 | 1101 | @ go back to ARM 1102 | .align 2 1103 | mov r1, r15 1104 | bx r1 1105 | 1106 | .align 2 1107 | .arm 1108 | 1109 | pop {r5-r7, r15} 1110 | 1111 | 1112 | run_tests_armv5_ldrpopr15: 1113 | push {r5-r7, r14} 1114 | 1115 | @ test ldr r15, [...] and pop {r15} being able to change state 1116 | ldr r3, =fail_test @ so we can do 'bx r3' instead of 'b fail_test_t' in thumb: the second doesn't work, it's too far away 1117 | ldr r5, =test_cpu_state @ we will branch to this address and it will return whether the branch ended in ARM or thumb (r7 = 1 or 2) 1118 | ldr r6, =test_cpu_state_thumb @ required for it to work 1119 | str r5, buffer 1120 | orr r2, r5, #1 @ r2 = r5 with thumb bit set 1121 | str r2, buffer+4 1122 | 1123 | @ test ldr r15, ... 1124 | mov r0, #0x000 1125 | mov r14, r15 1126 | ldr r15, buffer 1127 | cmp r7, #1 1128 | bne fail_test 1129 | 1130 | mov r0, #0x001 1131 | mov r14, r15 1132 | ldr r15, buffer+4 1133 | cmp r7, #2 1134 | bne fail_test 1135 | 1136 | @ test pop {r15}: pop multiple things because the assembler turns pop {r15} into ldr r15, [r13], #4 1137 | @ should probably just do .word (pop {r15} instruction) 1138 | mov r0, #0x002 1139 | push {r0, r5} 1140 | mov r14, r15 1141 | pop {r0, r15} 1142 | cmp r7, #1 1143 | bne fail_test 1144 | 1145 | mov r0, #0x003 1146 | push {r0, r2} 1147 | mov r14, r15 1148 | pop {r0, r15} 1149 | cmp r7, #2 1150 | bne fail_test 1151 | 1152 | @ make sure that mov r15, ... does not change to thumb 1153 | mov r0, #0x004 1154 | mov r14, r15 1155 | mov r15, r5 1156 | cmp r7, #1 1157 | bne fail_test 1158 | 1159 | mov r0, #0x005 1160 | mov r14, r15 1161 | mov r15, r2 1162 | cmp r7, #1 1163 | bne fail_test 1164 | 1165 | @@ now change to thumb mode and test pop {r15} (no ldr r15, ...) 1166 | add r1, r15, #1 1167 | bx r1 1168 | 1169 | .thumb 1170 | @ pop {r15} 1171 | mov r0, #0x006 1172 | push {r5} 1173 | @ set r14 to address of instruction after pop {r15}, + thumb bit (maybe change to PC relative load?) 1174 | mov r1, r15 @ r1 = address of "mov r14, r1" 1175 | add r1, #5 @ +5 -> address of "cmp r7, #1" + thumb bit 1176 | mov r14, r1 1177 | pop {r15} 1178 | cmp r7, #1 1179 | beq skip4 1180 | bx r3 1181 | skip4: 1182 | 1183 | mov r0, #0x007 1184 | push {r2} 1185 | @ set r14 to address of instruction after pop {r15}, + thumb bit 1186 | mov r1, r15 @ r1 = address of "mov r14, r1" 1187 | add r1, #5 @ +5 -> address of "cmp r7, #2" + thumb bit 1188 | mov r14, r1 1189 | pop {r15} 1190 | cmp r7, #2 1191 | beq skip5 1192 | bx r3 1193 | skip5: 1194 | @ make sure that mov r15, ... does not change to arm 1195 | mov r0, #0x008 1196 | @ set r14 to address of instruction after mov r15, r5, + thumb bit 1197 | mov r1, r15 @ r1 = address of "mov r14, r1" 1198 | add r1, #5 @ +5 -> address of "cmp r7, #2" + thumb bit 1199 | mov r14, r1 1200 | mov r15, r5 1201 | cmp r7, #2 1202 | beq skip6 1203 | bx r3 1204 | skip6: 1205 | 1206 | mov r0, #0x009 1207 | @ set r14 to address of instruction after mov r15, r2, + thumb bit 1208 | mov r1, r15 @ r1 = address of "mov r14, r1" 1209 | add r1, #5 @ +5 -> address of "cmp r7, #2" + thumb bit 1210 | mov r14, r1 1211 | mov r15, r2 1212 | cmp r7, #2 1213 | beq skip7 1214 | bx r3 1215 | skip7: 1216 | 1217 | @ go back to ARM 1218 | .align 2 1219 | mov r1, r15 1220 | bx r1 1221 | 1222 | .align 2 1223 | .arm 1224 | pop {r5-r7, r15} 1225 | @ will contain test_cpu_state and test_cpu_state|1 (thumb bit set) (could just be initialized in the ROM itself but whatever) 1226 | buffer: 1227 | .word 0, 0 1228 | 1229 | 1230 | 1231 | 1232 | wrong: 1233 | .word 0x11111111 1234 | .word 0x11111111 1235 | .word 0x11111111 1236 | .word 0x11111111 1237 | .word 0x11111111 1238 | .word 0x11111111 1239 | 1240 | random_data: 1241 | .word 0xC0FFEEAB 1242 | .word 0xDEADBEEF 1243 | .word 0xD00DFEED 1244 | .word 0xC0CAC01A 1245 | .word 0x01234567 1246 | .word 0x89ABCDEF 1247 | 1248 | old_state: 1249 | .space 0x40 1250 | 1251 | overwrite_me: 1252 | .space 0x40 1253 | 1254 | run_tests_armv5_ldm_stm: 1255 | @ save all the registers, because we're about to 1256 | @ overwrite them all (except r0 and r12) 1257 | ldr r0, =old_state 1258 | stmia r0!, {r1-r11, r13-r14} 1259 | 1260 | @ r0 = the test # we are on 1261 | mov r0, #0 1262 | 1263 | @ TEST: simple ldmia with writeback (ldmia r1!, {r2}) 1264 | @ expected: 1265 | @ 0. r2 = 0xC0FFEEAB 1266 | @ 1. r1 = r1 + 4 1267 | 1268 | ldr r1, =random_data 1269 | ldmia r1!, {r2} 1270 | 1271 | @ TEST 0 1272 | ldr r3, =random_data 1273 | ldr r3, [r3] 1274 | cmp r3, r2 1275 | bne fail_test_ldm_stm 1276 | add r0, #1 1277 | 1278 | @ TEST 1 1279 | ldr r3, =random_data 1280 | add r3, #4 1281 | cmp r3, r1 1282 | bne fail_test_ldm_stm 1283 | add r0, #1 1284 | 1285 | @ TEST: simple stmia with writeback (stmia r1!, {r2}) 1286 | @ expected: 1287 | @ 2. [r1] = 0xC0FFEEAB 1288 | @ 3. r1 = r1 + 4 1289 | 1290 | ldr r1, =overwrite_me 1291 | ldr r2, =random_data 1292 | ldr r2, [r2] 1293 | stmia r1!, {r2} 1294 | 1295 | @ TEST 2 1296 | ldr r3, =random_data 1297 | ldr r3, [r3] 1298 | ldr r4, =overwrite_me 1299 | ldr r4, [r4] 1300 | cmp r3, r4 1301 | bne fail_test_ldm_stm 1302 | add r0, #1 1303 | 1304 | @ TEST 3 1305 | ldr r3, =overwrite_me 1306 | add r3, #4 1307 | cmp r3, r1 1308 | bne fail_test_ldm_stm 1309 | add r0, #1 1310 | 1311 | @ those were just the sanity checks. let's get started 1312 | 1313 | @ TEST: ldmia with writeback with base in rlist (ldmia r1!, {r1}) 1314 | @ expected: 1315 | @ 4. r1 = r1 + 4 1316 | 1317 | ldr r1, =random_data 1318 | ldmia r1!, {r1} 1319 | 1320 | @ TEST 4 1321 | ldr r3, =random_data 1322 | add r3, #4 1323 | cmp r3, r1 1324 | bne fail_test_ldm_stm 1325 | add r0, #1 1326 | 1327 | @ TEST: ldmia with writeback with base last in rlist (ldmia r3!, {r1-r3}) 1328 | @ expected: 1329 | @ 5. r1 = 0xC0FFEEAB 1330 | @ 6. r2 = 0xDEADBEEF 1331 | @ 7. r3 = 0xD00DFEED 1332 | 1333 | ldr r3, =random_data 1334 | ldmia r3!, {r1-r3} 1335 | 1336 | ldr r4, =random_data 1337 | 1338 | @ TEST 5 1339 | ldr r5, [r4], #4 1340 | cmp r5, r1 1341 | bne fail_test_ldm_stm 1342 | add r0, #1 1343 | 1344 | @ TEST 6 1345 | ldr r5, [r4], #4 1346 | cmp r5, r2 1347 | bne fail_test_ldm_stm 1348 | add r0, #1 1349 | 1350 | @ TEST 7 1351 | ldr r5, [r4], #4 1352 | cmp r5, r3 1353 | bne fail_test_ldm_stm 1354 | add r0, #1 1355 | 1356 | @ TEST: ldmia with writeback with base not last in rlist (ldmia r2!, {r1-r3}) 1357 | @ expected: 1358 | @ 8. r1 = 0xC0FFEEAB 1359 | @ 9. r3 = 0xD00DFEED 1360 | @ A. r2 = r2 + 12 1361 | 1362 | ldr r2, =random_data 1363 | ldmia r2!, {r1-r3} 1364 | 1365 | ldr r4, =random_data 1366 | 1367 | @ TEST 8 1368 | ldr r5, [r4], #8 1369 | cmp r5, r1 1370 | bne fail_test_ldm_stm 1371 | add r0, #1 1372 | 1373 | @ TEST 9 1374 | ldr r5, [r4], #4 1375 | cmp r5, r3 1376 | bne fail_test_ldm_stm 1377 | add r0, #1 1378 | 1379 | @ TEST A 1380 | ldr r1, =random_data 1381 | add r1, #12 1382 | cmp r1, r2 1383 | bne fail_test_ldm_stm 1384 | add r0, #1 1385 | 1386 | @ TEST: ldmia with writeback with empty rlist (ldmia r2!, {}) 1387 | @ expected: 1388 | @ B. r2 = r2 + 0x40 1389 | 1390 | ldr r2, =random_data 1391 | .word 0xE8B20000 @ ldmia r2!, {r1-r3} 1392 | 1393 | @ TEST B 1394 | ldr r3, =random_data 1395 | add r3, #0x40 1396 | cmp r3, r2 1397 | bne fail_test_ldm_stm 1398 | add r0, #1 1399 | 1400 | @ TEST: simple ldmia with S bit with writeback (ldmia r13!, {r14}^) 1401 | @ expected: 1402 | @ C. r14_irq = 0 1403 | @ D. r13_irq = r1 + 4 1404 | @ E. r14_user = 0xC0FFEEAB 1405 | @ F. r13_user = &wrong 1406 | 1407 | ldr r13, =wrong @ make you read from some wrong place if you use the wrong reg bank 1408 | mov r14, #0 1409 | 1410 | mov r1, #0x12 @ IRQ mode 1411 | msr cpsr, r1 1412 | 1413 | ldr r13, =random_data 1414 | mov r14, #0 1415 | 1416 | ldmia r13!, {r14}^ 1417 | 1418 | @ TEST C 1419 | mov r3, #0 1420 | cmp r3, r14 1421 | bne fail_test_ldm_stm 1422 | add r0, #1 1423 | 1424 | @ TEST D 1425 | ldr r3, =random_data 1426 | add r3, #4 1427 | cmp r3, r13 1428 | bne fail_test_ldm_stm 1429 | add r0, #1 1430 | 1431 | mov r1, #0x1F @ User mode 1432 | msr cpsr, r1 1433 | 1434 | @ TEST E 1435 | ldr r3, =random_data 1436 | ldr r3, [r3] 1437 | cmp r3, r14 1438 | bne fail_test_ldm_stm 1439 | add r0, #1 1440 | 1441 | @ TEST F 1442 | ldr r3, =wrong 1443 | cmp r3, r13 1444 | bne fail_test_ldm_stm 1445 | add r0, #1 1446 | 1447 | @ TEST: ldmia with base in rlist with S bit (ldmia r13, {r13}^) 1448 | @ expected: 1449 | @ 10. r13_irq = unchanged 1450 | @ 11. r13_user = 0xC0FFEEAB 1451 | 1452 | ldr r13, =wrong @ make you read from some wrong place if you use the wrong reg bank 1453 | 1454 | mov r1, #0x12 @ IRQ mode 1455 | msr cpsr, r1 1456 | 1457 | ldr r13, =random_data 1458 | ldmia r13, {r13}^ 1459 | 1460 | @ TEST 10 1461 | ldr r3, =random_data 1462 | cmp r3, r13 1463 | bne fail_test_ldm_stm 1464 | add r0, #1 1465 | 1466 | mov r1, #0x1F @ User mode 1467 | msr cpsr, r1 1468 | 1469 | @ TEST 11 1470 | ldr r3, =random_data 1471 | ldr r3, [r3] 1472 | cmp r3, r13 1473 | bne fail_test_ldm_stm 1474 | add r0, #1 1475 | 1476 | @ TEST: stmia with writeback with base in rlist (stmia r1!, {r1}) 1477 | @ expected: 1478 | @ 12. r1 = r1 + 4 1479 | @ 13. [r1] = &overwrite_me 1480 | 1481 | ldr r1, =overwrite_me 1482 | stmia r1!, {r1} 1483 | 1484 | @ TEST 12 1485 | ldr r3, =overwrite_me 1486 | add r3, #4 1487 | cmp r3, r1 1488 | bne fail_test_ldm_stm 1489 | add r0, #1 1490 | 1491 | @ TEST 13 1492 | ldr r3, =overwrite_me 1493 | ldr r2, [r3] 1494 | cmp r2, r3 1495 | bne fail_test_ldm_stm 1496 | add r0, #1 1497 | 1498 | @ TEST: stmia with writeback with base last in rlist (stmia r3!, {r1-r3}) 1499 | @ expected: 1500 | @ 14. [r3 + 0] = 0xDEADBEEF 1501 | @ 15. [r3 + 4] = 0xC0FFEEAB 1502 | @ 16. [r3 + 8] = &overwrite_me 1503 | @ 17. r3 = r3 + 12 1504 | 1505 | ldr r3, =random_data 1506 | ldr r2, [r3], #4 1507 | ldr r1, [r3], #4 1508 | ldr r3, =overwrite_me 1509 | stmia r3!, {r1-r3} 1510 | 1511 | @ TEST 14 1512 | ldr r4, =random_data 1513 | ldr r4, [r4, #4] 1514 | ldr r5, =overwrite_me 1515 | ldr r5, [r5] 1516 | cmp r4, r5 1517 | bne fail_test_ldm_stm 1518 | add r0, #1 1519 | 1520 | @ TEST 15 1521 | ldr r4, =random_data 1522 | ldr r4, [r4] 1523 | ldr r5, =overwrite_me 1524 | ldr r5, [r5, #4] 1525 | cmp r4, r5 1526 | bne fail_test_ldm_stm 1527 | add r0, #1 1528 | 1529 | @ TEST 16 1530 | ldr r4, =overwrite_me 1531 | ldr r5, [r4, #8] 1532 | cmp r4, r5 1533 | bne fail_test_ldm_stm 1534 | add r0, #1 1535 | 1536 | @ TEST 17 1537 | ldr r4, =overwrite_me 1538 | add r4, #12 1539 | cmp r4, r3 1540 | bne fail_test_ldm_stm 1541 | add r0, #1 1542 | 1543 | end_test: 1544 | ldr r12, =old_state 1545 | ldmia r12!, {r1-r11, r13-r14} 1546 | bx lr 1547 | 1548 | fail_test_ldm_stm: 1549 | ldr r12, =old_state 1550 | ldmia r12!, {r1-r11, r13-r14} 1551 | b fail_test 1552 | 1553 | --------------------------------------------------------------------------------