From c67b61644f07ea4968c9f8dfb7e27307ee2fdf12 Mon Sep 17 00:00:00 2001
From: Roberto Hexsel <roberto@inf.ufpr.br>
Date: Tue, 10 May 2016 18:10:01 -0300
Subject: [PATCH] improved UART_rx_irq handler

---
 cMIPS/include/handlers.s | 30 ++++++++++++++++--------------
 cMIPS/tests/uart_irx.c   | 20 +++++++++-----------
 cMIPS/vhdl/core.vhd      | 18 +++++-------------
 3 files changed, 30 insertions(+), 38 deletions(-)

diff --git a/cMIPS/include/handlers.s b/cMIPS/include/handlers.s
index 3fe1148..4954400 100644
--- a/cMIPS/include/handlers.s
+++ b/cMIPS/include/handlers.s
@@ -95,34 +95,36 @@ Ud:	.comm   rx_queue 16       # reception queue and pointers
 	#           [4]=$ra, [5]=$a0, [6]=$a1, [7]=$a2, [8]=$a3
 	
 UARTinterr:
-	lui   $k0, %hi(HW_uart_addr)
-	ori   $k0, $k0, %lo(HW_uart_addr)
-	lw    $k1, 0($k0) 	    # Read status, remove interrupt request
-
-	lui   $k0, %hi(_uart_buff)
+	lui   $k0, %hi(_uart_buff)  # get buffer's address
 	ori   $k0, $k0, %lo(_uart_buff)
-	sw    $k1, 0*4($k0)         #  and save UART status to memory
 	
 	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  $a0, $k1, UART_rx_irq # Is this reception?
-	beq   $a0, $zero, UARTret   #   no, ignore it and return
+	andi  $a1, $k1, UART_rx_irq # Is this reception?
+	beq   $a1, $zero, UARTret   #   no, ignore it and return
+	nop
 
-	lui   $a0, %hi(HW_uart_addr)
-	ori   $a0, $a0, %lo(HW_uart_addr)
-	lw    $a1, 4($a0) 	    # Read data
+	# handle reception
+	lw    $a1, 4($a0) 	    # Read data from device
 	nop                         #   and store it to UART's buffer
-	sw    $a1, 4($k0)           #   and return from interrupt
+	sw    $a1, 2*4($k0)         #   and return from interrupt
 	addiu $a1, $zero, 1
-	sw    $a1, 8($k0)           # Signal new arrival 
-		
+	sw    $a1, 3*4($k0)         # Signal new arrival 
+
 UARTret:
 	lw    $a1, 6*4($k0)         # restore registers $a0,$a1, others?
 	lw    $a0, 5*4($k0)
