From c9400beacff8bd1f96eb8c42411f4cb6d4d7300a Mon Sep 17 00:00:00 2001
From: Roberto Hexsel <roberto@inf.ufpr.br>
Date: Tue, 28 Mar 2017 20:28:24 -0300
Subject: [PATCH] added program that turns the board into a clock

---
 cMIPS/bin/assemble.sh        |  10 +-
 cMIPS/bin/compile.sh         |  26 +-
 cMIPS/include/cMIPS.h        |  27 +-
 cMIPS/include/cMIPSio.c      |  27 ++
 cMIPS/include/syn_handlers.s | 617 +++++++++++++++++++++++++++++++++++
 cMIPS/include/syn_start.s    |  86 ++++-
 cMIPS/tests/mac_chrono.c     | 155 +++++++++
 cMIPS/v_irx.sav              |  21 +-
 cMIPS/v_rx.sav               |  57 ++--
 cMIPS/v_tx.sav               |  41 +--
 cMIPS/vhdl/core.vhd          |  14 +-
 11 files changed, 980 insertions(+), 101 deletions(-)
 create mode 100644 cMIPS/include/syn_handlers.s
 create mode 100644 cMIPS/tests/mac_chrono.c

diff --git a/cMIPS/bin/assemble.sh b/cMIPS/bin/assemble.sh
index 5fa45a8..39b832b 100755
--- a/cMIPS/bin/assemble.sh
+++ b/cMIPS/bin/assemble.sh
@@ -86,7 +86,7 @@ while true ; do
             ;;
         -n) names=true
             ;;
-        -mif|-m) miffile=true
+        -mif | -m | -syn ) miffile=true
             ;;
         -x) set -x
             ;;
@@ -103,6 +103,14 @@ if [ -z $inp ] ; then usage ; exit 1 ; fi
 
 pkg_vhd="${srcVHDL}"/packageMemory.vhd
 
+if [ $miffile = true ]; then
+   S="-D FOR_SYNTHESIS" ;
+   touch $pkg_vhd -r ${srcVHDL}/packageMemory_fpga.vhd 
+else 
+   S="-U FOR_SYNTHESIS" ;
+   touch $pkg_vhd -r ${srcVHDL}/packageMemory_simu.vhd 
+fi
+
 if [ $pkg_vhd -nt $c_ld -o  $pkg_vhd -nt $c_s ] ; then
     "${bin}"/edMemory.sh -v || errorED || exit 1
 fi
diff --git a/cMIPS/bin/compile.sh b/cMIPS/bin/compile.sh
index 0828bff..0bc781e 100755
--- a/cMIPS/bin/compile.sh
+++ b/cMIPS/bin/compile.sh
@@ -84,9 +84,8 @@ while true ; do
             ;;
         -n) names=false
             ;;
-        -mif) miffile=true
-            ;;
-        -syn) synth=true
+        -mif | -syn ) synth=true
+	    miffile=true
             ;;
         -x) set -x
             ;;
@@ -111,10 +110,22 @@ c_h="${include}"/cMIPS.h
 c_s="${include}"/cMIPS.s
 c_io="${include}"/cMIPSio
 # c_start="${include}"/start ## see below for synthesis version
-c_hndlrs="${include}"/handlers
+# c_hndlrs="${include}"/handlers ## see below for synthesis version
 
 pkg_vhd="${srcVHDL}"/packageMemory.vhd
 
+if [ $synth = true ]; then
+   S="-D FOR_SYNTHESIS" ;
+   c_start="${include}"/syn_start
+   c_hndlrs="${include}"/syn_handlers
+   touch $pkg_vhd -r ${srcVHDL}/packageMemory_fpga.vhd 
+else 
+   S="-U FOR_SYNTHESIS" ;
+   c_start="${include}"/start
+   c_hndlrs="${include}"/handlers
+   touch $pkg_vhd -r ${srcVHDL}/packageMemory_simu.vhd 
+fi
+
 if [ $pkg_vhd -nt $c_h  -o\
      $pkg_vhd -nt $c_ld -o\
      $pkg_vhd -nt $c_s  ] ; then
@@ -130,13 +141,6 @@ dat=data.bin
 
 if [ $verbose = true ]; then  memory_map="-Map ${inp}.map" ; fi
 
-if [ $synth = true ]; then
-   S="-D FOR_SYNTHESIS" ;
-   c_start="${include}"/syn_start
-else 
-   S="-U FOR_SYNTHESIS" ;
-   c_start="${include}"/start
-fi
 
 (mips-gcc -O${level} $warn -DcMIPS -mno-gpopt -I"${include}" \
           -S ${src} $S -o ${asm}  ||  exit 1) && \
diff --git a/cMIPS/include/cMIPS.h b/cMIPS/include/cMIPS.h
index 5e8b52a..2acad22 100644
--- a/cMIPS/include/cMIPS.h
+++ b/cMIPS/include/cMIPS.h
@@ -25,6 +25,14 @@
 
 
 extern void exit(int);
+
+extern void cmips_delay(int);
+extern void delay_us(int);
+extern void delay_ms(int);
+
+extern void enableInterr(void);
+extern void disableInterr(void);
+
 extern void print(int);
 extern void to_stdout(char c);
 extern int  from_stdin(void);
@@ -33,27 +41,22 @@ extern void writeInt(int);
 extern void writeClose(void);
 extern int  readInt(int*);
 extern void dumpRAM(void);
+extern int  print_sp(void);
 
-extern void cmips_delay(int);
-extern void delay_us(int);
-extern void delay_ms(int);
+extern char *memcpy(char*, const char*, int);
+extern char *memset(char*, const int, int);
 
 // external counter (peripheral)
 extern void startCounter(int, int);
 extern void stopCounter(void);
 extern int  readCounter(void);
 
-extern void enableInterr(void);
-extern void disableInterr(void);
-
 // internal counter, CP0 register COUNT
 extern int startCount(void);
 extern int stopCount(void);
 extern int readCount(void);
 
-extern char *memcpy(char*, const char*, int);
-extern char *memset(char*, const int, int);
-
+// LCD display (Macnica board)
 extern void LCDinit(void);
 extern int  LCDprobe(void); 
 extern int  LCDset(int);
