# HG changeset patch # User nkeynes # Date 1232973143 0 # Node ID e57a25d9eb7ded0fd03fbbc5f13a0ce91d91d709 # Parent 007bf7eb944f52c9a8a38d6d41d9636d5283b449 Add some initial TLB test cases --- a/test/Makefile.in Mon Jan 26 07:26:24 2009 +0000 +++ b/test/Makefile.in Mon Jan 26 12:32:23 2009 +0000 @@ -75,7 +75,7 @@ # $(RUNTEST) testide -d ../disc/test.nrg -build-tests: testsh4 testmath testide testta testregs testrend testdisp testspu testmmu +build-tests: testsh4 testmmu testmath testide testta testregs testrend testdisp testspu testmmu lib/crt0.so: lib/crt0.s $(mkdir_p) lib @@ -97,14 +97,15 @@ $(SH4CC) $(SH4LDFLAGS) $^ -o $@ $(SH4LIBS) $(SH4OBJCOPY) testsh4 testsh4.bin +testmmu: lib/crt0.so sh4/testmmu.so sh4/utlb.so sh4/testutlb.so sh4/mmummio.so + $(SH4CC) $(SH4LDFLAGS) $^ -o $@ $(SH4LIBS) + $(SH4OBJCOPY) testmmu testmmu.bin + + testide: lib/crt0.so $(SHARED_OBJECTS) testide.so ide.so $(SH4CC) $(SH4LDFLAGS) $^ -o $@ $(SH4LIBS) $(SH4OBJCOPY) testide testide.bin -testmmu: lib/crt0.so $(SHARED_OBJECTS) testmmu.so - $(SH4CC) $(SH4LDFLAGS) $^ -o $@ $(SH4LIBS) - $(SH4OBJCOPY) testmmu testmmu.bin - testmath: lib/crt0.so $(SHARED_OBJECTS) testmath.so math.so $(SH4CC) $(SH4LDFLAGS) $^ -o $@ $(SH4LIBS) --- a/test/lib.h Mon Jan 26 07:26:24 2009 +0000 +++ b/test/lib.h Mon Jan 26 12:32:23 2009 +0000 @@ -61,4 +61,23 @@ #define CHECK_IEQUALS( a, b ) if( a != b ) { fprintf(stderr, "Assertion failed at %s:%d: expected %08X, but was %08X\n", __FILE__, __LINE__, a, b ); return -1; } #define DMA_ALIGN(x) ((void *)((((unsigned int)(x))+0x1F)&0xFFFFFFE0)) + +/* SH4 Exceptions */ +#define POWERON 0x000 /* reset vector */ +#define MANRESET 0x020 /* reset vector */ +#define OTLBMULTIHIT 0x140 /* reset vector */ +#define RTLBMISS 0x040 /* TLB vector */ +#define WTLBMISS 0x060 /* TLB vector */ +#define FIRSTWRITE 0x080 +#define READPROT 0x0A0 +#define WRITEPROT 0x0C0 +#define RADDERR 0x0E0 +#define WADDERR 0x100 +#define FPUEXC 0x120 +#define ILLSLOT 0x1A0 +#define RESINST 0x180 +#define TRAP 0x160 +#define FPUDIS 0x800 +#define SLOTFPUDIS 0x820 + #endif --- a/test/lib/crt0.s Mon Jan 26 07:26:24 2009 +0000 +++ b/test/lib/crt0.s Mon Jan 26 12:32:23 2009 +0000 @@ -47,6 +47,9 @@ lds r3,fpscr #endif /* defined (__SH3E__) || defined(__SH4_SINGLE__) || defined(__SH4__) || defined(__SH4_SINGLE_ONLY__) */ + mov.l sr_data, r1 + ldc r1, sr + ! call the mainline mov.l main_k,r0 jsr @r0 @@ -103,6 +106,8 @@ .long start_2 p2_mask: .long 0xa0000000 +sr_data: + .long 0x400000f0 ccr_addr: .long 0xff00001c ccr_data: --- a/test/sh4/ldc.s Mon Jan 26 07:26:24 2009 +0000 +++ b/test/sh4/ldc.s Mon Jan 26 12:32:23 2009 +0000 @@ -4,17 +4,19 @@ .global _test_ldc _test_ldc: start_test + mov.l r8, @-r15 + mov.l r9, @-r15 test_ldcsr_1: add #1, r12 - stc sr, r0 + stc sr, r8 mov #-1, r1 ldc r1, sr - stc sr, r2 - ldc r0, sr + stc sr, r9 + ldc r8, sr mov.l sr_mask, r3 - cmp/eq r2, r3 + cmp/eq r9, r3 bt test_ldsfpscr_1 fail test_ldc_str_k @@ -31,6 +33,8 @@ fail test_ldc_str_k test_ldc_end: + mov.l @r15+, r9 + mov.l @r15+, r8 end_test test_ldc_str_k test_ldc_str: --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sh4/mmummio.c Mon Jan 26 12:32:23 2009 +0000 @@ -0,0 +1,61 @@ +#include +#include +#include "../lib.h" + +#define PTEH 0xFF000000 +#define PTEL 0xFF000004 +#define TTB 0xFF000008 +#define TEA 0xFF00000C +#define MMUCR 0xFF000010 +#define PTEA 0xFF000034 + +#define ITLB_ADDR(entry) (0xF2000000 + (entry<<8)) +#define ITLB_DATA(entry) (0xF3000000 + (entry<<8)) +#define UTLB_ADDR(entry) (0xF6000000 + (entry<<8)) +#define UTLB_DATA1(entry) (0xF7000000 + (entry<<8)) +#define UTLB_DATA2(entry) (0xF7800000 + (entry<<8)) + +/* Bang on the mmio side of the TLBs to make sure the bits + * respond appropriately (with AT disabled so we don't risk + * doing a hard crash) */ +void test_tlb_mmio() +{ + int entry; + for( entry=0; entry<64; entry++ ) { + long_write( UTLB_DATA1(entry), 0 ); + long_write( UTLB_ADDR(entry), 0xFFFFFFFF ); + assert( long_read( UTLB_ADDR(entry) ) == 0xFFFFFFFF ); + assert( long_read( UTLB_DATA1(entry) ) == 0x00000104 ); + long_write( UTLB_ADDR(entry), 0x00000000 ); + assert( long_read( UTLB_ADDR(entry) ) == 0x00000000 ); + assert( long_read( UTLB_DATA1(entry) ) == 0x00000000 ); + long_write( UTLB_DATA1(entry), 0xFFFFFFFF ); + assert( long_read( UTLB_DATA1(entry) ) == 0x1FFFFDFF ); + assert( long_read( UTLB_ADDR(entry) ) == 0x00000300 ); + long_write( UTLB_DATA1(entry), 0x00000000 ); + assert( long_read( UTLB_DATA1(entry) ) == 0x00000000 ); + assert( long_read( UTLB_ADDR(entry) ) == 0x00000000 ); + long_write( UTLB_DATA2(entry), 0xFFFFFFFF ); + assert( long_read( UTLB_DATA2(entry) ) == 0x0000000F ); + long_write( UTLB_DATA2(entry), 0x00000000 ); + assert( long_read( UTLB_DATA2(entry) ) == 0x00000000 ); + } + + for( entry=0; entry<4; entry++ ) { + long_write( ITLB_DATA(entry), 0 ); + long_write( ITLB_ADDR(entry), 0xFFFFFFFF ); + assert( long_read( ITLB_ADDR(entry) ) == 0xFFFFFDFF ); + assert( long_read( ITLB_DATA(entry) ) == 0x00000100 ); + long_write( ITLB_ADDR(entry), 0x00000000 ); + assert( long_read( ITLB_ADDR(entry) ) == 0x00000000 ); + assert( long_read( ITLB_DATA(entry) ) == 0x00000000 ); + long_write( ITLB_DATA(entry), 0xFFFFFFFF ); + assert( long_read( ITLB_DATA(entry) ) == 0x1FFFFDDA ); + assert( long_read( ITLB_ADDR(entry) ) == 0x00000100 ); + long_write( ITLB_DATA(entry), 0x00000000 ); + assert( long_read( ITLB_DATA(entry) ) == 0x00000000 ); + assert( long_read( ITLB_ADDR(entry) ) == 0x00000000 ); + + } +} + --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sh4/testmmu.c Mon Jan 26 12:32:23 2009 +0000 @@ -0,0 +1,117 @@ +#include "utlb.h" +#include "../lib.h" + +struct utlb_test_case { + const char *name; + uint32_t vma; + uint32_t pma; + int read_exc; + int write_exc; +}; + +#define OK 0 + +#define MAX_BATCH_ENTRIES 4 +#define MAX_BATCH_TESTS 8 + +uint32_t dummy; + +#define LOAD(ent,asid,vpn,ppn,mode) load_utlb_entry( ent, vpn, ppn, asid, mode ) +#define TEST(name,asid,vma,pma,sr,sw,ur,uw) run_utlb_test_case(name,asid,vma,pma,sr,sw,ur,uw) + +int run_utlb_priv_test( struct utlb_test_case *test ); +int run_utlb_user_test( struct utlb_test_case *test ); + +int cases_failed; +int cases_run; +int tests_failed; +int tests_run; +int tests_skipped; + +int run_utlb_test_case( const char *name, int asid, unsigned int vma, unsigned int pma, + int sr, int sw, int ur, int uw ) +{ + char tmp[64]; + struct utlb_test_case test = { tmp, vma, pma, sr, sw }; + int fails = 0; + + cases_run++; + + set_asid( asid ); + if( sr == OTLBMULTIHIT || sw == OTLBMULTIHIT ) { + fprintf( stderr, "%s: Skipping system test (multihit)\n", name ); + tests_skipped += 2; + } else { + snprintf(tmp,sizeof(tmp), "%s (System)", name ); + tests_run += 2; + fails += run_utlb_priv_test( &test ); + } + + if( ur == OTLBMULTIHIT || uw == OTLBMULTIHIT ) { + fprintf( stderr, "%s: Skipping user test '%s' (multihit)\n", name ); + tests_skipped += 2; + } else { + snprintf(tmp,sizeof(tmp), "%s (User)", name ); + test.read_exc = ur; + test.write_exc = uw; + tests_run += 2; + fails += run_utlb_user_test( &test ); + } + if( fails != 0 ) { + cases_failed++; + tests_failed += fails; + } + return fails; +} + +int main() +{ + /* Non-TLB behaviour tests */ + + + /* TLB tests */ + install_utlb_test_handler(); + invalidate_tlb(); + /* Permanently map the first and last MB of RAM into userspace - without + * this it's a bit hard to actually run any user-mode tests. + */ + LOAD(62, 0, 0x0C000000, 0x0C000000, TLB_VALID|TLB_USERMODE|TLB_WRITABLE|TLB_SIZE_1M|TLB_CACHEABLE|TLB_DIRTY|TLB_SHARE); + LOAD(63, 0, 0x0CF00000, 0x0CF00000, TLB_VALID|TLB_USERMODE|TLB_WRITABLE|TLB_SIZE_1M|TLB_CACHEABLE|TLB_DIRTY|TLB_SHARE); + set_tlb_enabled(1); + + /* Test miss */ + TEST( "U0", 0, 0x12345008, 0x0c000018, RTLBMISS, WTLBMISS, RTLBMISS, WTLBMISS ); + TEST( "P1", 0, 0x8c000018, 0x0c000018, OK, OK, RADDERR, WADDERR ); + TEST( "P1", 0, 0xac000018, 0x0c000018, OK, OK, RADDERR, WADDERR ); + TEST( "P3", 0, 0xC4345008, 0x0c000018, RTLBMISS, WTLBMISS, RADDERR, WADDERR ); + + /* Test flags with 1K pages */ + LOAD( 0, 0, 0x12345C00, 0x0C000000, TLB_VALID|TLB_USERMODE|TLB_WRITABLE|TLB_SIZE_1K|TLB_CACHEABLE|TLB_DIRTY ); + LOAD( 1, 1, 0x12345C00, 0x0CFFFC00, TLB_VALID|TLB_USERMODE|TLB_WRITABLE|TLB_SIZE_1K|TLB_CACHEABLE|TLB_DIRTY ); + LOAD( 2, 0, 0x12345800, 0x0C000800, TLB_VALID|TLB_WRITABLE|TLB_SIZE_1K|TLB_CACHEABLE|TLB_DIRTY ); + LOAD( 3, 0, 0x12345400, 0x0C000400, TLB_VALID|TLB_USERMODE|TLB_SIZE_1K|TLB_CACHEABLE|TLB_DIRTY ); + LOAD( 4, 0, 0x12345000, 0x0C000000, TLB_VALID|TLB_SIZE_1K|TLB_CACHEABLE|TLB_DIRTY ); + LOAD( 5, 1, 0x12345800, 0x0CF01800, TLB_VALID|TLB_USERMODE|TLB_WRITABLE|TLB_SIZE_1K|TLB_CACHEABLE ); + LOAD( 6, 1, 0x12346000, 0x0C000000, TLB_VALID|TLB_WRITABLE|TLB_SIZE_1K|TLB_CACHEABLE ); + LOAD( 7, 2, 0x12346800, 0x0C000400, TLB_VALID|TLB_USERMODE|TLB_WRITABLE|TLB_SIZE_1K|TLB_CACHEABLE|TLB_SHARE|TLB_DIRTY ); + TEST( "1K ASID 0", 0, 0x12345C18, 0x0C000018, OK, OK, OK, OK ); + TEST( "1K ASID 1", 1, 0x12345C18, 0x0CFFFC18, OK, OK, OK, OK ); + TEST( "1K ASID 2", 2, 0x12345C18, 0x0C000018, RTLBMISS, WTLBMISS, RTLBMISS, WTLBMISS ); + TEST( "1K PRIV", 0, 0x12345818, 0x0C000818, OK, OK, READPROT, WRITEPROT ); + TEST( "1K READONLY", 0, 0x12345418, 0x0C000418, OK, WRITEPROT, OK, WRITEPROT ); + TEST( "1K PRIVREAD", 0, 0x12345018, 0x0C000018, OK, WRITEPROT, READPROT, WRITEPROT ); + TEST( "1K FIRSTWR", 1, 0x12345818, 0x0CF01818, OK, FIRSTWRITE, OK, FIRSTWRITE ); + TEST( "1K PRIVFWR", 1, 0x12346018, 0x0C000018, OK, FIRSTWRITE, READPROT, WRITEPROT ); + TEST( "1K MISS", 1, 0x12346418, 0x0C000018, RTLBMISS, WTLBMISS, RTLBMISS, WTLBMISS ); + TEST( "1K SHARED 0", 0, 0x12346818, 0x0C000418, OK, OK, OK, OK ); + TEST( "1K SHARED 2", 2, 0x12346818, 0x0C000418, OK, OK, OK, OK ); + + + uninstall_utlb_test_handler(); + + + printf( "--> %d/%d Test cases passed (%d%%)\n", cases_run-cases_failed, cases_run, ( (cases_run-cases_failed)*100/cases_run) ); + printf( "--> %d/%d Tests passed (%d%%)\n", tests_run-tests_failed, tests_run, ( (tests_run-tests_failed)*100/tests_run) ); + + return cases_failed == 0 ? 0 : 1; +} --- a/test/sh4/testsh4.c Mon Jan 26 07:26:24 2009 +0000 +++ b/test/sh4/testsh4.c Mon Jan 26 12:32:23 2009 +0000 @@ -14,6 +14,9 @@ void test_print_failure( char *testname, int number, char *message ) { + fprintf( stderr, "Fail" ); + fprintf( stderr, testname ); + if( message == NULL ) { fprintf( stderr, "%s: Test %d failed!\n", testname, number ); } else { --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sh4/testutlb.s Mon Jan 26 12:32:23 2009 +0000 @@ -0,0 +1,720 @@ + + +.global _install_utlb_test_handler +_install_utlb_test_handler: + mov.l utlb_old_vbr_k, r0 + stc vbr, r1 + mov.l r1, @r0 + + mov.l utlb_vbr_k, r0 + ldc r0, vbr + rts + nop + +.global _uninstall_utlb_test_handler +_uninstall_utlb_test_handler: + mov.l utlb_old_vbr_k, r0 + mov.l @r0, r0 + ldc r0, vbr + rts + nop + +utlb_exc_handler: + mov.l utlb_exc_stack_k, r15 + mov.l r0, @-r15 + mov.l r1, @-r15 + mov.l r2, @-r15 + sts pr, r0 + mov.l r0, @-r15 + + mov.l mmu_expevt_k, r2 + mov.l @r2, r2 + mov r2, r0 + shlr2 r0 + cmp/eq #0x58, r0 + bt utlb_trap + + mov.l utlb_exc_k_1, r0 + mov.l @(16,r0), r1 + tst r1, r1 + bt utlb_exc_unexpected + + mov.l @r0, r1 + tst r1, r1 + bf utlb_exc_set + mov.l r2, @r0 + stc spc, r2 + mov.l r2, @(8,r0) + +utlb_exc_set: + mov.l @(4,r0), r2 + add #1, r2 + mov.l r2, @(4,r0) + + mov.l @(12,r0), r2 + stc spc, r1 + add r2, r1 + ldc r1, spc + +utlb_exc_done: + mov.l @r15+, r0 + lds r0, pr + mov.l @r15+, r2 + mov.l @r15+, r1 + mov.l @r15+, r0 + rte + stc sgr, r15 + +utlb_trap: + mov.l mmu_tra_k, r2 + mov.l @r2, r0 + shlr2 r0 + cmp/eq #42, r0 + bt utlb_trap_priv + cmp/eq #41, r0 + bt utlb_trap_printf + bra utlb_exc_done + nop +utlb_trap_priv: + stc ssr, r0 + mov.l mmu_sr_md, r1 + or r1, r0 + ldc r0, ssr + bra utlb_exc_done + nop +utlb_trap_printf: + stc sr, r0 + mov.l mmu_sr_rb_mask, r1 + and r1, r0 + ldc r0, sr + mov.l utlb_printf_k, r0 + jsr @r0 + nop + bra utlb_exc_done + nop +utlb_exc_unexpected: /* Report an unexpected exception. Save everything in case printf clobbers it */ + mov.l r3, @-r15 + mov.l r4, @-r15 + mov.l r5, @-r15 + mov.l r6, @-r15 + mov.l r7, @-r15 + mov.l r8, @-r15 + mov.l r9, @-r15 + mov.l r10, @-r15 + mov.l r11, @-r15 + mov.l r12, @-r15 + mov.l r13, @-r15 + mov.l r14, @-r15 + sts fpscr, r0 + mov.l r0, @-r15 + + stc spc, r6 + mov r2, r5 + mov.l utlb_unexpected_msg_k, r4 + mov.l utlb_printf_k, r3 + jsr @r3 + nop + + mov.l @r15+, r0 + lds r0, fpscr + mov.l @r15+, r14 + mov.l @r15+, r13 + mov.l @r15+, r12 + mov.l @r15+, r11 + mov.l @r15+, r10 + mov.l @r15+, r9 + mov.l @r15+, r8 + mov.l @r15+, r7 + mov.l @r15+, r6 + mov.l @r15+, r5 + mov.l @r15+, r4 + mov.l @r15+, r3 + mov.l utlb_exc_k_1, r0 + bra utlb_exc_set + nop + + +.align 4 +utlb_vbr_k: + .long utlb_vbr +utlb_old_vbr_k: + .long utlb_old_vbr +utlb_exc_k_1: + .long utlb_exc +mmu_expevt_k: + .long 0xFF000024 +mmu_tra_k: + .long 0xFF000020 +mmu_sr_md: + .long 0x40000000 +mmu_sr_rb_mask: + .long 0x50000000 +utlb_exc_stack_k: + .long utlb_exc_stack +utlb_printf_k: + .long _printf +utlb_unexpected_msg_k: + .long utlb_unexpected_msg + + .skip 0x1F00 /* 8K stack */ +utlb_vbr: + .skip 0x100 +utlb_exc_stack: + mov.l utlb_exc_handler_k1, r15 + jmp @r15 + nop + nop +utlb_exc_handler_k1: + .long utlb_exc_handler + + .skip 0x2F4 + mov.l utlb_exc_handler_k2, r15 + jmp @r15 + nop + nop +utlb_exc_handler_k2: + .long utlb_exc_handler + .skip 0x1F4 + rte + stc sgr, r15 + + +utlb_expect_exc: + mova utlb_exc, r0 + xor r1, r1 + mov.l r1, @r0 + mov.l r1, @(4,r0) + mov.l r1, @(8,r0) + mov #1, r1 + mov.l r1, @(16,r0) + mov #2, r1 + mov.l r1, @(12,r0) + rts + nop + +utlb_noexpect_exc: + mova utlb_exc, r0 + xor r1, r1 + mov.l r1, @r0 + mov.l r1, @(4,r0) + mov.l r1, @(8,r0) + mov.l r1, @(16,r0) + mov #2, r1 + mov.l r1, @(12,r0) + rts + nop + +/* Check the result of a read test. Call with: + * r0 = expected spc + * r1 = value read (if any) + * r9 = (char *) testname + * r10 = test VMA + * r11 = test PMA + * r12 = expected exc + * + * Trashes r0..r7 + */ +utlb_check_read_exc: + mov.l utlb_exc_k, r3 + mov.l addr_mask, r2 + and r2, r3 + + mov.l @r3, r2 + cmp/eq r2, r12 + bf test_read_exc_bad + tst r12, r12 + bt test_read_ok /* Expected no exception, and got none */ + mov.l @(4,r3), r2 + dt r2 + bf test_read_count_bad + mov.l @(8,r3), r2 + cmp/eq r0, r2 + bt test_read_ok +test_read_pc_bad: + add #1, r14 + mov r0, r6 + mov.l err_read_pc_msg_k, r4 + mov r2, r7 + mov r9, r5 + trapa #41 + bra test_read_ok + nop +test_read_count_bad: + add #1, r14 + add #2, r2 + mov.l err_read_count_msg_k, r4 + mov r2, r6 + mov r9, r5 + trapa #41 + bra test_read_ok + nop +test_read_exc_bad: + add #1, r14 + mov.l err_read_exc_msg_k, r4 + mov r12, r6 + mov r2, r7 + mov r9, r5 + trapa #41 + bra test_read_ok + nop +test_read_ok: + bra utlb_expect_exc + nop + +/* Check the result of a write test (and clears the exception). Call with: + * r0 = expected spc + * r1 = written value + * r9 = (char *) testname + * r10 = test VMA + * r11 = test PMA + * r13 = expected exc + * r14 = fail count (updated) + * + * Trashes r0..r7 + */ +utlb_check_write_exc: + mov.l utlb_exc_k, r3 + mov.l addr_mask, r2 + and r2, r3 + + mov.l @r3, r2 + cmp/eq r2, r13 + bf test_write_exc_bad + tst r13, r13 + bt test_write_ok /* Expected no exception, and got none */ + mov.l @(4,r3), r2 + dt r2 + bf test_write_count_bad + mov.l @(8,r3), r2 + cmp/eq r0, r2 + bt test_write_ok +test_write_pc_bad: + add #1, r14 + mov r0, r6 + mov.l err_write_pc_msg_k, r4 + mov r2, r7 + mov r9, r5 + trapa #41 + bra test_write_ok + nop +test_write_count_bad: + add #1, r14 + add #1, r2 + mov.l err_write_count_msg_k, r4 + mov r2, r6 + mov r9, r5 + trapa #41 + bra test_write_ok + nop +test_write_exc_bad: + add #1, r14 + mov.l err_write_exc_msg_k, r4 + mov r13, r6 + mov r2, r7 + mov r9, r5 + trapa #41 + bra test_write_ok + nop +test_write_ok: + bra utlb_expect_exc + nop +.align 4 +utlb_exc_k: + .long utlb_exc +err_read_exc_msg_k: + .long err_read_exc_msg +err_read_count_msg_k: + .long err_read_count_msg +err_read_pc_msg_k: + .long err_read_pc_msg +err_write_exc_msg_k: + .long err_write_exc_msg +err_write_count_msg_k: + .long err_write_count_msg +err_write_pc_msg_k: + .long err_write_pc_msg + +.align 4 +utlb_old_vbr: + .long 0 +utlb_exc: + .long 0 +utlb_exc_count: + .long 0 +utlb_exc_spc: + .long 0 +utlb_rte_offset: + .long 2 +utlb_expected: + .long 0 + +.global _run_utlb_priv_test +_run_utlb_priv_test: + mov.l r14, @-r15 + sts pr, r0 + mov.l r0, @-r15 + mov.l r13, @-r15 + mov.l r12, @-r15 + mov.l r11, @-r15 + mov.l r10, @-r15 + mov.l r9, @-r15 + mov.l r8, @-r15 + + mov.l @(0,r4), r9 /* Test name */ + mov.l @(4,r4), r10 /* Test VMA */ + mov.l @(8,r4), r11 /* Test PMA */ + mov.l @(12,r4), r12 /* Read exception */ + mov.l @(16,r4), r13 /* Write exception */ + xor r14, r14 /* Fail count */ + + mov.l @r11, r0 /* Save original memory value */ + ocbp @r11 + mov.l r0, @-r15 + + tst r12, r12 + bt utlb_read_test_noexc + +/* Exception test cases - all should fail with the same exception */ +utlb_read_test_exc: + mov r10, r8 + bsr utlb_expect_exc + nop + +/* Test mov.l Rm, Rn */ + mova test_readl_1, r0 +.align 4 +test_readl_1: + mov.l @r10, r1 + bsr utlb_check_read_exc + nop + +/* Test mov.l @Rm+, Rn */ + mova test_readl_2, r0 +.align 4 +test_readl_2: + mov.l @r8+, r1 + bsr utlb_check_read_exc + nop + cmp/eq r8,r10 + bt test_readl_2_ok + + add #1, r14 + mov.l err_readlp_bad_msg_k, r4 + mov r9, r5 + trapa #41 + +test_readl_2_ok: +/* Test mov.w @Rm, Rn */ + mova test_readw_1, r0 +.align 4 +test_readw_1: + mov.w @r10, r1 + bsr utlb_check_read_exc + nop + +/* Test mov.w @Rm+, Rn */ + mova test_readw_2, r0 +.align 4 +test_readw_2: + mov.w @r8+, r1 + bsr utlb_check_read_exc + nop + cmp/eq r8, r10 + bt test_readw_2_ok + + add #1, r14 + mov.l err_readwp_bad_msg_k, r4 + mov r9, r5 + trapa #41 + +test_readw_2_ok: + +/* Test mov.b @Rm, Rn */ + mova test_readb_1, r0 +.align 4 +test_readb_1: + mov.b @r10, r1 + bsr utlb_check_read_exc + nop + +/* Test mov.b @Rm+, Rn */ + mova test_readb_2, r0 +.align 4 +test_readb_2: + mov.b @r8+, r1 + bsr utlb_check_read_exc + nop + cmp/eq r8, r10 + bt test_readb_2_ok + + add #1, r14 + mov.l err_readbp_bad_msg_k, r4 + mov r9, r5 + trapa #41 + +test_readb_2_ok: + + bra utlb_read_test_done + nop + +/* Non-exception read tests */ +utlb_read_test_noexc: + mov.l utlb_exc_k_2, r8 + mov.l addr_mask, r0 + and r0, r8 + bsr utlb_noexpect_exc + nop + + mov.l @r10, r1 + not r1, r2 + mov.l r2, @r11 + ocbp @r11 + ocbi @r10 + mov.l @r10, r1 + ocbi @r10 + cmp/eq r1, r2 + bt noexc_readl_ok + + + add #1, r14 + mov.l err_read_mismatch_msg_k, r4 + mov r9, r5 + trapa #41 + +noexc_readl_ok: + + mov.l @(4,r8), r0 + add r0, r14 +utlb_read_test_done: + +/*********************** Begin write tests *****************************/ + tst r13, r13 + bt utlb_write_test_noexc + +/* Exception write tests */ +utlb_write_test_exc: + bsr utlb_expect_exc + nop + + mova test_writel_pc, r0 +.align 4 +test_writel_pc: + mov.l r1, @r10 + bsr utlb_check_write_exc + nop + + mova test_writelp_pc, r0 + mov r10, r8 +.align 4 +test_writelp_pc: + mov.l r1, @-r8 + bsr utlb_check_write_exc + nop + cmp/eq r8, r10 + bt test_writelp_ok + add #1, r14 + mov.l err_writelp_bad_msg_k, r4 + mov r9, r5 + trapa #41 +test_writelp_ok: + + mova test_writew_pc, r0 +.align 4 +test_writew_pc: + mov.w r1, @r10 + bsr utlb_check_write_exc + nop + + mova test_writewp_pc, r0 + mov r10, r8 +.align 4 +test_writewp_pc: + mov.w r1, @-r8 + bsr utlb_check_write_exc + nop + cmp/eq r8, r10 + bt test_writewp_ok + add #1, r14 + mov.l err_writewp_bad_msg_k, r4 + mov r9, r5 + trapa #41 +test_writewp_ok: + + mova test_writeb_pc, r0 +.align 4 +test_writeb_pc: + mov.b r1, @r10 + bsr utlb_check_write_exc + nop + + mova test_writebp_pc, r0 + mov r10, r8 +.align 4 +test_writebp_pc: + mov.b r1, @-r8 + bsr utlb_check_write_exc + nop + cmp/eq r8, r10 + bt test_writebp_ok + add #1, r14 + mov.l err_writelp_bad_msg_k, r4 + mov r9, r5 + trapa #41 +test_writebp_ok: + + bra utlb_write_test_done + nop + +/* Non-exception write tests */ +utlb_write_test_noexc: + mov.l utlb_exc_k_2, r8 + mov.l addr_mask, r0 + and r0, r8 + bsr utlb_noexpect_exc + nop + + mov.l @r11, r7 + ocbp @r11 + not r7, r1 + + mov.l r1, @r10 + ocbp @r10 + mov.l @r11, r6 + cmp/eq r6, r1 + bt test_writel_1_ok + + add #1, r14 + mov.l err_write_ignored_msg_k, r4 + mov r9, r5 + trapa #41 + +test_writel_1_ok: + + mov.l @(4,r8), r0 + add r0, r14 +utlb_write_test_done: + + xor r0, r0 + mov.l r0, @(16,r8) + + mov.l @r15+, r0 + mov.l r0, @r11 + mov.l @r15+, r8 + mov.l @r15+, r9 + mov.l @r15+, r10 + mov.l @r15+, r11 + mov.l @r15+, r12 + mov.l @r15+, r13 + mov.l @r15+, r1 + lds r1, pr + mov r14, r0 + mov.l @r15+, r14 + rts + nop + +.align 4 +err_read_mismatch_msg_k: + .long err_read_mismatch_msg +err_write_ignored_msg_k: + .long err_write_ignored_msg +err_readlp_bad_msg_k: + .long err_readlp_bad_msg +err_readwp_bad_msg_k: + .long err_readwp_bad_msg +err_readbp_bad_msg_k: + .long err_readbp_bad_msg +err_writelp_bad_msg_k: + .long err_readlp_bad_msg +err_writewp_bad_msg_k: + .long err_readwp_bad_msg +err_writebp_bad_msg_k: + .long err_readbp_bad_msg + + + +.global _run_utlb_user_test +_run_utlb_user_test: + sts pr, r0 + mov.l r0, @-r15 + stc sr, r2 + mov.l sr_mask, r1 + and r1, r2 + + mova user_entry_point, r0 + mov.l addr_mask, r1 + and r1, r0 + + mov.l r15, @-r15 + + jmp @r0 + nop + +user_entry_point: + nop + ldc r2, sr + + /* In user mode */ + + mov.l main_test_k, r0 + and r1, r0 + and r1, r4 + and r1, r15 + jsr @r0 + nop + + /* Done, return to priv mode */ + trapa #42 + mov.l user_retaddr, r1 + jmp @r1 + nop + +user_exit_point: + /* Back to priv mode */ + mov.l @r15+, r15 + mov.l @r15+, r1 + lds r1, pr + rts + nop +.align 4 + +utlb_exc_k_2: + .long utlb_exc +main_test_k: + .long _run_utlb_priv_test +addr_mask: + .long 0x1FFFFFFF +sr_mask: + .long 0x3FFFFFFF +user_retaddr: + .long user_exit_point + +err_read_exc_msg: + .string "%s: Read failed: Expected Exc %04X but got %04X\n" +err_read_count_msg: + .string "%s: Read bad exception: Exception 1 exception, but got %d\n" +err_read_pc_msg: + .string "%s: Read bad exception: Expected PC=%08X but was %08X\n" +err_read_mismatch_msg: + .string "%s: Read failed: Data mismatch!\n" +err_readlp_bad_msg: + .string "%s: Mov.l @Rm+, Rn failed: Rm changed!\n" +err_readwp_bad_msg: + .string "%s: Mov.w @Rm+, Rn failed: Rm changed!\n" +err_readbp_bad_msg: + .string "%s: Mov.b @Rm+, Rn failed: Rm changed!\n" +err_writelp_bad_msg: + .string "%s: Mov.l Rm, @-Rn failed: Rm changed!\n" +err_writewp_bad_msg: + .string "%s: Mov.w Rm, @-Rn failed: Rm changed!\n" +err_writebp_bad_msg: + .string "%s: Mov.b Rm, @-Rn failed: Rm changed!\n" +err_write_exc_msg: + .string "%s: Write failed: Expected Exc %04X but got %04X\n" +err_write_count_msg: + .string "%s: Write bad exception: Expected 1 exception, but got %d\n" +err_write_pc_msg: + .string "%s: Write bad exception: Expected PC=%08X but was %08X\n" +err_write_ignored_msg: + .string "%s: Write failed: write didn't happen!\n" +utlb_unexpected_msg: + .string "*** Unexpected exception %04X at %08X!\n" --- a/test/sh4/tlb.s Mon Jan 26 07:26:24 2009 +0000 +++ b/test/sh4/tlb.s Mon Jan 26 12:32:23 2009 +0000 @@ -104,6 +104,8 @@ bt test_tlb_6 test_tlb5_fail: fail test_tlb_str_k + bra test_tlb_6 + nop test_tlb5_addr: .long 0xF6000000 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sh4/utlb.c Mon Jan 26 12:32:23 2009 +0000 @@ -0,0 +1,99 @@ +/** + * $Id: utlb.c 831 2008-08-13 10:32:00Z nkeynes $ + * + * UTLB unit test support + * + * Copyright (c) 2006 Nathan Keynes. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include "utlb.h" +#include "../lib.h" + +#define TLB_VALID 0x00000100 +#define TLB_USERMODE 0x00000040 +#define TLB_WRITABLE 0x00000020 +#define TLB_SIZE_1K 0x00000000 +#define TLB_SIZE_4K 0x00000010 +#define TLB_SIZE_64K 0x00000080 +#define TLB_SIZE_1M 0x00000090 +#define TLB_CACHEABLE 0x00000008 +#define TLB_DIRTY 0x00000004 +#define TLB_SHARE 0x00000002 +#define TLB_WRITETHRU 0x00000001 + +#define PTEH 0xFF000000 +#define PTEL 0xFF000004 +#define TEA 0xFF00000C +#define MMUCR 0xFF000010 + +void set_tlb_enabled( int flag ) +{ + uint32_t val = long_read( MMUCR ); + if( flag ) { + val |= 1; + } else { + val &= ~1; + } + long_write( MMUCR, val ); +} + +void invalidate_tlb() +{ + uint32_t val = long_read( MMUCR ); + long_write( MMUCR, val | 4 ); +} + +void set_sv_enabled( int flag ) +{ + uint32_t val = long_read( MMUCR ); + if( flag ) { + val |= 0x100; + } else { + val &= ~0x100; + } + long_write( MMUCR, val ); +} + +void set_storequeue_protected( int flag ) +{ + uint32_t val = long_read( MMUCR ); + if( flag ) { + val |= 0x200; + } else { + val &= ~0x200; + } + long_write( MMUCR, val ); +} + + +void set_asid( int asid ) +{ + uint32_t val = long_read( PTEH ) & 0xFFFFFF00; + long_write( PTEH, val | asid ); +} + + +void load_utlb_entry( int entryNo, uint32_t vpn, uint32_t ppn, int asid, uint32_t mode ) +{ + long_write( (0xF6000000 | (entryNo<<8)), vpn | asid ); + long_write( (0xF7000000 | (entryNo<<8)), ppn | mode ); +} + + +void check_utlb_access( uint32_t addr, uint32_t direct_addr, int mode ) +{ + + +} + --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sh4/utlb.h Mon Jan 26 12:32:23 2009 +0000 @@ -0,0 +1,51 @@ +/** + * $Id: utlb.c 831 2008-08-13 10:32:00Z nkeynes $ + * + * UTLB unit test support + * + * Copyright (c) 2006 Nathan Keynes. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <../lib.h> + +#ifndef TEST_UTLB +#define TEST_UTLB 1 + +#define TLB_VALID 0x00000100 +#define TLB_USERMODE 0x00000040 +#define TLB_WRITABLE 0x00000020 +#define TLB_USERWRITABLE (TLB_WRITABLE|TLB_USERMODE) +#define TLB_SIZE_MASK 0x00000090 +#define TLB_SIZE_1K 0x00000000 +#define TLB_SIZE_4K 0x00000010 +#define TLB_SIZE_64K 0x00000080 +#define TLB_SIZE_1M 0x00000090 +#define TLB_CACHEABLE 0x00000008 +#define TLB_DIRTY 0x00000004 +#define TLB_SHARE 0x00000002 +#define TLB_WRITETHRU 0x00000001 + +void set_tlb_enabled( int flag ); +void invalidate_tlb(); +void set_sv_enabled( int flag ); +void set_storequeue_protected( int flag ); +void set_asid( int asid ); +void load_utlb_entry( int entryNo, uint32_t vpn, uint32_t ppn, int asid, uint32_t mode ); + +#define ACCESS_OK 0 +#define ACCESS_READONLY 1 +#define ACCESS_PRIVONLY 2 +#define ACCESS_USERMISS 4 +void check_utlb_access( uint32_t addr, uint32_t direct_addr, int mode ); + +#endif /* !TEST_UTLB */