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