@@ -63,13 +66,15 @@ extern void LCDtopLine(void);
 extern void LCDbotLine(void);
 extern void LCDgotoxy(int, int);
 extern void LCDputc(char);
+extern void LCDprint(unsigned int);
 
-extern void DSP7SEGput(int MSD, int MSdot, int lsd, int lsdot);
+// 7-segment display and keyboard (Macnica board)
+extern void DSP7SEGput(int, int, int, int);
 extern int  KBDget(void);
 extern int  SWget(void);
 
 
-// struct to access the system statistics "peripheral"
+// struct to access the cache system statistics "peripheral"
 typedef struct sStats {
   int dc_ref;      // data cache references
   int dc_rd_hit;   // data cache read-hits
diff --git a/cMIPS/include/cMIPSio.c b/cMIPS/include/cMIPSio.c
index 6cb11fa..5e04c49 100644
--- a/cMIPS/include/cMIPSio.c
+++ b/cMIPS/include/cMIPSio.c
@@ -350,6 +350,33 @@ void LCDputc(char c) {
   }
 }
 
+#define conv(c) ((c<10)?((c)+0x30):((c)+('a'-10)))
+
+// write an integer to the display
+void LCDprint(unsigned int n) {
+  int k;
+
+  k = (n     >>28);
+  LCDput( conv(k) );
+  k = (n<< 4)>>28;
+  LCDput( conv(k) );
+
+  k = (n<< 8)>>28;
+  LCDput( conv(k) );
+  k = (n<<12)>>28;
+  LCDput( conv(k) );
+
+  k = (n<<16)>>28;
+  LCDput( conv(k) );
+  k = (n<<20)>>28;
+  LCDput( conv(k) );
+
+  k = (n<<24)>>28;
+  LCDput( conv(k) );
+  k = (n<<28)>>28;
+  LCDput( conv(k) );
+}
+
 
 //-----------------------------------------------------------------------
 
