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