diff --git a/cMIPS/tests/uart_irx.c b/cMIPS/tests/uart_irx.c
index 2f6139c..a280a10 100644
--- a/cMIPS/tests/uart_irx.c
+++ b/cMIPS/tests/uart_irx.c
@@ -64,27 +64,25 @@ int main(void) { // receive a string through the UART serial interface
   ctrl.rts   = 0;  // make RTS=0 to hold remote unit
   ctrl.intTX = 0;
   ctrl.intRX = 0;
-  ctrl.speed = 1;  // operate at 1/2 of the highest data rate
+  ctrl.speed = 2;  // operate at 1/4 of the highest data rate
   uart->cs.ctl = ctrl; // initizlize UART
 
+  // handler sets flag=bfr[3] to 1 after new character is received;
+  // this program resets the flag on fetching a new character from buffer
+  bfr[3] = 0;      //   reset flag  
+
   ctrl.ign   = 0;
   ctrl.rts   = 1;  // make RTS=1 so RemoteUnit starts its transmission
   ctrl.intTX = 0;
   ctrl.intRX = 1;  // do generate interrupts on RXbuffer full
-  ctrl.speed = 1;  // operate at 1/2 of the highest data rate
+  ctrl.speed = 2;  // operate at 1/4 of the highest data rate
   uart->cs.ctl = ctrl;
 
-
-  // handler sets flag=bfr[2] to 1 after new character is received;
-  // this program resets the flag on fetching a new character from buffer
-
-  c = (char)bfr[2];   // interrupt handler's flag
-  
   do {
-    while ( (c = (char)bfr[2]) == 0 ) 
+    while ( (c = (char)bfr[3]) == 0 ) 
       {};                 // nothing new
-    c = (char)bfr[1];     // get new character
-    bfr[2] = 0;           //   and reset flag
+    c = (char)bfr[2];     // get new character
+    bfr[3] = 0;           //   and reset flag
     to_stdout( (int)c );
   } while (c != '\0');    // end of string?
 
diff --git a/cMIPS/vhdl/core.vhd b/cMIPS/vhdl/core.vhd
index 6e9164f..0bddb10 100644
--- a/cMIPS/vhdl/core.vhd
+++ b/cMIPS/vhdl/core.vhd
@@ -1967,6 +1967,9 @@ begin
         i_stall      := '0';            -- do not stall
         i_nullify    := TRUE;           -- nullify instructions in IF,RF
 
+
+      -- when processor goes into exception-level, IRQs are ignored,
+      --   hence disabled
         
       when exSYSCALL | exBREAK =>       -- SYSCALL, BREAK
         i_stall    := '0';
@@ -1977,7 +1980,6 @@ begin
         end if;  
         newSTATUS(STATUS_EXL) := '1';   -- at exception level
         newSTATUS(STATUS_UM)  := '0';   -- enter kernel mode          
-        -- newSTATUS(STATUS_IE)  := '0';   -- disable interrupts
         i_update   := '1';
         i_update_r := cop0reg_STATUS;
         i_stall    := '0';              -- do not stall
@@ -1996,7 +1998,6 @@ begin
         ExcCode <= cop0code_Tr;
         newSTATUS(STATUS_EXL) := '1';   -- at exception level
         newSTATUS(STATUS_UM)  := '0';   -- enter kernel mode          
-        -- newSTATUS(STATUS_IE)  := '0';   -- disable interrupts
         i_update   := '1';
         i_update_r := cop0reg_STATUS;
         i_stall    := '0';
@@ -2026,7 +2027,6 @@ begin
 
       when exOvfl =>                    -- OVERFLOW happened one cycle earlier
         newSTATUS(STATUS_EXL) := '1';   -- at exception level
-        -- newSTATUS(STATUS_IE)  := '0';   -- disable interrupts
         exception_taken <= '1';
         i_update        := '1';
         i_update_r      := cop0reg_STATUS;
@@ -2044,7 +2044,6 @@ begin
         
       when IFaddressError =>            -- fetch from UNALIGNED ADDRESS
         newSTATUS(STATUS_EXL) := '1';   -- at exception level
-        newSTATUS(STATUS_IE)  := '0';   -- disable interrupts
         exception_taken <= '1';
         i_update        := '1';
         i_update_r      := cop0reg_STATUS;
@@ -2058,7 +2057,6 @@ begin
       when MMaddressErrorLD | MMaddressErrorST =>
         -- load/store from/to UNALIGNED ADDRESS
         newSTATUS(STATUS_EXL) := '1';   -- at exception level
-        newSTATUS(STATUS_IE)  := '0';   -- disable interrupts
         exception_taken <= '1';
         i_update        := '1';
         i_update_r      := cop0reg_STATUS;
@@ -2096,7 +2094,6 @@ begin
           is_delayslot <= '0';
         end if;
         newSTATUS(STATUS_EXL) := '1';       -- at exception level
-        -- newSTATUS(STATUS_IE)  := '0';       -- disable interrupts
         i_update        := '1';
         i_update_r      := cop0reg_STATUS;
         i_epc_update    := '0';
@@ -2119,7 +2116,6 @@ begin
           is_delayslot <= MM_is_delayslot;
         end if;
         newSTATUS(STATUS_EXL) := '1';   -- at exception level
-        -- newSTATUS(STATUS_IE)  := '0';   -- disable interrupts
         i_update     := '1';
         i_update_r   := cop0reg_STATUS;
         i_epc_update := '0';
@@ -2135,7 +2131,6 @@ begin
           is_delayslot <= '0';
         end if;
         newSTATUS(STATUS_EXL) := '1';   -- at exception level
-        -- newSTATUS(STATUS_IE)  := '0';   -- disable interrupts
         i_update     := '1';
         i_update_r   := cop0reg_STATUS;
         i_epc_update := '0';
@@ -2161,7 +2156,6 @@ begin
           is_delayslot <= MM_is_delayslot;
         end if;
         newSTATUS(STATUS_EXL) := '1';   -- at exception level
-        -- newSTATUS(STATUS_IE)  := '0';   -- disable interrupts
         i_update     := '1';
         i_update_r   := cop0reg_STATUS;
         i_epc_update := '0';
@@ -2175,7 +2169,6 @@ begin
           ExcCode <= cop0code_DBE;
         end if;
         newSTATUS(STATUS_EXL) := '1';   -- at exception level
-        newSTATUS(STATUS_IE)  := '0';   -- disable interrupts
         i_update   := '1';
         i_update_r := cop0reg_STATUS;
         i_nullify  := TRUE;             -- nullify instructions in IF,RF,EX
@@ -2187,7 +2180,6 @@ begin
           interrupt_taken       <= '1';
           newSTATUS(STATUS_UM)  := '0'; -- enter kernel mode          
           newSTATUS(STATUS_EXL) := '1'; -- at exception level
-          newSTATUS(STATUS_IE)  := '0'; -- disable interrupts
           ExcCode      <= cop0code_Int;
           i_update     := '1';
           i_update_r   := cop0reg_STATUS;
@@ -2239,9 +2231,9 @@ begin
     update_reg      <= i_update_r;
 
     if is_exception = exMTC0 and MM_cop0_reg = cop0reg_EPC then
-      epc_update   <= i_epc_update;
+      epc_update    <= i_epc_update;
     else
-      epc_update   <= i_epc_update OR STATUS(STATUS_EXL);
+      epc_update    <= i_epc_update OR STATUS(STATUS_EXL);
     end if;
     epc_source      <= i_epc_source;
     
-- 
GitLab