diff --git a/cMIPS/include/syn_handlers.s b/cMIPS/include/syn_handlers.s
new file mode 100644
index 0000000..6f02f37
--- /dev/null
+++ b/cMIPS/include/syn_handlers.s
@@ -0,0 +1,617 @@
+	# interrupt handlers
+	.include "cMIPS.s"
+	.text
+	.set noreorder	# do not reorder instructions
+	.set noat	# do not use register $1 as $at
+        .align 2
+
+	.set M_StatusIEn,0x0000e011     # STATUS.intEn=1, user mode, EXL=0
+
+	#================================================================
+	# interrupt handler for external counter attached to IP5=HW3
+	# for extCounter address see vhdl/packageMemory.vhd
+	#
+	# counter set to interrupt 4 times per second (12,500,000*20ns)
+	#
+	.bss
+	.align  2
+	.global _counter_val	# accumulate number of interrupts
+_counter_val:	.space 4
+_counter_saves:	.space 8*4	# area to save up to 8 registers
+	# _counter_saves[0]=$a0, [1]=$a1, [2]=$a2, [3]=$a3, ...
+	
+	.set HW_counter_value,(0xc0000000 | 0x00bebc20) # 12,500,000
+
+	.text
+	.set    noreorder
+	.global extCounter
+	.ent    extCounter
+
+extCounter:
+	lui   $k0, %hi(HW_counter_addr)
+	ori   $k0, $k0, %lo(HW_counter_addr)
+	sw    $zero, 0($k0) 	# Reset counter, remove interrupt request
+
+	#----------------------------------
+	# if you change this handler, then save additional registers
+	# lui $k1, %hi(_counter_saves)
+	# ori $k1, $k1, %lo(_counter_saves)
+	# sw  $a0, 0*4($k1)
+	# sw  $a1, 1*4($k1)
+	#----------------------------------
+	
+	lui   $k1, %hi(HW_counter_value)
+	ori   $k1, $k1, %lo(HW_counter_value)
+	sw    $k1, 0($k0)	      # Reload counter so it starts again
+
+	lui   $k0, %hi(_counter_val)  # Increment interrupt event counter
+	ori   $k0, $k0, %lo(_counter_val)
+	lw    $k1,0($k0)
+	nop
+	addiu $k1,$k1,1
+	sw    $k1,0($k0)
+
+	#----------------------------------
+	# if you changed this handler, then restore those same registers
+	# lui $k1, %hi(_counter_saves)
+	# ori $k1, $k1, %lo(_counter_saves)
+	# lw  $a0, 0*4($k1)
+	# lw  $a1, 1*4($k1)
+	#----------------------------------
+	
+	mfc0  $k0, c0_status	    # Read STATUS register
+	ori   $k0, $k0, M_StatusIEn #   but do not modify its contents
+	mtc0  $k0, c0_status	    #   except for re-enabling interrupts
+	ehb
+	eret			    # Return from interrupt
+	.end extCounter
+	#----------------------------------------------------------------
+
+	
+	#================================================================
+	# interrupt handler for UART attached to IP6=HW4
+	# for UART's address see vhdl/packageMemory.vhd
+	#
+	.global Ud, _uart_buff
+	.bss 
+        .align  2
+Ud:
+rx_hd:	.space 4
+rx_tl:	.space 4
+rx_q:   .space 16       # reception queue and pointers
+tx_hd:	.space 4
+tx_tl:	.space 4
+tx_q:	.space 16	# transmission queue and pointers
+nrx:	.space 4	# characters in RX_queue
+ntx:	.space 4	# spaces left in TX_queue
+
+_uart_buff: .space 16*4 # up to 16 registers to be saved here
+
+	.set UART_rx_irq,0x08
+	.set UART_tx_irq,0x10
+
+	.text
+	.set    noreorder
+	.global UARTinterr
+	.ent    UARTinterr
+
+	# _uart_buff[0]=UARTstatus, [1]=UARTcontrol, [2]=data_inp, [3]=new,
+	#           [4]=$ra, [5]=$a0, [6]=$a1, [7]=$a2, [8]=$a3
+	
+UARTinterr:
+	lui   $k0, %hi(_uart_buff)  # get buffer's address
+	ori   $k0, $k0, %lo(_uart_buff)
+	
+	sw    $a0, 5*4($k0)	    # save registers $a0,$a1, others?
+	sw    $a1, 6*4($k0)
+
+	lui   $a0, %hi(HW_uart_addr)# get device's address
+	ori   $a0, $a0, %lo(HW_uart_addr)
+
+	lw    $k1, 0($a0) 	    # Read status, remove interrupt request
+	nop
+	sw    $k1, 0*4($k0)         #  and save UART status to memory
+	
+	#----------------------------------
+	# while you are developing the complete handler,
+	#    uncomment the line below and comment out lines up to UARTret
+	# .include "../tests/handlerUART.s"
+	#----------------------------------
+	
+	andi  $a1, $k1, UART_rx_irq # Is this reception?
+	beq   $a1, $zero, UARTret   #   no, ignore it and return
+	nop
+
+	# handle reception
+	lw    $a1, 4($a0) 	    # Read data from device
+	nop                         #   and store it to UART's buffer
+	sw    $a1, 2*4($k0)         #   and return from interrupt
+	addiu $a1, $zero, 1
+	sw    $a1, 3*4($k0)         # Signal new arrival 
+
+UARTret:
+	lw    $a1, 6*4($k0)         # restore registers $a0,$a1, others?
+	lw    $a0, 5*4($k0)
+
+	mfc0  $k0, c0_status	    # Read STATUS register
+	ori   $k0, $k0, M_StatusIEn #   but do not modify its contents
+	mtc0  $k0, c0_status	    #   except for re-enabling interrupts
+	eret			    # Return from interrupt
+	.end UARTinterr
+	#----------------------------------------------------------------
+
+	
+	#================================================================
+	# handler for COUNT-COMPARE registers -- IP7=HW5
+	.text
+	.set    noreorder
+	.equ	num_cycles, 64
+	.global countCompare
+	.ent    countCompare
+countCompare:
+	mfc0  $k1,c0_count    	 # read COUNT
+	addiu $k1,$k1,num_cycles # set next interrupt in so many ticks
+	mtc0  $k1,c0_compare	 # write to COMPARE to clear IRQ
+
+	mfc0  $k0, c0_status	 # Read STATUS register
+	ori   $k0, $k0, M_StatusIEn #   but do not modify its contents
+	mtc0  $k0, c0_status	 #   except for re-enabling interrupts
+	eret			 # Return from interrupt
+	.end countCompare
+	#----------------------------------------------------------------
+
+
+	#================================================================
+	# startCount enables the COUNT register, returns new CAUSE
+	#   CAUSE.dc <= 0 to enable counting
+	#----------------------------------------------------------------
+	.text
+	.set    noreorder
+	.global startCount
+	.ent    startCount
+startCount:
+	mfc0 $v0, c0_cause
+	lui  $v1, 0xf7ff
+	ori  $v1, $v1, 0xffff
+        and  $v0, $v0, $v1
+	jr   $ra
+	mtc0 $v0, c0_cause
+	.end    startCount
+	#----------------------------------------------------------------
+
+
+	#================================================================
+	# stopCount disables the COUNT register, returns new CAUSE
+	#   CAUSE.dc <= 1 to disable counting
+	#----------------------------------------------------------------
+	.text
+	.set    noreorder
+	.global stopCount
+	.ent    stopCount
+stopCount:
+	mfc0 $v0, c0_cause
+	lui  $v1, 0x0800
+        or   $v0, $v0, $v1
+	jr   $ra
+	mtc0 $v0, c0_cause
+	.end    stopCount
+	#----------------------------------------------------------------
+
+
+	#================================================================
+	# readCount returns the value of the COUNT register
+	#----------------------------------------------------------------
+	.text
+	.set    noreorder
+	.global readCount
+	.ent    readCount
+readCount:
+        mfc0 $v0, c0_count
+        jr   $ra
+        nop
+	.end    readCount
+	#----------------------------------------------------------------
+
+	
+	#================================================================
+	# functions to enable and disable interrupts, both return STATUS
+	.text
+	.set    noreorder
+	.global enableInterr,disableInterr
+	.ent    enableInterr
+enableInterr:
+	mfc0  $v0, c0_status	    # Read STATUS register
+	ori   $v0, $v0, 1           #   and enable interrupts
+	mtc0  $v0, c0_status
+	nop
+	jr    $ra                   # return updated STATUS
+	nop
+	.end enableInterr
+
+	.ent disableInterr
+disableInterr:
+	mfc0  $v0, c0_status	    # Read STATUS register
+	addiu $v1, $zero, -2        #   and disable interrupts
+	and   $v0, $v0, $v1         # -2 = 0xffff.fffe
+	mtc0  $v0, c0_status
+	nop
+	jr    $ra                   # return updated STATUS
+	nop
+	.end disableInterr
+	#----------------------------------------------------------------
+
+
+	#================================================================
+	## TLB handlers
+	## page table entry is { EntryLo0, int0, EntryLo1, int1 }
+	## int{0,1} is
+	## { fill_31..6, Modified_5, Used_4, Writable_3, eXecutable_2,
+	##    Status_10 },
+	## Status: 00=unmapped, 01=mapped, 10=secondary_storage, 11=panic
+	#================================================================
+	
+
+	#================================================================
+	# handle TLB Modified exception -- store to page with bit dirty=0
+	#
+	# (a) fix TLB entry, by setting dirty=1 ;
+	# (b) check permissions in PT entry and (maybe) kill the process
+	#     OR mark PT entry as Used and Modified, then
+	#     update TLB entry.
+	#
+	.global _excp_saves
+	.global _excp_0180ret
+	.global handle_Mod
+	.set noreorder
+	
+	.ent handle_Mod
+handle_Mod:			# EntryHi points to offending TLB entry
+	tlbp			# what is the offender's index?
+	lui  $k1, %hi(_excp_saves)
+        ori  $k1, $k1, %lo(_excp_saves)
+	sw   $a0,  9*4($k1)	# save registers
+	sw   $a1, 10*4($k1)
+	sw   $a2, 11*4($k1)
+
+	mfc0 $a0, c0_badvaddr
+	andi $a0, $a0, 0x1000	# check if even or odd page
+	beq  $a0, $zero, M_even
+	mfc0 $a0, c0_context
+
+M_odd:	addi $a2, $a0, 12	# address for odd entry
+	mfc0 $k0, c0_entrylo1
+	ori  $k0, $k0, 0x0004	# mark TLB entry as dirty/writable
+	j    M_test
+	mtc0 $k0, c0_entrylo1
+	
+M_even: addi $a2, $a0, 4	# address for even entry
+	mfc0 $k0, c0_entrylo0
+	ori  $k0, $k0, 0x0004	# mark TLB entry as dirty/writable
+	mtc0 $k0, c0_entrylo0
+
+M_test:	lw   $a1, 0($a2)	# read PT[badVAddr]
+	mfc0 $k0, c0_badvaddr	# get faulting address
+	andi $a0, $a1, 0x0001	# check if page is mapped
+	beq  $a0, $zero, M_seg_fault	# no, abort simulation
+	nop
+
+	andi $a0, $a1, 0x0008	# check if page is writable
+	beq  $a0, $zero, M_prot_viol	# no, abort simulation
+	nop
+
+	andi $a0, $a1, 0x0002	# check if page is in secondary memory
+	bne  $a0, $zero, M_sec_mem	# yes, abort simulation
+	nop
+
+	mfc0 $a0, c0_epc	# check if fault is on an instruction
+	beq  $a0, $k0, M_prot_viol	# k0 is badVAddr, if so, abort
+	nop
+
+	ori  $a1, $a1, 0x0030	# mark PT entry as modified, used
+	sw   $a1, 0($a2)
+
+	tlbwi			# write entry with dirty bit=1 back to TLB
+	
+	lw   $a0,  9*4($k1)	# restore saved registers and return
+	lw   $a1, 10*4($k1)
+	j    _excp_0180ret
+	lw   $a2, 11*4($k1)
+
+M_seg_fault:	# print message and abort simulation
+	la   $k1, x_IO_BASE_ADDR
+	sw   $k0, 0($k1)
+	jal  cmips_kmsg
+	la   $k1, 3		# segmentation fault
+	nop
+	nop
+	nop
+	wait 0x41
+	
+M_prot_viol:	# print message and abort simulation
+	la   $k1, x_IO_BASE_ADDR
+	sw   $k0, 0($k1)
+	jal  cmips_kmsg
+	la   $k1, 2		# protection violation
+	nop
+	nop
+	nop
+	wait 0x42
+
+M_sec_mem:	# print message and abort simulation
+	la   $k1, x_IO_BASE_ADDR
+	sw   $k0, 0($k1)
+	jal  cmips_kmsg
+	la   $k1, 4		# secondary memory
+	nop
+	nop
+	nop
+	wait 0x43
+	
+	.end handle_Mod
+	#----------------------------------------------------------------
+
+
+	#================================================================
+	# handle TLB Load exception: double-fault caused by a TLB miss
+	#   to the Page Table -- mapping pointing to PT is not on TLB
+	#
+	# (a) fix the fault by (re)loading the mapping into TLB[4];
+	# (b) check permissions in PT entry and (maybe) kill the process.
+	#
+	.global handle_TLBL
+	.global _PT
+        .set MIDDLE_RAM, (x_DATA_BASE_ADDR + (x_DATA_MEM_SZ/2))
+
+	.ent handle_TLBL
+handle_TLBL:			# EntryHi points to offending TLB entry
+	tlbp			# probe it to find the offender's index
+	lui  $k1, %hi(_excp_saves)
+        ori  $k1, $k1, %lo(_excp_saves)
+	sw   $a0,  9*4($k1)
+	sw   $a1, 10*4($k1)
+	sw   $a2, 11*4($k1)
+
+	mfc0 $a0, c0_badvaddr
+	la   $a1, (_PT + (x_INST_BASE_ADDR >>13)*16)
+
+	slt  $a2, $a0, $a1	# a2 <- (badVAddr <= PageTable)
+	bne  $a2, $zero, L_chks	#   fault is not to PageTable
+	nop
+
+	# this is same code as in start.s
+        # get physical page number for two pages at the bottom of PageTable
+        la    $a0, ( MIDDLE_RAM >>13 )<<13
+        mtc0  $a0, c0_entryhi           # tag for bottom double-page
+
+        la    $a0, ( (MIDDLE_RAM + 0*4096) >>12 )<<6
+        ori   $a1, $a0, 0b00000000000000000000000000000111 # ccc=0, d,v,g1
+        mtc0  $a1, c0_entrylo0          # bottom page (even)
+
+        la    $a0, ( (MIDDLE_RAM + 1*4096) >>12 )<<6
+        ori   $a1, $a0, 0b00000000000000000000000000000111 # ccc=0, d,v,g1
+        mtc0  $a1, c0_entrylo1          # bottom page + 1 (odd)
+
+        # and write it to TLB[4]
+        li    $k0, 4
+        mtc0  $k0, c0_index
+        tlbwi
+	j     L_ret		# all work done, return
+	nop
+
+L_chks: andi $a0, $a0, 0x1000	# check if even or odd page
+	beq  $a0, $zero, L_even
+	mfc0 $a0, c0_context
+
+L_odd:	j    L_test
+	addi $a2, $a0, 12	# address for odd intLo1 entry
+	
+L_even: addi $a2, $a0, 4	# address for even intLo0 entry
+
+L_test:	lw   $a1, 0($a2)	# get intLo{0,1}
+	mfc0 $k0, c0_badvaddr	# get faulting address for printing
+	andi $a0, $a1, 0x0001	# check if page is mapped
+	beq  $a0, $zero, M_seg_fault	# no, abort simulation
+	nop
+
+	andi $a0, $a1, 0x0002	# check if page is in secondary memory
+	bne  $a0, $zero, M_sec_mem	# yes, abort simulation
+	nop
+
+	ori  $a1, $a1, 0x0010	# mark PT entry as used
+	sw   $a1, 0($a2)
+
+	# if this were handler_TLBS, now is the time to also mark the
+	#    PT entry as Modified
+
+L_ret:	lw   $a0,  9*4($k1)	# nothing else to do, return
+	lw   $a1, 10*4($k1)
+	j    _excp_0180ret
+	lw   $a2, 11*4($k1)
+
+	.end handle_TLBL
+	#----------------------------------------------------------------
+
+
+	#================================================================
+	# purge an entry from the TLB
+	# int TLB_purge(void *V_addr)
+	#   returns 0 if V_addr purged, 1 if V_addr not in TLB (probe failure)
+	#
+	.text
+	.set noreorder
+	.ent TLB_purge
+TLB_purge:
+	srl  $a0, $a0, 13	# clear out in-page address bits
+	sll  $a0, $a0, 13	# 
+	mtc0 $a0, c0_entryhi
+	nop
+	tlbp			# probe the TLB
+	nop
+	mfc0 $a0, c0_index	# check for hit
+	srl  $a0, $a0, 31	# keeo only MSbit
+	bne  $a0, $zero, pu_miss # address not in TLB
+	move $v0, $a0		# V_addr not in TLB
+
+	tlbr			# read the entry
+	li   $a0, -8192		# -8192 = 0xffff.e000
+	mtc0 $a0, c0_entryhi	# and write an un-mapped address to tag
+
+	addi $v0, $zero, -3	# -3 = 0xffff.fffd to clear valid bit
+	mfc0 $a0, c0_entrylo0	# invalidate the mappings
+	and  $a0, $v0, $a0
+	mtc0 $a0, c0_entrylo0
+
+	mfc0 $a0, c0_entrylo1
+	and  $a0, $v0, $a0
+	mtc0 $a0, c0_entrylo1
+	move $v0, $zero		# V_addr was purged from TLB
+
+	tlbwi			# write invalid mappings to TLB
+	ehb
+	
+pu_miss: jr  $ra
+	nop
+	.end TLB_purge
+	##---------------------------------------------------------------
+
+
+	
+	#================================================================	
+	# delays processing by approx 4*$a0 processor cycles
+	.text
+	.set    noreorder
+	.global cmips_delay, delay_cycle, delay_us, delay_ms
+	.ent    cmips_delay
+delay_cycle:	
+cmips_delay:
+	addiu $a0, $a0, -1
+        nop
+        bne   $a0, $zero, cmips_delay
+        nop
+        jr    $ra
+        nop
+	.end    cmips_delay
+	#----------------------------------------------------------------
+
+	#================================================================	
+	# delays processing by $a0 times 1 microsecond
+	#   loop takes 4 cycles = 80ns @ 50MHz
+	#   1.000ns / 80 = 12.5
+	#   multiply by 2 (sll), add 1, multiply by 12, divide by 2 (sra)
+	.text
+	.set    noreorder
+	.ent    delay_us
+delay_us:
+	sll   $a0, $a0, 1
+	addiu $a0, $a0, 1
+	li    $v0, 12
+	mult  $v0, $a0
+	nop
+	mflo  $a0
+	sra   $a0, $a0, 1
+_d_us:	addiu $a0, $a0, -1
+        nop
+        bne   $a0, $zero, _d_us
+        nop
+        jr    $ra
+        nop
+	.end    delay_us
+	#----------------------------------------------------------------
+
+	#================================================================	
+	# delays processing by $a0 times 1 msecond
+	#   loop takes 4 cycles = 80ns @ 50MHz
+	#   1.000.000ns / 80 = 12500
+	.text
+	.set    noreorder
+	.ent    delay_ms
+delay_ms:	
+	li    $v0, 12500
+	mult  $v0, $a0
+	nop
+	mflo  $a0
+_d_ms:	addiu $a0, $a0, -1
+        nop
+        bne   $a0, $zero, _d_ms
+        nop
+        jr    $ra
+        nop
+	.end    delay_ms
+	#----------------------------------------------------------------
+
+
+	#================================================================	
+	# print a message from within "the kernel"
+	#   void cmips_kmsg( $k1 )
+	# this function preserves registers other than k0,k1
+	#
+	.bss
+        .align  2
+_kmsg_saves:	.space 4*4		# area to save 4 registers
+		# _kmsg_saves[0]=$a0, [1]=$a1, [2]=$a2, [3]=$a3
+
+	.text
+	.align  2
+	.set    noreorder
+	.set    noat
+	.equ	stdout,(x_IO_BASE_ADDR + 1*x_IO_ADDR_RANGE);
+
+	.global cmips_kmsg
+	.ent    cmips_kmsg
+cmips_kmsg:
+	lui   $k0, %hi(_kmsg_saves)
+	ori   $k0, $k0, %lo(_kmsg_saves)
+	sw    $a0, 0*4($k0)
+	sw    $a1, 1*4($k0)
+	sw    $a2, 2*4($k0)
+	
+	lui   $a1, %hi(_kmsg_list)
+	ori   $a1, $a1, %lo(_kmsg_list)
+
+	sll   $k1, $k1, 2		# adjust index onto table
+	addu  $a1, $a1, $k1
+	lw    $a1, 0($a1)		# de-reference pointer
+	
+	lui   $a2, %hi(stdout)
+	ori   $a2, $a2, %lo(stdout)
+	
+k_for:	lbu   $a0, 0($a1)
+	addiu $a1, $a1, 1
+	bne   $a0, $zero, k_for
+	sb    $a0, 0($a2)		# send it to simulator's stdout
+	
+	lw    $a0, 0*4($k0)
+	lw    $a1, 1*4($k0)
+	jr    $ra
+	lw    $a2, 2*4($k0)
+
+	.end    cmips_kmsg
+
+	.equ kmsg_interr,0
+	.equ kmsg_excep,1
+
+	.section .rodata
+        .align  2
+_kmsg_interr:	.asciiz "\n\t00 - interrupt\n\n"
+_kmsg_excep:	.asciiz "\n\t01 - exception\n\n"
+_kmsg_prot_viol:	.asciiz "\n\t02 - protection violation\n\n"
+_kmsg_seg_fault: 	.asciiz "\n\t03 - segmentation fault\n\n"
+_kmsg_sec_mem: 		.asciiz "\n\t04 - in secondary memory\n\n"
+
+	.global _kmsg_list
+	.section .rodata
+        .align  2
+_kmsg_list:
+	.word _kmsg_interr,_kmsg_excep, _kmsg_prot_viol, _kmsg_seg_fault
+	.word _kmsg_sec_mem
+
+	##
+	## need this so the allocation of the PageTable does not break B^(
+	##
+	.section .data
+        .align  2
+_end_of_data:
+	.word 0
+
+	#----------------------------------------------------------------
+
diff --git a/cMIPS/include/syn_start.s b/cMIPS/include/syn_start.s
index 40ce6a7..bb87e88 100644
--- a/cMIPS/include/syn_start.s
+++ b/cMIPS/include/syn_start.s
@@ -67,7 +67,6 @@ _start:	nop
         # set STATUS, cop0, hw interrupt IRQ7,IRQ6,IRQ5 enabled, user mode
         li   $k0, 0x1000e011
         mtc0 $k0, cop0_STATUS
