diff --git a/cMIPS/docs/cMIPS.pdf b/cMIPS/docs/cMIPS.pdf index bc980295cb6293853cf80e63065c716fa2ca2aba..ca7ba41e753e0f3c2d12abb9f5f6af37727c5314 100644 Binary files a/cMIPS/docs/cMIPS.pdf and b/cMIPS/docs/cMIPS.pdf differ diff --git a/cMIPS/docs/figs/circuit1.pdf b/cMIPS/docs/figs/circuit1.pdf new file mode 100644 index 0000000000000000000000000000000000000000..9b4f95006edb69904eb59854b0193c06e4b1f515 Binary files /dev/null and b/cMIPS/docs/figs/circuit1.pdf differ diff --git a/cMIPS/docs/figs/circuit2.pdf b/cMIPS/docs/figs/circuit2.pdf new file mode 100644 index 0000000000000000000000000000000000000000..1c526b89bd5afba32d00cf7e9d039d1bde3804f3 Binary files /dev/null and b/cMIPS/docs/figs/circuit2.pdf differ diff --git a/cMIPS/docs/figs/circuit3.pdf b/cMIPS/docs/figs/circuit3.pdf new file mode 100644 index 0000000000000000000000000000000000000000..bf946527eae132928abf123dace45ae284a7fa44 Binary files /dev/null and b/cMIPS/docs/figs/circuit3.pdf differ diff --git a/cMIPS/docs/installCrosscompiler b/cMIPS/docs/installCrosscompiler index 66e8b62d3b8af80a7b519e3e43e293d89e9d8331..8426561132d0650848a070aee5ed8f65c65b2fd8 100644 --- a/cMIPS/docs/installCrosscompiler +++ b/cMIPS/docs/installCrosscompiler @@ -53,3 +53,20 @@ make all-gcc make install-gcc cd .. + +# once GCC and Binutils are compiled and installed, all that is needed is +# for you to add the new path to your PATH, preferably in your ~/.bashrc +export PATH=${PATH}:${PREFIX}/bin +export MANPATH=${MANPATH}:${PREFIX}/man + + +# and that ends the cross-compiler installation. + + + +# You may also want/need to install GHDL on your machine. As of March, +# 2015, there is no official Debian package. You must download the +# unofficial package from Sourceforge at: +# https://sourceforge.net/p/ghdl-updates/wiki/Debian%20Instructions/ +# and pick the appropriate version for your computer (32 or 64 bit). + diff --git a/cMIPS/include/stop.s b/cMIPS/include/stop.s index c70594cb7bd7f527dc3ad91f7cb554903acec196..5849ebc8b5287a77c4ca7c77fff767b3f701369c 100644 --- a/cMIPS/include/stop.s +++ b/cMIPS/include/stop.s @@ -1,5 +1,4 @@ .section .bss,"aw",@nobits .align 3 .global _highmem - .comm _highmem 16 - + .comm _highmem 4 diff --git a/cMIPS/tests/badVAddr.s b/cMIPS/tests/badVAddr.s index 019289f45f0c256ab7823762843eed37a7417f2f..4f10da1ccd92f2ee44ba30d9269845a948cc1626 100644 --- a/cMIPS/tests/badVAddr.s +++ b/cMIPS/tests/badVAddr.s @@ -3,18 +3,18 @@ .text .align 2 .set noreorder - .global _start - .global _exit - .global exit + .global _start, _exit, .ent _start _start: nop li $sp,(x_DATA_BASE_ADDR+x_DATA_MEM_SZ-8) # initialize SP: ramTop-8 - la $k0, main - nop - mtc0 $k0, cop0_EPC - nop - eret # leave exception level, all else disabled + + ## set STATUS, cop0, no interrupts enabled, user mode + li $k0, 0x10000010 + mtc0 $k0, cop0_STATUS + + j main nop + exit: _exit: nop # flush pipeline nop @@ -37,10 +37,9 @@ excp_180: mfc0 $k0, cop0_CAUSE sw $k0, 0($14) # print CAUSE + mfc0 $k0, cop0_EPC # fix return address sw $k0, 0($14) # print EPC - addiu $7, $7, -1 - addiu $k1, $zero, -4 # -4 = 0xffff.fffc and $k1, $k1, $k0 # fix the invalid address mtc0 $k1, cop0_EPC @@ -50,15 +49,16 @@ excp_180: li $k0, '\n' sw $k0, x_IO_ADDR_RANGE($14) + addiu $7, $7, -1 eret .end excp_180 - .org x_ENTRY_POINT,0 # normal code start + .org x_ENTRY_POINT,0 # normal code start main: la $14, x_IO_BASE_ADDR # used by handler la $15, x_IO_BASE_ADDR li $7, 3 - la $3, here + la $3, here # address for misaigned fetches nop here: sw $3, 0($15) @@ -67,8 +67,8 @@ here: sw $3, 0($15) nop addiu $3, $3, 1 nop # do not stall on $3 - nop - jr $3 + nop # two nops needed here + jr $3 # jump to misaligned addresses nop nop nop diff --git a/cMIPS/tests/badVAddrMM.s b/cMIPS/tests/badVAddrMM.s index e07e82c5fe4939d2cbf1d0e0d6f43b84b4451254..a6aa4d91f359f170d4412f887d60017193a4e39c 100644 --- a/cMIPS/tests/badVAddrMM.s +++ b/cMIPS/tests/badVAddrMM.s @@ -3,19 +3,18 @@ .text .set noreorder .align 2 - .global _start - .global _exit - .global exit + .global _start, _exit .ent _start _start: nop li $sp,(x_DATA_BASE_ADDR+x_DATA_MEM_SZ-8) # initialize SP: ramTop-8 - la $k0, main - nop - mtc0 $k0, cop0_EPC - nop - eret # leave exception level, all else disabled + + ## set STATUS, cop0, no interrupts enabled, user mode + li $k0, 0x10000010 + mtc0 $k0, cop0_STATUS + + j main nop - nop + exit: _exit: nop # flush pipeline nop @@ -27,6 +26,7 @@ _exit: nop # flush pipeline nop .end _start + .org x_EXCEPTION_0180,0 # exception vector_180 .global excp_180 .ent excp_180 @@ -35,10 +35,9 @@ excp_180: sw $k0, x_IO_ADDR_RANGE($14) li $k0, '\n' # to separate output sw $k0, x_IO_ADDR_RANGE($14) - - mfc0 $k0, cop0_CAUSE - sw $k0, 0($14) # print CAUSE + mfc0 $k0, cop0_CAUSE # print CAUSE + sw $k0, 0($14) mfc0 $k0, cop0_EPC # print EPC sw $k0, 0($14) @@ -46,8 +45,6 @@ excp_180: mfc0 $k0, cop0_BadVAddr # print BadVAddr sw $k0, 0($14) - addiu $7, $7, -1 # repetiton counter - addiu $k1, $zero, -4 # -4 = 0xffff.fffc and $15, $15, $k1 # fix the invalid address @@ -56,8 +53,8 @@ excp_180: li $k0, '\n' # to separate output sw $k0, x_IO_ADDR_RANGE($14) + addiu $7, $7, -1 # repetiton counter eret - .end excp_180 @@ -71,7 +68,7 @@ excp_180: main: la $14, x_IO_BASE_ADDR # used by exception handler la $15, x_IO_BASE_ADDR # used to generate misaligned references li $7, 3 # do 4 rounds for each type of exception - li $3, 0 # exception handler decreases $7 + li $3, 0 # exception handler decreaments $7 nop here: nop diff --git a/cMIPS/tests/break.s b/cMIPS/tests/break.s index 9492d9d61fb8657683707a75eafb4732eec97f04..b988cc1aeccce0bc03ea5a0d717f79cdc12a0a80 100644 --- a/cMIPS/tests/break.s +++ b/cMIPS/tests/break.s @@ -2,23 +2,23 @@ .include "cMIPS.s" .text .align 2 - .global _start - .global _exit - .global exit .set noreorder + .global _start, _exit .ent _start ## ## reset leaves processor in kernel mode, all else disabled ## _start: nop - li $sp,(x_DATA_BASE_ADDR+x_DATA_MEM_SZ-8) # initialize SP: ramTop-8 - la $k0, main - nop - mtc0 $k0, cop0_EPC - nop - eret # go into user mode, all else disabled - nop + li $sp,(x_DATA_BASE_ADDR+x_DATA_MEM_SZ-8) # initialize SP: ramTop-8 + nop + + ## set STATUS, cop0, no interrupts enabled, user mode + li $k0, 0x10000010 + mtc0 $k0, cop0_STATUS + + j main + nop exit: _exit: nop # flush pipeline nop @@ -31,8 +31,7 @@ _exit: nop # flush pipeline .end _start .org x_EXCEPTION_0180,0 # exception vector_180 - .global _excp_180 - .global excp_180 + .global _excp_180, excp_180 .ent _excp_180 excp_180: _excp_180: @@ -40,13 +39,15 @@ _excp_180: sw $k0, 0($15) # print CAUSE li $k0, '\n' sw $k0, x_IO_ADDR_RANGE($15) # print new-line - addiu $7, $7, -1 + mfc0 $k1, cop0_EPC # advance EPC to next instruction + addi $k1, $k1, 4 + mtc0 $k1, cop0_EPC + addiu $7, $7, -1 eret .end _excp_180 .org x_EXCEPTION_0200,0 # exception vector_200 - .global _excp_200 - .global excp_200 + .global _excp_200, excp_200 .ent _excp_200 excp_200: _excp_200: @@ -55,19 +56,27 @@ _excp_200: ## mfc0 $k0, cop0_CAUSE sw $k0,0($15) # print CAUSE - addiu $7,$7,+1 + li $k1, 'e' + sw $k1, x_IO_ADDR_RANGE($15) + li $k1, 'r' + sw $k1, x_IO_ADDR_RANGE($15) + li $k1, 'r' + sw $k1, x_IO_ADDR_RANGE($15) + li $k1, '\n' + sw $k1, x_IO_ADDR_RANGE($15) eret .end _excp_200 - .org x_ENTRY_POINT,0 # normal code start + .org 0x0280 # normal code start main: la $15,x_IO_BASE_ADDR li $7,4 li $5,0 here: sw $5, 0($15) - addiu $5, $5,2 + break 15 + bne $7, $zero, here nop diff --git a/cMIPS/tests/doTests.sh b/cMIPS/tests/doTests.sh index 2c1a368948ff41be429becc457f97bfdefe835a5..1375893d1d216e3f57a515268a98718f5562fa7b 100755 --- a/cMIPS/tests/doTests.sh +++ b/cMIPS/tests/doTests.sh @@ -70,10 +70,10 @@ a_FUN="jaljr jr_2 jal_fun_jr jalr_jr bltzal_fun_jr" a_OTH="mult div sll slr movz wsbh_seb extract insert" 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_CTR="teq_tne teq_jal 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" -a_EXC="mmu_refill mmu_refill2 mmu_inval mmu_inval2 mmu_mod mmu_double" +a_EXC="mmu_refill mmu_refill2 mmu_refill3 mmu_inval mmu_inval2 mmu_mod mmu_mod2 mmu_double mmu_double2" ## these tests MUST be run with FAKE CACHES # a_IOs="kbd7seg" diff --git a/cMIPS/tests/ll_sc.s b/cMIPS/tests/ll_sc.s index f140d0117d91b6e28cd275e2593b07a246c82853..2611de3371bfa63b499f9e202f56174faf5eeb88 100644 --- a/cMIPS/tests/ll_sc.s +++ b/cMIPS/tests/ll_sc.s @@ -14,7 +14,7 @@ _start: nop li $k0, 0x1000ff01 # enable interrupts mtc0 $k0, cop0_STATUS nop - jal main + j main nop exit: _exit: nop # flush pipeline @@ -22,7 +22,7 @@ _exit: nop # flush pipeline nop nop nop - wait # then stop VHDL simulation + wait # then stop VHDL simulation nop nop .end _start @@ -34,11 +34,11 @@ _exit: nop # flush pipeline excp_180: mfc0 $k0, cop0_CAUSE # show cause sw $k0, 0($15) - li $k0, 0x10000000 # disable interrupts + li $k0, 0x10000000 # disable interrupts, kernel mode mtc0 $k0, cop0_STATUS li $k1, 0x00000000 # remove SW interrupt request mtc0 $k1, cop0_CAUSE - li $k0, 0x1000ff01 # enable interrupts + li $k0, 0x1000ff01 # enable interrupts, user mode mtc0 $k0, cop0_STATUS eret nop @@ -47,19 +47,18 @@ excp_180: .org x_ENTRY_POINT,0 .ent main -main: la $15,x_IO_BASE_ADDR # print $5=8 and count downwards - li $5,8 - li $6,4 - li $t1,0 +main: la $15,x_IO_BASE_ADDR # print $5=8 and count downwards + li $5,8 + li $6,4 + li $t1,0 la $t0, x_DATA_BASE_ADDR sw $zero, 0($t0) nop loop: sw $5, 0($15) # print-out $5 nop L: ll $t1, 0($t0) # load-linked - - addiu $5,$5,-1 - bne $5,$6,fwd # four rounds yet? + addiu $5, $5, -1 + bne $5, $6, fwd # four rounds yet? nop li $k1, 0x00000100 # cause SW interrupt after 4 rounds diff --git a/cMIPS/tests/mfc0CONFIG.s b/cMIPS/tests/mfc0CONFIG.s index 85b96176c90bd4fb26456c99b7c0292cb3a0376c..91c705b4d4b7754d695a8469df66e86bfbc493c7 100644 --- a/cMIPS/tests/mfc0CONFIG.s +++ b/cMIPS/tests/mfc0CONFIG.s @@ -2,14 +2,14 @@ .include "cMIPS.s" .text .align 2 - .global _start - .global _exit - .global exit + .set noreorder + .global _start, _exit + .ent _start _start: nop li $sp,(x_DATA_BASE_ADDR+x_DATA_MEM_SZ-8) # initialize SP: ramTop-8 nop - jal main + j main nop exit: _exit: nop # flush pipeline @@ -22,35 +22,35 @@ _exit: nop # flush pipeline nop .end _start - .org x_EXCEPTION_0180,0 # exception vector_180 - .global _excp_180 + .org x_EXCEPTION_0180,0 # exception vector_180 .ent _excp_180 _excp_180: mfc0 $k0, cop0_CAUSE - sw $k0,0($15) # print CAUSE - addiu $7,$7,-1 + sw $k0, 0($15) # print CAUSE + addiu $7, $7, -1 li $k0, 0x10000300 # disable interrupts mtc0 $k0, cop0_STATUS eret .end _excp_180 - .org x_ENTRY_POINT,0 # normal code starts at ENTRY_POINT -main: la $15,x_IO_BASE_ADDR + .org 0x0100,0 # normal code +main: la $15, x_IO_BASE_ADDR nop - mfc0 $6,cop0_STATUS + mfc0 $6, cop0_STATUS sw $6, 0($15) nop - mfc0 $6,cop0_CAUSE + mfc0 $6, cop0_CAUSE sw $6, 0($15) nop - mfc0 $6,cop0_CONFIG,0 + mfc0 $6, cop0_CONFIG,0 sw $6, 0($15) nop - mfc0 $6,cop0_CONFIG,1 + mfc0 $6, cop0_CONFIG,1 li $7, 0x8000007f # mask off TLB/cache configuration - and $6,$6,$7 # so changes in TLB/caches won't break this + and $6, $6, $7 # so changes in TLB/caches won't break this sw $6, 0($15) j exit - + nop + diff --git a/cMIPS/tests/mmu_context.expected b/cMIPS/tests/mmu_context.expected index 10add15e59a0629aca23fcf5561c87503fb164f8..6a722397f0b94e55c599e2ce7338cf1fd68cdd99 100644 --- a/cMIPS/tests/mmu_context.expected +++ b/cMIPS/tests/mmu_context.expected @@ -5,3 +5,4 @@ ok excp ok ok + diff --git a/cMIPS/tests/mmu_context.s b/cMIPS/tests/mmu_context.s index 1d737ac5ed22de9ee75b8e0ee23adb460e20adc2..47475794ca447df9dcc1b15fee69f8a55def0128 100644 --- a/cMIPS/tests/mmu_context.s +++ b/cMIPS/tests/mmu_context.s @@ -15,7 +15,7 @@ .set MMU_CAPACITY, 8 .set MMU_WIRED, 2 ### do not change mapping for base of ROM, I/O - # New entries cannot overwrite tlb[0,1] which maps base of ROM + I/O + # New entries cannot overwrite tlb[0,1] that map base of ROM + I/O # EntryHi cannot have an ASID different from zero, otw TLB misses .set entryHi_1, 0x00012000 # pfn0 zzcc cdvg @@ -35,14 +35,15 @@ .set entryLo1_4, 0x00000412 # x0 x0 x0 x0 x0 0100 0001 0010 x412 .set MMU_ini_tag_RAM0, x_DATA_BASE_ADDR - .set MMU_ini_dat_RAM0, 0x0100005 # this mapping is INVALID - .set MMU_ini_dat_RAM1, 0x0100047 + .set MMU_ini_dat_RAM0, 0x0001005 # this mapping is INVALID + .set MMU_ini_dat_RAM1, 0x0001047 .text .align 2 .set noreorder .set noat - .globl _start + .globl _start,_exit + .ent _start _start: @@ -63,14 +64,12 @@ _start: ## exception vector_0180 TLBrefill, from See MIPS Run pg 145 ## .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 +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 @@ -88,7 +87,6 @@ _excp: tlbp # probe for the guilty entry li $30, '\n' sw $30, x_IO_ADDR_RANGE($31) eret - .end _excp ## @@ -97,7 +95,7 @@ _excp: tlbp # probe for the guilty entry ## .org x_ENTRY_POINT,0 -main: la $31, x_IO_BASE_ADDR +main: la $31, x_IO_BASE_ADDR ## ## write PTEbase, twice @@ -125,6 +123,7 @@ error1: li $30, 'e' sw $30, x_IO_ADDR_RANGE($31) sw $30, x_IO_ADDR_RANGE($31) + next1: li $30, '\n' sw $30, x_IO_ADDR_RANGE($31) @@ -227,7 +226,8 @@ next3: li $30, '\n' ## mfc0 $28, cop0_BadVAddr - # sw $28, 0($31) + #sw $28, 0($31) + #sw $8, 0($31) bne $28, $8, error4 nop @@ -245,10 +245,9 @@ error4: li $30, 'e' next4: li $30, '\n' sw $30, x_IO_ADDR_RANGE($31) + sw $30, x_IO_ADDR_RANGE($31) - - - nop +_exit: nop nop nop nop diff --git a/cMIPS/tests/mmu_double.s b/cMIPS/tests/mmu_double.s index 729906decd40bcd032b20823d33a34b12438844b..dd6ac744f9b836a836785cfde2c37c783048f71f 100644 --- a/cMIPS/tests/mmu_double.s +++ b/cMIPS/tests/mmu_double.s @@ -1,5 +1,9 @@ ## - ## Cause a TLB miss on a fetch, refill handler causes double fault + ## Cause a TLB miss on a fetch, on an invalid mapping, + ## refill handler causes double fault, then fix it at + ## general exception handler + ## + ## Ensure instruction in delay slot, prior to fault, completes ## ## ## EntryHi : EntryLo0 : EntryLo1 @@ -7,9 +11,9 @@ .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 + .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 @@ -71,7 +75,8 @@ _excp_100: mfc0 $k1, cop0_Context 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) + eret .end _excp_100 @@ -86,8 +91,9 @@ _excp_100: mfc0 $k1, cop0_Context .set noat ## EntryHi holds VPN2(31..13), probe the TLB for the offending entry + ## VPN2 g ASID : PPN0 ccc0 d0 v0 g0 : PPN1 ccc1 d1 v1 g1 _excp_180: tlbp # probe for the guilty entry - nop + mfc0 $k1, cop0_CAUSE # clear CAUSE tlbr # it will surely hit, just use Index to point at it mfc0 $k1, cop0_EntryLo0 ori $k1, $k1, 0x0002 # make V=1 @@ -96,7 +102,7 @@ _excp_180: tlbp # probe for the guilty entry li $30, 'h' sw $30, x_IO_ADDR_RANGE($20) - li $30, 'e' + li $30, 'e' sw $30, x_IO_ADDR_RANGE($20) li $30, 'r' sw $30, x_IO_ADDR_RANGE($20) @@ -181,15 +187,15 @@ main: la $20, x_IO_BASE_ADDR ## make invalid TLB entry mapping the page table ## ## read tlb[4] (1st RAM mapping) and clear the V bit - li $5, 4 +fix5: 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 + addi $7, $zero, -3 # 0xffff.fffd = 1111.1111.1111.1101 + and $8, $7, $6 # clear V bit mtc0 $8, cop0_EntryLo0 @@ -199,46 +205,47 @@ main: la $20, x_IO_BASE_ADDR nop nop + li $19, '?' # try to catch an error in EPC updates ## - ## cause a TLB miss + ## cause a TLB miss on a fetch ## - jal there - nop +jump: jal there + li $19, 't' # this instr must be executed - 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) + li $19, 'a' + sw $19, x_IO_ADDR_RANGE($20) + li $19, 'n' + sw $19, x_IO_ADDR_RANGE($20) + li $19, 'd' + sw $19, x_IO_ADDR_RANGE($20) + li $19, ' ' + sw $19, x_IO_ADDR_RANGE($20) + li $19, 'b' + sw $19, x_IO_ADDR_RANGE($20) + li $19, 'a' + sw $19, x_IO_ADDR_RANGE($20) + li $19, 'c' + sw $19, x_IO_ADDR_RANGE($20) + li $19, 'k' + sw $19, x_IO_ADDR_RANGE($20) + li $19, ' ' + sw $19, x_IO_ADDR_RANGE($20) + li $19, 'a' + sw $19, x_IO_ADDR_RANGE($20) + li $19, 'g' + sw $19, x_IO_ADDR_RANGE($20) + li $19, 'a' + sw $19, x_IO_ADDR_RANGE($20) + li $19, 'i' + sw $19, x_IO_ADDR_RANGE($20) + li $19, 'n' + sw $19, x_IO_ADDR_RANGE($20) + li $19, '\n' + sw $19, x_IO_ADDR_RANGE($20) + sw $19, x_IO_ADDR_RANGE($20) - nop +_exit: nop nop nop nop @@ -251,18 +258,18 @@ main: la $20, x_IO_BASE_ADDR .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) +there: # li $19, 't' # this instr went to de delay slot + sw $19, x_IO_ADDR_RANGE($20) + li $19, 'h' + sw $19, x_IO_ADDR_RANGE($20) + li $19, 'e' + sw $19, x_IO_ADDR_RANGE($20) + li $19, 'r' + sw $19, x_IO_ADDR_RANGE($20) + li $19, 'e' + sw $19, x_IO_ADDR_RANGE($20) + li $19, '\n' + sw $19, x_IO_ADDR_RANGE($20) jr $31 nop diff --git a/cMIPS/tests/mmu_index.expected b/cMIPS/tests/mmu_index.expected index 68503f14e6396f3db011b1e790766e14908f94bd..9e93b5c6d387b1a9988d819c4ce3be89eca46e78 100644 --- a/cMIPS/tests/mmu_index.expected +++ b/cMIPS/tests/mmu_index.expected @@ -1,31 +1,5 @@ -00000005 -00000001 -00000004 -00000007 -00000003 -00000006 +ok +ok +ok +ok -00000006 -00000007 -00000003 -00000004 -00000005 -00000006 - -00000007 -00000007 -00000007 -00000007 -00000007 -00000007 - -00000005 -00000000 -00000003 -00000006 -00000001 -00000004 -00000007 -00000002 -00000005 -00000000 diff --git a/cMIPS/tests/mmu_index.s b/cMIPS/tests/mmu_index.s index a7cd3b5d844746d7b07e1955c35d180721cdf201..c8df76c2102a3f108264de1f6e212ac8a7f954df 100644 --- a/cMIPS/tests/mmu_index.s +++ b/cMIPS/tests/mmu_index.s @@ -5,73 +5,176 @@ .include "cMIPS.s" - .set MMU_CAPACITY, 8 - .set MMU_WIRED, 1 ### do not change mapping for base of ROM - .text .align 2 .set noreorder - .globl _start + .globl _start, _exit + + .set MMU_CAPACITY, 8 + .set MMU_WIRED, 1 ### do not change mapping for base of ROM + .ent _start _start: li $5, MMU_WIRED + mtc0 $5, cop0_Wired ### make sure all but 0'th TLB entries are usable li $6, MMU_CAPACITY - 1 + mtc0 $6, cop0_Index + la $15, x_IO_BASE_ADDR + nop nop nop # give the RANDOM counter some time after resetting, - nop # so it can advance freely a few cycles + nop # so it can advance freely for a few cycles nop nop - mtc0 $6, cop0_Index - mtc0 $5, cop0_Wired ### make sure all but 0'th TLB entries are usable + ## ok, waited for several cycles - li $7, MMU_CAPACITY - 2 # waited for several cycles, now -L1: addiu $7, $7, -1 # print 6 random values in 1..CAPACITY-1 - mfc0 $25, cop0_Random # 1 entry wired(0) + ## + ## print 6 random values in 1..CAPACITY-1 + ## + + li $7, MMU_CAPACITY - 2 # one entry wired -> TLB(0) + mfc0 $25, cop0_Random # read one value + #sw $25, 0($15) + nop # there must be more than 6 instructions + nop # in between two comparisons + +L1: addiu $7, $7, -1 + mfc0 $26, cop0_Random # read new value + nop + nop + #sw $26, 0($15) + nop + beq $26, $25, error # stop if last two values read are equal + nop + move $25, $26 # keep last value read + nop bne $7, $zero, L1 - sw $25, 0($15) + nop + li $30, 'o' # print a blank line + sw $30, x_IO_ADDR_RANGE($15) + li $30, 'k' # print a blank line + sw $30, x_IO_ADDR_RANGE($15) li $30, '\n' # print a blank line sw $30, x_IO_ADDR_RANGE($15) - li $7, MMU_CAPACITY - 2 # print 6 random values in 3..CAPACITY-1 + + ## + ## print 6 random values in 3..CAPACITY-1 + ## + + li $7, MMU_CAPACITY - 2 li $5, MMU_WIRED + 2 # 3 entries are wired (0..2) mtc0 $5, cop0_Wired + mfc0 $25, cop0_Random # read one value + #sw $25, 0($15) + nop # there must be more than 6 instructions + nop # in between two comparisons + + L2: addiu $7, $7,-1 - mfc0 $25, cop0_Random + mfc0 $26, cop0_Random + nop + nop + #sw $26, 0($15) + beq $26, $25, error # stop if last two values read are equal + nop + nop + move $25, $26 # keep last value read + nop bne $7, $zero, L2 - sw $25, 0($15) + nop + li $30, 'o' # print a blank line + sw $30, x_IO_ADDR_RANGE($15) + li $30, 'k' # print a blank line + sw $30, x_IO_ADDR_RANGE($15) li $30, '\n' # print a blank line sw $30, x_IO_ADDR_RANGE($15) - li $7, MMU_CAPACITY - 2 # print 6 random values in 7..7=CAPACITY-1 + + ## + ## print 6 random values in 7..7=CAPACITY-1 + ## + + li $7, MMU_CAPACITY - 2 li $5, MMU_CAPACITY - 1 # 7 entries are wired (0..6) mtc0 $5, cop0_Wired + mfc0 $25, cop0_Random # read one value + #sw $25, 0($15) + L3: addiu $7, $7,-1 - mfc0 $25, cop0_Random + mfc0 $26, cop0_Random + nop + nop + #sw $26, 0($15) + bne $26, $25, error # stop if last two values read differ + nop + nop + move $25, $26 # keep last value read + nop bne $7, $zero, L3 - sw $25, 0($15) + nop - + li $30, 'o' # print a blank line + sw $30, x_IO_ADDR_RANGE($15) + li $30, 'k' # print a blank line + sw $30, x_IO_ADDR_RANGE($15) li $30, '\n' # print a blank line sw $30, x_IO_ADDR_RANGE($15) - li $7, 10 # print 10 random values in 0..CAPACITY-1 + + ## + ## print 10 random values in 0..CAPACITY-1 + ## + + li $7, 10 li $5, 0 # no entries are wired mtc0 $5, cop0_Wired -L4: addiu $7, $7,-1 + mfc0 $25, cop0_Random # read one value + #sw $25, 0($15) nop - mfc0 $25, cop0_Random - bne $7, $zero, L4 - sw $25, 0($15) +L4: addiu $7, $7,-1 + mfc0 $26, cop0_Random nop + #sw $26, 0($15) + beq $26, $25, error # stop if last two values read are equal nop + move $25, $26 # keep last value read + nop + bne $7, $zero, L4 + nop + + li $30, 'o' # print a blank line + sw $30, x_IO_ADDR_RANGE($15) + li $30, 'k' # print a blank line + sw $30, x_IO_ADDR_RANGE($15) + li $30, '\n' # print a blank line + sw $30, x_IO_ADDR_RANGE($15) + j exit + sw $30, x_IO_ADDR_RANGE($15) + + +error: li $30, 'e' + sw $30, x_IO_ADDR_RANGE($15) + li $30, 'r' + sw $30, x_IO_ADDR_RANGE($15) + sw $30, x_IO_ADDR_RANGE($15) + li $31, 'o' + sw $31, x_IO_ADDR_RANGE($15) + sw $30, x_IO_ADDR_RANGE($15) + li $31, '\n' # print a blank line + sw $31, x_IO_ADDR_RANGE($15) + sw $31, x_IO_ADDR_RANGE($15) + +exit: nop +_exit: nop nop nop nop diff --git a/cMIPS/tests/mmu_inval.s b/cMIPS/tests/mmu_inval.s index 5334859fac788fa6b786ccabee6d657a5e4da120..ecf097556040f5dea50b54cde3d2b83f9983cd12 100644 --- a/cMIPS/tests/mmu_inval.s +++ b/cMIPS/tests/mmu_inval.s @@ -1,5 +1,5 @@ ## - ## Perform a store to a clean page, then set the mapping as dirty + ## Perform a store to an invalid page, then set the mapping valid ## ## ## EntryHi : EntryLo0 : EntryLo1 @@ -33,7 +33,7 @@ .set noreorder .set noat .org x_INST_BASE_ADDR,0 - .globl _start + .globl _start,_exit .ent _start ## set STATUS, cop0, no interrupts enabled @@ -53,20 +53,14 @@ _start: li $k0, 0x10000000 .set noreorder .set noat - excp: # EntryHi holds VPN2(31..13) _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 - + ehb tlbwi # write entry back li $30, 't' @@ -85,15 +79,21 @@ _excp: tlbp # probe for the guilty entry eret .end _excp + ## ##================================================================ ## normal code starts here ## .org x_ENTRY_POINT,0 - .ent main + + ## EntryHi : EntryLo0 : EntryLo1 + ## VPN2 g ASID : PPN0 ccc0 d0 v0 g0 : PPN1 ccc1 d1 v1 g1 + main: la $20, x_IO_BASE_ADDR + li $k0, MMU_WIRED + mtc0 $k0, cop0_Wired # Wire to the TLB entries 0 (ROM) and 1 (IO) ## read tlb[5] (2nd RAM mapping) and clear the V bit li $5, 5 @@ -103,8 +103,8 @@ main: la $20, x_IO_BASE_ADDR mfc0 $6, cop0_EntryLo0 - addi $7, $zero, -3 # 0xffff.fffd = 1111.1111.1111.1011 - and $8, $7, $6 # clear D bit + addi $7, $zero, -3 # 0xffff.fffd = 1111.1111.1111.1101 + and $8, $7, $6 # clear V bit mtc0 $8, cop0_EntryLo0 @@ -112,8 +112,9 @@ main: la $20, x_IO_BASE_ADDR tlbwi # write entry back to TLB - - ## cause an exception by writing to that same page + ## + ## now cause an exception by writing to that same page + ## la $10, 0xffffe000 # mask off non-VPN bits and $10, $10, $9 @@ -154,7 +155,7 @@ main: la $20, x_IO_BASE_ADDR sw $30, x_IO_ADDR_RANGE($20) - nop +_exit: nop nop nop nop diff --git a/cMIPS/tests/mmu_inval2.s b/cMIPS/tests/mmu_inval2.s index 64611415d533928c7f97a31c2aef3050e674baf2..36e3ac4d530f892d67a19efa0589aefbfc6b597c 100644 --- a/cMIPS/tests/mmu_inval2.s +++ b/cMIPS/tests/mmu_inval2.s @@ -1,5 +1,5 @@ ## - ## Perform a store to a clean page, then set the mapping as dirty + ## Perform a store to an invalid page, then set the mapping valid ## ## ## EntryHi : EntryLo0 : EntryLo1 @@ -33,7 +33,7 @@ .set noreorder .set noat .org x_INST_BASE_ADDR,0 - .globl _start + .globl _start,_exit .ent _start ## set STATUS, cop0, no interrupts enabled @@ -53,21 +53,14 @@ _start: li $k0, 0x10000000 .set noreorder .set noat - excp: # EntryHi holds VPN2(31..13) _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 - + ori $k1, $k1, 0x0002 # make V=1 mtc0 $k1, cop0_EntryLo0 - - tlbwi # write entry back + tlbwi # write entry back li $30, 't' sw $30, x_IO_ADDR_RANGE($20) @@ -94,7 +87,10 @@ _excp: tlbp # probe for the guilty entry .ent main main: la $20, x_IO_BASE_ADDR + li $k0, MMU_WIRED + mtc0 $k0, cop0_Wired # Wire to the TLB entries 0 (ROM) and 1 (IO) + ## read tlb[5] (2nd RAM mapping) and clear the V bit li $5, 5 mtc0 $5, cop0_Index @@ -103,15 +99,13 @@ main: la $20, x_IO_BASE_ADDR mfc0 $6, cop0_EntryLo0 - addi $7, $zero, -3 # 0xffff.fffd = 1111.1111.1111.1011 + addi $7, $zero, -3 # 0xffff.fffd = 1111.1111.1111.1101 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 @@ -164,7 +158,7 @@ dest: nop sw $30, x_IO_ADDR_RANGE($20) - nop +_exit: nop nop nop nop diff --git a/cMIPS/tests/mmu_mod.s b/cMIPS/tests/mmu_mod.s index 8f1da11688320aaf0f5bae26b9459b937d550468..d705110eda6bebdee70a8dcee3c2623c6af4fb80 100644 --- a/cMIPS/tests/mmu_mod.s +++ b/cMIPS/tests/mmu_mod.s @@ -34,7 +34,7 @@ .set noreorder .set noat .org x_INST_BASE_ADDR,0 - .globl _start + .globl _start,_exit .ent _start ## set STATUS, cop0, no interrupts enabled @@ -55,11 +55,10 @@ _start: li $k0, 0x10000000 .set noat ## EntryHi holds VPN2(31..13), probe the TLB for the offending entry + ## VPN2 g ASID : PPN0 ccc0 d0 v0 g0 : PPN1 ccc1 d1 v1 g1 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 @@ -82,7 +81,7 @@ _excp: tlbp # probe for the guilty entry sw $30, x_IO_ADDR_RANGE($20) li $30, '\n' sw $30, x_IO_ADDR_RANGE($20) - + li $30, '?' # try to catch error in EPC update eret .end _excp @@ -91,10 +90,14 @@ _excp: tlbp # probe for the guilty entry ## normal code starts here ## .org x_ENTRY_POINT,0 - .ent main + + ## VPN2 g ASID : PPN0 ccc0 d0 v0 g0 : PPN1 ccc1 d1 v1 g1 + main: la $20, x_IO_BASE_ADDR + li $k0, MMU_WIRED + mtc0 $k0, cop0_Wired # Wire TLB entries 0 (ROM) and 1 (IO) ## read tlb[5] (2nd RAM mapping) and clear the D bit li $5, 5 @@ -111,6 +114,7 @@ main: la $20, x_IO_BASE_ADDR mfc0 $9, cop0_EntryHi + ehb tlbwi # write entry back to TLB @@ -119,9 +123,10 @@ main: la $20, x_IO_BASE_ADDR la $10, 0xffffe000 # mask off non-VPN bits and $10, $10, $9 + li $30, '?' # try to catch error on EPC updates + # error may miss 'a' sw $zero, 16($10) - li $30, 'a' sw $30, x_IO_ADDR_RANGE($20) li $30, 'n' @@ -155,7 +160,7 @@ main: la $20, x_IO_BASE_ADDR sw $30, x_IO_ADDR_RANGE($20) - nop +_exit: nop nop nop nop diff --git a/cMIPS/tests/mmu_refill.s b/cMIPS/tests/mmu_refill.s index 768772d30c6b6d0a720bb7c96d0ee7555cccf975..3e16fb944d4e58fc2eac11c0e1ee73aac4d9cefb 100644 --- a/cMIPS/tests/mmu_refill.s +++ b/cMIPS/tests/mmu_refill.s @@ -88,6 +88,10 @@ _excp: mfc0 $k1, cop0_Context .set PTbase, x_DATA_BASE_ADDR .ent main main: la $20, x_IO_BASE_ADDR + + li $k0, MMU_WIRED + mtc0 $k0, cop0_Wired # Wire to the TLB entries 0 (ROM) and 1 (IO) + ## ## setup a PageTable diff --git a/cMIPS/tests/mmu_refill2.s b/cMIPS/tests/mmu_refill2.s index 65ae103e15e7da340b5d549bf1d91751a58465d4..471e44e18c6c9b572321f1fb5e25c906cdd1e255 100644 --- a/cMIPS/tests/mmu_refill2.s +++ b/cMIPS/tests/mmu_refill2.s @@ -28,17 +28,17 @@ .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 - .set MMU_WIRED, 2 ### do not change mapping for base of ROM, I/O + .set MMU_WIRED, 2 ### do not change mapping for ROM-0, I/O .text .align 2 .set noreorder .set noat .org x_INST_BASE_ADDR,0 - .globl _start + .globl _start, _exit .ent _start - ## set STATUS, cop0, no interrupts enabled + ## set STATUS, cop0, no interrupts enabled, kernel mode _start: li $k0, 0x10000000 mtc0 $k0, cop0_STATUS @@ -70,6 +70,7 @@ _excp: mfc0 $k1, cop0_Context mtc0 $k0, cop0_Index ehb tlbwi # update TLB + li $30, 'h' sw $30, x_IO_ADDR_RANGE($20) li $30, 'e' @@ -77,9 +78,11 @@ _excp: mfc0 $k1, cop0_Context li $30, 'r' sw $30, x_IO_ADDR_RANGE($20) li $30, 'e' - sw $30, x_IO_ADDR_RANGE($20) + sw $30, x_IO_ADDR_RANGE($20) li $30, '\n' - sw $30, x_IO_ADDR_RANGE($20) + sw $30, x_IO_ADDR_RANGE($20) + mfc0 $k1, cop0_CAUSE # clear CAUSE + eret .end _excp @@ -156,7 +159,7 @@ main: la $20, x_IO_BASE_ADDR mfc0 $7, cop0_EntryLo1 # sw $7, 0($20) - .set ram6_displ,((x_DATA_BASE_ADDR + 6*4096)>>(13-4)) ## num(VPN2)*16 + .set ram6_displ,((x_DATA_BASE_ADDR + 6*4096)>>(13-4)) # num(VPN2)*16 # li $1, ram6_displ # sw $1, 0($20) @@ -168,7 +171,7 @@ main: la $20, x_IO_BASE_ADDR ## change mapping for 3rd RAM TLB entry, thus causing a miss - li $5, 7 # 3rd RAM mapping +chnge3: li $5, 7 # 3rd RAM mapping mtc0 $5, cop0_Index li $9, 0x8000 @@ -194,8 +197,18 @@ main: la $20, x_IO_BASE_ADDR last: jal there lw $16, 0($15) + ## + ## try to catch error in EPC. Return address adjusted below + ## + li $30, '@' + sw $30, x_IO_ADDR_RANGE($20) + sw $30, x_IO_ADDR_RANGE($20) + sw $30, x_IO_ADDR_RANGE($20) + li $30, '\n' + sw $30, x_IO_ADDR_RANGE($20) - li $30, 'a' + +goBack: li $30, 'a' sw $30, x_IO_ADDR_RANGE($20) li $30, 'n' sw $30, x_IO_ADDR_RANGE($20) @@ -254,11 +267,15 @@ there: li $30, 't' li $30, '\n' sw $30, x_IO_ADDR_RANGE($20) + ## + ## adjust return address to catch error in EPC + ## + la $31, goBack jr $31 nop - nop +_exit: nop nop nop nop diff --git a/cMIPS/tests/mmu_tlbwi.s b/cMIPS/tests/mmu_tlbwi.s index 7f1d689adf4a7d41252a72bb3cfd0fd6196b9602..44d656f309d35a4ec775538cc25976fa46a82019 100644 --- a/cMIPS/tests/mmu_tlbwi.s +++ b/cMIPS/tests/mmu_tlbwi.s @@ -36,7 +36,8 @@ .align 2 .set noreorder .set noat - .globl _start + .globl _start,_exit + .ent _start _start: la $31, x_IO_BASE_ADDR @@ -65,13 +66,15 @@ _start: la $31, x_IO_BASE_ADDR mtc0 $zero, cop0_EntryHi mtc0 $zero, cop0_EntryLo0 mtc0 $zero, cop0_EntryLo1 + + ehb addi $30, $1, '0' sw $30, x_IO_ADDR_RANGE($31) li $30, '\n' sw $30, x_IO_ADDR_RANGE($31) - tlbr # read TLB at index = 3 +read3: tlbr # read TLB at index = 3 mfc0 $23, cop0_EntryHi sw $23, 0($31) mfc0 $24, cop0_EntryLo0 @@ -257,7 +260,7 @@ _start: la $31, x_IO_BASE_ADDR nop nop - nop +_exit: nop nop nop nop diff --git a/cMIPS/tests/mtc0CAUSE2.s b/cMIPS/tests/mtc0CAUSE2.s index 7fe52e5582551554f6194f2a56e0a5a93430cb39..5ef81df96fcea6b8165458456c0ec4a63f4758f9 100644 --- a/cMIPS/tests/mtc0CAUSE2.s +++ b/cMIPS/tests/mtc0CAUSE2.s @@ -2,48 +2,43 @@ .include "cMIPS.s" .text .align 2 - .global _start - .global _exit - .global exit + .set noreorder + .global _exit, _start .ent _start _start: nop li $k0, 0x10000002 # RESET_STATUS, kernel mode, all else disabled mtc0 $k0, cop0_STATUS li $sp,(x_DATA_BASE_ADDR+x_DATA_MEM_SZ-8) # initialize SP: ramTop-8 - li $k0, 0x0000007c # CAUSE_STATUS, no exceptions - mtc0 $k0, cop0_CAUSE # clear CAUSE - + li $k0, 0x0000007c # CAUSE_STATUS, no exceptions + mtc0 $k0, cop0_CAUSE # clear CAUSE nop - jal main + j main nop exit: -_exit: nop # flush pipeline +_exit: nop # flush pipeline nop nop nop nop - wait # then stop VHDL simulation + wait # then stop VHDL simulation nop nop .end _start .org x_EXCEPTION_0180,0 # exception vector_180 - .global _excp_180 - .global excp_180 .ent _excp_180 -excp_180: _excp_180: mfc0 $k0, cop0_CAUSE sw $k0,0($15) # print CAUSE addiu $7,$7,-1 - li $k0, 0x10000300 # disable interrupts except SW0,1 + li $k0, 0x10000310 # disable interrupts except SW0,1, user mode mtc0 $k0, cop0_STATUS mtc0 $zero, cop0_CAUSE # clear CAUSE eret .end _excp_180 - .org x_ENTRY_POINT,0 # normal code starts here + .org 0x0100 # normal code starts here main: la $15,x_IO_BASE_ADDR li $7,4 # do four rounds li $5,0 @@ -56,10 +51,15 @@ here: sw $5, 0($15) addiu $5,$5,2 - li $6, 0x10000301 # user mode, enable sw interrupts + li $6, 0x10000311 # user mode, enable sw interrupts mtc0 $6,cop0_STATUS - nop # SW interrupt here + nop + nop + nop + nop # wait for software interrupt bne $7,$zero, here - + nop + j exit + nop diff --git a/cMIPS/tests/syscall.s b/cMIPS/tests/syscall.s index 72e025c2c957d1e3fb6f12bc4ac99d6ae1f826c1..2fe7efc30b64f868a7c817b4976828c1938a96fa 100644 --- a/cMIPS/tests/syscall.s +++ b/cMIPS/tests/syscall.s @@ -2,6 +2,7 @@ .include "cMIPS.s" .text .align 2 + .set noreorder .global _start .global _exit .global exit @@ -10,13 +11,15 @@ ## reset leaves processor in kernel mode, all else disabled ## _start: nop - li $sp,(x_DATA_BASE_ADDR+x_DATA_MEM_SZ-8) # initialize SP: ramTop-8 - la $k0, main - nop - mtc0 $k0, cop0_EPC - nop - eret # go into user mode, all else disabled + li $sp,(x_DATA_BASE_ADDR+x_DATA_MEM_SZ-8) # initialize SP: ramTop-8 + + ## set STATUS, cop0, no interrupts enabled + li $k0, 0x10000000 + mtc0 $k0, cop0_STATUS + + j main nop + exit: _exit: nop # flush pipeline nop @@ -28,33 +31,27 @@ _exit: nop # flush pipeline nop .end _start - .org x_EXCEPTION_0180,0 # exception vector_180 at 0x00000060 - .global _excp_180 - .global excp_180 - .global _excp_200 - .global excp_200 + .org x_EXCEPTION_0180,0 # exception vector_180 .ent _excp_180 -excp_180: _excp_180: -excp_200: -_excp_200: mfc0 $k0, cop0_CAUSE + li $k1, 0x18000310 # disable interrupts, user level sw $k0,0($15) # print CAUSE - li $k0, 0x18000300 # disable interrupts - mtc0 $k0, cop0_STATUS + mtc0 $k1, cop0_STATUS + mfc0 $k0, cop0_EPC # advance EPC to next instruction + addi $k0, $k0, 4 addiu $7,$7,-1 + mtc0 $k0, cop0_EPC eret .end _excp_180 - .org x_ENTRY_POINT,0 # normal code starts at 0x0000.0100 + .org 0x100,0 # normal code starts at 0x0000.0100 main: la $15, x_IO_BASE_ADDR li $7, 4 li $5, 0 -here: sw $5, 0($15) - #li $6, 0x18000302 # kernel mode, disable interrupts - #mtc0 $6, cop0_STATUS +here: sw $5, 0($15) addiu $5, $5, 2 syscall bne $7, $zero, here @@ -62,4 +59,3 @@ here: sw $5, 0($15) j exit nop - diff --git a/cMIPS/tests/teq_tne.s b/cMIPS/tests/teq_tne.s index 47c38b45505025618a8276f428386423064e1754..b7eb0a35b2da20d1cb900cb016dfa0415b0dd95a 100644 --- a/cMIPS/tests/teq_tne.s +++ b/cMIPS/tests/teq_tne.s @@ -14,10 +14,9 @@ _start: nop li $sp,(x_DATA_BASE_ADDR+x_DATA_MEM_SZ-8) # initialize SP: ramTop-8 - la $k0, cop0_STATUS_reset # go into user mode - addi $k0, $k0, -2 - addi $k0, $k0, 0b10000 - mtc0 $k0, cop0_STATUS + ## set STATUS, cop0, no interrupts enabled + li $k0, 0x10000000 + mtc0 $k0, cop0_STATUS j main nop @@ -55,9 +54,11 @@ _excp_180: mfc0 $k1, cop0_EPC # move EPC forward to next instruction addi $k1, $k1, 4 - mtc0 $k1, cop0_EPC # move EPC forward to next instruction - mfc0 $k0, cop0_STATUS # go back to user mode - ori $k0, $k0, 0x0010 + mtc0 $k1, cop0_EPC + + mfc0 $k0, cop0_STATUS # go back to user mode, EXL=0 + li $k1, -16 # ffff.fff0 + and $k0, $k0, $k1 mtc0 $k0, cop0_STATUS excp_180ret: eret @@ -99,7 +100,7 @@ main: la $15, x_IO_BASE_ADDR # print out address (simulator's stdout) ## here: sw $5, 0($15) # print out value: 3 times (0,2,4,6,8,34) addiu $5, $5, 2 # value += 2 - nop # do not cause TRAP to stall on $5 + addiu $31, $zero,31 # do not cause TRAP to stall on $5 teq $5, $6 # trap if value = 10, handler does $7-- beq $7, $zero, there # if done 3 rounds, go on to next test nop @@ -108,7 +109,7 @@ here: sw $5, 0($15) # print out value: 3 times (0,2,4,6,8,34) ## print out '\n' to separate tests there: li $28, '\n' - sw $28, x_IO_ADDR_RANGE($15) + sw $28, x_IO_ADDR_RANGE($15) ## ## print sequence 4,cause,3,cause,2,cause,1,cause @@ -149,5 +150,8 @@ then2: sw $7, 0($15) # print out values: (5,34,4,34,3,34,2,34,1,34) tnei $7, 0 # trap handler decreases $7 bnez $7, then2 nop - j exit + + j exit nop + + diff --git a/cMIPS/tests/tlt_tlti.s b/cMIPS/tests/tlt_tlti.s index 8dc25ddc2e7e963665a074751c06fcec3e0a2a89..6a57f4f8c89ec2edcb76f4451967651dcb2c7fb4 100644 --- a/cMIPS/tests/tlt_tlti.s +++ b/cMIPS/tests/tlt_tlti.s @@ -10,11 +10,7 @@ .global _start .global _exit .global exit - .global _excp_180 - .global excp_180 - .global _excp_200 - .global excp_200 - + ## ## reset leaves processor in kernel mode, all else disabled ## @@ -22,9 +18,8 @@ _start: nop li $sp,(x_DATA_BASE_ADDR+x_DATA_MEM_SZ-8) # initialize SP: ramTop-8 - la $k0, cop0_STATUS_reset # go into user mode - addi $k0, $k0, -2 - addi $k0, $k0, 0b10000 + ## set STATUS, cop0, no interrupts enabled + li $k0, 0x10000000 mtc0 $k0, cop0_STATUS j main @@ -44,7 +39,7 @@ _exit: nop # flush pipeline ## ## print CAUSE, decrement iteration control ## - .org x_EXCEPTION_0180,0 # exception vector_180 at 0x00000060 + .org x_EXCEPTION_0180,0 # exception vector_180 .ent _excp_180 _excp_180: mfc0 $k0, cop0_CAUSE @@ -62,8 +57,10 @@ _excp_180: mfc0 $k1, cop0_EPC # move EPC forward to next instruction addi $k1, $k1, 4 mtc0 $k1, cop0_EPC - mfc0 $k0, cop0_STATUS # go back into user mode - ori $k0, $k0, 0x0010 + + mfc0 $k0, cop0_STATUS # go back to user mode, EXL=0 + li $k1, -16 # ffff.fff0 + and $k0, $k0, $k1 mtc0 $k0, cop0_STATUS excp_180ret: eret @@ -106,7 +103,7 @@ main: la $15, x_IO_BASE_ADDR # simulator's stdout ## here: sw $5, 0($15) addiu $5, $5, 2 - nop # so trap will not stall on $5 + addi $31, $0, 31 # so trap will not stall on $5 tlt $5, $6 beq $7,$zero, there nop @@ -124,6 +121,7 @@ there: li $28, '\n' li $7, 4 then: sw $5, 0($15) addiu $5, $5, 2 + addi $31, $0, 31 # so trap will not stall on $5 tlti $5, 10 bnez $7, then nop @@ -159,7 +157,7 @@ there2: sw $7, 0($15) # trapped 3 times: 4-3=1 li $6, 10 li $7, 4 then2: sw $6, 0($15) - nop + addi $31, $0, 31 # so trap will not stall on $5 tgei $6, 1 addiu $6, $6, -2 bnez $7, then2 diff --git a/cMIPS/tests/uartrx.c b/cMIPS/tests/uartrx.c index 968ae8ac759e318119ef9ef5ddd5b4de5d2f674f..ab0480f1fe6f7a8ac50396bd955e6fca090eb5f4 100644 --- a/cMIPS/tests/uartrx.c +++ b/cMIPS/tests/uartrx.c @@ -2,27 +2,23 @@ typedef struct control { // control register fields (uses only ls byte) int ign : 24, // ignore uppermost bits - rts : 1, // Request to Send out (bit 7) + rts : 1, // Request to Send output (bit 7) ign2 : 2, // bits 6,5 ignored intTX : 1, // interrupt on TX buffer empty (bit 4) intRX : 1, // interrupt on RX buffer full (bit 3) speed : 3; // 4,8,16..256 tx-rx clock data rates (bits 0..2) } Tcontrol; -typedef struct status { // status register fields (uses only ls byte) -#if 0 - int s; -#else - int ign : 24, // ignore uppermost 3 bytes - cts : 1, // Clear To Send inp=1 (bit 7) - txEmpty : 1, // TX register is empty (bit 6) - rxFull : 1, // octet available from RX register (bit 5) - int_TX_empt: 1, // interrupt pending on TX empty (bit 4) - int_RX_full: 1, // interrupt pending on RX full (bit 3) - ign2 : 1, // ignored (bit 2) - framing : 1, // framing error (bit 1) - overun : 1; // overun error (bit 0) -#endif +typedef struct status { // status register fields (uses only ls byte) + unsigned int ign : 24, // ignore uppermost 3 bytes + cts : 1, // Clear To Send input=1 (bit 7) + txEmpty : 1, // TX register is empty (bit 6) + rxFull : 1, // octet available from RX register (bit 5) + int_TX_empt: 1, // interrupt pending on TX empty (bit 4) + int_RX_full: 1, // interrupt pending on RX full (bit 3) + ign1 : 1, // ignored (bit 2) + framing : 1, // framing error (bit 1) + overun : 1; // overun error (bit 0) } Tstatus; #define RXfull 0x00000020 @@ -73,7 +69,6 @@ int main(void) { // receive a string through the UART serial interface do { i = i+1; - // while ( ! ( (state = uart->cs.stat.s) & RXfull ) ) while ( (state = (int)uart->cs.stat.rxFull) == 0 ) if (state == 0) cmips_delay(1); // just do something with state s[i] = (char)uart->d.rx; @@ -81,6 +76,6 @@ int main(void) { // receive a string through the UART serial interface } while (s[i] != '\0'); - return 0; + return(state); } diff --git a/cMIPS/tests/uarttx.c b/cMIPS/tests/uarttx.c index 67c3af530fbdd80afd55434214497c52b445487e..09d212e92c4b8b9b7fe5c7cc949279288e1275b7 100644 --- a/cMIPS/tests/uarttx.c +++ b/cMIPS/tests/uarttx.c @@ -3,27 +3,23 @@ typedef struct control { // control register fields (uses only ls byte) int ign : 24, // ignore uppermost bits - rts : 1, // Request to Send out (bit 7) + rts : 1, // Request to Send output (bit 7) ign2 : 2, // bits 6,5 ignored intTX : 1, // interrupt on TX buffer empty (bit 4) intRX : 1, // interrupt on RX buffer full (bit 3) speed : 3; // 4,8,16..256 tx-rx clock data rates (bits 0..2) } Tcontrol; -typedef struct status { // status register fields (uses only ls byte) -#if 0 - int s; -#else - int ign : 24, // ignore uppermost 3 bytes - cts : 1, // Clear To Send inp=1 (bit 7) - txEmpty : 1, // TX register is empty (bit 6) - rxFull : 1, // octet available from RX register (bit 5) - int_TX_empt: 1, // interrupt pending on TX empty (bit 4) - int_RX_full: 1, // interrupt pending on RX full (bit 3) - ign2 : 1, // ignored (bit 2) - framing : 1, // framing error (bit 1) - overun : 1; // overun error (bit 0) -#endif +typedef struct status { // status register fields (uses only ls byte) + unsigned int ign : 24, // ignore uppermost 3 bytes + cts : 1, // Clear To Send input=1 (bit 7) + txEmpty : 1, // TX register is empty (bit 6) + rxFull : 1, // octet available from RX register (bit 5) + int_TX_empt: 1, // interrupt pending on TX empty (bit 4) + int_RX_full: 1, // interrupt pending on RX full (bit 3) + ign1 : 1, // ignored (bit 2) + framing : 1, // framing error (bit 1) + overun : 1; // overun error (bit 0) } Tstatus; #define RXfull 0x00000020 @@ -47,7 +43,7 @@ typedef struct serial { #define LONG_STRING 1 #if LONG_STRING -char *dog = "\tthe quick brown fox jumps over the lazy dog"; +char *dog = "\n\tthe quick brown fox jumps over the lazy dog\n"; char s[32]; #else char s[32]; // = "123"; @@ -71,7 +67,8 @@ int strcopy(const char *y, char *x) int main(void) { // send a string through the UART serial interface int i; - volatile int state, val; + volatile unsigned int state, val; + volatile Tserial *uart; // tell GCC to not optimize away tests Tcontrol ctrl; @@ -99,9 +96,8 @@ int main(void) { // send a string through the UART serial interface do { i = i+1; - // while ( ! ( (state = uart->cs.stat.s) & TXempty ) ) while ( (state = (int)uart->cs.stat.txEmpty) == 0 ) - if (state == 1) cmips_delay(2); // just do something with state + {}; // if (state == 1) cmips_delay(2); // just do something with state uart->d.tx = (int)s[i]; } while (s[i] != '\0'); // '\0' is transmitted in previous line @@ -111,7 +107,7 @@ int main(void) { // send a string through the UART serial interface startCounter(COUNTING, 0); while ( (val=(readCounter() & 0x3fffffff)) < COUNTING ) - {}; + {}; return val; // so compiler won't optimize away the last loop } diff --git a/cMIPS/tests/uarttx.expected b/cMIPS/tests/uarttx.expected index 50c330a807644d3c27c8afd026624b13efdf144a..55747baac2bce6b6340fa2ffd40bfe2386392a75 100644 Binary files a/cMIPS/tests/uarttx.expected and b/cMIPS/tests/uarttx.expected differ diff --git a/cMIPS/vhdl/core.vhd b/cMIPS/vhdl/core.vhd index 8e173c81754027ed7e42e0823b0e53656d01124c..9c60723176f2e255464708010fb3e581f379d44d 100644 --- a/cMIPS/vhdl/core.vhd +++ b/cMIPS/vhdl/core.vhd @@ -63,94 +63,99 @@ architecture rtl of core is component reg_excp_RF_EX is port(clk, rst, ld: in std_logic; + RF_cop0_reg: in reg5; + EX_cop0_reg: out reg5; + RF_cop0_sel: in reg3; + EX_cop0_sel: out reg3; RF_can_trap: in std_logic_vector; EX_can_trap: out std_logic_vector; RF_exception: in exception_type; EX_exception: out exception_type; RF_trap_instr: in instr_type; EX_trap_instr: out instr_type; - RF_cop0_reg: in std_logic_vector; - EX_cop0_reg: out std_logic_vector; - RF_cop0_sel: in std_logic_vector; - EX_cop0_sel: out std_logic_vector; RF_is_delayslot: in std_logic; EX_is_delayslot: out std_logic; RF_PC_abort: in boolean; EX_PC_abort: out boolean; RF_PC: in std_logic_vector; EX_PC: out std_logic_vector; - RF_nmi: in std_logic; - EX_nmi: out std_logic; - RF_interrupt: in std_logic; - EX_interrupt: out std_logic; - RF_int_req: in std_logic_vector; - EX_int_req: out std_logic_vector; RF_trap_taken: in boolean; EX_trapped: out boolean); end component reg_excp_RF_EX; component reg_excp_EX_MM is port(clk, rst, ld: in std_logic; + EX_cop0_reg: in reg5; + MM_cop0_reg: out reg5; + EX_cop0_sel: in reg3; + MM_cop0_sel: out reg3; EX_can_trap: in std_logic_vector; MM_can_trap: out std_logic_vector; - EX_excp_type: in exception_type; - MM_excp_type: out exception_type; EX_PC: in std_logic_vector; MM_PC: out std_logic_vector; - EX_cop0_LLbit: in std_logic; - MM_cop0_LLbit: out std_logic; + EX_v_addr: in std_logic_vector; + MM_v_addr: out std_logic_vector; + nullify: in boolean; + MM_nullify: out boolean; addrError: in boolean; - MM_abort: out boolean; + MM_addrError: out boolean; + addrErr_stage_mm: in boolean; + MM_addrErr_stage_mm: out boolean; + mem_excp_type: in exception_type; + MM_mem_excp_type: out exception_type; EX_is_delayslot: in std_logic; MM_is_delayslot: out std_logic; - EX_cop0_a_c: in std_logic_vector; - MM_cop0_a_c: out std_logic_vector; - EX_cop0_val: in std_logic_vector; - MM_cop0_val: out std_logic_vector; EX_ovfl: in boolean; MM_ex_ovfl: out boolean; - EX_mfc0: in std_logic; - MM_mfc0: out std_logic); + EX_trapped: in boolean; + MM_trapped: out boolean; + EX_pc_abort: in boolean; + MM_pc_abort: out boolean; + EX_exception: in exception_type; + MM_exception: out exception_type; + TLB_exception: in boolean; + MM_tlb_exception: out boolean; + tlb_stage_MM: in boolean; + MM_tlb_stage_MM: out boolean; + TLB_excp_type: in exception_type; + MM_TLB_excp_type: out exception_type; + EX_nmi: in std_logic; + MM_nmi: out std_logic; + EX_interrupt: in std_logic; + MM_interrupt: out std_logic; + EX_int_req: in reg8; + MM_int_req: out reg8); end component reg_excp_EX_MM; component reg_excp_MM_WB is port(clk, rst, ld: in std_logic; - MM_can_trap: in std_logic_vector; - WB_can_trap: out std_logic_vector; - MM_excp_type: in exception_type; - WB_excp_type: out exception_type; MM_PC: in std_logic_vector; WB_PC: out std_logic_vector; MM_cop0_LLbit: in std_logic; WB_cop0_LLbit: out std_logic; - MM_abort: in boolean; - WB_abort: out boolean; MM_is_delayslot: in std_logic; WB_is_delayslot: out std_logic; - MM_cop0_a_c: in std_logic_vector; - WB_cop0_a_c: out std_logic_vector; MM_cop0_val: in std_logic_vector; WB_cop0_val: out std_logic_vector); end component reg_excp_MM_WB; - signal i_addr_error : std_logic; - - signal interrupt,EX_interrupt, exception_stall : std_logic; + signal annul_1, annul_2, annul_twice : std_logic; + signal interrupt,MM_interrupt, exception_stall : std_logic; signal exception_taken, interrupt_taken : std_logic; - signal nullify, nullify_EX, abort : std_logic; - signal addrError, MM_abort, WB_abort: boolean; - signal PC_abort, RF_PC_abort, EX_PC_abort : boolean; - signal IF_excp_type,RF_excp_type,EX_excp_type,WB_excp_type: exception_type := exNOP; - signal MM_excp_type, MM_excp_type_i, TLB_excp_type : exception_type; + signal nullify_fetch, nullify, MM_nullify : boolean; + signal addrError, MM_addrError, abort_ref, MM_mfc0 : boolean; + signal PC_abort, RF_PC_abort, EX_PC_abort, MM_PC_abort : boolean; + signal IF_excp_type,RF_excp_type: exception_type; + signal mem_excp_type, MM_mem_excp_type : exception_type; + signal TLB_excp_type, MM_TLB_excp_type : exception_type; signal trap_instr,EX_trap_instr: instr_type; signal RF_PC,EX_PC,MM_PC,WB_PC, LLaddr: reg32; - signal EX_LLbit,MM_LLbit,WB_LLbit: std_logic; + signal MM_LLbit,WB_LLbit: std_logic; signal LL_update,LL_SC_abort,LL_SC_differ: std_logic; - signal EX_trapped, EX_ovfl,MM_ex_ovfl, trap_taken: boolean; - signal int_req, EX_int_req: reg8; - signal RF_nmi,EX_nmi : std_logic; - signal EX_mfc0, MM_mfc0 : std_logic; - signal can_trap,EX_can_trap,MM_can_trap,WB_can_trap: reg2; + signal EX_trapped, MM_trapped, EX_ovfl,MM_ex_ovfl, trap_taken: boolean; + signal int_req, MM_int_req: reg8; + signal EX_nmi,MM_nmi : std_logic; + signal can_trap,EX_can_trap,MM_can_trap: reg2; signal is_trap, tr_signed, tr_stall: std_logic; signal tr_is_equal, tr_less_than: std_logic; signal tr_fwd_A, tr_fwd_B, tr_result : reg32; @@ -160,27 +165,26 @@ architecture rtl of core is signal status_update,epc_update,compare_update: std_logic; signal cause_update, disable_count, compare_set, compare_clr: std_logic; signal STATUSinp,STATUS, CAUSEinp,CAUSE, EPCinp,EPC : reg32; - signal COUNT,COMPARE : reg32; + signal COUNT, COMPARE : reg32; signal count_eq_compare,count_update,count_enable : std_logic; - signal exception,EX_exception,is_exception : exception_type := exNOP; + signal exception,EX_exception,MM_exception, is_exception : exception_type; signal ExcCode : reg5 := cop0code_NULL; signal exception_num,exception_dec,TLB_excp_num,trap_dec: integer; -- debugging signal RF_is_delayslot,EX_is_delayslot,MM_is_delayslot,WB_is_delayslot,is_delayslot : std_logic; - signal cop0_sel, EX_cop0_sel, epc_source : reg3; - signal cop0_reg,EX_cop0_reg : reg5; - signal cop0_inp, RF_cop0_val,EX_cop0_val,MM_cop0_val,WB_cop0_val : reg32; - signal EX_cop0_a_c,MM_cop0_a_c,WB_cop0_a_c : reg5; + signal cop0_sel, EX_cop0_sel, MM_cop0_sel, epc_source : reg3; + signal cop0_reg,EX_cop0_reg,MM_cop0_reg : reg5; + signal cop0_inp, RF_cop0_val,MM_cop0_val,WB_cop0_val : reg32; signal BadVAddr, BadVAddr_inp : reg32; signal BadVAddr_update : std_logic; -- MMU signals -- signal INDEX, index_inp, RANDOM, WIRED, wired_inp : reg32; signal index_update, wired_update : std_logic; - signal EntryLo0, EntryLo1, EntryLo0_inp, EntryLo1_inp, v_addr : reg32; - signal EntryHi, EntryHi_inp : reg32; + signal EntryLo0, EntryLo1, EntryLo0_inp, EntryLo1_inp : reg32; + signal EntryHi, EntryHi_inp, v_addr, MM_v_addr : reg32; signal Context, PageMask, PageMask_inp : reg32; signal entryLo0_update, entryLo1_update, entryHi_update : std_logic; - signal context_upd_pte, context_upd_bad, tlb_read : std_logic; + signal context_upd_pte, context_upd_bad, tlb_read, tlb_ex_2 : std_logic; signal tlb_entrylo0_mm, tlb_entrylo1_mm, tlb_entryhi : reg32; signal tlb_tag0_updt, tlb_tag1_updt, tlb_tag2_updt, tlb_tag3_updt : std_logic; signal tlb_tag4_updt, tlb_tag5_updt, tlb_tag6_updt, tlb_tag7_updt : std_logic; @@ -190,7 +194,8 @@ architecture rtl of core is signal hit4_pc, hit5_pc, hit6_pc, hit7_pc : boolean; signal hit0_mm, hit1_mm, hit2_mm, hit3_mm, hit_mm : boolean; signal hit4_mm, hit5_mm, hit6_mm, hit7_mm: boolean; - signal tlb_miss, tlb_exception, tlb_stage_MM, addrErr_stage_mm : boolean; + signal tlb_exception,MM_tlb_exception,tlb_stage_mm,MM_tlb_stage_mm : boolean; + signal addrErr_stage_mm, MM_addrErr_stage_mm : boolean; signal hit_mm_v, hit_mm_d, hit_pc_v : std_logic; signal tlb_adr_mm : MMU_idx_bits; signal tlb_probe, probe_hit, hit_mm_bit : std_logic; @@ -343,7 +348,8 @@ architecture rtl of core is -- data memory -- signal rd_data_raw, rd_data, WB_rd_data, WB_mem_data: reg32; - signal MM_B_data, WB_B_data, d_addr_pre: reg32; + signal MM_B_data, WB_B_data: reg32; + signal d_addr_pre: reg2; signal jr_stall, br_stall, fwd_lwlr, sw_stall : std_logic; signal fwd_mem, WB_addr2: reg2; @@ -761,17 +767,16 @@ begin x_EXCEPTION_0000 when PCsel_EXC_0000, -- NMI or soft-reset handler (others => 'X') when others; - IF_excp_type <= IFaddressError when PC(1 downto 0) /= b"00" else - exNOP; - PC_abort <= PC(1 downto 0) /= b"00"; + + IF_excp_type <= IFaddressError when PC_abort else exNOP; + PIPESTAGE_PC: register32 generic map (x_INST_BASE_ADDR) port map (clk, rst, PCload, PCinp, PC); PC_aligned <= PC(31 downto 2) & b"00"; - -- U_INCPC: adder32 port map (x"00000004", PC_aligned, PCincd); -- PCincd <= std_logic_vector( 4 + signed(PC_aligned) ); U_INCPC: mf_alt_add_4 PORT MAP( datab => PC_aligned, result => PCincd ); @@ -781,9 +786,14 @@ begin -- uncomment this when making use of the TLB i_addr <= phy_i_addr; - - instr_fetched <= instr when (nullify = '0' and abort = '0' and not(PC_abort)) - else NULL_INSTRUCTION; -- x"fc000000"; + + nullify_fetch <= (MM_tlb_exception and not(MM_tlb_stage_mm)); + + instr_fetched(25 downto 0) <= instr(25 downto 0); + instr_fetched(31 downto 26) <= instr(31 downto 26) + when not(nullify_fetch or PC_abort + or MM_addrError) + else NULL_INSTRUCTION(31 downto 26); -- x"fc"; PIPESTAGE_IF_RF: reg_IF_RF @@ -793,7 +803,11 @@ begin -- INSTRUCTION DECODE AND REGISTER FETCH ----------------- - opcode <= RF_instruction(31 downto 26) when (nullify = '0' and abort = '0') else + annul_1 <= BOOL2SL(nullify or MM_addrError); + U_NULLIFY_TWICE: FFD port map (clk, rst, '1', annul_1, annul_2); + annul_twice <= annul_1 or annul_2; + + opcode <= RF_instruction(31 downto 26) when annul_twice = '0' else NULL_INSTRUCTION (31 downto 26); a_rs <= RF_instruction(25 downto 21); @@ -809,11 +823,11 @@ begin funct_word <= func_table( to_integer(unsigned(func)) ) when opcode = b"000000" else - func_table( 63 ); -- empty and void table entry + func_table( 63 ); -- null instruction (sigs inactive) rimm_word <= rimm_table( to_integer(unsigned(a_rt)) ) when opcode = b"000001" else - rimm_table( 31 ); -- empty and void table entry + rimm_table( 31 ); -- null instruction (sigs inactive) is_branch <= '1' when ((ctrl_word.br_t /= cNOP) or((rimm_word.br_t /= cNOP)and(rimm_word.trap='0'))) @@ -930,7 +944,7 @@ begin RF_FORWARDING_BRANCH: process (a_rs,a_rt,EX_wreg,EX_a_c,MM_wreg,MM_a_c, - MM_aVal,MM_result,MM_mfc0,MM_cop0_val, + MM_aVal,MM_result,MM_cop0_val,MM_mfc0, regs_A,regs_B,is_branch) begin br_stall <= '0'; @@ -943,7 +957,7 @@ begin if ( (MM_aVal = '0') and (is_branch = '1') ) then -- LW load-delay slot br_stall <= '1'; eq_fwd_A <= regs_A; - elsif MM_mfc0 = '1' then -- non-LW + elsif MM_mfc0 then -- non-LW eq_fwd_A <= MM_cop0_val; else eq_fwd_A <= MM_result; @@ -960,7 +974,7 @@ begin if ( (MM_aVal = '0') and (is_branch = '1') ) then -- LW load-delay slot br_stall <= '1'; eq_fwd_B <= regs_B; - elsif MM_mfc0 = '1' then -- non-LW + elsif MM_mfc0 then -- non-LW eq_fwd_B <= MM_cop0_val; else eq_fwd_B <= MM_result; @@ -1036,8 +1050,8 @@ begin RF_DECODE_FUNCT: process (opcode,IF_RF_ld,ctrl_word,funct_word,rimm_word, - func,shamt, a_rs,a_rd, STATUS, addrError, - RF_excp_type,RF_instruction,MM_excp_type) + func,shamt, a_rs,a_rd, STATUS, + RF_excp_type,RF_instruction,mem_excp_type) variable i_wreg : std_logic; variable i_csel : reg2; variable i_oper : t_alu_fun := opNOP; @@ -1158,12 +1172,6 @@ begin case opcode is when b"110000" => i_exception := exLL; -- not REALLY exceptions when b"111000" => i_exception := exSC; - -- when b"111111" => - -- if addrError then - -- i_exception := MM_excp_type; - -- else - -- i_exception := RF_excp_type; -- delayed by pipe - -- end if; when others => null; -- i_exception := exRESV_INSTR; end case; i_wreg := ctrl_word.wreg; @@ -1242,7 +1250,7 @@ begin begin FORWARD_A: if ((MM_wreg = '0')and(MM_a_c /= b"00000")and(MM_a_c = EX_a_rs)) then - if MM_mfc0 /= '1' then + if not(MM_mfc0) then i_A := MM_result; else i_A := MM_cop0_val; @@ -1258,7 +1266,7 @@ begin FORWARD_B: if ((MM_wreg = '0')and(MM_a_c /= b"00000")and(MM_a_c = EX_a_rt)) then - if MM_mfc0 /= '1' then + if not(MM_mfc0) then i_B := MM_result; else i_B := MM_cop0_val; @@ -1279,20 +1287,6 @@ begin alu_inp_A, alu_inp_B, result, LO, HI, alu_move_ok, EX_oper,EX_postn,EX_shamt, ovfl); - EX_wreg <= EX_wreg_pre -- movz,movn, move/DO_NOT move - or nullify_EX; -- abort wr if prev excep in EX - - EX_wrmem_cond <= EX_wrmem - or nullify_EX -- abort write if exception in EX - or LL_SC_abort -- abort write if SC fails - or abort; -- abort write if exception in MEM - - EX_aVal_cond <= EX_aVal - or nullify_EX -- abort ref if previous excep in EX - or abort; -- abort ref if exception in MEM - - abort <= '1' when (addrError or (tlb_exception and tlb_stage_mm)) else '0'; - -- this adder performs address calculation so the TLB can be checked during -- EX and thus signal an exception as early as possible @@ -1300,7 +1294,8 @@ begin U_EX_ADDR_ERR_EXCP: process(EX_mem_t,EX_aVal,EX_wrmem, v_addr) - variable i_stage_mm : boolean; + variable i_stage_mm, i_addrError : boolean; + variable i_excp_type : exception_type; begin case EX_mem_t(1 downto 0) is -- xx,by,hf,wd @@ -1308,55 +1303,75 @@ begin if ( EX_mem_t(3) = '0' and -- normal LOAD, not LWL,LWR EX_aVal = '0' and v_addr(1 downto 0) /= b"00" ) then if EX_wrmem = '1' then - MM_excp_type <= MMaddressErrorLD; + i_excp_type := MMaddressErrorLD; else - MM_excp_type <= MMaddressErrorST; + i_excp_type := MMaddressErrorST; end if; - addrError <= TRUE; - i_stage_mm := TRUE; + i_addrError := TRUE; + i_stage_mm := TRUE; else - MM_excp_type <= exNOP; - addrError <= FALSE; + i_excp_type := exNOP; + i_addrError := FALSE; i_stage_mm := FALSE; end if; when b"10" => -- LH*, SH if EX_aVal = '0' and v_addr(0) /= '0' then if EX_wrmem = '1' then - MM_excp_type <= MMaddressErrorLD; + i_excp_type := MMaddressErrorLD; else - MM_excp_type <= MMaddressErrorST; + i_excp_type := MMaddressErrorST; end if; - addrError <= TRUE; - i_stage_mm := TRUE; + i_addrError := TRUE; + i_stage_mm := TRUE; else - MM_excp_type <= exNOP; - addrError <= FALSE; + i_excp_type := exNOP; + i_addrError := FALSE; i_stage_mm := FALSE; end if; when others => -- LB*, SB - MM_excp_type <= exNOP; - addrError <= FALSE; + i_excp_type := exNOP; + i_addrError := FALSE; i_stage_mm := FALSE; end case; + mem_excp_type <= i_excp_type; addrErr_stage_mm <= i_stage_mm; + addrError <= i_addrError; - -- assert MM_excp_type = exNOP -- DEBUG + -- assert mem_excp_type = exNOP -- DEBUG -- report "SIMULATION ERROR -- data addressing error: " & - -- integer'image(exception_type'pos(MM_excp_type)) & + -- integer'image(exception_type'pos(mem_excp_type)) & -- " at address: " & SLV32HEX(v_addr) -- severity error; end process U_EX_ADDR_ERR_EXCP; ---------------------------------- - EX_addr <= phy_d_addr; -- with TLB + EX_addr <= phy_d_addr; -- with 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 "mapping mismatch V:P "&SLV32HEX(v_addr)&":"&SLV32HEX(phy_d_addr); + + + + EX_wreg <= EX_wreg_pre -- movz,movn, move/DO_NOT move + or ( BOOL2SL(nullify) and not(MM_is_delayslot) ); + -- abort wr if prev excep in EX + + EX_wrmem_cond <= EX_wrmem + or BOOL2SL(abort_ref) -- abort write if exception in MEM + or ( BOOL2SL(nullify) and not(MM_is_delayslot) ); + -- abort memWrite if exception in EX + + EX_aVal_cond <= EX_aVal + or BOOL2SL(abort_ref) -- abort ref if exception in MEM + or ( BOOL2SL(nullify) and not(MM_is_delayslot) ); + -- abort memRef if previous excep in EX + + abort_ref <= (addrError or (tlb_exception and tlb_stage_mm)); + + -- ---------------------------------------------------------------------- PIPESTAGE_EX_MM: reg_EX_MM port map (clk,rst, EX_MM_ld, @@ -1382,33 +1397,34 @@ begin ram_stall <= not(daVal) and not(d_wait); -- end DATA_BUS_STATE_MACHINE ------------------------------------- - wr <= MM_wrmem; + wr <= MM_wrmem or LL_SC_abort; -- abort write if SC fails + rd_data_raw <= data_inp when (MM_wrmem = '1' and MM_aVal = '0') else (others => 'X'); - d_addr <= d_addr_pre; + d_addr <= MM_addr(31 downto 2) & d_addr_pre; - MM_MEM_CTRL_INTERFACE: process(MM_mem_t, MM_aVal, MM_addr) - variable i_d_addr : reg32; + MM_MEM_CTRL_INTERFACE: process(MM_mem_t, MM_aVal, MM_addr(1 downto 0)) + variable i_d_addr : reg2; variable i_byte_sel : reg4; begin - case MM_mem_t(1 downto 0) is -- xx,by,hf,wd + case MM_mem_t(1 downto 0) is -- xx,by,hf,wd when b"11" => - i_byte_sel := b"1111"; -- LW, SW, LWL, LWR - i_d_addr := MM_addr(31 downto 2) & b"00"; -- align reference + i_byte_sel := b"1111"; -- LW, SW, LWL, LWR + i_d_addr := b"00"; -- align reference when b"10" => - i_d_addr := MM_addr(31 downto 1) & '0'; -- align reference - if MM_addr(1) = '0' then -- LH*, SH + i_d_addr := MM_addr(1) & '0'; -- align reference + if MM_addr(1) = '0' then -- LH*, SH i_byte_sel := b"0011"; else i_byte_sel := b"1100"; end if; - when b"01" => -- LB*, SB - i_d_addr := MM_addr; + when b"01" => -- LB*, SB + i_d_addr := MM_addr(1 downto 0); case MM_addr(1 downto 0) is when b"00" => i_byte_sel := b"0001"; when b"01" => i_byte_sel := b"0010"; @@ -1417,7 +1433,7 @@ begin end case; when others => - i_d_addr := (others => 'X'); -- MM_addr; + i_d_addr := (others => 'X'); -- MM_addr; i_byte_sel := b"0000"; end case; @@ -1482,8 +1498,7 @@ begin variable f_m: reg2; variable i_data : reg32; begin - FORWARD_M: if ( (MM_wrmem = '0') and (MM_aVal = '0') ) - then + if ( (MM_wrmem = '0') and (MM_aVal = '0') ) then if ( (MM_a_rt = WB_a_c) and (WB_wreg = '0') and (WB_a_c /= b"00000")) then f_m := "01"; -- forward from WB i_data := WB_C; @@ -1505,9 +1520,9 @@ begin variable f_m: std_logic; variable i_data : reg32; begin - FORWARD_M: if ( (MM_wreg = '0') and (MM_aVal = '0') and - (MM_a_rt = WB_a_c) and (WB_wreg = '0') and - (WB_a_c /= b"00000") ) then + if ( (MM_wreg = '0') and (MM_aVal = '0') and + (MM_a_rt = WB_a_c) and (WB_wreg = '0') and + (WB_a_c /= b"00000") ) then f_m := '1'; -- forward from WB i_data := WB_C; else @@ -1520,7 +1535,7 @@ begin MM_wreg_cond <= '1' when ( (ram_stall = '1') - or MM_abort -- abort regWrite if excptn in MEM + or MM_addrError -- abort regWrite if excptn in MEM or (MM_move = '1' and MM_alu_move_ok = '0') ) else MM_wreg; @@ -1607,20 +1622,6 @@ begin -- RF decode & register fetch --------------------------------------------- - RF_nmi <= nmi; - int_req(7) <= (irq(5) or count_eq_compare); - int_req(6) <= irq(4); - int_req(5) <= irq(3); - int_req(4) <= irq(2); - int_req(3) <= irq(1); - int_req(2) <= irq(0); - int_req(1) <= CAUSE(CAUSE_IP1); - int_req(0) <= CAUSE(CAUSE_IP0); - - interrupt <= int_req(7) or int_req(6) or int_req(5) or int_req(4) or - int_req(3) or int_req(2) or int_req(1) or int_req(0); - - RF_FORWARDING_TRAPS: process (a_rs,a_rt,rimm_word,displ32, EX_wreg,EX_a_c,MM_wreg,MM_a_c, @@ -1700,44 +1701,72 @@ begin -- ---------------------------------------------------------------------- PIPESTAGE_EXCP_RF_EX: reg_excp_RF_EX - port map (clk, rst, excp_RF_EX_ld, can_trap,EX_can_trap, - exception,EX_exception, trap_instr,EX_trap_instr, + port map (clk, rst, excp_RF_EX_ld, cop0_reg,EX_cop0_reg, cop0_sel,EX_cop0_sel, + can_trap,EX_can_trap, + exception,EX_exception, trap_instr,EX_trap_instr, RF_is_delayslot,EX_is_delayslot, - RF_PC_abort,EX_PC_abort, RF_PC,EX_PC, RF_nmi,EX_nmi, - interrupt,EX_interrupt, int_req,EX_int_req, + RF_PC_abort,EX_PC_abort, RF_PC,EX_PC, trap_taken,EX_trapped); - -- EX execute exception --------------------------------------------- + EX_nmi <= nmi; + int_req(7) <= (irq(5) or count_eq_compare); + int_req(6) <= irq(4); + int_req(5) <= irq(3); + int_req(4) <= irq(2); + int_req(3) <= irq(1); + int_req(2) <= irq(0); + int_req(1) <= CAUSE(CAUSE_IP1); + int_req(0) <= CAUSE(CAUSE_IP0); + + interrupt <= int_req(7) or int_req(6) or int_req(5) or int_req(4) or + int_req(3) or int_req(2) or int_req(1) or int_req(0); - -- check for overflow in EX, send it to MM for later processing EX_ovfl <= (EX_can_trap = b"10" and ovfl = '1'); + -- ---------------------------------------------------------------------- + PIPESTAGE_EXCP_EX_MM: reg_excp_EX_MM + port map (clk, rst, excp_EX_MM_ld, + EX_cop0_reg, MM_cop0_reg, EX_cop0_sel, MM_cop0_sel, + EX_can_trap,MM_can_trap, EX_PC,MM_PC, + v_addr,MM_v_addr, nullify,MM_nullify, + addrError,MM_addrError, addrErr_stage_mm,MM_addrErr_stage_mm, + mem_excp_type,MM_mem_excp_type, EX_is_delayslot,MM_is_delayslot, + EX_ovfl,MM_ex_ovfl, EX_trapped,MM_trapped, + EX_PC_abort,MM_PC_abort, + EX_exception,MM_exception, tlb_exception,MM_tlb_exception, + tlb_stage_mm,MM_tlb_stage_mm, TLB_excp_type,MM_TLB_excp_type, + EX_nmi,MM_nmi, interrupt,MM_interrupt, int_req,MM_int_req); + + + - is_exception <= TLB_excp_type when tlb_exception else - MM_excp_type when addrError else - exTrap when Ex_trapped else - exOvfl when MM_ex_ovfl else - IFaddressError when EX_PC_abort else - EX_exception; + is_exception <= MM_TLB_excp_type when MM_tlb_exception else + MM_mem_excp_type when MM_addrError else + exTrap when MM_trapped else + exOvfl when MM_ex_ovfl else + IFaddressError when MM_PC_abort else + MM_exception; exception_num <= exception_type'pos(is_exception); -- for debugging only + MM_mfc0 <= (is_exception = exMFC0); -- STATUS -- pg 79 -- cop0_12 -------------------- COP0_DECODE_EXCEPTION_AND_UPDATE_STATUS: - process (EX_a_rt, is_exception, cop0_inp, - EX_cop0_reg, EX_cop0_sel, EX_nmi, EX_interrupt,EX_int_req, + process (MM_a_rt, is_exception, cop0_inp, + MM_cop0_reg, MM_cop0_sel, MM_nmi, MM_interrupt,MM_int_req, RF_is_delayslot, EX_is_delayslot, MM_is_delayslot, WB_is_delayslot, + rom_stall,ram_stall, MM_mfc0, INDEX, RANDOM, EntryLo0, EntryLo1, CONTEXT, PAGEMASK, WIRED, - EntryHi, COUNT, COMPARE, STATUS, CAUSE, EPC, BadVAddr, - rom_stall,ram_stall) + EntryHi, COUNT, COMPARE, STATUS, CAUSE, EPC, BadVAddr) variable newSTATUS, i_COP0_rd : reg32; - variable i_update,i_epc_update,i_stall,i_nullify : std_logic; - variable i_a_c,i_update_r : reg5; + variable i_update,i_epc_update,i_stall : std_logic; + variable i_nullify: boolean; + variable i_update_r : reg5; variable i_epc_source : reg3; begin @@ -1747,17 +1776,13 @@ begin i_epc_source := EPC_src_PC; i_update := '0'; i_update_r := b"00000"; - i_a_c := b"00000"; i_COP0_rd := x"00000000"; i_stall := '0'; - i_nullify := '0'; - + i_nullify := FALSE; - nullify_EX <= '0'; exception_taken <= '0'; -- for debugging only interrupt_taken <= '0'; ExcCode <= cop0code_NULL; - EX_mfc0 <= '0'; is_delayslot <= '0'; newSTATUS := STATUS; -- preserve as needed @@ -1770,22 +1795,22 @@ begin case is_exception is when exMTC0 => -- move to COP-0 - i_update_r := EX_cop0_reg; - case EX_cop0_reg is + i_update_r := MM_cop0_reg; + case MM_cop0_reg is when cop0reg_STATUS => newSTATUS := cop0_inp; i_update := '1'; - i_stall := '1'; + i_stall := '0'; when cop0reg_COUNT | cop0reg_COMPARE | cop0reg_CAUSE | cop0reg_EntryLo0 | cop0reg_EntryLo1 | cop0reg_EntryHi => i_update := '1'; - i_stall := '1'; + i_stall := '0'; when cop0reg_Index | cop0reg_Context | cop0reg_Wired => i_update := '1'; i_stall := '0'; when cop0reg_EPC => i_epc_update := '0'; - i_epc_source := EPC_src_B; -- EX_B + i_epc_source := EPC_src_B; i_stall := '0'; when others => i_stall := '0'; @@ -1797,7 +1822,6 @@ begin i_update := '1'; i_update_r := cop0reg_STATUS; i_COP0_rd := STATUS; - i_a_c := EX_a_rt; i_stall := '1'; when exDI => -- disable interrupts @@ -1805,11 +1829,11 @@ begin i_update := '1'; i_update_r := cop0reg_STATUS; i_COP0_rd := STATUS; - i_a_c := EX_a_rt; i_stall := '1'; - when exMFC0 => -- move from COP-0 - case EX_cop0_reg is + when exMFC0 => -- move from COP-0 + i_stall := '0'; + case MM_cop0_reg is when cop0reg_Index => i_COP0_rd := INDEX; when cop0reg_Random => i_COP0_rd := RANDOM; when cop0reg_EntryLo0 => i_COP0_rd := EntryLo0; @@ -1825,23 +1849,20 @@ begin when cop0reg_EPC => i_COP0_rd := EPC; when cop0reg_BadVAddr => i_COP0_rd := BadVAddr; when cop0reg_CONFIG => - if EX_cop0_sel = b"000" then + if MM_cop0_sel = b"000" then i_COP0_rd := CONFIG0; else i_COP0_rd := CONFIG1; end if; when others => i_COP0_rd := (others => 'X'); end case; - i_a_c := EX_a_rt; - i_stall := '0'; - 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_nullify := '1'; -- nullify instructions in IF,RF + i_nullify := TRUE; -- nullify instructions in IF,RF when exSYSCALL | exBREAK => -- SYSCALL, BREAK @@ -1857,18 +1878,18 @@ begin i_update := '1'; i_update_r := cop0reg_STATUS; i_stall := '0'; -- do not stall - i_epc_update := '0'; - i_nullify := '1'; -- nullify instructions in IF,RF - if EX_is_delayslot = '1' then -- instr is in delay slot - i_epc_source := EPC_src_EX; -- EX_PC, re-execute branch/jump - is_delayslot <= EX_is_delayslot; + i_epc_update := '0'; + i_nullify := TRUE; -- nullify instructions in IF,RF + if MM_is_delayslot = '1' then -- instr is in delay slot + i_epc_source := EPC_src_WB; -- re-execute branch/jump + is_delayslot <= WB_is_delayslot; else - i_epc_source := EPC_src_RF; -- RF_PC - is_delayslot <= RF_is_delayslot; + i_epc_source := EPC_src_MM; + is_delayslot <= MM_is_delayslot; end if; - when exTRAP => -- TRAP detected one cycle earlier + when exTRAP => ExcCode <= cop0code_Tr; newSTATUS(STATUS_EXL) := '1'; -- at exception level newSTATUS(STATUS_UM) := '0'; -- enter kernel mode @@ -1877,17 +1898,17 @@ begin i_update_r := cop0reg_STATUS; i_stall := '0'; i_epc_update := '0'; - i_nullify := '1'; -- nullify instructions in IF,RF - if EX_is_delayslot = '1' then -- instr is in delay slot - i_epc_source := EPC_src_MM; -- EX_PC, re-execute branch/jump - is_delayslot <= EX_is_delayslot; + i_nullify := TRUE; -- nullify instructions in IF,RF,EX + if MM_is_delayslot = '1' then -- instr is in delay slot + i_epc_source := EPC_src_WB; -- WB_PC, re-execute branch/jump + is_delayslot <= WB_is_delayslot; else - i_epc_source := EPC_src_EX; -- RF_PC - is_delayslot <= RF_is_delayslot; + i_epc_source := EPC_src_MM; -- MM_PC + is_delayslot <= MM_is_delayslot; end if; - when exLL => -- load linked (not a real exception) + when exLL => -- load linked (not a real exception) i_update := '1'; i_update_r := cop0reg_LLaddr; @@ -1908,8 +1929,7 @@ begin i_update_r := cop0reg_STATUS; i_epc_update := '0'; ExcCode <= cop0code_Ov; - i_nullify := '1'; -- nullify instructions in IF,RF - nullify_EX <= '1'; -- and instruction in EX + i_nullify := TRUE; -- nullify instructions in IF,RF,EX if WB_is_delayslot = '1' then -- instr is in delay slot i_epc_source := EPC_src_WB; -- WB_PC, re-execute branch/jump is_delayslot <= WB_is_delayslot; @@ -1919,72 +1939,90 @@ begin end if; - when IFaddressError | MMaddressErrorLD | MMaddressErrorST => - -- fetch/load/store from/to UNALIGNED ADDRESS + 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; + ExcCode <= cop0code_AdEL; + i_nullify := TRUE; -- nullify instructions in IF,RF,EX + i_epc_source := EPC_src_MM; -- bad address is in EXCP_MM_PC + i_epc_update := '0'; + is_delayslot <= MM_is_delayslot; + + + 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; i_epc_update := '0'; + i_nullify := TRUE; -- nullify instructions in IF,RF,EX if is_exception = MMaddressErrorST then ExcCode <= cop0code_AdES; else ExcCode <= cop0code_AdEL; end if; - if is_exception = IFaddressError then - i_nullify := '1'; -- nullify instructions in IF,RF + if WB_is_delayslot = '1' then -- instr is in delay slot + i_epc_source := EPC_src_WB; -- WB_PC, re-execute branch/jump + is_delayslot <= WB_is_delayslot; + else + i_epc_source := EPC_src_MM; -- offending instr PC is in MM_PC + is_delayslot <= MM_is_delayslot; end if; - i_epc_source := EPC_src_EX; -- bad address is in EXCP_EX_PC - is_delayslot <= EX_is_delayslot; - + + when exEHB => -- stall processor to clear hazards i_stall := '1'; when exTLBP | exTLBR | exTLBWI | exTLBWR => -- TLB access - i_stall := '1'; -- stall the processor + i_stall := '0'; -- stall the processor - when exTLBrefillIF | exTLBrefillRD | exTLBrefillWR => + when exTLBrefillIF => + ExcCode <= cop0code_TLBL; + if RF_is_delayslot = '1' then -- instr is in delay slot + i_epc_source := EPC_src_EX; -- EX_PC, re-execute branch/jump + is_delayslot <= RF_is_delayslot; + else + i_epc_source := EPC_src_RF; -- RF_PC + 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'; + i_nullify := TRUE; -- nullify instructions in IF,RF,EX + + when exTLBrefillRD | exTLBrefillWR => case is_exception is - when exTLBrefillIF => - ExcCode <= cop0code_TLBL; - if RF_is_delayslot = '1' then -- instr is in delay slot - i_epc_source := EPC_src_RF; -- RF_PC, re-execute branch/jump - is_delayslot <= RF_is_delayslot; - else - i_epc_source := EPC_src_PC; -- PC - is_delayslot <= '0'; - end if; when exTLBrefillRD => ExcCode <= cop0code_TLBL; - if MM_is_delayslot = '1' then -- instr is in delay slot - i_epc_source := EPC_src_MM; -- MM_PC, re-execute branch/jump - is_delayslot <= MM_is_delayslot; - else - i_epc_source := EPC_src_EX; -- EX_PC - is_delayslot <= EX_is_delayslot; - end if; when exTLBrefillWR => ExcCode <= cop0code_TLBS; - if MM_is_delayslot = '1' then -- instr is in delay slot - i_epc_source := EPC_src_MM; -- MM_PC, re-execute branch/jump - is_delayslot <= MM_is_delayslot; - else - i_epc_source := EPC_src_EX; -- EX_PC - is_delayslot <= EX_is_delayslot; - 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_epc_update := '0'; - - + if WB_is_delayslot = '1' then -- instr is in delay slot + i_epc_source := EPC_src_WB; -- MM_PC, re-execute branch/jump + is_delayslot <= WB_is_delayslot; + else + i_epc_source := EPC_src_MM; -- EX_PC + 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'; + i_nullify := TRUE; -- nullify instructions in IF,RF,EX + when exTLBdblFaultIF | exTLBdblFaultRD | exTLBdblFaultWR | exTLBinvalIF | exTLBinvalRD | exTLBinvalWR | exTLBmod => case is_exception is @@ -1999,30 +2037,30 @@ begin end if; when exTLBinvalRD | exTLBdblFaultRD => ExcCode <= cop0code_TLBL; - if MM_is_delayslot = '1' then -- instr is in delay slot - i_epc_source := EPC_src_MM; -- MM_PC, re-execute branch/jump - is_delayslot <= MM_is_delayslot; + if WB_is_delayslot = '1' then -- instr is in delay slot + i_epc_source := EPC_src_WB; -- MM_PC, re-execute branch/jump + is_delayslot <= WB_is_delayslot; else - i_epc_source := EPC_src_EX; -- EX_PC - is_delayslot <= EX_is_delayslot; + i_epc_source := EPC_src_MM; -- EX_PC + is_delayslot <= MM_is_delayslot; end if; when exTLBinvalWR | exTLBdblFaultWR => ExcCode <= cop0code_TLBS; - if MM_is_delayslot = '1' then -- instr is in delay slot - i_epc_source := EPC_src_MM; -- MM_PC, re-execute branch/jump - is_delayslot <= MM_is_delayslot; + if WB_is_delayslot = '1' then -- instr is in delay slot + i_epc_source := EPC_src_WB; -- MM_PC, re-execute branch/jump + is_delayslot <= WB_is_delayslot; else - i_epc_source := EPC_src_EX; -- EX_PC - is_delayslot <= EX_is_delayslot; + i_epc_source := EPC_src_MM; -- EX_PC + is_delayslot <= MM_is_delayslot; end if; when exTLBmod => ExcCode <= cop0code_Mod; - if MM_is_delayslot = '1' then -- instr is in delay slot - i_epc_source := EPC_src_MM; -- MM_PC, re-execute branch/jump - is_delayslot <= MM_is_delayslot; + if WB_is_delayslot = '1' then -- instr is in delay slot + i_epc_source := EPC_src_WB; -- MM_PC, re-execute branch/jump + is_delayslot <= WB_is_delayslot; else - i_epc_source := EPC_src_EX; -- EX_PC - is_delayslot <= EX_is_delayslot; + i_epc_source := EPC_src_MM; -- EX_PC + is_delayslot <= MM_is_delayslot; end if; when others => null; end case; @@ -2030,15 +2068,14 @@ begin newSTATUS(STATUS_IE) := '0'; -- disable interrupts i_update := '1'; i_update_r := cop0reg_STATUS; - i_epc_update := '0'; - - + i_epc_update := '0'; + i_nullify := TRUE; -- nullify instructions in IF,RF,EX when others => -- interrupt pending? - if ( (EX_nmi = '1') and (STATUS(STATUS_ERL) = '0') ) then + if ( (MM_nmi = '1') and (STATUS(STATUS_ERL) = '0') ) then -- non maskable interrupt - -- assert false report "NM interrupt PC="&SLV32HEX(PC) severity note; + -- assert false report "NMinterrupt PC="&SLV32HEX(PC) severity note; exception_taken <= '1'; newSTATUS(STATUS_BEV) := '1'; -- locationVector at bootstrap newSTATUS(STATUS_TS) := '0'; -- not TLBmatchesSeveral @@ -2049,17 +2086,17 @@ begin i_update_r := cop0reg_STATUS; i_stall := '0'; i_epc_update := '0'; - i_nullify := '1'; -- nullify instructions in IF,RF + i_nullify := TRUE; -- nullify instructions in IF,RF,EX if EX_is_delayslot = '1' then -- instr is in delay slot - i_epc_source := EPC_src_EX; -- EX_PC, re-execute branch/jump - is_delayslot <= EX_is_delayslot; + i_epc_source := EPC_src_MM; -- re-execute branch/jump + is_delayslot <= MM_is_delayslot; else - i_epc_source := EPC_src_RF; -- RF_PC - is_delayslot <= RF_is_delayslot; + i_epc_source := EPC_src_EX; + is_delayslot <= EX_is_delayslot; end if; elsif ( (STATUS(STATUS_EXL) = '0') and (STATUS(STATUS_ERL) = '0') and - (STATUS(STATUS_IE) = '1') and (EX_interrupt = '1') and + (STATUS(STATUS_IE) = '1') and (MM_interrupt = '1') and (rom_stall = '0' and ram_stall = '0')) then -- normal interrupt -- assert false report "interrupt PC="&SLV32HEX(PC) severity note; @@ -2072,32 +2109,31 @@ begin i_update_r := cop0reg_STATUS; i_stall := '0'; i_epc_update := '0'; - i_nullify := '1'; -- nullify instructions in IF,RF - if EX_is_delayslot = '1' then -- instr is in delay slot - i_epc_source := EPC_src_EX; -- EX_PC, re-execute branch/jump - is_delayslot <= EX_is_delayslot; + i_nullify := TRUE; -- nullify instructions in IF,RF,EX + if MM_is_delayslot = '1' then -- instr is in delay slot + i_epc_source := EPC_src_MM; -- re-execute branch/jump + is_delayslot <= MM_is_delayslot; else - i_epc_source := EPC_src_RF; -- RF_PC - is_delayslot <= RF_is_delayslot; + i_epc_source := EPC_src_EX; + is_delayslot <= EX_is_delayslot; end if; end if; -- NMI or else interrupt end case; - STATUSinp <= newSTATUS; - EX_cop0_val <= i_COP0_rd; - EX_cop0_a_c <= i_a_c; -- only for forwarding COP0 values - update <= i_update; - update_reg <= i_update_r; + STATUSinp <= newSTATUS; + MM_cop0_val <= i_COP0_rd; + update <= i_update; + update_reg <= i_update_r; - if is_exception = exMTC0 and EX_cop0_reg = cop0reg_EPC then + if is_exception = exMTC0 and MM_cop0_reg = cop0reg_EPC then epc_update <= i_epc_update; else epc_update <= i_epc_update OR STATUS(STATUS_EXL); end if; - epc_source <= i_epc_source; - + epc_source <= i_epc_source; + exception_stall <= i_stall; nullify <= i_nullify; @@ -2105,8 +2141,8 @@ begin -- Select input to PC on an exception -------------------- - COP0_SEL_EPC: process (is_exception, EX_nmi, EX_interrupt, STATUS, CAUSE, - EX_trapped, rom_stall, ram_stall) + COP0_SEL_EPC: process (is_exception, MM_nmi, MM_interrupt, STATUS, CAUSE, + MM_trapped, rom_stall, ram_stall) variable i_excp_PCsel : reg3; begin @@ -2124,7 +2160,7 @@ begin i_excp_PCsel := PCsel_EXC_0180; -- PC <= exception_180 when exTRAP => - if EX_trapped then + if MM_trapped then i_excp_PCsel := PCsel_EXC_0180; -- PC <= exception_180 else i_excp_PCsel := PCsel_EXC_none; @@ -2135,12 +2171,12 @@ begin when others => -- interrupt pending? - if ( (EX_nmi = '1') and (STATUS(STATUS_ERL) = '0') ) then + if ( (MM_nmi = '1') and (STATUS(STATUS_ERL) = '0') ) then -- non maskable interrupt - i_excp_PCsel := PCsel_EXC_0000; -- PC <= exception_0000 + i_excp_PCsel := PCsel_EXC_0180; -- PC <= 0xBFC0.0000 elsif ( (STATUS(STATUS_EXL) = '0') and (STATUS(STATUS_ERL) = '0') and - (STATUS(STATUS_IE) = '1') and (EX_interrupt = '1') and + (STATUS(STATUS_IE) = '1') and (MM_interrupt = '1') and (rom_stall = '0' and ram_stall = '0')) then -- normal interrupt if CAUSE(CAUSE_IV) = '1' then @@ -2160,45 +2196,37 @@ begin - - COP0_FORWARDING: - process (EX_a_rt,EX_a_c, MM_a_c,MM_wreg,MM_result, WB_a_c,WB_wreg, - WB_C,EX_B, MM_cop0_val, MM_cop0_a_c,EX_cop0_a_c) + COP0_FORWARDING: process (WB_a_c,WB_wreg,MM_a_rt,WB_C,MM_B) variable i_B : reg32; begin - if ((MM_wreg = '0')and(MM_a_c /= b"00000")and(MM_a_c = EX_a_rt)) then - i_B := MM_result; - elsif ((MM_wreg = '0')and - (MM_cop0_a_c /= b"00000")and(MM_cop0_a_c = EX_cop0_a_c)) then - i_B := MM_cop0_val; - elsif ((WB_wreg = '0')and(WB_a_c /= b"00000")and(WB_a_c = EX_a_rt)) then + if ((WB_wreg = '0')and(WB_a_c /= b"00000")and(WB_a_c = MM_a_rt)) then i_B := WB_C; else - i_B := EX_B; + i_B := MM_B; end if; cop0_inp <= i_B; end process COP0_FORWARDING; + -- STATUS -- pg 79 -- cop0_12 -------------------- 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 -- pg 92-- cop0_13 -------------------------- - COP0_COMPUTE_CAUSE: process(rst, update,update_reg, - EX_int_req, ExcCode, cop0_inp, is_delayslot, + COP0_COMPUTE_CAUSE: process(rst,clk, update,update_reg, + MM_int_req, ExcCode, cop0_inp, is_delayslot, count_eq_compare,count_enable, STATUS, CAUSE) variable newCAUSE : reg32; begin if STATUS(STATUS_EXL) = '0' then - newCAUSE(CAUSE_BD) := is_delayslot; -- instr is in delay slot + newCAUSE(CAUSE_BD) := is_delayslot; -- instr is in delay slot else newCAUSE(CAUSE_BD) := CAUSE(CAUSE_BD); -- hold it on a double fault end if; @@ -2211,12 +2239,12 @@ begin newCAUSE(CAUSE_IV) := CAUSE(CAUSE_IV); newCAUSE(CAUSE_WP) := '0'; newCAUSE(21 downto 16) := b"000000"; - newCAUSE(CAUSE_IP7) := EX_int_req(7); - newCAUSE(CAUSE_IP6) := EX_int_req(6); - newCAUSE(CAUSE_IP5) := EX_int_req(5); - newCAUSE(CAUSE_IP4) := EX_int_req(4); - newCAUSE(CAUSE_IP3) := EX_int_req(3); - newCAUSE(CAUSE_IP2) := EX_int_req(2); + newCAUSE(CAUSE_IP7) := MM_int_req(7); + newCAUSE(CAUSE_IP6) := MM_int_req(6); + newCAUSE(CAUSE_IP5) := MM_int_req(5); + newCAUSE(CAUSE_IP4) := MM_int_req(4); + newCAUSE(CAUSE_IP3) := MM_int_req(3); + newCAUSE(CAUSE_IP2) := MM_int_req(2); newCAUSE(CAUSE_IP1) := CAUSE(CAUSE_IP1); newCAUSE(CAUSE_IP0) := CAUSE(CAUSE_IP0); newCAUSE(7) := '0'; @@ -2235,16 +2263,16 @@ begin end if; end process COP0_COMPUTE_CAUSE; - COP0_CAUSE_HOLD: process(rst,clk, - ExcCode,is_exception,EX_cop0_reg,not_stalled) + COP0_CAUSE_HOLD: process(rst,clk, ExcCode,is_exception,MM_cop0_reg,not_stalled) + variable state: reg32; begin if rst = '0' then -- hold CAUSE until it is read cause_update <= '0'; elsif ( rising_edge(clk) and (ExcCode /= cop0code_NULL) ) then cause_update <= '1'; -- syscall/trap/interrupt/exception elsif ( rising_edge(clk) and (is_exception = exMFC0) and - EX_cop0_reg = cop0reg_CAUSE and (not_stalled = '1') ) then - cause_update <= '0'; -- CAUSE is being read + MM_cop0_reg = cop0reg_CAUSE and (not_stalled = '1') ) then + cause_update <= '0'; -- CAUSE is being read end if; end process COP0_CAUSE_HOLD; @@ -2259,7 +2287,7 @@ begin EX_PC when EPC_src_EX, -- interrupt, eret, overflow MM_PC when EPC_src_MM, -- data memory exception WB_PC when EPC_src_WB, -- overflow in a branch delay slot - alu_fwd_B when EPC_src_B, -- mtc0 + MM_B when EPC_src_B, -- mtc0 (others => 'X') when others; -- invalid selection COP0_EPC: register32 generic map (x"00000000") @@ -2294,14 +2322,33 @@ begin -- BadVAddr -- pg 74 --------------------------- - -- Dtlb | misaligned - BadVAddr_inp <= v_addr when ( (addrError and addrErr_stage_mm) or - (tlb_exception and tlb_stage_mm) ) else - EX_PC when EX_PC_abort else -- fetch misaligned - PC; -- I-TLB - BadVAddr_update <= '0' when tlb_exception or addrError else '1'; - + U_BadVAddr_UPDATE: process(is_exception, RF_is_delayslot, RF_PC, EX_PC, + MM_v_addr) + variable i_update : std_logic; + begin + case is_exception is + when IFaddressError | exTLBrefillIF | exTLBdblFaultIF | exTLBinvalIF => + if RF_is_delayslot = '1' then -- instr is in delay slot + BadVAddr_inp <= EX_PC; + else + BadVAddr_inp <= RF_PC; + end if; + i_update := '0'; + + when MMaddressErrorLD | MMaddressErrorST | exTLBrefillRD | exTLBrefillWR + | exTLBdblFaultRD | exTLBdblFaultWR | exTLBinvalRD | exTLBinvalWR + | exTLBmod => + BadVAddr_inp <= MM_v_addr; + i_update := '0'; + + when others => + BadVAddr_inp <= (others => 'X'); + i_update := '1'; + end case; + BadVAddr_update <= i_update; + end process U_BadVAddr_UPDATE; + COP0_BadVAddr: register32 generic map(x"00000000") port map (clk, rst, BadVAddr_update, BadVAddr_inp, BadVAddr); @@ -2309,35 +2356,34 @@ begin -- LLaddr & LLbit ------------------------------ LL_update <= '0' when (update = '1' and update_reg = cop0reg_LLAddr) else '1'; - + COP0_LLaddr: register32 generic map(x"00000000") - port map (clk, rst, LL_update, result, LLaddr); + port map (clk, rst, LL_update, MM_result, LLaddr); - LL_SC_differ <= '0' when (result = LLaddr) else '1'; + LL_SC_differ <= '0' when (MM_result = LLaddr) else '1'; - LL_SC_abort <= (LL_SC_differ or EX_LLbit) when (is_exception = exSC) else - '0'; + LL_SC_abort <= (LL_SC_differ or not(MM_LLbit)) when (is_exception = exSC) + else '0'; COP0_LLbit: process(rst,clk) begin if rst = '0' then - EX_LLbit <= '0'; -- break SC -> LL + MM_LLbit <= '0'; -- break SC -> LL elsif rising_edge(clk) then case is_exception is when exERET => - EX_LLbit <= '0'; -- break SC -> LL + MM_LLbit <= '0'; -- break SC -> LL when exLL => - EX_LLbit <= not LL_update; -- update only if instr is a LL + MM_LLbit <= not LL_update; -- update only if instr is a LL when others => null; end case; end if; end process COP0_LLbit; - EX_excp_type <= exNOP; - -- MMU-TLB =========================================================== + -- MMU-TLB =============================================================== -- MMU Index -- cop0_0 ------------------------- @@ -2426,6 +2472,10 @@ begin context_upd_pte <= '0' when (update = '1' and update_reg = cop0reg_Context) else '1'; + -- + -- these registers are non-compliant so the Page Table can be at low addresses + -- + -- MMU_ContextPTE: registerN generic map(9, ContextPTE_init) -- port map (clk, rst, context_upd_pte, -- cop0_inp(31 downto 23), Context(31 downto 23)); @@ -2433,7 +2483,7 @@ begin port map (clk, rst, context_upd_pte, cop0_inp(31 downto 18), Context(31 downto 18)); - context_upd_bad <= '0' when tlb_exception else '1'; + context_upd_bad <= '0' when MM_tlb_exception else '1'; -- MMU_ContextBAD: registerN generic map(19, b"0000000000000000000") -- port map (clk, rst, context_upd_bad, tlb_context_inp, Context(22 downto 4)); @@ -2461,86 +2511,101 @@ begin -- EntryHi holds the ASID of the current process, to check for a match entryHi_update <= '0' when ( (update = '1' and update_reg = cop0reg_EntryHi) - or ( tlb_exception ) ) - else not(tlb_read); + or ( MM_tlb_exception ) ) + else not(tlb_read); - entryHi_inp <= tlb_excp_VA & EHI_ZEROS & EntryHi(EHI_G_BIT) & EntryHi(EHI_ASIDHI_BIT downto EHI_ASIDLO_BIT) when tlb_exception else - cop0_inp when tlb_read = '0' else + entryHi_inp <= tlb_excp_VA & EHI_ZEROS & EntryHi(EHI_G_BIT) & EntryHi(EHI_ASIDHI_BIT downto EHI_ASIDLO_BIT) when MM_tlb_exception else + cop0_inp when tlb_read = '0' else tlb_entryhi; MMU_EntryHi: register32 generic map(x"00000000") port map (clk, rst, entryHi_update, entryHi_inp, EntryHi); - + + + -- == MMU =============================================================== + -- -- pg 41 ---------------------------------- - MMU_exceptions: process(iaVal, EX_wrmem, EX_aVal, tlb_miss, hit_mm, hit_pc, - hit_mm_v, hit_mm_d, hit_pc_v, STATUS) - variable i_stage_mm : boolean; + MMU_exceptions: process(iaVal, EX_wrmem, EX_aVal, hit_mm, hit_pc, + hit_mm_v, hit_mm_d, hit_pc_v, STATUS, tlb_ex_2) + variable i_stage_mm, i_exception, i_miss_mm, i_miss_pc : boolean; + variable i_excp_type : exception_type; begin - -- check first for events down in the pipeline: LOADS and STORES + i_miss_pc := not(hit_pc) and (iAval = '0'); - if tlb_miss then + i_miss_mm := not(hit_mm) and (EX_aval = '0'); + + -- check first for events later in the pipeline: LOADS and STORES - if not(hit_mm) and EX_wrmem = '0' then - if STATUS(STATUS_EXL) = '1' then - TLB_excp_type <= exTLBdblFaultWR; - else - TLB_excp_type <= exTLBrefillWR; - end if; - elsif not(hit_mm) then + if i_miss_mm then + + if EX_wrmem = '0' then if STATUS(STATUS_EXL) = '1' then - TLB_excp_type <= exTLBdblFaultRD; + i_excp_type := exTLBdblFaultWR; else - TLB_excp_type <= exTLBrefillRD; + i_excp_type := exTLBrefillWR; end if; - elsif not(hit_pc) then + else if STATUS(STATUS_EXL) = '1' then - TLB_excp_type <= exTLBdblFaultIF; + i_excp_type := exTLBdblFaultRD; else - TLB_excp_type <= exTLBrefillIF; + i_excp_type := exTLBrefillRD; end if; - else - TLB_excp_type <= exNOP; end if; + i_stage_mm := TRUE; + i_exception := TRUE; + + elsif i_miss_pc then - if not(hit_mm) then - i_stage_mm := TRUE; + if STATUS(STATUS_EXL) = '1' then + i_excp_type := exTLBdblFaultIF; else - i_stage_mm := FALSE; + i_excp_type := exTLBrefillIF; end if; - - elsif hit_mm then + i_exception := TRUE; + i_stage_mm := FALSE; + + elsif hit_mm and EX_aVal = '0' then - if (EX_aVal = '0' and hit_mm_v = '0') then -- check for TLBinvalid + if hit_mm_v = '0' then -- check for TLBinvalid if EX_wrmem = '0' then - TLB_excp_type <= exTLBinvalWR; + i_excp_type := exTLBinvalWR; else - TLB_excp_type <= exTLBinvalRD; + i_excp_type := exTLBinvalRD; end if; + i_exception := TRUE; elsif (EX_wrmem = '0' and hit_mm_d = '0') then -- check for TLBmodified - TLB_excp_type <= exTLBmod; + i_excp_type := exTLBmod; + i_exception := TRUE; else - TLB_excp_type <= exNOP; + i_excp_type := exNOP; + i_exception := FALSE; end if; i_stage_mm := TRUE; - elsif (hit_pc and hit_pc_v = '0' and iaVal = '0') then -- check for TLBinvalid - - TLB_excp_type <= exTLBinvalIF; - i_stage_mm := FALSE; - + elsif (hit_pc and hit_pc_v = '0' and iaVal = '0') then -- TLBinvalid IF? + + i_excp_type := exTLBinvalIF; + i_stage_mm := FALSE; + i_exception := TRUE; + else - TLB_excp_type <= exNOP; - i_stage_mm := FALSE; + i_excp_type := exNOP; + i_stage_mm := FALSE; + i_exception := FALSE; end if; - - tlb_stage_MM <= i_stage_mm; + + TLB_excp_type <= i_excp_type; + tlb_stage_MM <= i_stage_mm; + tlb_exception <= i_exception and not(SL2BOOL(tlb_ex_2)); end process MMU_exceptions; -- ----------------------------------------- - tlb_exception <= (TLB_excp_type /= exNOP); - + -- catch only first exception, if there are two in consecutive cycles + U_TLB_EXCP_ONCE: FFD port map (clk, rst, '1', + BOOL2SL(tlb_exception), tlb_ex_2); + TLB_excp_num <= exception_type'pos(TLB_excp_type); -- for debugging only @@ -2549,7 +2614,7 @@ begin -- TLB_tag: 31..13 = VPN, 12..9 = 0, 8 = G, 7..0 = ASID -- TLB_dat: 29..6 = PPN, 5..3 = C, 2 = D, 1 = V, 0 = G - MMU_CONTROL: process(EX_exception, INDEX, RANDOM) + MMU_CONTROL: process(is_exception, INDEX, RANDOM) variable i_tlb_adr : integer range MMU_CAPACITY-1 downto 0; begin @@ -2561,6 +2626,7 @@ begin tlb_tag5_updt <= '1'; tlb_tag6_updt <= '1'; tlb_tag7_updt <= '1'; + tlb_dat0_updt <= '1'; tlb_dat1_updt <= '1'; tlb_dat2_updt <= '1'; @@ -2570,7 +2636,7 @@ begin tlb_dat6_updt <= '1'; tlb_dat7_updt <= '1'; - case EX_exception is + case is_exception is when exTLBP => tlb_probe <= '1'; @@ -2587,7 +2653,7 @@ begin tlb_probe <= '0'; tlb_read <= '0'; - if EX_exception = exTLBWI then + if is_exception = exTLBWI then i_tlb_adr := to_integer(unsigned(INDEX(MMU_CAPACITY-1 downto 0))); else i_tlb_adr := to_integer(unsigned(RANDOM)); @@ -2692,10 +2758,7 @@ begin mm <= entryHi(EHI_AHI_BIT downto EHI_ALO_BIT) when tlb_probe = '1' else v_addr(VA_HI_BIT downto VA_LO_BIT); - tlb_miss <= ( (not(hit_pc) and (iAval = '0')) or - (not(hit_mm) and ((EX_mem_t /= b"0000") and (EX_aval = '0'))) ); - - tlb_excp_VA <= v_addr(VA_HI_BIT downto VA_LO_BIT) when tlb_stage_MM else + tlb_excp_VA <= MM_v_addr(VA_HI_BIT downto VA_LO_BIT) when MM_tlb_stage_mm else PC(VA_HI_BIT downto VA_LO_BIT); @@ -2965,24 +3028,15 @@ begin -- MMU-TLB == end ======================================================= - - -- ---------------------------------------------------------------------- - PIPESTAGE_EXCP_EX_MM: reg_excp_EX_MM - port map (clk, rst, excp_EX_MM_ld, EX_can_trap,MM_can_trap, - EX_excp_type,MM_excp_type_i, EX_PC,MM_PC, - EX_LLbit,MM_LLbit, addrError,MM_abort, - EX_is_delayslot,MM_is_delayslot, - EX_cop0_a_c,MM_cop0_a_c, EX_cop0_val,MM_cop0_val, - EX_ovfl, MM_ex_ovfl, EX_mfc0,MM_mfc0); + -- ---------------------------------------------------------------------- PIPESTAGE_EXCP_MM_WB: reg_excp_MM_WB - port map (clk, rst, excp_MM_WB_ld, MM_can_trap,WB_can_trap, - MM_excp_type, WB_excp_type, MM_PC,WB_PC, - MM_LLbit,WB_LLbit, MM_abort,WB_abort, + port map (clk, rst, excp_MM_WB_ld, + MM_PC,WB_PC, MM_LLbit,WB_LLbit, MM_is_delayslot,WB_is_delayslot, - MM_cop0_a_c,WB_cop0_a_c, MM_cop0_val,WB_cop0_val); + MM_cop0_val,WB_cop0_val); -- WB is shared with datapath ------------------------------------------- diff --git a/cMIPS/vhdl/exception.vhd b/cMIPS/vhdl/exception.vhd index 6cf8343b0fa6ec1de17e4ee1c8f9aaef09a60cf2..5ee2f2be4b2b4693f3f8cec7aee3a3db92f9da60 100644 --- a/cMIPS/vhdl/exception.vhd +++ b/cMIPS/vhdl/exception.vhd @@ -63,28 +63,22 @@ use work.p_WIRES.all; use work.p_EXCEPTION.all; entity reg_excp_RF_EX is port(clk, rst, ld: in std_logic; + RF_cop0_reg: in reg5; + EX_cop0_reg: out reg5; + RF_cop0_sel: in reg3; + EX_cop0_sel: out reg3; RF_can_trap: in reg2; EX_can_trap: out reg2; RF_exception: in exception_type; EX_exception: out exception_type; RF_trap_instr: in instr_type; EX_trap_instr: out instr_type; - RF_cop0_reg: in reg5; - EX_cop0_reg: out reg5; - RF_cop0_sel: in reg3; - EX_cop0_sel: out reg3; RF_is_delayslot: in std_logic; EX_is_delayslot: out std_logic; RF_PC_abort: in boolean; EX_PC_abort: out boolean; RF_PC: in reg32; EX_PC: out reg32; - RF_nmi: in std_logic; - EX_nmi: out std_logic; - RF_interrupt: in std_logic; - EX_interrupt: out std_logic; - RF_int_req: in reg8; - EX_int_req: out reg8; RF_trap_taken: in boolean; EX_trapped: out boolean); end reg_excp_RF_EX; @@ -99,17 +93,14 @@ begin EX_trapped <= FALSE; elsif rising_edge(clk) then if ld = '0' then + EX_cop0_reg <= RF_cop0_reg ; + EX_cop0_sel <= RF_cop0_sel ; EX_can_trap <= RF_can_trap ; EX_exception <= RF_exception ; EX_trap_instr <= RF_trap_instr ; - EX_cop0_reg <= RF_cop0_reg ; - EX_cop0_sel <= RF_cop0_sel ; EX_is_delayslot <= RF_is_delayslot ; EX_PC_abort <= RF_PC_abort ; EX_PC <= RF_PC ; - EX_nmi <= RF_nmi ; - EX_interrupt <= RF_interrupt ; - EX_int_req <= RF_int_req ; EX_trapped <= RF_trap_taken ; end if; end if; @@ -127,26 +118,46 @@ use work.p_WIRES.all; use work.p_EXCEPTION.all; entity reg_excp_EX_MM is port(clk, rst, ld: in std_logic; + EX_cop0_reg: in reg5; + MM_cop0_reg: out reg5; + EX_cop0_sel: in reg3; + MM_cop0_sel: out reg3; EX_can_trap: in reg2; MM_can_trap: out reg2; - EX_excp_type: in exception_type; - MM_excp_type: out exception_type; EX_PC: in reg32; MM_PC: out reg32; - EX_cop0_LLbit: in std_logic; - MM_cop0_LLbit: out std_logic; + EX_v_addr: in reg32; + MM_v_addr: out reg32; + nullify: in boolean; + MM_nullify: out boolean; addrError: in boolean; - MM_abort: out boolean; + MM_addrError: out boolean; + addrErr_stage_mm: in boolean; + MM_addrErr_stage_mm: out boolean; + mem_excp_type: in exception_type; + MM_mem_excp_type: out exception_type; EX_is_delayslot: in std_logic; MM_is_delayslot: out std_logic; - EX_cop0_a_c: in reg5; - MM_cop0_a_c: out reg5; - EX_cop0_val: in reg32; - MM_cop0_val: out reg32; EX_ovfl: in boolean; MM_ex_ovfl: out boolean; - EX_mfc0: in std_logic; - MM_mfc0: out std_logic); + EX_trapped: in boolean; + MM_trapped: out boolean; + EX_pc_abort: in boolean; + MM_pc_abort: out boolean; + EX_exception: in exception_type; + MM_exception: out exception_type; + tlb_exception: in boolean; + MM_tlb_exception: out boolean; + tlb_stage_mm: in boolean; + MM_tlb_stage_mm: out boolean; + TLB_excp_type: in exception_type; + MM_TLB_excp_type: out exception_type; + EX_nmi: in std_logic; + MM_nmi: out std_logic; + EX_interrupt: in std_logic; + MM_interrupt: out std_logic; + EX_int_req: in reg8; + MM_int_req: out reg8); end reg_excp_EX_MM; architecture funcional of reg_excp_EX_MM is @@ -154,21 +165,36 @@ begin process(clk, rst, ld) begin if rst = '0' then - MM_can_trap <= b"00"; - MM_cop0_LLbit <= '0'; - MM_ex_ovfl <= FALSE; + MM_can_trap <= b"00"; + MM_trapped <= FALSE; + MM_pc_abort <= FALSE; + MM_nullify <= FALSE; + MM_addrError <= FALSE; + MM_ex_ovfl <= FALSE; + MM_tlb_exception <= FALSE; + MM_exception <= exNOP; elsif rising_edge(clk) then if ld = '0' then - MM_excp_type <= EX_excp_type ; - MM_can_trap <= EX_can_trap ; - MM_PC <= EX_PC ; - MM_cop0_LLbit <= EX_cop0_LLbit ; - MM_abort <= addrError ; - MM_is_delayslot <= EX_is_delayslot; - MM_cop0_a_c <= EX_cop0_a_c ; - MM_cop0_val <= EX_cop0_val ; - MM_ex_ovfl <= EX_ovfl ; - MM_mfc0 <= EX_mfc0 ; + MM_cop0_reg <= EX_cop0_reg ; + MM_cop0_sel <= EX_cop0_sel ; + MM_can_trap <= EX_can_trap ; + MM_PC <= EX_PC ; + MM_v_addr <= EX_v_addr ; + MM_nullify <= nullify ; + MM_addrError <= addrError ; + MM_addrErr_stage_mm <= addrErr_stage_mm; + MM_mem_excp_type <= mem_excp_type ; + MM_is_delayslot <= EX_is_delayslot; + MM_ex_ovfl <= EX_ovfl ; + MM_trapped <= EX_trapped ; + MM_pc_abort <= EX_pc_abort ; + MM_exception <= EX_exception ; + MM_tlb_exception <= TLB_exception ; + MM_tlb_stage_MM <= tlb_stage_MM ; + MM_TLB_excp_type <= TLB_excp_type ; + MM_nmi <= EX_nmi ; + MM_interrupt <= EX_interrupt ; + MM_int_req <= EX_int_req ; end if; end if; end process; @@ -185,20 +211,12 @@ use work.p_WIRES.all; use work.p_EXCEPTION.all; entity reg_excp_MM_WB is port(clk, rst, ld: in std_logic; - MM_can_trap: in reg2; - WB_can_trap: out reg2; - MM_excp_type: in exception_type; - WB_excp_type: out exception_type; MM_PC: in reg32; WB_PC: out reg32; MM_cop0_LLbit: in std_logic; WB_cop0_LLbit: out std_logic; - MM_abort: in boolean; - WB_abort: out boolean; MM_is_delayslot: in std_logic; WB_is_delayslot: out std_logic; - MM_cop0_a_c: in reg5; - WB_cop0_a_c: out reg5; MM_cop0_val: in reg32; WB_cop0_val: out reg32); end reg_excp_MM_WB; @@ -208,18 +226,12 @@ begin process(clk, rst, ld) begin if rst = '0' then - WB_can_trap <= b"00"; WB_cop0_LLbit <= '0'; - WB_abort <= FALSE; elsif rising_edge(clk) then if ld = '0' then - WB_excp_type <= MM_excp_type ; WB_PC <= MM_PC ; - WB_can_trap <= MM_can_trap ; WB_cop0_LLbit <= MM_cop0_LLbit ; - WB_abort <= MM_abort ; WB_is_delayslot <= MM_is_delayslot; - WB_cop0_a_c <= MM_cop0_a_c ; WB_cop0_val <= MM_cop0_val ; end if; end if; diff --git a/cMIPS/vhdl/packageExcp.vhd b/cMIPS/vhdl/packageExcp.vhd index e9aaae067c92caa990bf58a6301215ea357ed7db..997a3239fe032db90c7e9f1a3a518b7cdd0aaa13 100644 --- a/cMIPS/vhdl/packageExcp.vhd +++ b/cMIPS/vhdl/packageExcp.vhd @@ -150,6 +150,7 @@ package p_EXCEPTION is constant EPC_src_MM : reg3 := b"011"; -- from MM pipestage constant EPC_src_WB : reg3 := b"100"; -- from WB pipestage constant EPC_src_B : reg3 := b"101"; -- from B register + end p_EXCEPTION; diff --git a/cMIPS/vhdl/packageWires.vhd b/cMIPS/vhdl/packageWires.vhd index 459f38e3217e232b319042c480727b7e7433eaaa..a2c5197c359dcd7835a739fbe29228827d06c9ca 100644 --- a/cMIPS/vhdl/packageWires.vhd +++ b/cMIPS/vhdl/packageWires.vhd @@ -173,6 +173,7 @@ package p_WIRES is function SLV2STR(s: in std_logic_vector) return string; function SLV32HEX(w: in std_logic_vector(31 downto 0)) return string; function BOOL2SL(b: in boolean) return std_logic; + function SL2BOOL(s: in std_logic) return boolean; function SLV2ASCII(s: std_logic_vector(7 downto 0)) return character; function SH_LEFT (inp: std_logic_vector; num_bits: integer) return std_logic_vector; @@ -341,6 +342,20 @@ package body p_WIRES is -- --------------------------------------------------------- + -- --------------------------------------------------------- + -- convert boolean to std_logic + function SL2BOOL(s: in std_logic) return boolean is + variable b : boolean; + begin + case s is + when '1' => b := TRUE; + when others => b := FALSE; + end case; + return b; + end; + -- --------------------------------------------------------- + + -- --------------------------------------------------------- function SLV2ASCII(s: std_logic_vector(7 downto 0)) return character is variable ascii_table : string(1 to 256) := ( diff --git a/cMIPS/vhdl/tb_cMIPS.vhd b/cMIPS/vhdl/tb_cMIPS.vhd index 00602785420c66944341849782d91471c56235bb..c8c6fc243e9bc7b692b4e33516bf0b9ba64345f1 100644 --- a/cMIPS/vhdl/tb_cMIPS.vhd +++ b/cMIPS/vhdl/tb_cMIPS.vhd @@ -557,7 +557,7 @@ begin -- TB U_RAM: simul_RAM generic map ("data.bin", "dump.data") -- U_RAM: fpga_RAM generic map ("data.bin", "dump.data") - port map (rst, clk, mem_d_sel, ram_rdy, mem_wr, phi1, + port map (rst, clk, mem_d_sel, ram_rdy, mem_wr, phi2, mem_addr, datram_out, datram_inp, mem_xfer, dump_ram); U_read_inp: read_data_file generic map ("input.data")