From 66dd7b5b858039475849c98b160075a112d4fb80 Mon Sep 17 00:00:00 2001 From: Roberto Hexsel <roberto@inf.ufpr.br> Date: Sat, 16 May 2015 12:26:07 -0300 Subject: [PATCH] TLB operating --- cMIPS/include/cMIPS.s | 2 +- cMIPS/include/start.s | 56 +++--- cMIPS/tests/doTests.sh | 5 +- cMIPS/tests/mmu_context.s | 13 +- cMIPS/tests/mmu_double.expected | 5 + cMIPS/tests/mmu_double.s | 286 ++++++++++++++++++++++++++++ cMIPS/tests/mmu_inval.expected | 3 + cMIPS/tests/mmu_inval.s | 168 +++++++++++++++++ cMIPS/tests/mmu_mod.expected | 3 + cMIPS/tests/mmu_mod.s | 169 +++++++++++++++++ cMIPS/tests/mmu_pc_hit.s | 323 ++++++++++++++++++++++++++++++++ cMIPS/tests/mmu_refill.s | 8 +- cMIPS/vhdl/core.vhd | 63 ++++--- cMIPS/vhdl/packageMemory.vhd | 2 +- 14 files changed, 1040 insertions(+), 66 deletions(-) create mode 100644 cMIPS/tests/mmu_double.expected create mode 100644 cMIPS/tests/mmu_double.s create mode 100644 cMIPS/tests/mmu_inval.expected create mode 100644 cMIPS/tests/mmu_inval.s create mode 100644 cMIPS/tests/mmu_mod.expected create mode 100644 cMIPS/tests/mmu_mod.s create mode 100644 cMIPS/tests/mmu_pc_hit.s diff --git a/cMIPS/include/cMIPS.s b/cMIPS/include/cMIPS.s index 39c4b21..4fca90a 100644 --- a/cMIPS/include/cMIPS.s +++ b/cMIPS/include/cMIPS.s @@ -18,7 +18,7 @@ .set HW_lcd_addr, (x_IO_BASE_ADDR + 11 * x_IO_ADDR_RANGE) # see vhdl/packageExcp.vhd for addresses - .set x_EXCEPTION_0000,0x00000080 + .set x_EXCEPTION_0000,0x00000060 .set x_EXCEPTION_0100,0x000000A0 .set x_EXCEPTION_0180,0x000000C0 .set x_EXCEPTION_0200,0x00000200 diff --git a/cMIPS/include/start.s b/cMIPS/include/start.s index d15f84e..defb8b4 100644 --- a/cMIPS/include/start.s +++ b/cMIPS/include/start.s @@ -17,13 +17,17 @@ # initialize SP: ramTop-8 _start: li $sp,(x_DATA_BASE_ADDR+x_DATA_MEM_SZ-8) - # set STATUS, cop0, hw interrupt IRQ7,IRQ6,IRQ5 enabled + # set STATUS, cop0, hw interrupt IRQ7,IRQ6,IRQ5 enabled, user mode li $k0, 0x1000e001 mtc0 $k0, cop0_STATUS - + + # pin down first two MMU entries: ROM[0] and I/O + li $k0, 2 + mtc0 $k0, cop0_Wired + nop jal main # on returning from main(), MUST go into exit() - nop # to stop the simulation. + nop # to stop the simulation. exit: _exit: nop # flush pipeline nop @@ -52,13 +56,9 @@ _exit: nop # flush pipeline .ent _excp_0000 excp_0000: _excp_0000: - mfc0 $k0, cop0_STATUS - j nmi_reset_handler - nop - #excp_0000ret: - # li $k0, 0x1000ff01 # enable interrupts, user mode - # mtc0 $k0, cop0_STATUS - # eret + # li $k0, 0x1000ff01 # enable interrupts, user mode + # mtc0 $k0, cop0_STATUS + # eret #---------------------------------------------------------------- # handler for NMI or soft-reset -- simply abort simulation @@ -115,7 +115,7 @@ _excp_0180: mfc0 $k0, cop0_CAUSE sw $k0, 0*4($k1) - andi $k0, $k0, 0x3f # keep only the first 16 ExceptionCode & b"00" + andi $k0, $k0, 0x3f # keep only the first 16 ExceptionCodes & b"00" sll $k0, $k0, 1 # displacement in vector is 8 bytes lui $k1, %hi(excp_tbl) ori $k1, $k1, %lo(excp_tbl) @@ -136,9 +136,9 @@ excp_tbl: # see Table 8-25, pg 95,96 j h_TLBS # 3 nop - wait 0x04 # 4 AdEL addr error -- abort simulation + wait 0x04 # 4 AdEL addr error -- abort simulation nop - wait 0x05 # 5 AdES addr error -- abort simulation + wait 0x05 # 5 AdES addr error -- abort simulation nop wait 0x06 # 6 IBE addr error -- abort simulation nop @@ -163,21 +163,21 @@ excp_tbl: # see Table 8-25, pg 95,96 j h_trap # 13 trap nop - wait 0x14 # reserved, should never get here -- abort simulation + wait 0x14 # reserved, should never get here -- abort simulation nop wait 0x15 # PF exception, should never get here -- abort simulation nop -h_Mod: -h_TLBL: +h_Mod: +h_TLBL: h_TLBS: h_syscall: -h_breakpoint: -h_RI: -h_CpU: -h_Ov: -h_trap: +h_breakpoint: +h_RI: +h_CpU: +h_Ov: +h_trap: excp_0180ret: lui $k1, %hi(_excp_saves) # Read previous contents of STATUS @@ -199,10 +199,10 @@ excp_0180ret: ##=============================================================== ## interrupt handlers at exception vector 0200 ## - # name all handlers here - .extern countCompare # IRQ7 = hwIRQ5, see vhdl/tb_cMIPS.vhd - .extern UARTinterr # IRQ6 - hwIRQ4 - .extern extCounter # IRQ5 - hwIRQ3 + # declare all handlers here, these must be in file handlers.s + .extern countCompare # IRQ7 = hwIRQ5, Cop0 counter + .extern UARTinterr # IRQ6 - hwIRQ4, see vhdl/tb_cMIPS.vhd + .extern extCounter # IRQ5 - hwIRQ3, see vhdl/tb_cMIPS.vhd .set M_CauseIM,0x0000ff00 # keep bits 15..8 -> IM = IP .set M_StatusIEn,0x0000ff01 # user mode, enable all interrupts @@ -214,11 +214,11 @@ excp_0180ret: excp_0200: _excp_0200: mfc0 $k0, cop0_CAUSE - andi $k0, $k0, M_CauseIM # Keep only IP bits from Cause + andi $k0, $k0, M_CauseIM # Keep only IP bits from Cause mfc0 $k1, cop0_STATUS - and $k0, $k0, $k1 # and mask with IM bits + and $k0, $k0, $k1 # and mask with IM bits - srl $k0, $k0, 11 # keep only 3 MS bits of IP (irq7..5) + srl $k0, $k0, 11 # keep only 3 MS bits of IP (irq7..5) lui $k1, %hi(handlers_tbl) # plus displacement in j-table of 8 bytes ori $k1, $k1, %lo(handlers_tbl) add $k1, $k1, $k0 diff --git a/cMIPS/tests/doTests.sh b/cMIPS/tests/doTests.sh index b105dab..eb0b7d0 100755 --- a/cMIPS/tests/doTests.sh +++ b/cMIPS/tests/doTests.sh @@ -72,7 +72,8 @@ a_BHW="lbsb lhsh lwsw lwswIncr swlw lwl_lwr" a_MEM="lwSweepRAM" a_CTR="teq_tne tlt_tlti tltu_tgeu eiDI ll_sc overflow" a_COP="mtc0CAUSE2 mtc0EPC syscall break mfc0CONFIG badVAddr badVAddrMM" -a_MMU="mmu_index mmu_tlbwi mmu_tlbp mmu_tlbwr mmu_context mmu_refill" +a_MMU="mmu_index mmu_tlbwi mmu_tlbp mmu_tlbwr mmu_context" +a_EXC="mmu_refill mmu_inval mmu_mod mmu_double" ## these tests MUST be run with FAKE CACHES # a_IOs="kbd7seg" @@ -87,7 +88,7 @@ rm -f *.simout *.elf stoptime=20ms if [ 0 = 0 ] ; then - for F in $(echo $a_FWD $a_CAC $a_BEQ $a_FUN $a_OTH $a_BHW $a_MEM $a_CTR $a_COP $a_MMU $a_IOs); + for F in $(echo $a_FWD $a_CAC $a_BEQ $a_FUN $a_OTH $a_BHW $a_MEM $a_CTR $a_COP $a_MMU $a_EXC $a_IOs); do $bin/assemble.sh ${F}.s ${simulator} --ieee-asserts=disable --stop-time=$stoptime \ diff --git a/cMIPS/tests/mmu_context.s b/cMIPS/tests/mmu_context.s index 4d513f9..1d737ac 100644 --- a/cMIPS/tests/mmu_context.s +++ b/cMIPS/tests/mmu_context.s @@ -1,7 +1,7 @@ ## ## Test the Context register. ## - ## Write to the upper 9 bits (PTEbase) then read it back ; + ## Write to the upper 9 bits (PTEbase) then read it back ## ## Cause an exception by referencing an unmapped address and ## then check BadVPN2 @@ -67,8 +67,17 @@ _start: .set noreorder .set noat + ## EntryHi holds VPN2(31..13), probe the TLB for the offending entry + excp: -_excp: li $30, 'e' +_excp: tlbp # probe for the guilty entry + tlbr # it will surely hit, use Index to point at it + mfc0 $k1, cop0_EntryLo0 + ori $k1, $k1, 0x0002 # make V=1 + mtc0 $k1, cop0_EntryLo0 + tlbwi # write entry back + + li $30, 'e' sw $30, x_IO_ADDR_RANGE($31) li $30, 'x' sw $30, x_IO_ADDR_RANGE($31) diff --git a/cMIPS/tests/mmu_double.expected b/cMIPS/tests/mmu_double.expected new file mode 100644 index 0000000..8f15ba3 --- /dev/null +++ b/cMIPS/tests/mmu_double.expected @@ -0,0 +1,5 @@ +here +then +there +and back again + diff --git a/cMIPS/tests/mmu_double.s b/cMIPS/tests/mmu_double.s new file mode 100644 index 0000000..a6242e5 --- /dev/null +++ b/cMIPS/tests/mmu_double.s @@ -0,0 +1,286 @@ + ## + ## Cause a TLB miss on a fetch, refill handler causes double fault + ## + ## + ## EntryHi : EntryLo0 : EntryLo1 + ## VPN2 g ASID : PPN0 ccc0 d0 v0 g0 : PPN1 ccc1 d1 v1 g1 + + .include "cMIPS.s" + + .set MMU_WIRED, 2 ### do not change mapping for base of ROM, I/O + + # New entries cannot overwrite tlb[0,1] which map base of ROM, I/O + + # EntryHi cannot have an ASID different from zero, otw TLB misses + .set entryHi_1, 0x00012000 # pfn0 zzcc cdvg + .set entryLo0_1, 0x0000091b # x0 x0 x0 x0 x0 1001 0001 1011 x91b + .set entryLo1_1, 0x00000c1b # x0 x0 x0 x0 x0 1100 0001 1011 xc1b + + .set entryHi_2, 0x00014000 # pfn0 zzcc cdvg + .set entryLo0_2, 0x00001016 # x0 x0 x0 x0 x1 0000 0001 0110 x1016 + .set entryLo1_2, 0x0000141e # x0 x0 x0 x0 x1 0100 0001 1110 x141e + + .set entryHi_3, 0x00016000 # pfn0 zzcc cdvg + .set entryLo0_3, 0x0000191f # x0 x0 x0 x0 x1 1001 0001 1111 x191f + .set entryLo1_3, 0x00001d3f # x0 x0 x0 x0 x1 1101 0011 1111 x1d3f + + .set entryHi_4, 0x00018000 # pfn0 zzcc cdvg + .set entryLo0_4, 0x00000012 # x0 x0 x0 x0 x0 0000 0001 0010 x12 + .set entryLo1_4, 0x00000412 # x0 x0 x0 x0 x0 0100 0001 0010 x412 + + .text + .align 2 + .set noreorder + .set noat + .org x_INST_BASE_ADDR,0 + .globl _start + .ent _start + + ## set STATUS, cop0, no interrupts enabled +_start: li $k0, 0x10000000 + mtc0 $k0, cop0_STATUS + + j main + nop + .end _start + + ## + ##================================================================ + ## exception vector_0000 TLBrefill, from See MIPS Run pg 145 + ## + .org x_EXCEPTION_0000,0 + .ent _excp_100 + .set noreorder + .set noat + +_excp_100: mfc0 $k1, cop0_Context + lw $k0, 0($k1) # k0 <- TP[Context.lo] + lw $k1, 8($k1) # k1 <- TP[Context.hi] + mtc0 $k0, cop0_EntryLo0 # EntryLo0 <- k0 = even element + mtc0 $k1, cop0_EntryLo1 # EntryLo1 <- k1 = odd element + ehb + tlbwr # update TLB + li $30, 't' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'h' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'e' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'n' + sw $30, x_IO_ADDR_RANGE($20) + li $30, '\n' + sw $30, x_IO_ADDR_RANGE($20) + eret + .end _excp_100 + + + ## + ##================================================================ + ## general exception vector_0180 + ## + .org x_EXCEPTION_0180,0 + .ent _excp_180 + .set noreorder + .set noat + + ## EntryHi holds VPN2(31..13), probe the TLB for the offending entry +_excp_180: tlbp # probe for the guilty entry + nop + tlbr # it will surely hit, just use Index to point at it + mfc0 $k1, cop0_EntryLo0 + ori $k1, $k1, 0x0002 # make V=1 + mtc0 $k1, cop0_EntryLo0 + tlbwi # write entry back + + li $30, 'h' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'e' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'r' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'e' + sw $30, x_IO_ADDR_RANGE($20) + li $30, '\n' + sw $30, x_IO_ADDR_RANGE($20) + + eret + .end _excp_180 + + + ## + ##================================================================ + ## normal code starts here + ## + .org x_ENTRY_POINT,0 + + + ## dirty trick: there is not enough memory for a full PT, thus + ## we set the PT at the bottom of RAM addresses and have + ## Context pointing into that address range + + .set PTbase, x_DATA_BASE_ADDR + .ent main +main: la $20, x_IO_BASE_ADDR + + ## + ## setup a PageTable + ## + ## 16 bytes per entry: + ## EntryLo0 : EntryLo1 + ## PPN0 ccc0 d0 v0 g0 : PPN1 ccc1 d1 v1 g1 + ## + + la $4, PTbase + + li $5, 0 # 1st ROM mapping + mtc0 $5, cop0_Index + nop + tlbr + + mfc0 $6, cop0_EntryLo0 + # sw $6, 0($20) + mfc0 $7, cop0_EntryLo1 + # sw $7, 0($20) + + # 1st entry: PPN0 & PPN1 ROM + sw $6, 0($4) + sw $0, 4($4) + sw $7, 8($4) + sw $0, 12($4) + + li $5, 7 # 2nd ROM mapping + mtc0 $5, cop0_Index + nop + tlbr + + mfc0 $6, cop0_EntryLo0 + # sw $6, 0($20) + mfc0 $7, cop0_EntryLo1 + # sw $7, 0($20) + + # 2nd entry: PPN2 & PPN3 ROM + sw $6, 16($4) + sw $0, 20($4) + sw $7, 24($4) + sw $0, 28($4) + + # load Context with PTbase + mtc0 $4, cop0_Context + + ## change mapping for 2nd ROM TLB entry, thus causing a miss + + li $9, 0x2000 + sll $9, $9, 8 + + mfc0 $8, cop0_EntryHi + + add $8, $9, $8 # change tag + + mtc0 $8, cop0_EntryHi + + tlbwi # and write it back to TLB + + + ## + ## make invalid TLB entry mapping the page table + ## + ## read tlb[4] (1st RAM mapping) and clear the V bit + li $5, 4 + mtc0 $5, cop0_Index + + tlbr + + mfc0 $6, cop0_EntryLo0 + + addi $7, $zero, -3 # 0xffff.fffd = 1111.1111.1111.1011 + and $8, $7, $6 # clear D bit + + mtc0 $8, cop0_EntryLo0 + + tlbwi # write entry back to TLB + + nop + nop + nop + + ## cause a TLB miss + + jal there + nop + + li $30, 'a' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'n' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'd' + sw $30, x_IO_ADDR_RANGE($20) + li $30, ' ' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'b' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'a' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'c' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'k' + sw $30, x_IO_ADDR_RANGE($20) + li $30, ' ' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'a' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'g' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'a' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'i' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'n' + sw $30, x_IO_ADDR_RANGE($20) + li $30, '\n' + sw $30, x_IO_ADDR_RANGE($20) + sw $30, x_IO_ADDR_RANGE($20) + + + nop + nop + nop + nop + nop + nop + wait + nop + nop + + + .org (x_INST_BASE_ADDR + 2*4096), 0 + +there: li $30, 't' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'h' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'e' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'r' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'e' + sw $30, x_IO_ADDR_RANGE($20) + li $30, '\n' + sw $30, x_IO_ADDR_RANGE($20) + + jr $31 + nop + + + + + nop + nop + nop + nop + nop + nop + wait + nop + nop + .end main + diff --git a/cMIPS/tests/mmu_inval.expected b/cMIPS/tests/mmu_inval.expected new file mode 100644 index 0000000..32e5a88 --- /dev/null +++ b/cMIPS/tests/mmu_inval.expected @@ -0,0 +1,3 @@ +there +and back again + diff --git a/cMIPS/tests/mmu_inval.s b/cMIPS/tests/mmu_inval.s new file mode 100644 index 0000000..31f3fb6 --- /dev/null +++ b/cMIPS/tests/mmu_inval.s @@ -0,0 +1,168 @@ + ## + ## Perform a store to a clean page, then set the mapping as dirty + ## + ## + ## EntryHi : EntryLo0 : EntryLo1 + ## VPN2 g ASID : PPN0 ccc0 d0 v0 g0 : PPN1 ccc1 d1 v1 g1 + + .include "cMIPS.s" + + .set MMU_WIRED, 2 ### do not change mapping for base of ROM, I/O + + # New entries cannot overwrite tlb[0,1] which map base of ROM, I/O + + # EntryHi cannot have an ASID different from zero, otw TLB misses + .set entryHi_1, 0x00012000 # pfn0 zzcc cdvg + .set entryLo0_1, 0x0000091b # x0 x0 x0 x0 x0 1001 0001 1011 x91b + .set entryLo1_1, 0x00000c1b # x0 x0 x0 x0 x0 1100 0001 1011 xc1b + + .set entryHi_2, 0x00014000 # pfn0 zzcc cdvg + .set entryLo0_2, 0x00001016 # x0 x0 x0 x0 x1 0000 0001 0110 x1016 + .set entryLo1_2, 0x0000141e # x0 x0 x0 x0 x1 0100 0001 1110 x141e + + .set entryHi_3, 0x00016000 # pfn0 zzcc cdvg + .set entryLo0_3, 0x0000191f # x0 x0 x0 x0 x1 1001 0001 1111 x191f + .set entryLo1_3, 0x00001d3f # x0 x0 x0 x0 x1 1101 0011 1111 x1d3f + + .set entryHi_4, 0x00018000 # pfn0 zzcc cdvg + .set entryLo0_4, 0x00000012 # x0 x0 x0 x0 x0 0000 0001 0010 x12 + .set entryLo1_4, 0x00000412 # x0 x0 x0 x0 x0 0100 0001 0010 x412 + + .text + .align 2 + .set noreorder + .set noat + .org x_INST_BASE_ADDR,0 + .globl _start + .ent _start + + ## set STATUS, cop0, no interrupts enabled +_start: li $k0, 0x10000000 + mtc0 $k0, cop0_STATUS + + j main + nop + .end _start + + ## + ##================================================================ + ## general exception vector_0180 + ## + .org x_EXCEPTION_0180,0 + .ent _excp + .set noreorder + .set noat + + ## EntryHi holds VPN2(31..13), probe the TLB for the offending entry +excp: +_excp: tlbp # probe for the guilty entry + + nop + + tlbr # it will surely hit, just use Index to point at it + + mfc0 $k1, cop0_EntryLo0 + + ori $k1, $k1, 0x0002 # make V=1 + + mtc0 $k1, cop0_EntryLo0 + + tlbwi # write entry back + + li $30, 't' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'h' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'e' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'r' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'e' + sw $30, x_IO_ADDR_RANGE($20) + li $30, '\n' + sw $30, x_IO_ADDR_RANGE($20) + + eret + .end _excp + + ## + ##================================================================ + ## normal code starts here + ## + .org x_ENTRY_POINT,0 + + .ent main +main: la $20, x_IO_BASE_ADDR + + + ## read tlb[5] (2nd RAM mapping) and clear the V bit + li $5, 5 + mtc0 $5, cop0_Index + + tlbr + + mfc0 $6, cop0_EntryLo0 + + addi $7, $zero, -3 # 0xffff.fffd = 1111.1111.1111.1011 + and $8, $7, $6 # clear D bit + + mtc0 $8, cop0_EntryLo0 + + mfc0 $9, cop0_EntryHi + + tlbwi # write entry back to TLB + + + ## cause an exception by writing to that same page + + la $10, 0xffffe000 # mask off non-VPN bits + and $10, $10, $9 + + sw $zero, 16($10) + + + li $30, 'a' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'n' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'd' + sw $30, x_IO_ADDR_RANGE($20) + li $30, ' ' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'b' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'a' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'c' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'k' + sw $30, x_IO_ADDR_RANGE($20) + li $30, ' ' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'a' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'g' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'a' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'i' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'n' + sw $30, x_IO_ADDR_RANGE($20) + li $30, '\n' + sw $30, x_IO_ADDR_RANGE($20) + sw $30, x_IO_ADDR_RANGE($20) + + + nop + nop + nop + nop + nop + nop + wait + nop + nop + + .end main + diff --git a/cMIPS/tests/mmu_mod.expected b/cMIPS/tests/mmu_mod.expected new file mode 100644 index 0000000..32e5a88 --- /dev/null +++ b/cMIPS/tests/mmu_mod.expected @@ -0,0 +1,3 @@ +there +and back again + diff --git a/cMIPS/tests/mmu_mod.s b/cMIPS/tests/mmu_mod.s new file mode 100644 index 0000000..8f1da11 --- /dev/null +++ b/cMIPS/tests/mmu_mod.s @@ -0,0 +1,169 @@ + ## + ## Perform a store to a write-protected page, + ## then set the mapping as dirty and retry the store + ## + ## + ## EntryHi : EntryLo0 : EntryLo1 + ## VPN2 g ASID : PPN0 ccc0 d0 v0 g0 : PPN1 ccc1 d1 v1 g1 + + .include "cMIPS.s" + + .set MMU_WIRED, 2 ### do not change mapping for base of ROM, I/O + + # New entries cannot overwrite tlb[0,1] which map base of ROM, I/O + + # EntryHi cannot have an ASID different from zero, otw TLB misses + .set entryHi_1, 0x00012000 # pfn0 zzcc cdvg + .set entryLo0_1, 0x0000091b # x0 x0 x0 x0 x0 1001 0001 1011 x91b + .set entryLo1_1, 0x00000c1b # x0 x0 x0 x0 x0 1100 0001 1011 xc1b + + .set entryHi_2, 0x00014000 # pfn0 zzcc cdvg + .set entryLo0_2, 0x00001016 # x0 x0 x0 x0 x1 0000 0001 0110 x1016 + .set entryLo1_2, 0x0000141e # x0 x0 x0 x0 x1 0100 0001 1110 x141e + + .set entryHi_3, 0x00016000 # pfn0 zzcc cdvg + .set entryLo0_3, 0x0000191f # x0 x0 x0 x0 x1 1001 0001 1111 x191f + .set entryLo1_3, 0x00001d3f # x0 x0 x0 x0 x1 1101 0011 1111 x1d3f + + .set entryHi_4, 0x00018000 # pfn0 zzcc cdvg + .set entryLo0_4, 0x00000012 # x0 x0 x0 x0 x0 0000 0001 0010 x12 + .set entryLo1_4, 0x00000412 # x0 x0 x0 x0 x0 0100 0001 0010 x412 + + .text + .align 2 + .set noreorder + .set noat + .org x_INST_BASE_ADDR,0 + .globl _start + .ent _start + + ## set STATUS, cop0, no interrupts enabled +_start: li $k0, 0x10000000 + mtc0 $k0, cop0_STATUS + + j main + nop + .end _start + + ## + ##================================================================ + ## general exception vector_0180 + ## + .org x_EXCEPTION_0180,0 + .ent _excp + .set noreorder + .set noat + + ## EntryHi holds VPN2(31..13), probe the TLB for the offending entry +excp: +_excp: tlbp # probe for the guilty entry + + nop + + tlbr # it will surely hit, just use Index to point at it + + mfc0 $k1, cop0_EntryLo0 + + ori $k1, $k1, 0x0004 # make D=1 + + mtc0 $k1, cop0_EntryLo0 + + tlbwi # write entry back + + li $30, 't' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'h' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'e' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'r' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'e' + sw $30, x_IO_ADDR_RANGE($20) + li $30, '\n' + sw $30, x_IO_ADDR_RANGE($20) + + eret + .end _excp + + ## + ##================================================================ + ## normal code starts here + ## + .org x_ENTRY_POINT,0 + + .ent main +main: la $20, x_IO_BASE_ADDR + + + ## read tlb[5] (2nd RAM mapping) and clear the D bit + li $5, 5 + mtc0 $5, cop0_Index + + tlbr + + mfc0 $6, cop0_EntryLo0 + + addi $7, $zero, -5 # 0xffff.fffb = 1111.1111.1111.1011 + and $8, $7, $6 # clear D bit + + mtc0 $8, cop0_EntryLo0 + + mfc0 $9, cop0_EntryHi + + tlbwi # write entry back to TLB + + + ## cause an exception by writing to that same page + + la $10, 0xffffe000 # mask off non-VPN bits + and $10, $10, $9 + + sw $zero, 16($10) + + + li $30, 'a' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'n' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'd' + sw $30, x_IO_ADDR_RANGE($20) + li $30, ' ' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'b' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'a' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'c' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'k' + sw $30, x_IO_ADDR_RANGE($20) + li $30, ' ' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'a' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'g' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'a' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'i' + sw $30, x_IO_ADDR_RANGE($20) + li $30, 'n' + sw $30, x_IO_ADDR_RANGE($20) + li $30, '\n' + sw $30, x_IO_ADDR_RANGE($20) + sw $30, x_IO_ADDR_RANGE($20) + + + nop + nop + nop + nop + nop + nop + wait + nop + nop + + .end main + diff --git a/cMIPS/tests/mmu_pc_hit.s b/cMIPS/tests/mmu_pc_hit.s new file mode 100644 index 0000000..4ca722c --- /dev/null +++ b/cMIPS/tests/mmu_pc_hit.s @@ -0,0 +1,323 @@ + ## + ## Test the TLB as if it were just a memory array + ## Perform a random write, then probe for it + ## writes are such thar first two probes fail, next two succeed + ## Because of timing, only one WRITE -> PROBE can be tested + ## "deterministically" as any change in core timing breaks the test + ## + + ## EntryHi : EntryLo0 : EntryLo1 + ## VPN2 g ASID : PPN0 ccc0 d0 v0 g0 : PPN1 ccc1 d1 v1 g1 + + ## TLB(i): VPN2 g ASID : PFN0 ccc0 d0 v0 : PFN1 ccc1 d1 v1 + ## TLB(0): 0 0 00 : x00 010 0 1 : x11 010 0 1 + ## TLB(1): 1 1 ff : x21 011 0 1 : x31 011 0 1 + ## TLB(2): 2 0 77 : x41 010 1 1 : x51 011 1 1 + ## TLB(3): 3 1 01 : x61 011 1 1 : x71 111 1 1 + + .include "cMIPS.s" + + .set MMU_CAPACITY, 4 + .set MMU_WIRED, 0 + + .set entryHi_0, 0x00000000 # pfn0 cc cdvg + .set entryLo0_0, 0x00000012 # x0 x0 x0 x0 x0 00 00 00 01 0010 x12 + #.set entryLo1_0, 0x00000052 # x0 x0 x0 x0 x0 00 00 01 01 0010 x52 + + .set entryHi_1, 0x00000400 # pfn0 cc cdvg + .set entryLo0_1, 0x00000052 # x0 x0 x0 x0 x0 00 00 01 01 0010 x52 + #.set entryLo1_1, 0x0000035b # x0 x0 x0 x0 x0 00 00 11 01 0010 x35b + + .set entryHi_2, 0x00000800 # pfn0 cc cdvg + .set entryLo0_2, 0x00000092 # x0 x0 x0 x0 x0 00 00 10 01 0010 x92 + #.set entryLo1_2, 0x0000145e # x0 x0 x0 x0 x0 01 00 01 01 1110 x145e + + .set entryHi_3, 0x00000c00 # pfn0 cc cdvg + .set entryLo0_3, 0x000000d2 # x0 x0 x0 x0 x0 00 00 11 01 0010 xd2 + #.set entryLo1_3, 0x00001c7f # x0 x0 x0 x0 x1 11 00 01 11 1111 x1c7f + + # initialize TLB with these + .set entryHi_i, 0x00ffffff # pfn0 cc cdvg + .set entryLo0_i, 0x0fff185f # x0 x0 x0 xf xf 11 11 11 00 0000 xfffc0 + .set entryLo1_i, 0x0fff1c7f # x0 xf xf xf xf 11 11 11 00 0000 xfffc0 + + + .text + .align 2 + .set noreorder + .set noat + .globl _start + .ent _start +_start: la $31, x_IO_BASE_ADDR + + mtc0 $zero, cop0_Wired # make sure all TLB entries are usable + + ## initialize TLB with entries that will not match in tests below + ## NOTE: this is strictly forbidden as all entries are equal + ## we only do this while testing the TLB + + la $2, entryHi_0 + mtc0 $2, cop0_EntryHi + la $3, entryLo0_0 + mtc0 $3, cop0_EntryLo0 + #la $4, entryLo1_0 + #mtc0 $4, cop0_EntryLo1 + + li $5, 0 + mtc0 $5, cop0_Index + tlbwi + + + la $2, entryHi_1 + mtc0 $2, cop0_EntryHi + la $3, entryLo0_1 + mtc0 $3, cop0_EntryLo0 + #la $4, entryLo1_1 + #mtc0 $4, cop0_EntryLo1 + li $5, 1 + mtc0 $5, cop0_Index + tlbwi + + + + la $2, entryHi_2 + mtc0 $2, cop0_EntryHi + la $3, entryLo0_2 + mtc0 $3, cop0_EntryLo0 + #la $4, entryLo1_2 + #mtc0 $4, cop0_EntryLo1 + li $5, 2 + mtc0 $5, cop0_Index + tlbwi + + + la $2, entryHi_3 + mtc0 $2, cop0_EntryHi + la $3, entryLo0_3 + mtc0 $3, cop0_EntryLo0 + #la $4, entryLo1_3 + #mtc0 $4, cop0_EntryLo1 + li $5, 3 + mtc0 $5, cop0_Index + tlbwi + + li $5,2 + mtc0 $5, cop0_Wired # pin down entries with startup code + + + mfc0 $19, cop0_Random # check for randomness + sw $19, 0($31) + mfc0 $19, cop0_Random # check for randomness + sw $19, 0($31) + nop + mfc0 $19, cop0_Random # check for randomness + sw $19, 0($31) + mfc0 $19, cop0_Random # check for randomness + sw $19, 0($31) + li $30, '\n' + sw $30, x_IO_ADDR_RANGE($31) + + + ## write to a random location + la $2, entryHi_3 + mtc0 $2, cop0_EntryHi + la $3, entryLo0_3 + mtc0 $3, cop0_EntryLo0 + #la $4, entryLo1_3 + #mtc0 $4, cop0_EntryLo1 + + tlbwr # write 0x00006001, 0x0000185f, 0x00001c7f to TLB, ranndom loc + + nop + nop + nop + nop + + ## check first record was written + ## make sure it will miss by probing for 0,0,0 + ## + mtc0 $zero, cop0_EntryHi + mtc0 $zero, cop0_EntryLo0 + #mtc0 $zero, cop0_EntryLo1 + + nop + nop + + tlbp + + mfc0 $19, cop0_Index # check for bit31=1 + sw $19, 0($31) + + slt $20, $19, $zero # $20 <- (bit31 = 1) + beq $20, $zero, hit3 + nop + +miss3: li $30, 'm' + sw $30, x_IO_ADDR_RANGE($31) + li $30, '\n' + sw $30, x_IO_ADDR_RANGE($31) + j next2 + nop + +hit3: li $30, 'h' + sw $30, x_IO_ADDR_RANGE($31) + li $30, '=' + sw $30, x_IO_ADDR_RANGE($31) + andi $30, $19, (MMU_CAPACITY - 1) + addi $30, $30, '0' + sw $30, x_IO_ADDR_RANGE($31) + li $30, '\n' + sw $30, x_IO_ADDR_RANGE($31) + nop + nop + sw $30, x_IO_ADDR_RANGE($31) + + + +next2: li $30, '\n' + sw $30, x_IO_ADDR_RANGE($31) + + # write into another randomly selected entry + la $5, entryHi_2 + mtc0 $5, cop0_EntryHi + la $6, entryLo0_2 + mtc0 $6, cop0_EntryLo0 + #la $7, entryLo1_2 + #mtc0 $7, cop0_EntryLo1 + nop + + tlbwr + + nop + nop + + ## check second record was written + ## make sure it will miss by probing for 0,0,0 + ## + mtc0 $zero, cop0_EntryHi + mtc0 $zero, cop0_EntryLo0 + #mtc0 $zero, cop0_EntryLo1 + + nop + nop + + tlbp + + ehb + + mfc0 $19, cop0_Index # check for bit31=1 + sw $19, 0($31) + + slt $20, $19, $zero # $20 <- (bit31 = 1) + beq $20, $zero, hit2 + nop + +miss2: li $30, 'm' + sw $30, x_IO_ADDR_RANGE($31) + li $30, '\n' + sw $30, x_IO_ADDR_RANGE($31) + j next1 + nop + + +hit2: li $30, 'h' + sw $30, x_IO_ADDR_RANGE($31) + li $30, '=' + sw $30, x_IO_ADDR_RANGE($31) + andi $30, $19, (MMU_CAPACITY - 1) + addi $30, $30, '0' + sw $30, x_IO_ADDR_RANGE($31) + li $30, '\n' + sw $30, x_IO_ADDR_RANGE($31) + nop + nop + sw $30, x_IO_ADDR_RANGE($31) + + + +next1: li $30, '\n' + sw $30, x_IO_ADDR_RANGE($31) + + ## now check for last entry written -- must be a hit + la $5, entryHi_2 + mtc0 $5, cop0_EntryHi + + nop + nop + nop + + tlbp + + mfc0 $19, cop0_Index # check for bit31=1 + sw $19, 0($31) + + slt $20, $19, $zero # $20 <- (bit31 = 1) + beq $20, $zero, hit1 + nop + +miss1: li $30, 'm' + sw $30, x_IO_ADDR_RANGE($31) + li $30, '\n' + sw $30, x_IO_ADDR_RANGE($31) + j next0 + +hit1: li $30, 'h' + sw $30, x_IO_ADDR_RANGE($31) + li $30, '=' + sw $30, x_IO_ADDR_RANGE($31) + andi $30, $19, (MMU_CAPACITY - 1) + addi $30, $30, '0' + sw $30, x_IO_ADDR_RANGE($31) + li $30, '\n' + sw $30, x_IO_ADDR_RANGE($31) + + +next0: li $30, '\n' + sw $30, x_IO_ADDR_RANGE($31) + + ## now check for one of the initialization values -- must be a hit + la $5, entryHi_i + mtc0 $5, cop0_EntryHi + + nop + nop + nop + + tlbp + + mfc0 $19, cop0_Index # check for bit31=1 + sw $19, 0($31) + + slt $20, $19, $zero # $20 <- (bit31 = 1) + beq $20, $zero, hit0 + nop + +miss0: li $30, 'm' + sw $30, x_IO_ADDR_RANGE($31) + li $30, '\n' + sw $30, x_IO_ADDR_RANGE($31) + j done + +hit0: li $30, 'h' + sw $30, x_IO_ADDR_RANGE($31) + li $30, '=' + sw $30, x_IO_ADDR_RANGE($31) + andi $30, $19, (MMU_CAPACITY - 1) + addi $30, $30, '0' + sw $30, x_IO_ADDR_RANGE($31) + li $30, '\n' + sw $30, x_IO_ADDR_RANGE($31) + nop + nop + sw $30, x_IO_ADDR_RANGE($31) + +done: nop + nop + nop + nop + wait + nop + nop + .end _start + + diff --git a/cMIPS/tests/mmu_refill.s b/cMIPS/tests/mmu_refill.s index f5931d8..b087aac 100644 --- a/cMIPS/tests/mmu_refill.s +++ b/cMIPS/tests/mmu_refill.s @@ -1,7 +1,5 @@ ## - ## Test the TLB as if it were just a memory array - ## Perform a series of indexed writes, then a series of probes - ## first two fail, next two succeed + ## Cause a TLB miss on a fetch, then copy a mapping from page table ## ## ## EntryHi : EntryLo0 : EntryLo1 @@ -84,8 +82,8 @@ _excp: mfc0 $k1, cop0_Context ## dirty trick: there is not enough memory for a full PT, thus - ## we set the PT at the bottom of RAM addresses and trick - ## Context into accessing a low address range + ## we set the PT at the bottom of RAM addresses and have + ## Context pointing into that address range .set PTbase, x_DATA_BASE_ADDR .ent main diff --git a/cMIPS/vhdl/core.vhd b/cMIPS/vhdl/core.vhd index ef183f3..5fbae21 100644 --- a/cMIPS/vhdl/core.vhd +++ b/cMIPS/vhdl/core.vhd @@ -1504,7 +1504,7 @@ begin else MM_wreg; - -- ------------------------------------------------------------------ + -- ---------------------------------------------------------------------- PIPESTAGE_MM_WB: reg_MM_WB port map (clk,rst, MM_WB_ld, MM_a_c,WB_a_c, MM_wreg_cond,WB_wreg, MM_muxC,WB_muxC, @@ -1513,7 +1513,7 @@ begin MM_result(1 downto 0),WB_addr2, MM_mem_t(3 downto 2),WB_mem_t, MM_pc_p8,WB_pc_p8); - -- WRITE BACK ------------------------------------------- + -- WRITE BACK ----------------------------------------------------------- -- merge unaligned loads LWL,LWR @@ -1674,14 +1674,15 @@ begin - is_exception <= TLB_excp_type when tlb_exception else + is_exception <= TLB_excp_type when tlb_exception else MM_excp_type when addrError else exOvfl when MM_ex_trapped = '1' else IFaddressError when EX_PC_abort else EX_exception; exception_num <= exception_type'pos(is_exception); -- for debugging only - + + -- STATUS -- pg 79 -- cop0_12 -------------------- COP0_DECODE_EXCEPTION_AND_UPDATE_STATUS: process (EX_a_rt, is_exception, EX_trap_instr, EX_cop0_reg, EX_cop0_sel, EX_nmi, EX_interrupt,EX_int_req, @@ -1795,12 +1796,13 @@ begin EX_mfc0 <= '1'; when exERET => -- exception return + newSTATUS(STATUS_EXL) := '0'; -- leave exception level i_update := '1'; i_update_r := cop0reg_STATUS; i_stall := '0'; -- do not stall i_excp_PCsel := PCsel_EXC_EPC; -- PC <= EPC i_nullify := '1'; -- nullify instructions in IF,RF - newSTATUS(STATUS_EXL) := '0'; -- leave exception level + when exTRAP | exSYSCALL | exBREAK => -- trap instruction i_stall := '0'; @@ -1929,6 +1931,8 @@ begin end case; newSTATUS(STATUS_EXL) := '1'; -- at exception level newSTATUS(STATUS_IE) := '0'; -- disable interrupts + i_update := '1'; + i_update_r := cop0reg_STATUS; i_excp_PCsel := PCsel_EXC_0000; -- PC <= exception_0000 i_epc_update := '0'; @@ -1946,28 +1950,30 @@ begin when exTLBinvalRD | exTLBdblFaultRD => ExcCode <= cop0code_TLBL; if EX_is_delayslot = '1' then -- instr is in delay slot - i_epc_source := b"010"; -- EX_PC, re-execute branch/jump + i_epc_source := b"011"; -- MM_PC, re-execute branch/jump else - i_epc_source := b"001"; -- RF_PC + i_epc_source := b"010"; -- EX_PC end if; when exTLBinvalWR | exTLBdblFaultWR => ExcCode <= cop0code_TLBS; if EX_is_delayslot = '1' then -- instr is in delay slot - i_epc_source := b"010"; -- EX_PC, re-execute branch/jump + i_epc_source := b"011"; -- MM_PC, re-execute branch/jump else - i_epc_source := b"001"; -- RF_PC + i_epc_source := b"010"; -- EX_PC end if; when exTLBmod => ExcCode <= cop0code_Mod; if EX_is_delayslot = '1' then -- instr is in delay slot - i_epc_source := b"010"; -- EX_PC, re-execute branch/jump + i_epc_source := b"011"; -- MM_PC, re-execute branch/jump else - i_epc_source := b"001"; -- RF_PC + i_epc_source := b"010"; -- EX_PC end if; when others => null; end case; newSTATUS(STATUS_EXL) := '1'; -- at exception level newSTATUS(STATUS_IE) := '0'; -- disable interrupts + i_update := '1'; + i_update_r := cop0reg_STATUS; i_excp_PCsel := PCsel_EXC_0180; -- PC <= exception_0180 i_epc_update := '0'; @@ -2072,15 +2078,17 @@ begin status_update <= '0' when (update = '1' and update_reg = cop0reg_STATUS and not_stalled = '1') else '1'; - + + -- STATUS -- pg 79 -- cop0_12 -------------------- COP0_STATUS: register32 generic map (RESET_STATUS) port map (clk, rst, status_update, STATUSinp, STATUS); - -- CAUSE ------------------------------ - COP0_COMPUTE_CAUSE: - process(rst, update,update_reg, EX_int_req, ExcCode, cop0_inp, - EX_is_delayslot, count_eq_compare,count_enable, CAUSE) + -- CAUSE -- pg 92-- cop0_13 -------------------------- + COP0_COMPUTE_CAUSE: process(rst, update,update_reg, + EX_int_req, ExcCode, cop0_inp, + EX_is_delayslot, + count_eq_compare,count_enable, CAUSE) variable newCAUSE : reg32; begin @@ -2139,7 +2147,7 @@ begin port map (clk, rst, cause_update, CAUSEinp, CAUSE); - -- EPC -- pg 97 --------------------- + -- EPC -- pg 97 -- cop0_14 ------------------- with epc_source select EPCinp <= PC when b"000", -- instr fetch exception RF_PC when b"001", -- invalid instr exception @@ -2152,7 +2160,7 @@ begin port map (clk, rst, epc_update, EPCinp, EPC); - -- COUNT & COMPARE -- pg 75, 78 ----------------- not_stalled = '1' + -- COUNT & COMPARE -- pg 75, 78 ----------------- compare_update <= '0' when (update = '1' and update_reg = cop0reg_COMPARE) else '1'; @@ -2249,7 +2257,7 @@ begin port map (clk, rst, index_update, index_inp, INDEX); - -- MMU Wired -- cop0_6 -- pg 72 ---------------- + -- MMU Wired -- pg 72 -- cop0_6 ---------------- wired_update <= '0' when (update = '1' and update_reg = cop0reg_Wired) else '1'; @@ -2301,13 +2309,13 @@ begin -- MMU Context -- pg 67 -- cop0_4 ------------ - assert true -- DEBUG - report "pgSz " & integer'image(PAGE_SZ_BITS) & - " va-1 " & integer'image(VABITS-1) & - " pg+1 " & integer'image(PAGE_SZ_BITS+1) & - " add " & integer'image(VABITS-1 - PAGE_SZ_BITS+1) & - " lef " & integer'image( PC(VABITS-1 downto PAGE_SZ_BITS+1)'left )& - " rig " & integer'image( PC(VABITS-1 downto PAGE_SZ_BITS+1)'right ); + -- assert false -- true -- DEBUG + -- report "pgSz " & integer'image(PAGE_SZ_BITS) & + -- " va-1 " & integer'image(VABITS-1) & + -- " pg+1 " & integer'image(PAGE_SZ_BITS+1) & + -- " add " & integer'image(VABITS-1 - PAGE_SZ_BITS+1) & + -- " lef " & integer'image( PC(VABITS-1 downto PAGE_SZ_BITS+1)'left )& + -- " rig " & integer'image( PC(VABITS-1 downto PAGE_SZ_BITS+1)'right ); context_upd_pte <= '0' when (update = '1' and update_reg = cop0reg_Context) else '1'; @@ -2325,7 +2333,7 @@ begin Context(3 downto 0) <= b"0000"; - -- MMU Pagemask -- cop0_5 -- pg 68 ----------- + -- MMU Pagemask -- pg 68 -- cop0_5 ----------- -- page size is fixed = 4k, thus PageMask is not register -- pageMask_update <= '0' when (update='1' and update_reg=cop0reg_PageMask) @@ -2393,6 +2401,7 @@ begin end if; elsif hit_mm then + if (EX_aVal = '0' and hit_mm_v = '0') then -- check for TLBinvalid if EX_aVal = '0' then TLB_excp_type <= exTLBinvalWR; diff --git a/cMIPS/vhdl/packageMemory.vhd b/cMIPS/vhdl/packageMemory.vhd index 9821eda..5df5092 100644 --- a/cMIPS/vhdl/packageMemory.vhd +++ b/cMIPS/vhdl/packageMemory.vhd @@ -47,7 +47,7 @@ package p_MEMORY is constant x_IO_BASE_ADDR : reg32 := x"0F000000"; constant x_IO_MEM_SZ : reg32 := x"00002000"; constant x_IO_ADDR_RANGE : reg32 := x"00000020"; - constant x_EXCEPTION_0000 : reg32 := x"00000080"; + constant x_EXCEPTION_0000 : reg32 := x"00000060"; constant x_EXCEPTION_0100 : reg32 := x"000000A0"; constant x_EXCEPTION_0180 : reg32 := x"000000C0"; constant x_EXCEPTION_0200 : reg32 := x"00000200"; -- GitLab