-
 	
         j main
         nop
@@ -77,7 +76,7 @@ _start:	nop
 	##
 exit:	
 _exit:	la   $k0, HW_dsp7seg_addr  	# 7 segment display
-	li   $k1, 0x0311		# display .1.1
+	li   $k1, 0x0300		# display .0.0
 	sw   $k1, 0($k0)		# write to 7 segment display
 
 hexit:	j hexit	  # wait forever
@@ -85,6 +84,15 @@ hexit:	j hexit	  # wait forever
 	.end _start
 
 
+	##
+	## read contants of the stack-pointer (for debugging)
+	##
+	.global print_sp
+	.ent print_sp
+print_sp:
+	jr   $ra
+	move $v0, $sp
+	.end print_sp
 	
         ##
         ##================================================================
@@ -139,7 +147,8 @@ h0100:	j    h0100			# wait forever
         .org x_EXCEPTION_0180,0
 _excp_0180:
 	la   $k0, HW_dsp7seg_addr  	# 7 segment display
-	li   $k1, 0x0377		# display .7.7
+	mfc0 $k1, c0_cause
+	andi $k1, $k1, 0x07f		# display .7.7
 	sw   $k1, 0($k0)		# write to 7 segment display
 h0180:	j    h0180			# wait forever
 	nop
