diff --git a/dcache.vhdl b/dcache.vhdl index 0d8d354..dcde2ee 100644 --- a/dcache.vhdl +++ b/dcache.vhdl @@ -1703,8 +1703,10 @@ begin r1.wb.adr <= next_row_wb_addr(r1.wb.adr); end if; - -- If this is a touch, complete the instruction - if r1.full = '1' and r1.req.touch = '1' and r1.req.hit_reload = '1' then + -- If this is a touch, complete the instruction, but not + -- until the new tag for this cache line has been written. + if r1.full = '1' and r1.req.touch = '1' and r1.req.hit_reload = '1' and + r1.write_tag = '0' then r1.full <= '0'; r1.slow_valid <= '1'; r1.ls_valid <= '1'; diff --git a/icache.vhdl b/icache.vhdl index 7b0ae59..1240d8b 100644 --- a/icache.vhdl +++ b/icache.vhdl @@ -595,6 +595,7 @@ begin r.hit_valid <= '0'; r.stalled_hit <= '0'; r.stalled_way <= to_unsigned(0, WAY_BITS); + r.fetch_failed <= '0'; elsif stall_in = '1' then if r.state = CLR_TAG then r.stalled_hit <= '0'; diff --git a/tests/mmu/head.S b/tests/mmu/head.S index 824ad67..c2b5731 100644 --- a/tests/mmu/head.S +++ b/tests/mmu/head.S @@ -23,6 +23,7 @@ ori r,r, (e)@l; .section ".head","ax" + .machine "power10" /* * Microwatt currently enters in LE mode at 0x0, so we don't need to @@ -45,82 +46,97 @@ _start: 2: LOAD_IMM64(%r1,__stack_top) li %r0,0 stdu %r0,-16(%r1) + pla %r9,3f-. + mtsprg1 %r9 LOAD_IMM64(%r12, main) mtctr %r12 bctrl - attn // terminate on exit +3: attn // terminate on exit b . /* Read a location with translation on */ .globl test_read test_read: + mfsprg1 %r10 + pla %r9,1f-. + mtsprg1 %r9 mfmsr %r9 ori %r8,%r9,0x10 /* set MSR_DR */ mtmsrd %r8,0 mr %r6,%r3 li %r3,0 ld %r5,0(%r6) - li %r3,1 - /* land here if DSI occurred */ mtmsrd %r9,0 +1: /* land here if DSI occurred */ std %r5,0(%r4) + mtsprg1 %r10 blr /* Write a location with translation on */ .globl test_write test_write: + mfsprg1 %r10 + pla %r9,1f-. + mtsprg1 %r9 mfmsr %r9 ori %r8,%r9,0x10 /* set MSR_DR */ mtmsrd %r8,0 mr %r6,%r3 li %r3,0 std %r4,0(%r6) - li %r3,1 - /* land here if DSI occurred */ mtmsrd %r9,0 +1: /* land here if DSI occurred */ + mtsprg1 %r10 blr /* Do a dcbz with translation on */ .globl test_dcbz test_dcbz: + mfsprg1 %r10 + pla %r9,1f-. + mtsprg1 %r9 mfmsr %r9 ori %r8,%r9,0x10 /* set MSR_DR */ mtmsrd %r8,0 mr %r6,%r3 li %r3,0 dcbz 0,%r6 - li %r3,1 - /* land here if DSI occurred */ mtmsrd %r9,0 +1: /* land here if DSI occurred */ + mtsprg1 %r10 blr .globl test_exec test_exec: + mfsprg1 %r10 + pla %r9,1f-. + mtsprg1 %r9 mtsrr0 %r4 mtsrr1 %r5 rfid +1: /* land here if an interrupt occurred */ + mtsprg1 %r10 + blr #define EXCEPTION(nr) \ .= nr ;\ attn - /* DSI vector - skip the failing instruction + the next one */ + /* DSI vector - set r3 to 0x300, jump to addr in SPRG1 */ . = 0x300 - mtsprg0 %r10 - mfsrr0 %r10 - addi %r10,%r10,8 - mtsrr0 %r10 - rfid + li %r3,0x300 + mfsprg1 %r9 + mtctr %r9 + bctr EXCEPTION(0x380) - /* - * ISI vector - jump to LR to return from the test, - * with r3 cleared - */ + /* ISI vector - set r3 to 0x400, jump to addr in SPRG1 */ . = 0x400 - li %r3,0 - blr + li %r3,0x400 + mfsprg1 %r9 + mtctr %r9 + bctr /* More exception stubs */ EXCEPTION(0x480) @@ -138,7 +154,9 @@ test_exec: * may have been set. */ . = 0xc00 - blr + mfsprg1 %r9 + mtctr %r9 + bctr EXCEPTION(0xd00) EXCEPTION(0xe00) @@ -162,12 +180,13 @@ test_exec: test_start: nop nop - cmpdi %r3,1 + mr %r6,%r3 + li %r3,0 + cmpdi %r6,1 beq test_1 - cmpdi %r3,2 + cmpdi %r6,2 beq test_2 test_return: - li %r3,1 sc . = 0x1ff8 @@ -177,3 +196,14 @@ test_1: b test_return /* test flowing from one page to the next */ test_2: nop b test_return + + . = 0x2fe8 + /* test generating an interrupt just before an instruction page fault */ + .globl test_2_faults +test_2_faults: + nop + nop + mr %r6,%r3 + li %r3,0 + lwz %r7,0(%r6) + ld %r7,0(%r7) diff --git a/tests/mmu/mmu.c b/tests/mmu/mmu.c index ff6a582..749c121 100644 --- a/tests/mmu/mmu.c +++ b/tests/mmu/mmu.c @@ -192,7 +192,7 @@ int mmu_test_1(void) long val; /* this should fail */ - if (test_read(ptr, &val, 0xdeadbeefd00d)) + if (!test_read(ptr, &val, 0xdeadbeefd00d)) return 1; /* dest reg of load should be unchanged */ if (val != 0xdeadbeefd00d) @@ -215,7 +215,7 @@ int mmu_test_2(void) /* initialize the memory content */ mem[33] = 0xbadc0ffee; /* this should succeed and be a cache miss */ - if (!test_read(&ptr[33], &val, 0xdeadbeefd00d)) + if (test_read(&ptr[33], &val, 0xdeadbeefd00d)) return 1; /* dest reg of load should have the value written */ if (val != 0xbadc0ffee) @@ -223,13 +223,13 @@ int mmu_test_2(void) /* load a second TLB entry in the same set as the first */ map(ptr2, mem, DFLT_PERM); /* this should succeed and be a cache hit */ - if (!test_read(&ptr2[33], &val, 0xdeadbeefd00d)) + if (test_read(&ptr2[33], &val, 0xdeadbeefd00d)) return 3; /* dest reg of load should have the value written */ if (val != 0xbadc0ffee) return 4; /* check that the first entry still works */ - if (!test_read(&ptr[33], &val, 0xdeadbeefd00d)) + if (test_read(&ptr[33], &val, 0xdeadbeefd00d)) return 5; if (val != 0xbadc0ffee) return 6; @@ -247,7 +247,7 @@ int mmu_test_3(void) /* initialize the memory content */ mem[45] = 0xfee1800d4ea; /* this should succeed and be a cache miss */ - if (!test_read(&ptr[45], &val, 0xdeadbeefd0d0)) + if (test_read(&ptr[45], &val, 0xdeadbeefd0d0)) return 1; /* dest reg of load should have the value written */ if (val != 0xfee1800d4ea) @@ -255,7 +255,7 @@ int mmu_test_3(void) /* remove the PTE */ unmap(ptr); /* this should fail */ - if (test_read(&ptr[45], &val, 0xdeadbeefd0d0)) + if (!test_read(&ptr[45], &val, 0xdeadbeefd0d0)) return 3; /* dest reg of load should be unchanged */ if (val != 0xdeadbeefd0d0) @@ -278,7 +278,7 @@ int mmu_test_4(void) /* initialize the memory content */ mem[27] = 0xf00f00f00f00; /* this should succeed and be a cache miss */ - if (!test_write(&ptr[27], 0xe44badc0ffee)) + if (test_write(&ptr[27], 0xe44badc0ffee)) return 1; /* memory should now have the value written */ if (mem[27] != 0xe44badc0ffee) @@ -286,14 +286,14 @@ int mmu_test_4(void) /* load a second TLB entry in the same set as the first */ map(ptr2, mem, DFLT_PERM); /* this should succeed and be a cache hit */ - if (!test_write(&ptr2[27], 0x6e11ae)) + if (test_write(&ptr2[27], 0x6e11ae)) return 3; /* memory should have the value written */ if (mem[27] != 0x6e11ae) return 4; /* check that the first entry still exists */ /* (assumes TLB is 2-way associative or more) */ - if (!test_read(&ptr[27], &val, 0xdeadbeefd00d)) + if (test_read(&ptr[27], &val, 0xdeadbeefd00d)) return 5; if (val != 0x6e11ae) return 6; @@ -309,7 +309,7 @@ int mmu_test_5(void) /* create PTE */ map(ptr, mem, DFLT_PERM); /* this should fail */ - if (test_read(ptr, &val, 0xdeadbeef0dd0)) + if (!test_read(ptr, &val, 0xdeadbeef0dd0)) return 1; /* dest reg of load should be unchanged */ if (val != 0xdeadbeef0dd0) @@ -330,7 +330,7 @@ int mmu_test_6(void) /* initialize memory */ *mem = 0x123456789abcdef0; /* this should fail */ - if (test_write(ptr, 0xdeadbeef0dd0)) + if (!test_write(ptr, 0xdeadbeef0dd0)) return 1; /* DAR and DSISR should be set correctly */ if (mfspr(DAR) != ((long)ptr & ~0xfff) + 0x1000 || mfspr(DSISR) != 0x42000000) @@ -348,7 +348,7 @@ int mmu_test_7(void) /* create PTE without R or C */ map(ptr, mem, PERM_RD | PERM_WR); /* this should fail */ - if (test_read(ptr, &val, 0xdeadd00dbeef)) + if (!test_read(ptr, &val, 0xdeadd00dbeef)) return 1; /* dest reg of load should be unchanged */ if (val != 0xdeadd00dbeef) @@ -357,7 +357,7 @@ int mmu_test_7(void) if (mfspr(DAR) != (long) ptr || mfspr(DSISR) != 0x00040000) return 3; /* this should fail */ - if (test_write(ptr, 0xdeadbeef0dd0)) + if (!test_write(ptr, 0xdeadbeef0dd0)) return 4; /* DAR and DSISR should be set correctly */ if (mfspr(DAR) != (long)ptr || mfspr(DSISR) != 0x02040000) @@ -378,10 +378,10 @@ int mmu_test_8(void) /* create PTE with R but not C */ map(ptr, mem, REF | PERM_RD | PERM_WR); /* this should succeed */ - if (!test_read(ptr, &val, 0xdeadd00dbeef)) + if (test_read(ptr, &val, 0xdeadd00dbeef)) return 1; /* this should fail */ - if (test_write(ptr, 0xdeadbeef0dd1)) + if (!test_write(ptr, 0xdeadbeef0dd1)) return 2; /* DAR and DSISR should be set correctly */ if (mfspr(DAR) != (long)ptr || mfspr(DSISR) != 0x02040000) @@ -402,7 +402,7 @@ int mmu_test_9(void) /* create PTE without read or write permission */ map(ptr, mem, REF); /* this should fail */ - if (test_read(ptr, &val, 0xdeadd00dbeef)) + if (!test_read(ptr, &val, 0xdeadd00dbeef)) return 1; /* dest reg of load should be unchanged */ if (val != 0xdeadd00dbeef) @@ -411,7 +411,7 @@ int mmu_test_9(void) if (mfspr(DAR) != (long) ptr || mfspr(DSISR) != 0x08000000) return 3; /* this should fail */ - if (test_write(ptr, 0xdeadbeef0dd1)) + if (!test_write(ptr, 0xdeadbeef0dd1)) return 4; /* DAR and DSISR should be set correctly */ if (mfspr(DAR) != (long)ptr || mfspr(DSISR) != 0x0a000000) @@ -432,10 +432,10 @@ int mmu_test_10(void) /* create PTE with read but not write permission */ map(ptr, mem, REF | PERM_RD); /* this should succeed */ - if (!test_read(ptr, &val, 0xdeadd00dbeef)) + if (test_read(ptr, &val, 0xdeadd00dbeef)) return 1; /* this should fail */ - if (test_write(ptr, 0xdeadbeef0dd1)) + if (!test_write(ptr, 0xdeadbeef0dd1)) return 2; /* DAR and DSISR should be set correctly */ if (mfspr(DAR) != (long)ptr || mfspr(DSISR) != 0x0a000000) @@ -451,7 +451,7 @@ int mmu_test_11(void) unsigned long ptr = 0x523000; /* this should fail */ - if (test_exec(0, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) + if (!test_exec(0, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) return 1; /* SRR0 and SRR1 should be set correctly */ if (mfspr(SRR0) != (long) ptr || @@ -469,12 +469,12 @@ int mmu_test_12(void) /* create PTE */ map((void *)ptr, (void *)mem, PERM_EX | REF); /* this should succeed and be a cache miss */ - if (!test_exec(0, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) + if (test_exec(0, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) return 1; /* create a second PTE */ map((void *)ptr2, (void *)mem, PERM_EX | REF); /* this should succeed and be a cache hit */ - if (!test_exec(0, ptr2, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) + if (test_exec(0, ptr2, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) return 2; return 0; } @@ -488,14 +488,14 @@ int mmu_test_13(void) /* create a PTE */ map((void *)ptr, (void *)mem, PERM_EX | REF); /* this should succeed */ - if (!test_exec(1, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) + if (test_exec(1, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) return 1; /* invalidate the PTE */ unmap((void *)ptr); /* install a second PTE */ map((void *)ptr2, (void *)mem, PERM_EX | REF); /* this should fail */ - if (test_exec(1, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) + if (!test_exec(1, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) return 2; /* SRR0 and SRR1 should be set correctly */ if (mfspr(SRR0) != (long) ptr || @@ -514,7 +514,7 @@ int mmu_test_14(void) /* create a PTE */ map((void *)ptr, (void *)mem, PERM_EX | REF); /* this should fail due to second page not being mapped */ - if (test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) + if (!test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) return 1; /* SRR0 and SRR1 should be set correctly */ if (mfspr(SRR0) != ptr2 || @@ -523,7 +523,7 @@ int mmu_test_14(void) /* create a PTE for the second page */ map((void *)ptr2, (void *)mem2, PERM_EX | REF); /* this should succeed */ - if (!test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) + if (test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) return 3; return 0; } @@ -536,7 +536,7 @@ int mmu_test_15(void) /* create a PTE without execute permission */ map((void *)ptr, (void *)mem, DFLT_PERM); /* this should fail */ - if (test_exec(0, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) + if (!test_exec(0, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) return 1; /* SRR0 and SRR1 should be set correctly */ if (mfspr(SRR0) != ptr || @@ -557,7 +557,7 @@ int mmu_test_16(void) /* create a PTE for the second page without execute permission */ map((void *)ptr2, (void *)mem2, PERM_RD | REF); /* this should fail due to second page being no-execute */ - if (test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) + if (!test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) return 1; /* SRR0 and SRR1 should be set correctly */ if (mfspr(SRR0) != ptr2 || @@ -566,7 +566,7 @@ int mmu_test_16(void) /* create a PTE for the second page with execute permission */ map((void *)ptr2, (void *)mem2, PERM_RD | PERM_EX | REF); /* this should succeed */ - if (!test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) + if (test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) return 3; return 0; } @@ -579,7 +579,7 @@ int mmu_test_17(void) /* create a PTE without the ref bit set */ map((void *)ptr, (void *)mem, PERM_EX); /* this should fail */ - if (test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) + if (!test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) return 1; /* SRR0 and SRR1 should be set correctly */ if (mfspr(SRR0) != (long) ptr || @@ -589,7 +589,7 @@ int mmu_test_17(void) unmap((void *)ptr); map((void *)ptr, (void *)mem, 0); /* this should fail */ - if (test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) + if (!test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE)) return 1; /* SRR0 and SRR1 should be set correctly */ /* RC update fail bit should not be set */ @@ -608,12 +608,12 @@ int mmu_test_18(void) /* create PTE */ map(ptr, mem, DFLT_PERM); /* this should succeed and be a cache miss */ - if (!test_dcbz(&ptr[129])) + if (test_dcbz(&ptr[129])) return 1; /* create a second PTE */ map(ptr2, mem, DFLT_PERM); /* this should succeed and be a cache hit */ - if (!test_dcbz(&ptr2[130])) + if (test_dcbz(&ptr2[130])) return 2; return 0; } @@ -627,7 +627,7 @@ int mmu_test_19(void) /* create PTE with read but not write permission */ map(ptr, mem, REF | PERM_RD); /* this should fail and create a TLB entry */ - if (test_write(ptr, 0xdeadbeef0dd1)) + if (!test_write(ptr, 0xdeadbeef0dd1)) return 1; /* DAR and DSISR should be set correctly */ if (mfspr(DAR) != (long)ptr || mfspr(DSISR) != 0x0a000000) @@ -635,11 +635,26 @@ int mmu_test_19(void) /* Update the PTE to have write permission */ map(ptr, mem, REF | CHG | PERM_RD | PERM_WR); /* this should succeed */ - if (!test_write(ptr, 0xdeadbeef0dd1)) + if (test_write(ptr, 0xdeadbeef0dd1)) return 3; return 0; } +int mmu_test_20(void) +{ + unsigned long mem = 0x2000; + unsigned long ptr = 0x324000; + unsigned long ret; + + /* create a PTE with execute permission */ + map((void *)ptr, (void *)mem, PERM_EX | PERM_PRIV | REF); + ret = test_exec(0x124000, ptr + 0xfe8, MSR_SF | MSR_HV | MSR_IR | MSR_DR | MSR_LE); + /* Should see a 300 from the load, not a 400 from the page crossing */ + if (ret != 0x300) + return ret + 1; + return 0; +} + int fail = 0; void do_test(int num, int (*test)(void)) @@ -656,7 +671,10 @@ void do_test(int num, int (*test)(void)) } else { fail = 1; print_string("FAIL "); - putchar(ret + '0'); + if (ret < 10) + putchar(ret + '0'); + else + print_hex(ret); if (num <= 10 || num == 19) { print_string(" DAR="); print_hex(mfspr(DAR)); @@ -696,6 +714,7 @@ int main(void) do_test(17, mmu_test_17); do_test(18, mmu_test_18); do_test(19, mmu_test_19); + do_test(20, mmu_test_20); return fail; } diff --git a/tests/test_mmu.bin b/tests/test_mmu.bin index 6e352a7..1c4f876 100755 Binary files a/tests/test_mmu.bin and b/tests/test_mmu.bin differ diff --git a/tests/test_mmu.console_out b/tests/test_mmu.console_out index cb4ad85..aea206f 100644 --- a/tests/test_mmu.console_out +++ b/tests/test_mmu.console_out @@ -17,3 +17,4 @@ test 16:PASS test 17:PASS test 18:PASS test 19:PASS +test 20:PASS