Commit b80a0478 authored by Roberto Hexsel's avatar Roberto Hexsel

forward progress holds with simultaneous interrupts

parent bdff9da6
Pipeline #2219 skipped
......@@ -65,7 +65,7 @@ touch input.data serial.inp
a_FWD="fwdAddAddAddSw fwd_SW lwFWDsw lwFWDsw2 slt32 slt_u_32 slt_s_32 reg0"
a_CAC="dCacheTst lhUshUCache lbUsbUCache lbsbCache dCacheTstH dCacheTstB"
a_BEQ="lw-bne bXtz sltbeq beq_dlySlot jr_dlySlot interrJR_dlySlot"
a_BEQ="lw-bne bXtz sltbeq beq_dlySlot jr_dlySlot interr_x2 interrJR_dlySlot"
a_FUN="jaljr jr_2 jal_fun_jr jalr_jr jallwjr bltzal_fun_jr"
a_OTH="mult div mul sll slr movz wsbh_seb extract insert"
a_BHW="lbsb lhsh lwsw lwswIncr swlw lwl_lwr"
......
00000013
00000012
c0808000
0000003f
00000046
0000003c
00000042
c0808000
# Testing the internal counter is difficult because it counts clock cycles
# rather than instructions -- if the I/O or memory latencies change then
# the simulation output also changes and comparisons are impossible.
# the simulation output also changes and comparisons may be impossible.
.include "cMIPS.s"
.text
......@@ -17,7 +17,7 @@ _start: nop
li $k0, c0_status_reset # RESET, kernel mode, all else disabled
mtc0 $k0, c0_status
li $sp,(x_DATA_BASE_ADDR+x_DATA_MEM_SZ-8) # initialize SP: ramTop-8
li $k0, 0x1800ff01 # RESET_STATUS, kernel mode, interr enabled
li $k0, 0x1000ff01 # RESET_STATUS, kernel mode, interr enabled
mtc0 $k0, c0_status
li $k0, c0_cause_rst # RESET, disable counter
mtc0 $k0, c0_cause
......@@ -78,11 +78,10 @@ _excp_180:
.org x_EXCEPTION_0200,0
_excp_200:
mfc0 $k1, c0_count # read current COUNT
sw $k1, 0($15)
sw $k1, 0($15) # and print it
mfc0 $k0, c0_cause # read CAUSE and
nop
sw $k0, 0($15) # print CAUSE
mfc0 $k0, c0_cause # read CAUSE
sw $k0, 0($15) # and print it
li $k0, 0 # remove IRQ
mtc0 $k0, c0_compare
......@@ -90,7 +89,6 @@ _excp_200:
li $k0, 0x10008001 # CP0active, enable COUNT interrupts
mtc0 $k0, c0_status
ehb
eret
#
#================================================================
......@@ -121,9 +119,13 @@ main: la $15, x_IO_BASE_ADDR
li $13, '\n'
li $11, 0 # used with the identifiable NOPs
#
# let us cause an interrupt on a stalled JALR
#
##
## let us cause an interrupt on a stalled JALR
## interrupt MUST occur on the dly-slot caused by a previous LOAD
## JALR must be restarted and return address cannot be saved by JALR
## since that instruction was neither started nor completed
##
.set numCy, 12 # magic number: cycles needed to ensure
# interrupt hits the JALR
......@@ -144,6 +146,7 @@ two_instr:
la $12, err0
sw $12, 4($20) # write error message to memory
nop # align COUNT==COMPARE with JR
nop
sw $21, 0($20) # store jump target
li $11, 0 # this is a NOP
li $11, 1 # this is a NOP
......@@ -160,13 +163,14 @@ one_instr:
# $19 must be zero
# handler copies $24 -> $19
nop # to ensure JALR did not change $24
bne $zero, $19, err2 # check if return addess was changed
bne $zero, $19, err2 # check if return address was changed
nop
#
# let us cause an interrupt on a JR, delayed by a LW
#
##
## let us cause an interrupt on a JR, delayed by a LW
##
.set numCy, 22 # magic number: cycles needed to ensure
# interrupt hits the JALR
......@@ -181,6 +185,7 @@ one_instr:
and $5, $5, $6
mtc0 $5, c0_cause # enable counter
nop
nop # align interr with JALR
sw $9, 0($15) # show old+numCycles
......@@ -193,10 +198,10 @@ one_instr:
li $11, 10 # this is a NOP
li $11, 11 # this is a NOP
li $11, 12 # this is a NOP
lw $23, 0($20) # load target address to cause delay slot
lw $23, 0($20) # load target address to cause 2x delay slots
jalr $24, $23 # save ra in $24
li $11, 13 # this is a NOP
one: li $11, 14 # this is a NOP
one: li $11, 14 # this is a NOP, return address from jalr
li $11, 15 # this is a NOP
zero_instr:
......@@ -205,7 +210,7 @@ zero_instr:
# $19 must be zero
# handler copies $24 -> $19
nop # to ensure JALR did not change $24
bne $zero, $19, err1 # check if return addess was changed
bne $zero, $19, err1 # check if return address was changed
nop
li $11, 16 # this is a NOP
......
C
e
e
C
e
e
C
e
e
C
e
e
C
e
e
C
e
e
C
e
e
C
e
# Objective: test two more or less simultaneous interrupts, one by internal
# counter and one by the external counter.
#
# 1st test: hi priority (internal cntr) arrives first
# 2nd test: lo priority (external cntr) arrives first
# then the two alternate
# Testing the internal counter is difficult because it counts clock cycles
# rather than instructions -- if the I/O or memory latencies change then
# the simulation output also changes and comparisons may be impossible.
.include "cMIPS.s"
.text
.align 2
.set noat
.set noreorder
.set numCy, 64
.global _start
.global _exit
.set c0_cause_rst, 0x0880007c # disable counter, separate IntVector
.set ext_restart, 0xc0000000 # start ext_counter, intrr enable
_start: nop
li $k0, c0_status_reset # RESET, kernel mode, all else disabled
mtc0 $k0, c0_status
li $sp,(x_DATA_BASE_ADDR+x_DATA_MEM_SZ-8) # initialize SP: ramTop-8
li $k0, 0x1000ff01 # RESET_STATUS, kernel mode, interr enabled
mtc0 $k0, c0_status
li $k0, c0_cause_rst # RESET, disable counter
mtc0 $k0, c0_cause
la $15,x_IO_BASE_ADDR
nop
j main
nop
exit:
_exit: nop # flush pipeline
nop
nop
nop
nop
nop
wait # then stop VHDL simulation
nop
#----------------------------------------------------------------
.org x_EXCEPTION_0000,0
_excp_0000: wait 0x01
la $k0, x_IO_BASE_ADDR
mfc0 $k1, c0_cause
sw $k1, 0($k0) # print CAUSE, flush pipe and stop simulation
nop
nop
nop
wait 0x01
nop
#----------------------------------------------------------------
.org x_EXCEPTION_0100,0
_excp_0100: wait 0x02
la $k0, x_IO_BASE_ADDR
mfc0 $k1, c0_cause
sw $k1, 0($k0) # print CAUSE, flush pipe and stop simulation
nop
nop
nop
wait 0x02
nop
#----------------------------------------------------------------
.org x_EXCEPTION_0180,0
_excp_180: wait 0x03
la $k0, x_IO_BASE_ADDR
mfc0 $k1, c0_cause
sw $k1, 0($k0) # print CAUSE, flush pipe and stop simulation
nop
nop
nop
wait 0x03
nop
#
# interrupt handler =============================================
#
.org x_EXCEPTION_0200,0
_excp_200:
nop # wait a looong time to ensure both
nop # interrupts are signalled
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
mfc0 $k0, c0_cause # read CAUSE and
nop
nop # sw $k0, 0($15) # print it
andi $k1, $k0, 0x8000 # is hi_priority active?
beq $k1, $zero, lo_pri # YES, handle it
nop
hi_pri: li $k0, 0 # remove IRQ
mtc0 $k0, c0_compare
mfc0 $k1, c0_count # read current COUNT
nop # sw $k1, 0($15)
addi $k1, $k1, (numCy+10) # interrupt again in numCy cycles
mtc0 $k1, c0_compare
li $k1, 'C' # tell it was Counter
j rf_irq # and return
nop
lo_pri: lui $k0, %hi(ext_restart)
ori $k0, $k0, (numCy-40) # interrupt again in numCy cycles
lui $k1, %hi(HW_counter_addr)
ori $k1, $k1,%lo(HW_counter_addr)
sw $k0, 0($k1) # restart external counter
li $k1, 'e' # tell it was external counter
rf_irq: sw $k1, 0x20($15) # print IRQ source
sw $13, 0x20($15)
li $k0, 0x1000f001 # CP0active, enable COUNT interrupts
mtc0 $k0, c0_status
eret
#
#================================================================
#
#----------------------------------------------------------------
.org x_EXCEPTION_BFC0,0
_excp_BFC0: wait 0x04
la $k0, x_IO_BASE_ADDR
mfc0 $k1, c0_cause
sw $k1, 0($k0) # print CAUSE, flush pipe and stop simulation
nop
nop
wait 0x04
nop
##
##-----------------------------------------------------------------
##
.set TRUE, 1
.set FALSE, 0
.org x_ENTRY_POINT,0
main: la $15, x_IO_BASE_ADDR
li $13, '\n'
li $11, 0 # used with the identifiable NOPs
#
# let us cause two interrupts
#
li $5, numCy # interrupt again in numCy cycles
mtc0 $5, c0_compare
# enable Counter
mfc0 $5, c0_cause
li $6, 0xf7ffffff # CAUSE.DisableCount <= false
and $5, $5, $6
mtc0 $5, c0_cause # enable counter
# start external counter
lui $5, %hi(ext_restart)
ori $5, $5, (numCy+4) # interrupt in numCy cycles
lui $6, %hi(HW_counter_addr) # AFTER Count=Compare interrupt
ori $6, $6, %lo(HW_counter_addr)
sw $5, 0($6) # restart external counter
nop
# lets do nothing for a long time.
li $20, 0
li $21, 20
loop: addi $20, $20, 1
li $2, 1
li $2, 2
li $2, 3
li $2, 4
li $2, 5
li $2, 6
bne $20, $21, loop
nop
nop
j exit
nop
......@@ -21,9 +21,6 @@ typedef struct status { // status register fields (uses only ls byte)
overun : 1; // overun error (bit 0)
} Tstatus;
#define RXfull 0x00000020
#define TXempty 0x00000040
typedef union ctlStat { // control + status on same address
Tcontrol ctl; // write-only
......@@ -53,12 +50,20 @@ int main(void) { // receive a string through the UART serial interface
uart = (void *)IO_UART_ADDR; // bottom of UART address range
ctrl.ign = 0;
ctrl.rts = 0;
ctrl.rts = 0; // make RTS=0 to hold remote unit
ctrl.intTX = 0;
ctrl.intRX = 1;
ctrl.speed = 1; // operate at 1/2 of the highest data rate
ctrl.intRX = 0;
ctrl.speed = 1; // operate at 1/2 of the highest data rate
uart->cs.ctl = ctrl; // initizlize UART
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
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
......
......@@ -22,8 +22,6 @@ typedef struct status { // status register fields (uses only ls byte)
overun : 1; // overun error (bit 0)
} Tstatus;
#define RXfull 0x00000020
#define TXempty 0x00000040
typedef union ctlStat { // control + status on same address
Tcontrol ctl; // write-only
......@@ -89,7 +87,7 @@ int main(void) { // send a string through the UART serial interface
ctrl.intRX = 0;
ctrl.ign2 = 0;
ctrl.ign = 0;
ctrl.rts = 1;
ctrl.rts = 0; // make RTS=0 so RemoteUnit won't transmit, just receive
uart->cs.ctl = ctrl;
i = -1;
......
[*]
[*] GTKWave Analyzer v3.3.37 (w)1999-2012 BSI
[*] Sun May 17 23:18:38 2015
[*] Fri Apr 8 16:29:19 2016
[*]
[dumpfile] "/home/roberto/cMIPS/v_cMIPS.vcd"
[dumpfile_mtime] "Sun May 17 23:11:59 2015"
[dumpfile_size] 27081351
[dumpfile_mtime] "Fri Apr 8 13:54:30 2016"
[dumpfile_size] 11860622
[savefile] "/home/roberto/cMIPS/v_rx.sav"
[timestart] 56766300000
[size] 1062 914
[timestart] 1652600000
[size] 1133 1018
[pos] -1 -1
*-27.000000 56960000000 -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
*-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
[treeopen] u_core.
[treeopen] u_core.u_alu.
[treeopen] u_simple_uart.
[sst_width] 210
[signals_width] 227
[signals_width] 218
[sst_expanded] 1
[sst_vpaned_height] 267
[sst_vpaned_height] 304
@28
clk
@22
......@@ -23,9 +25,9 @@ u_core.instr_fetched[31:0]
@200
- decode, reg fetch
@22
u_core.rf_instruction[31:0]
u_core.regs_a[31:0]
u_core.regs_b[31:0]
u_core.rf_instruction[31:0]
@200
- exec
@24
......@@ -39,55 +41,65 @@ u_core.result[31:0]
@28
u_core.b_sel[3:0]
@22
u_core.data_inp[31:0]
u_core.data_out[31:0]
d_addr[31:0]
@28
cpu_d_aval
u_core.mm_wrmem
@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_core.data_inp[31:0]
u_core.data_out[31:0]
@200
- UART
- UART
@28
u_simple_uart.u_uart.rts
u_simple_uart.u_uart.s_stat
u_simple_uart.u_uart.status[7:0]
@22
u_simple_uart.u_uart.status[7:0]
@28
u_simple_uart.u_uart.s_ctrl
@22
u_simple_uart.u_uart.ctrl[7:0]
@28
u_simple_uart.u_uart.s_rx
@22
u_simple_uart.u_uart.rxreg[7:0]
@200
- reception
- reception circuit
@24
u_simple_uart.u_uart.rxcpu_dbg_st[31:0]
u_simple_uart.u_uart.rx_dbg_st[31:0]
@29
u_simple_uart.u_uart.s_rx
@22
u_simple_uart.u_uart.rxreg[7:0]
@28
u_simple_uart.u_uart.rx_bfr_full
u_simple_uart.u_uart.interr_rx_full
@200
- transmission circuit
@24
u_simple_uart.u_uart.rx_dbg_st[31:0]
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.sta_recv_sto[9:0]
u_simple_uart.u_uart.rxclk
u_simple_uart.u_uart.rxdat
u_simple_uart.u_uart.txclk
u_simple_uart.u_uart.txdat
u_simple_uart.u_uart.interr_tx_empty
@200
- REMOTE (fake) UART
@28
u_uart_remota.start
@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]
[pattern_trace] 1
[pattern_trace] 0
......@@ -135,6 +135,7 @@ architecture rtl of core is
signal nullify_MM_pre, nullify_MM_int :std_logic;
signal annul_1, annul_2, annul_twice : std_logic;
signal interrupt, exception_stall : std_logic;
signal dly_i0, dly_i1, dly_i2, dly_interr: std_logic;
signal exception_taken, interrupt_taken : std_logic;
signal nullify_fetch, nullify, MM_nullify : boolean;
signal addrError, MM_addrError, abort_ref, MM_ll_sc_abort : boolean;
......@@ -1254,7 +1255,7 @@ begin
end if;
end process RF_DECODE_FUNCT;
exception_dec <= exception_type'pos(exception); -- debugging only
-- exception_dec <= exception_type'pos(exception); -- debugging only
can_trap <= ctrl_word.excp or funct_word.excp or rimm_word.excp;
......@@ -1795,7 +1796,20 @@ begin
is_interr <= ( (interrupt = '1') and
(STATUS(STATUS_EXL) = '0') and
(STATUS(STATUS_ERL) = '0') and
(STATUS(STATUS_IE) = '1') );
(STATUS(STATUS_IE) = '1') and
(dly_interr = '0') and
(interrupt_taken = '0') ); -- single cycle exception req
-- While returning from an exception (especially another interrupt),
-- delay the IRQ to make sure the interrupted instruction completes;
-- This is needed to ensure forward-progress: at least one instruction
-- must complete before another interrupt may be taken.
dly_i0 <= '1' when is_exception = exERET else '0';
U_DLY_INT1: FFD port map (clk, rst, '1',dly_i0, dly_i1);
U_DLY_INT2: FFD port map (clk, rst, '1',dly_i1, dly_i2);
dly_interr <= dly_i0 or dly_i1 or dly_i2;
-- check for overflow in EX, send it to MM for later processing
is_ovfl <= (EX_can_trap = b"10" and ovfl = '1');
......@@ -1821,6 +1835,7 @@ begin
exInterr when is_interr else
EX_exception;
exception_dec <= exception_type'pos(EX_is_exception); -- debugging only
-- ----------------------------------------------------------------------
PIPESTAGE_EXCP_EX_MM: reg_excp_EX_MM
......@@ -1837,8 +1852,10 @@ begin
int_req,MM_int_req,
is_SC, MM_is_SC, is_MFC0, MM_is_MFC0,
EX_is_exception, is_exception);
-- exception_dec <= exception_type'pos(is_exception); -- debugging only
-- STATUS -- pg 79 -- cop0_12 --------------------
COP0_DECODE_EXCEPTION_AND_UPDATE_STATUS:
process (MM_a_rt, is_exception, cop0_inp,
......@@ -1872,7 +1889,7 @@ begin
nullify_MM_pre <= '0';
newSTATUS := STATUS; -- preserve as needed
newSTATUS(STATUS_BEV) := '0'; -- interrupts at offset 0x200
newSTATUS(STATUS_BEV) := '0'; -- interrupts at offset 0x200, not boot
newSTATUS(STATUS_CU3) := '0'; -- COP-3 absent (always)
newSTATUS(STATUS_CU2) := '0'; -- COP-2 absent (always)
newSTATUS(STATUS_CU1) := '0'; -- COP-1 absent (always)
......@@ -2067,7 +2084,7 @@ begin
when exTLBP | exTLBR | exTLBWI | exTLBWR => -- TLB access
i_stall := '0'; -- stall the processor
i_stall := '0'; -- do not stall the processor
when exTLBrefillIF =>
......@@ -2106,8 +2123,8 @@ begin
newSTATUS(STATUS_IE) := '0'; -- disable interrupts
i_update := '1';
i_update_r := cop0reg_STATUS;
i_epc_update := '0';
i_nullify := TRUE; -- nullify instructions in IF,RF,EX
i_epc_update := '0';
i_nullify := TRUE; -- nullify instructions in IF,RF,EX
when exTLBdblFaultIF | exTLBinvalIF =>
ExcCode <= cop0code_TLBL;
......@@ -2122,8 +2139,8 @@ begin
newSTATUS(STATUS_IE) := '0'; -- disable interrupts
i_update := '1';
i_update_r := cop0reg_STATUS;
i_epc_update := '0';
i_nullify := TRUE; -- nullify instructions in IF,RF,EX
i_epc_update := '0';
i_nullify := TRUE; -- nullify instructions in IF,RF,EX
when exTLBdblFaultRD | exTLBdblFaultWR |
......@@ -2168,7 +2185,7 @@ begin
when exInterr => -- normal interrupt
if (rom_stall = '0') and (ram_stall = '0') then
-- assert false report "interrupt PC="&SLV32HEX(PC) severity note;
interrupt_taken <= '1'; -- debugging only
interrupt_taken <= '1';
newSTATUS(STATUS_UM) := '0'; -- enter kernel mode
newSTATUS(STATUS_EXL) := '1'; -- at exception level
newSTATUS(STATUS_IE)