@@ -157,17 +166,76 @@ heret:	j    heret			# wait forever
 	nop
 	
 
+
         ##
         ##===============================================================
         ## interrupt handlers at exception vector 0200
         ##
-        .org x_EXCEPTION_0200,0
+        # declare all handlers here, these must be in file syn_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,0x0000e000   # keep bits 15..8 -> IM = IP
+        .set M_StatusIEn,0xe011     # user mode, enable all interrupts, EXL=0
+
+        .set noreorder
+
+        .org x_EXCEPTION_0200,0     # exception vector_200, interrupt handlers
+        .ent _excp_0200
 _excp_0200:
-	la   $k0, HW_dsp7seg_addr  	# 7 segment display
-	li   $k1, 0x0366		# display .6.6
-	sw   $k1, 0($k0)		# write to 7 segment display
-h0200:	j    h0200			# wait forever
-	nop
+        mfc0 $k0, c0_cause
+        andi $k0, $k0, M_CauseIM   # Keep only IP bits from Cause
+        mfc0 $k1, c0_status
+        and  $k0, $k0, $k1         # and mask with IM bits 
+
+        srl  $k0, $k0, 10          # 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
+        nop
+        jr   $k1
+        nop
+
+
+        ## the code for each handler must repeat the exception return
+        ##   sequence shown below in excp_0200ret.
+handlers_tbl:
+        j dismiss                  # no request: 000
+        nop
+
+        j extCounter               # lowest priority, IRQ5: 001
+        nop
+
+        j UARTinterr               # mid priority, IRQ6: 01x
+        nop
+        j UARTinterr
+        nop
+
+        j countCompare             # highest priority, IRQ7: 1xx
+        nop
+        j countCompare
+        nop
+        j countCompare
+        nop
+        j countCompare
+        nop
+
+
+dismiss: # No pending request, must have been noise
+         #  do nothing and return
+
+_excp_0200ret:
+        mfc0 $k0, c0_status        # Read STATUS register
+        ori  $k0, $k0, M_StatusIEn #  and re-enable interrupts
+        mtc0 $k0, c0_status        #  else keep as it was on int entry 
+        eret                       # Return from interrupt
+        nop
+
+        .end _excp_0200
+        #-----------------------------------------------------------------
+
+
 	
 
         ##
diff --git a/cMIPS/tests/mac_chrono.c b/cMIPS/tests/mac_chrono.c
new file mode 100644
index 0000000..d9605c3
--- /dev/null
+++ b/cMIPS/tests/mac_chrono.c
@@ -0,0 +1,155 @@
+//
+// chronometer on the LCD display
+// 
+// external counter interrupts 4 times per second
+// displays shows a tumbling star plus counter that increments every second
+//
+
+#include "cMIPS.h"
+
+extern int _counter_val;
+
+int conv1(int);
+
+#define FALSE (0==1)
+#define TRUE  !FALSE
+
+#define QUARTER 12500000
+
+int main(void) {
+  int i, j, k;
+  volatile int old_val;
+  int sec, min, hour;
+
+  LCDinit();
+
+  LCDtopLine();
+
+#if 1
+  LCDput(' ');
+  LCDput('H');
+  LCDput('e');
+  LCDput('l');
+  LCDput('l');
+  LCDput('o');
+  LCDput(' ');
+  LCDput('w');
+  LCDput('o');
+  LCDput('r');
+  LCDput('l');
+  LCDput('d');
+  LCDput('!');
+#else
+  LCDprint( print_sp() );
+#endif
+
+  LCDbotLine();
+
+  _counter_val = 0;   // variable to accumulate number of interrupts
+
+  old_val = _counter_val;
+
+  enableInterr();
+  startCounter(QUARTER,TRUE);   // counter will interrupt after N cycles
+
+  sec = min = hour = 0;
+
+  i = 0;
+
+  while (TRUE) {
+  
+    while (old_val == _counter_val) {// wait for interrupt
+      delay_us(i);
+    }
+
+    old_val = _counter_val;
+
+    switch(i) {
+    case 0:
+      j = 0x09; break;
+    case 1:
+      j = 0x0b; break;
+    case 2:
+      j = 0x0c; break;
+    default:
+      j = 0xa; i = -1; sec += 1 ; break;
+    };
+   i += 1; 
+ 
+    LCDgotoxy(1, 2);
+    LCDput(j);
+
+    if (sec == 60) {
+      min += 1;
+      sec = 0;
+    }
+
+    if (min == 60) {
+      hour += 1;
+      min = 0;
+    }
+
+    LCDgotoxy(4, 2);
+
+#define conv(a) ((a<10)?((a)+0x30):((a)+('a'-10)))
+
+    k = (hour>>4) & 0x0f;
+    LCDput( conv(k) );
+    k = hour & 0x0f;
+    LCDput( conv(k) );
+
+    LCDput(':');
+
+    k = (min>>4) & 0x0f;
+    LCDput( conv(k) );
+    k = min & 0x0f;
+    LCDput( conv(k) );
+
+    LCDput(':');
+
+    k = (sec>>4) & 0x0f;
+    LCDput( conv(k) );
+    k = sec & 0x0f;
+    LCDput( conv(k) );
+
+  }
+
+  return 0;
+
+}
+
+
+
+int conv1(int c) {
+  int i;
+
+    switch(c) {
+    case 0:
+    case 1:
+    case 2:
+    case 3:
+    case 4:
+    case 5:
+    case 6:
+    case 7:
+    case 8:
+    case 9:
+      i = c + 0x30; ; break;
+    case 10:
+      i = 'a'; break;
+    case 11:
+      i = 'b'; break;
+    case 12:
+      i = 'c'; break;
+    case 13:
+      i = 'd'; break;
+    case 14:
+      i = 'e'; break;
+    case 15:
+      i = 'f'; break;
+    default:
+      i = '*';
+    }
+
+    return(i);
+}
diff --git a/cMIPS/v_irx.sav b/cMIPS/v_irx.sav
index 66c2a0e..a2b570a 100644
--- a/cMIPS/v_irx.sav
+++ b/cMIPS/v_irx.sav
@@ -1,20 +1,20 @@
 [*]
 [*] GTKWave Analyzer v3.3.37 (w)1999-2012 BSI
-[*] Sun May 17 23:47:43 2015
+[*] Tue Mar 28 23:27:02 2017
 [*]
 [dumpfile] "/home/roberto/cMIPS/v_cMIPS.vcd"
-[dumpfile_mtime] "Sun May 17 23:34:01 2015"
-[dumpfile_size] 24210019
+[dumpfile_mtime] "Tue Mar 28 23:24:11 2017"
+[dumpfile_size] 24414101
 [savefile] "/home/roberto/cMIPS/v_irx.sav"
-[timestart] 6435000000
-[size] 1200 908
-[pos] 676 118
-*-29.000000 7800000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[timestart] 14501000000
+[size] 1200 905
+[pos] 676 70
+*-30.000000 7800000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
 [treeopen] u_simple_uart.
 [sst_width] 210
 [signals_width] 221
 [sst_expanded] 1
-[sst_vpaned_height] 266
+[sst_vpaned_height] 269
 @28
 clk
 @22
@@ -23,8 +23,6 @@ u_core.pc[31:0]
 -    decode, reg fetch
 @22
 u_core.rf_instruction[31:0]
-u_core.regs_a[31:0]
-u_core.regs_b[31:0]
 @200
 -    exec
 @24
@@ -72,7 +70,7 @@ u_simple_uart.u_uart.s_ctrl
 u_simple_uart.u_uart.ctrl[7:0]
 @28
 u_simple_uart.u_uart.s_rx
-@22
+@821
 u_simple_uart.u_uart.rxreg[7:0]
 @28
 u_simple_uart.irq
@@ -93,5 +91,6 @@ u_simple_uart.u_uart.rxdat
 u_uart_remota.tx_dbg_st[31:0]
 @28
 u_uart_remota.outdat
+u_uart_remota.tx_clk
 [pattern_trace] 1
 [pattern_trace] 0
diff --git a/cMIPS/v_rx.sav b/cMIPS/v_rx.sav
index 2b871ff..225ae46 100644
--- a/cMIPS/v_rx.sav
+++ b/cMIPS/v_rx.sav
@@ -1,22 +1,22 @@
 [*]
 [*] GTKWave Analyzer v3.3.37 (w)1999-2012 BSI
-[*] Fri Apr  8 16:29:19 2016
+[*] Tue Mar 28 23:23:27 2017
 [*]
 [dumpfile] "/home/roberto/cMIPS/v_cMIPS.vcd"
-[dumpfile_mtime] "Fri Apr  8 13:54:30 2016"
-[dumpfile_size] 11860622
+[dumpfile_mtime] "Tue Mar 28 23:18:27 2017"
+[dumpfile_size] 12342617
 [savefile] "/home/roberto/cMIPS/v_rx.sav"
-[timestart] 1652600000
-[size] 1133 1018
-[pos] -1 -1
-*-26.000000 1820000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[timestart] 0
+[size] 1133 881
+[pos] 40 -1
+*-31.000000 2283000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
 [treeopen] u_core.
 [treeopen] u_core.u_alu.
 [treeopen] u_simple_uart.
 [sst_width] 210
 [signals_width] 218
 [sst_expanded] 1
-[sst_vpaned_height] 304
+[sst_vpaned_height] 255
 @28
 clk
 @22
@@ -49,6 +49,14 @@ u_core.mm_wrmem
 u_core.data_inp[31:0]
 u_core.data_out[31:0]
 @200
+-    write-back
+@28
+u_core.wb_muxc[2:0]
+u_core.wb_wreg
+@22
+u_core.wb_a_c[4:0]
+u_core.wb_c[31:0]
+@200
 -   UART
 @28
 u_simple_uart.u_uart.rts
@@ -64,42 +72,21 @@ u_simple_uart.u_uart.ctrl[7:0]
 @24
 u_simple_uart.u_uart.rxcpu_dbg_st[31:0]
 u_simple_uart.u_uart.rx_dbg_st[31:0]
-@29
+@28
 u_simple_uart.u_uart.s_rx
 @22
 u_simple_uart.u_uart.rxreg[7:0]
 @28
-u_simple_uart.u_uart.interr_rx_full
-@200
--  transmission circuit
-@24
-u_simple_uart.u_uart.txcpu_dbg_st[31:0]
-u_simple_uart.u_uart.tx_dbg_st[31:0]
-@22
-u_simple_uart.u_uart.txreg[7:0]
-@28
-u_simple_uart.u_uart.txclk
-u_simple_uart.u_uart.txdat
-u_simple_uart.u_uart.interr_tx_empty
+u_simple_uart.u_uart.sta_recv_sto[9:0]
+u_simple_uart.u_uart.rxdat
+@29
+u_simple_uart.u_uart.rxclk
 @200
 -  REMOTE (fake) UART
 @24
 u_uart_remota.tx_dbg_st[31:0]
 @28
 u_uart_remota.outdat
-@24
-u_uart_remota.rx_dbg_st[31:0]
-@28
-u_uart_remota.recv[7:0]
-@22
-u_uart_remota.recv[7:0]
-@200
--    write-back
-@28
-u_core.wb_muxc[2:0]
-u_core.wb_wreg
-@22
-u_core.wb_a_c[4:0]
-u_core.wb_c[31:0]
+u_uart_remota.tx_clk
 [pattern_trace] 1
 [pattern_trace] 0
diff --git a/cMIPS/v_tx.sav b/cMIPS/v_tx.sav
index 261b731..77d368a 100644
--- a/cMIPS/v_tx.sav
+++ b/cMIPS/v_tx.sav
@@ -1,22 +1,22 @@
 [*]
 [*] GTKWave Analyzer v3.3.37 (w)1999-2012 BSI
-[*] Sun May 17 23:22:05 2015
+[*] Tue Mar 28 23:17:37 2017
 [*]
 [dumpfile] "/home/roberto/cMIPS/v_cMIPS.vcd"
-[dumpfile_mtime] "Sun May 17 23:20:27 2015"
-[dumpfile_size] 22609843
+[dumpfile_mtime] "Tue Mar 28 23:15:02 2017"
+[dumpfile_size] 21988875
 [savefile] "/home/roberto/cMIPS/v_tx.sav"
-[timestart] 1526000000
-[size] 1062 917
-[pos] 676 109
-*-30.000000 2000000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[timestart] 0
+[size] 1062 876
+[pos] 854 8
+*-33.000000 7730600000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
 [treeopen] u_core.
 [treeopen] u_core.u_alu.
 [treeopen] u_simple_uart.
 [sst_width] 210
 [signals_width] 218
 [sst_expanded] 1
-[sst_vpaned_height] 268
+[sst_vpaned_height] 255
 @28
 clk
 @22
@@ -27,6 +27,7 @@ u_core.instr_fetched[31:0]
 @22
 u_core.regs_a[31:0]
 u_core.regs_b[31:0]
+u_core.rf_instruction[31:0]
 @200
 -    exec
 @24
@@ -45,11 +46,21 @@ d_addr[31:0]
 cpu_d_aval
 u_core.mm_wrmem
 @22
-u_print_data.data[31:0]
+u_core.data_inp[31:0]
+u_core.data_out[31:0]
 @200
--   UART
+-    write-back
 @28
+u_core.wb_muxc[2:0]
+u_core.wb_wreg
+@22
+u_core.wb_a_c[4:0]
+u_core.wb_c[31:0]
+@200
+-   UART
+@29
 u_simple_uart.u_uart.s_stat
+@28
 u_simple_uart.u_uart.status[7:0]
 u_simple_uart.u_uart.s_ctrl
 u_simple_uart.u_uart.ctrl[7:0]
@@ -68,7 +79,7 @@ u_simple_uart.u_uart.tx_dbg_st[31:0]
 u_simple_uart.u_uart.tx_shr_full
 u_simple_uart.u_uart.txclk
 u_simple_uart.u_uart.txdat
-@23
+@22
 u_interrupt_counter.q[29:0]
 @200
 -  REMOTE (fake) UART
@@ -78,13 +89,5 @@ u_uart_remota.rx_dbg_st[31:0]
 u_uart_remota.recv[7:0]
 @22
 u_uart_remota.recv[7:0]
-@200
--    write-back
-@28
-u_core.wb_muxc[2:0]
-u_core.wb_wreg
-@22
-u_core.wb_a_c[4:0]
-u_core.wb_c[31:0]
 [pattern_trace] 1
 [pattern_trace] 0
diff --git a/cMIPS/vhdl/core.vhd b/cMIPS/vhdl/core.vhd
index a5bc888..c4910c4 100644
--- a/cMIPS/vhdl/core.vhd
+++ b/cMIPS/vhdl/core.vhd
@@ -1407,7 +1407,7 @@ begin
     addrError        <= i_addrError;
     
     -- assert mem_excp_type = exNOP  -- DEBUG
-    --   report "SIMULATION ERROR -- data addressing error: " &
+    --   report LF & "SIMULATION ERROR -- data addressing error: " &
     --   integer'image(exception_type'pos(mem_excp_type)) &
     --   " at address: " & SLV32HEX(v_addr)
     --   severity error;
@@ -1422,7 +1422,7 @@ begin
   -- EX_addr <= v_addr;                    -- without TLB  
 
   -- assert ( (phy_d_addr = v_addr) and (EX_aVal = '0') )  -- DEBUG
-  --  report "mapping mismatch V:P "&SLV32HEX(v_addr)&":"&SLV32HEX(phy_d_addr);
+  --  report LF&"mapping mismatch V:P "&SLV32HEX(v_addr)&":"&SLV32HEX(phy_d_addr);
 
 
   EX_wreg <= EX_wreg_pre                  -- movz,movn, move/DO_NOT move
@@ -2690,11 +2690,17 @@ begin
       i_stage_mm  := FALSE;
       i_exception := FALSE;
     end if;
-  
+
+    -- uncomment when making use of the TLB
     TLB_excp_type <= i_excp_type;
     tlb_stage_MM  <= i_stage_mm;
     tlb_exception <= i_exception and not(SL2BOOL(tlb_ex_2));
-    
+
+    -- uncomment when NOT making use of the TLB
+    -- TLB_excp_type <= exNOP;
+    -- tlb_stage_MM  <= FALSE;
+    -- tlb_exception <= FALSE;
+
   end process MMU_exceptions; -- -----------------------------------------
 
   -- catch only first exception, if there are two in consecutive cycles
-- 
GitLab