On Mon, Apr 16, 2012 at 2:02 AM, Julius Baxter <[email protected]> wrote: > On Mon, Apr 16, 2012 at 1:54 AM, Julius Baxter <[email protected]> wrote: >> The following is the second version of a patch implementing correct DSX bit >> behaviour in the supervisor register and software tests in ORPSoC. There >> have been some fixes to the first software test, and a new software test has >> been added ensuring the DSX bit is correctly set on ITLB misses which occur >> on instructions in the delay slot of a jump/branch instruction.\ > > Argh, sorry about the formatting on this. I copy and paste patches > from SVN into Gmail in Chrome and I'd read that switching to "rich > formatting" in the browser stopped the line breaks being inserted, but > apparently it doesn't and it makes the formatting even worse! > > Anyway, I hope you get the point. > > Julius
Can I get an ACK on this? Trailing is the final patch I propose to add (basically also adding the tests to the default test list.) This implements the feature as indicated lacking by bug 85: http://bugzilla.opencores.org/bugzilla4/show_bug.cgi?id=85 I can confirm the basic regression suite still passes with this. Index: rtl/verilog/or1200/or1200_sprs.v =================================================================== --- rtl/verilog/or1200/or1200_sprs.v (revision 798) +++ rtl/verilog/or1200/or1200_sprs.v (working copy) @@ -57,7 +57,7 @@ // Internal CPU interface flagforw, flag_we, flag, cyforw, cy_we, carry, - ovforw, ov_we, + ovforw, ov_we, dsx, addrbase, addrofs, dat_i, branch_op, ex_spr_read, ex_spr_write, epcr, eear, esr, except_started, @@ -99,6 +99,7 @@ output carry; // SR[CY] input ovforw; // From ALU input ov_we; // From ALU + input dsx; // From except input [width-1:0] addrbase; // SPR base address input [15:0] addrofs; // SPR offset input [width-1:0] dat_i; // SPR write data @@ -289,7 +290,7 @@ // What to write into SR // assign to_sr[`OR1200_SR_FO:`OR1200_SR_OVE] - = (except_started) ? {sr[`OR1200_SR_FO:`OR1200_SR_DSX],1'b0} : + = (except_started) ? {sr[`OR1200_SR_FO:`OR1200_SR_EPH],dsx,1'b0} : (branch_op == `OR1200_BRANCHOP_RFE) ? esr[`OR1200_SR_FO:`OR1200_SR_OVE] : (spr_we && sr_sel) ? {1'b1, spr_dat_o[`OR1200_SR_FO-1:`OR1200_SR_OVE]} : Index: rtl/verilog/or1200/or1200_cpu.v =================================================================== --- rtl/verilog/or1200/or1200_cpu.v (revision 798) +++ rtl/verilog/or1200/or1200_cpu.v (working copy) @@ -289,6 +289,7 @@ wire sr_we; wire [`OR1200_SR_WIDTH-1:0] to_sr; wire [`OR1200_SR_WIDTH-1:0] sr; +wire dsx; wire except_flushpipe; wire except_start; wire except_started; @@ -723,7 +724,8 @@ .sr_we(sr_we), .to_sr(to_sr), .sr(sr), - .branch_op(branch_op) + .branch_op(branch_op), + .dsx(dsx) ); // @@ -877,7 +879,8 @@ .sr_we(sr_we), .to_sr(to_sr), .sr(sr), - .abort_ex(abort_ex) + .abort_ex(abort_ex), + .dsx(dsx) ); // Index: rtl/verilog/or1200/or1200_except.v =================================================================== --- rtl/verilog/or1200/or1200_except.v (revision 798) +++ rtl/verilog/or1200/or1200_except.v (working copy) @@ -78,7 +78,8 @@ except_stop, except_trig, ex_void, abort_mvspr, branch_op, spr_dat_ppc, spr_dat_npc, datain, du_dsr, epcr_we, eear_we, esr_we, pc_we, epcr, eear, du_dmr1, du_hwbkpt, du_hwbkpt_ls_r, esr, sr_we, to_sr, sr, lsu_addr, - abort_ex, icpu_ack_i, icpu_err_i, dcpu_ack_i, dcpu_err_i, sig_fp, fpcsr_fpee + abort_ex, icpu_ack_i, icpu_err_i, dcpu_ack_i, dcpu_err_i, sig_fp, fpcsr_fpee, + dsx ); @@ -147,7 +148,8 @@ input icpu_err_i; input dcpu_ack_i; input dcpu_err_i; - +output dsx; + // // Internal regs and wires // @@ -177,6 +179,7 @@ wire tick_pending; wire fp_pending; wire range_pending; +reg dsx; reg trace_trap ; reg ex_freeze_prev; @@ -462,6 +465,7 @@ eear <= 32'b0; esr <= {2'h1, {`OR1200_SR_WIDTH-3{1'b0}}, 1'b1}; extend_flush_last <= 1'b0; + dsx <= 1'b0; end else begin `ifdef OR1200_CASE_DEFAULT @@ -482,6 +486,7 @@ ex_pc : ex_pc; epcr <= ex_dslot ? wb_pc : ex_pc; + dsx <= ex_dslot; end `endif `ifdef OR1200_EXCEPT_IPF @@ -495,6 +500,7 @@ wb_pc : delayed1_ex_dslot ? id_pc : delayed2_ex_dslot ? id_pc : id_pc; + dsx <= ex_dslot; end `endif `ifdef OR1200_EXCEPT_BUSERR @@ -504,6 +510,7 @@ wb_pc : ex_pc; epcr <= ex_dslot ? wb_pc : ex_pc; + dsx <= ex_dslot; end `endif `ifdef OR1200_EXCEPT_ILLEGAL @@ -512,6 +519,7 @@ eear <= ex_pc; epcr <= ex_dslot ? wb_pc : ex_pc; + dsx <= ex_dslot; end `endif `ifdef OR1200_EXCEPT_ALIGN @@ -520,6 +528,7 @@ eear <= lsu_addr; epcr <= ex_dslot ? wb_pc : ex_pc; + dsx <= ex_dslot; end `endif `ifdef OR1200_EXCEPT_DTLBMISS @@ -529,6 +538,7 @@ epcr <= ex_dslot ? wb_pc : delayed1_ex_dslot ? dl_pc : ex_pc; + dsx <= ex_dslot; end `endif `ifdef OR1200_EXCEPT_TRAP @@ -537,6 +547,7 @@ epcr <= ex_dslot ? wb_pc : delayed1_ex_dslot ? id_pc : ex_pc; + dsx <= ex_dslot; end `endif `ifdef OR1200_EXCEPT_SYSCALL @@ -546,6 +557,7 @@ wb_pc : delayed1_ex_dslot ? id_pc : delayed2_ex_dslot ? id_pc : id_pc; + dsx <= ex_dslot; end `endif `ifdef OR1200_EXCEPT_DPF @@ -555,6 +567,7 @@ epcr <= ex_dslot ? wb_pc : delayed1_ex_dslot ? dl_pc : ex_pc; + dsx <= ex_dslot; end `endif `ifdef OR1200_EXCEPT_BUSERR @@ -564,6 +577,7 @@ epcr <= ex_dslot ? wb_pc : delayed1_ex_dslot ? dl_pc : ex_pc; + dsx <= ex_dslot; end `endif `ifdef OR1200_EXCEPT_RANGE @@ -573,24 +587,28 @@ wb_pc : delayed1_ex_dslot ? id_pc : delayed2_ex_dslot ? id_pc : id_pc; + dsx <= ex_dslot; end `endif `ifdef OR1200_EXCEPT_FLOAT 14'b00_0000_0000_01??: begin except_type <= `OR1200_EXCEPT_FLOAT; epcr <= id_pc; + dsx <= ex_dslot; end `endif `ifdef OR1200_EXCEPT_INT 14'b00_0000_0000_001?: begin except_type <= `OR1200_EXCEPT_INT; epcr <= id_pc; + dsx <= ex_dslot; end `endif `ifdef OR1200_EXCEPT_TICK 14'b00_0000_0000_0001: begin except_type <= `OR1200_EXCEPT_TICK; epcr <= id_pc; + dsx <= ex_dslot; end `endif default: Index: sim/bin/Makefile =================================================================== --- sim/bin/Makefile (revision 798) +++ sim/bin/Makefile (working copy) @@ -68,6 +68,8 @@ or1200-ov \ or1200-sf \ or1200-ffl1 \ + or1200-dsx \ + or1200-dsxinsn \ or1200-linkregtest \ or1200-tick \ or1200-ticksyscall \ Index: sw/tests/or1200/sim/or1200-dsx.S =================================================================== --- sw/tests/or1200/sim/or1200-dsx.S (revision 0) +++ sw/tests/or1200/sim/or1200-dsx.S (revision 0) @@ -0,0 +1,531 @@ +/* + Delay-slot exception bit (DSX) test. + + Generate some exceptions in delay slots and not in delay slots + and confirm the SR[DSX] bit gets set. + + Just synchronous exceptions for now (a bit trickier to test + asynchronous ones like timer and interrupts.) + + Set r10 to hold whether we are expecting SR[DSX] to be set or + not. Exceptions will advance the PC by 0x8 to step over both + the jump/branch and instruction causing an exception. + + Julius Baxter <[email protected]> + +*/ +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2012 Authors and OPENCORES.ORG //// +//// //// +//// This source file may be used and distributed without //// +//// restriction provided that this copyright statement is not //// +//// removed from the file and that any derivative work contains //// +//// the original copyright notice and the associated disclaimer. //// +//// //// +//// This source file is free software; you can redistribute it //// +//// and/or modify it under the terms of the GNU Lesser General //// +//// Public License as published by the Free Software Foundation; //// +//// either version 2.1 of the License, or (at your option) any //// +//// later version. //// +//// //// +//// This source is distributed in the hope that it will be //// +//// useful, but WITHOUT ANY WARRANTY; without even the implied //// +//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// +//// PURPOSE. See the GNU Lesser General Public License for more //// +//// details. //// +//// //// +//// You should have received a copy of the GNU Lesser General //// +//// Public License along with this source; if not, download it //// +//// from http://www.opencores.org/lgpl.shtml //// +//// //// +////////////////////////////////////////////////////////////////////// + +#include "spr-defs.h" +#include "board.h" + +#define TEST_DSX_AND_RETURN ; \ + l.mfspr r3,r0,SPR_EPCR_BASE /* Get EPC */ ; \ + l.nop 2 /* Report PC for diagnostic purpose */ ; \ + /* Check SR[DSX] was as expected */ ; \ + l.mfspr r8,r0,SPR_SR /* Get SR */ ; \ + l.andi r8,r8,SPR_SR_DSX /* Clear all bits except DSX */ ; \ + l.xor r8,r8,r10 /* r8 will be >0 if error */ ; \ + l.sfne r8,r0 ; \ + l.bf test_fail ; \ + l.nop ; \ + /* Check if we were in delay slot, if so just advance by 8, else 4 */ ; \ + l.addi r3,r3,4 /* Step two instructions past where ; \ + exception occurred */ ; \ + l.srli r8,r10,11 /* If we were in delay slot, add extra ; \ + 4 to PC (0x2000>>11=4)*/ ; \ + l.add r3,r3,r8 ; \ + l.mtspr r0,r3,SPR_EPCR_BASE ; \ + l.rfe + + +/* =================================================== [ exceptions ] === */ + .section .vectors, "ax" + + +/* ---[ 0x100: RESET exception ]----------------------------------------- */ + .org 0x100 + l.movhi r0, 0 + /* Clear status register */ + l.ori r1, r0, SPR_SR_SM + l.mtspr r0, r1, SPR_SR + /* Clear timer */ + l.mtspr r0, r0, SPR_TTMR + /* Init the stack */ + .global stack + l.movhi r1, hi(stack) + l.ori r1, r1, lo(stack) + l.addi r2, r0, -3 + l.and r1, r1, r2 + /* Jump to program initialisation code */ + .global _start + l.movhi r4, hi(_start) + l.ori r4, r4, lo(_start) + l.jr r4 + l.nop + + +/* ---[ 0x200: BUS error ]------------------------------------------------ */ + .org 0x200 + .global _bus_handler +_bus_handler: + TEST_DSX_AND_RETURN + + +/* ---[ 0x600: ALIGN error ]------------------------------------------------ */ + .org 0x600 + .global _align_handler +_align_handler: + TEST_DSX_AND_RETURN + + +/* ---[ 0x700: ILLEGAL INSN exception ]------------------------------------- */ + .org 0x700 + .global _illinsn_handler +_illinsn_handler: + TEST_DSX_AND_RETURN + +/* ---[ 0x900: DTLB exception ]--------------------------------------------- */ + .org 0x900 + .global _dtlb_handler + TEST_DSX_AND_RETURN + +/* ---[ 0xe00: TRAP error ]------------------------------------------------ */ + .org 0xe00 + .global _trap_handler +_trap_handler: + TEST_DSX_AND_RETURN + + +/* =================================================== [ text section ] === */ + .section .text + +/* =================================================== [ start ] === */ + + .global _start +_start: + /* r2 is test counter - put in r3 and will be printed out for each + successful call to test_func */ + l.movhi r2,0 + + l.movhi r9,hi(test_fail) + l.ori r9,r9,lo(test_fail) + + /* Alignment exception tests */ + + /* This test should _NOT_ set DSX, so clear r10 */ + l.movhi r10,0 + /* Should cause an alignment error */ + l.lwz r1,1(r0) + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.sfeq r0,r0 + l.bf test_func + /* Should cause an alignment error */ + l.lwz r1,1(r0) + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.sfne r0,r0 + l.bnf test_func + /* Should cause an alignment error */ + l.lwz r1,1(r0) + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.j test_func + /* Should cause an alignment error */ + l.lwz r1,1(r0) + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.jal test_func + /* Should cause an alignment error */ + l.lwz r1,1(r0) + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.movhi r5,hi(test_func) + l.ori r5,r5,lo(test_func) + l.jr r5 + /* Should cause an alignment error */ + l.lwz r1,1(r0) + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.movhi r5,hi(test_func) + l.ori r5,r5,lo(test_func) + l.jalr r5 + /* Should cause an alignment error */ + l.lwz r1,1(r0) + + /* Make some calls to the functions which will trigger exceptions + to check that the DSX bit is not set */ + l.ori r10,r0,0 + l.jal align_func + l.nop + + + /* Illegal instruction exception tests */ + + /* This test should _NOT_ set DSX, so clear r10 */ + l.movhi r10,0 + /* Should cause an illegal insn error */ + .word 0xef000000 + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.sfeq r0,r0 + l.bf test_func + /* Should cause an illegal insn error */ + .word 0xef000000 + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.sfne r0,r0 + l.bnf test_func + /* Should cause an illegal insn error */ + .word 0xef000000 + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.j test_func + /* Should cause an illegal insn error */ + .word 0xef000000 + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.jal test_func + /* Should cause an illegal insn error */ + .word 0xef000000 + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.movhi r5,hi(test_func) + l.ori r5,r5,lo(test_func) + l.jr r5 + /* Should cause an illegal insn error */ + .word 0xef000000 + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.movhi r5,hi(test_func) + l.ori r5,r5,lo(test_func) + l.jalr r5 + /* Should cause an illegal insn error */ + .word 0xef000000 + + /* Make some calls to the functions which will trigger exceptions + to check that the DSX bit is not set */ + l.ori r10,r0,0 + l.jal illegal_insn_func + l.nop + + /* Bus error exceptions */ + + /* This test should _NOT_ set DSX, so clear r10 */ + l.movhi r10,0 + /* This should cause a bus error */ + l.lwz r1,-4(r0) + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.sfeq r0,r0 + l.bf test_func + /* This should cause a bus error */ + l.lwz r1,-4(r0) + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.sfne r0,r0 + l.bnf test_func + /* This should cause a bus error */ + l.lwz r1,-4(r0) + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.j test_func + /* This should cause a bus error */ + l.lwz r1,-4(r0) + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.jal test_func + /* This should cause a bus error */ + l.lwz r1,-4(r0) + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.movhi r5,hi(test_func) + l.ori r5,r5,lo(test_func) + l.jr r5 + /* This should cause a bus error */ + l.lwz r1,-4(r0) + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.movhi r5,hi(test_func) + l.ori r5,r5,lo(test_func) + l.jalr r5 + /* This should cause a bus error */ + l.lwz r1,-4(r0) + + /* Make some calls to the functions which will trigger exceptions + to check that the DSX bit is not set */ + l.ori r10,r0,0 + l.jal bus_err_func + l.nop + + /* Trap instruction exception tests */ + + /* This test should _NOT_ set DSX, so clear r10 */ + l.movhi r10,0 + /* Should cause an trap error */ + l.trap 0 + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.sfeq r0,r0 + l.bf test_func + /* Should cause an trap error */ + l.trap 0 + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.sfne r0,r0 + l.bnf test_func + /* Should cause an trap error */ + l.trap 0 + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.j test_func + /* Should cause an trap error */ + l.trap 0 + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.jal test_func + /* Should cause an trap error */ + l.trap 0 + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.movhi r5,hi(test_func) + l.ori r5,r5,lo(test_func) + l.jr r5 + /* Should cause an trap error */ + l.trap 0 + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.movhi r5,hi(test_func) + l.ori r5,r5,lo(test_func) + l.jalr r5 + /* Should cause an trap error */ + l.trap 0 + + /* Make some calls to the functions which will trigger exceptions + to check that the DSX bit is not set */ + l.ori r10,r0,0 + l.jal trap_func + l.nop + + /* DMMU miss test */ + + /* Check if we have a DMMU */ + l.mfspr r3,r0,SPR_UPR + l.andi r3,r3,SPR_UPR_DMP + l.sfeq r3,r0 + /* Flag set if no DMMU */ + l.bf dmmu_test_done + l.nop + + /* Just enabling the DMMU with no valid match match registers should + be enough to determine number of DMMU entries - hold this value in r3 */ + l.mfspr r3,r0,SPR_DMMUCFGR + l.andi r4,r3,SPR_DMMUCFGR_NTS + l.srli r4,r4,SPR_DMMUCFGR_NTS_OFF + l.ori r6,r0,1 + l.sll r3,r6,r4 + + /* Setup the Data MMU's TLBS - invalidate them */ + l.movhi r4, hi(SPR_DTLBMR_BASE(0)) + l.ori r4, r4, lo(SPR_DTLBMR_BASE(0)) + + /* DTLB invalidate loop */ +1: + l.mtspr r4, r0, 0x0 + l.addi r4, r4, 0x1 + l.sfeq r3, r0 + l.bnf 1b + l.addi r3, r3, -1 + + .extern lo_dmmu_en + /* Now enable the DMMU */ + l.movhi r4, hi(lo_dmmu_en) + l.ori r4, r4, lo(lo_dmmu_en) + l.jalr r4 + l.nop + + /* Now any data access should cause a miss */ + + /* This test should _NOT_ set DSX, so clear r10 */ + l.movhi r10,0 + /* This should cause a DLTB miss */ + l.lwz r1,0(r0) + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.sfeq r0,r0 + l.bf test_func + /* This should cause a DLTB miss */ + l.lwz r1,0(r0) + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.sfne r0,r0 + l.bnf test_func + /* This should cause a DLTB miss */ + l.lwz r1,0(r0) + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.j test_func + /* This should cause a DLTB miss */ + l.lwz r1,0(r0) + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.jal test_func + /* This should cause a DLTB miss */ + l.lwz r1,0(r0) + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.movhi r5,hi(test_func) + l.ori r5,r5,lo(test_func) + l.jr r5 + /* This should cause a DLTB miss */ + l.lwz r1,0(r0) + + /* This test should_ set DSX, so put SPR_SR_DSX in r10 */ + l.ori r10,r0,SPR_SR_DSX + l.movhi r5,hi(test_func) + l.ori r5,r5,lo(test_func) + l.jalr r5 + /* This should cause a DLTB miss */ + l.lwz r1,0(r0) + + /* Make some calls to the functions which will trigger exceptions + to check that the DSX bit is not set */ + l.ori r10,r0,0 + l.jal dtlb_func + l.nop + + /* Now disable DMMU */ + l.mfspr r3,r0,SPR_SR + l.xori r3,r3,SPR_SR_DME + l.mtspr r0,r3,SPR_ESR_BASE + l.movhi r9,hi(dmmu_test_done) + l.ori r9,r9,lo(dmmu_test_done) + l.mtspr r0,r9,SPR_EPCR_BASE + l.rfe + +dmmu_test_done: + + /* Check if we have an instruction cache */ + l.mfspr r3,r0,SPR_UPR + l.andi r3,r3,SPR_UPR_ICP + l.sfeq r3,r0 + /* Flag set if no icache */ + l.bf test_ok + l.nop + + /* Now repeat the tests with caches enabled if they weren't */ + l.mfspr r1,r0,SPR_SR + l.andi r1,r1,SPR_SR_ICE + l.sfeq r0,r1 /* Set flag if caches not enabled */ + l.bf restart_with_caches_enabled + l.nop + +test_ok: + l.movhi r3,0x8000 + l.ori r3,r3,0x000d + l.nop 2 + l.or r3,r0,r0 + l.nop 1 + +test_func: + /* A test function to call, just return */ + l.jr r9 + l.nop 2 /* print out whatever is in r3 */ + +test_fail: + l.movhi r3,0xbaaa + l.ori r3,r3,0xaaad + l.nop 2 + l.ori r3,r0,1 + l.nop 1 + +align_func: + /* DSX should _not_ be set on exception here */ + l.lwz r1,1(r0) + l.jr r9 + l.nop + +illegal_insn_func: + /* DSX should _not_ be set on exception here */ + .word 0xef000000 + l.jr r9 + l.nop + +bus_err_func: + /* DSX should _not_ be set on exception here */ + l.lwz r1,-4(r0) + l.jr r9 + l.nop + +trap_func: + /* DSX should _not_ be set on exception here */ + l.trap 0 + l.jr r9 + l.nop + +dtlb_func: + /* DSX should _not_ be set on exception here */ + l.lwz r1,0(r0) + l.jr r9 + l.nop + +restart_with_caches_enabled: + l.jal _cache_init + l.nop + l.j _start + l.nop Index: sw/tests/or1200/sim/or1200-dsxinsn.S =================================================================== --- sw/tests/or1200/sim/or1200-dsxinsn.S (revision 0) +++ sw/tests/or1200/sim/or1200-dsxinsn.S (revision 0) @@ -0,0 +1,289 @@ +/* + Test correct delay-slot exception bit (DSX) behavior on + instruction-fetch related exceptions. + + The only case where DSX is set on instruction-fetch related + exception is when instructions in delay slots occur in a new + page which needs to be mapped. + + In this test we will trigger an instruction MMU miss for an + instruction in a delay slot. To do this, we need to have a + branch instruction as the very last instruction of a page, + with the delay slot instruction being on a new unmapped page. + + Set r10 to hold whether we are expecting SR[DSX] to be set or + not. Exceptions will advance the PC by 0x8 to step over both + the jump/branch and instruction causing an exception. + + Julius Baxter <[email protected]> + +*/ +////////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2012 Authors and OPENCORES.ORG //// +//// //// +//// This source file may be used and distributed without //// +//// restriction provided that this copyright statement is not //// +//// removed from the file and that any derivative work contains //// +//// the original copyright notice and the associated disclaimer. //// +//// //// +//// This source file is free software; you can redistribute it //// +//// and/or modify it under the terms of the GNU Lesser General //// +//// Public License as published by the Free Software Foundation; //// +//// either version 2.1 of the License, or (at your option) any //// +//// later version. //// +//// //// +//// This source is distributed in the hope that it will be //// +//// useful, but WITHOUT ANY WARRANTY; without even the implied //// +//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// +//// PURPOSE. See the GNU Lesser General Public License for more //// +//// details. //// +//// //// +//// You should have received a copy of the GNU Lesser General //// +//// Public License along with this source; if not, download it //// +//// from http://www.opencores.org/lgpl.shtml //// +//// //// +////////////////////////////////////////////////////////////////////// + +#include "spr-defs.h" +#include "board.h" + +/* =================================================== [ exceptions ] === */ + .section .vectors, "ax" + + +/* ---[ 0x100: RESET exception ]----------------------------------------- */ + .org 0x100 + l.movhi r0, 0 + /* Clear status register */ + l.ori r1, r0, SPR_SR_SM + l.mtspr r0, r1, SPR_SR + /* Clear timer */ + l.mtspr r0, r0, SPR_TTMR + /* Init the stack */ + .global stack + l.movhi r1, hi(stack) + l.ori r1, r1, lo(stack) + l.addi r2, r0, -3 + l.and r1, r1, r2 + /* Jump to program initialisation code */ + .global _start + l.movhi r4, hi(_start) + l.ori r4, r4, lo(_start) + l.jr r4 + l.nop + +/* ---[ 0x200: BUS error ]------------------------------------------------ */ + .org 0x200 + l.j test_fail + l.nop + +/* ---[ 0x600: ALIGN error ]------------------------------------------------ */ + .org 0x600 + l.j test_fail + l.nop + +/* ---[ 0x700: ILLEGAL INSN exception ]------------------------------------- */ + .org 0x700 + l.j test_fail + l.nop + +/* ---[ 0x900: DTLB exception ]--------------------------------------------- */ + .org 0x900 + l.j test_fail + l.nop + +/* ---[ 0xa00: itlb miss ]---------------------------------------------- */ + .org 0xa00 + + /* First check if we're expecting a miss in a delay slot - check r10 */ + l.mfspr r3,r0,SPR_EEAR_BASE /* Get EPC */ + l.nop 2 /* Report PC for diagnostic purpose */ + /* Check SR[DSX] was as expected */ + l.mfspr r8,r0,SPR_SR /* Get SR */ + l.andi r8,r8,SPR_SR_DSX /* Clear all bits except DSX */ + l.xor r8,r8,r10 /* r8 will be >0 if error */ + l.sfne r8,r0 + l.bf test_fail + l.nop + + /* Simple itlb miss handler - install 1-1 mappings on misses */ + l.mfspr r12,r0,SPR_EEAR_BASE /* Get the PC of the exception */ + l.srli r13,r12,13 /* Get the page number, divide by 8K, store in r13 */ + /* Set up the match registers */ + l.movhi r14,hi(SPR_ITLBMR_VPN) + l.ori r14,r14,lo(SPR_ITLBMR_VPN) + l.and r14,r12,r14 /* Mask in the VPN */ + l.ori r15,r14,SPR_ITLBMR_V /* Set this match as valid */ + /* Write it into the appropriate match register, way 0 only */ + l.mtspr r13,r15,SPR_ITLBMR_BASE(0) + /* Set up the translate register - no restrictions */ + l.ori r15,r14,ITLB_PR_NOLIMIT + /* Write it into the appropriate translate register */ + l.mtspr r13,r15,SPR_ITLBTR_BASE(0) + /* MMU setup should now be complete, let's go back */ + l.rfe + +/* ---[ 0xe00: TRAP error ]------------------------------------------------ */ + .org 0xe00 + l.j test_fail + l.nop + +/* =================================================== [ text section ] === */ + .section .text + +/* =================================================== [ start ] === */ + + .global _start +_start: + /* First initialise the instruction MMU */ + + l.mfspr r3,r0,SPR_IMMUCFGR + l.andi r4,r3,SPR_IMMUCFGR_NTS + l.srli r4,r4,SPR_IMMUCFGR_NTS_OFF + l.ori r6,r0,1 + l.sll r3,r6,r4 + + /* Setup the IMMU's TLBs - invalidate them */ + l.movhi r4, hi(SPR_ITLBMR_BASE(0)) + l.ori r4, r4, lo(SPR_ITLBMR_BASE(0)) + + /* ITLB invalidate loop */ +1: + l.mtspr r4, r0, 0x0 + l.addi r4, r4, 0x1 + l.sfeq r3, r0 + l.bnf 1b + l.addi r3, r3, -1 + + /* Enable MMU - we should get a miss for this page */ + l.movhi r10,0 /* Clear r10 - not expecting to be in a delay slot + when this TLB miss occurs */ + + .extern lo_immu_en + /* Now enable the IMMU */ + l.movhi r4, hi(lo_immu_en) + l.ori r4, r4, lo(lo_immu_en) + l.jalr r4 + l.nop + + /* Copy the 2 instructions from the ljr9_function function to + places which should cause TLB misses in the delay slot */ + l.movhi r6,hi(ljr9_function) + l.ori r6,r6,lo(ljr9_function) + + /* r13 should have the page number we're in from the TLB miss we caused + when enabling the immu. Take that and add 16 to determine the page + boundary we'll play with */ + l.addi r4,r13,16 + + /* Calculate the physical address for this page */ + l.slli r8,r4,13 + + /* Copy our function to the last 2 instructions of the page before */ + l.lwz r1,0(r6) + l.sw -8(r8),r1 + l.lwz r1,4(r6) + l.sw -4(r8),r1 + + /* Call it - we should _not_ have DSX set on the itbl miss */ + l.movhi r10,0 + l.addi r1,r8,-8 + + /* Report value */ + l.or r3,r1,r1 + l.nop 2 + + l.jalr r1 + l.nop + + /* Tests finish */ + + /* Now do what we've done for the miss but put delay slot instruction + in the new page */ + + /* Calculate the physical address for this page */ + l.slli r8,r4,13 + + /* Copy our function to the last 2 instructions of the page before */ + l.lwz r1,0(r6) + l.sw -4(r8),r1 + l.lwz r1,4(r6) + l.sw 0(r8),r1 + + /* Clear insn cache for this area (need to if it's enabled so we + don't get the cached instructions from the previous test) */ + l.mtspr r0,r8,SPR_ICBIR + l.addi r1,r8,-4 + l.mtspr r0,r1,SPR_ICBIR + + /* Jump to (r8-0x4) - we _should_ have DSX set on the itbl miss as + the jump instruction will be on the last instruction of the previous + page (already mapped in ITLB) and the delay slot will be the first + instruction on the next page, which is unmapped at this stage and + should cause an ITLB miss*/ + l.ori r10,r0,SPR_SR_DSX + l.addi r1,r8,-4 + + /* Report value */ + l.or r3,r1,r1 + l.nop 2 + + l.jalr r1 + l.nop + + + /* TODO - track and check the number of TLB misses we should + have incurred */ + + /* Now repeat the tests with caches enabled if they weren't */ + l.mfspr r1,r0,SPR_SR + l.andi r1,r1,SPR_SR_ICE + l.sfeq r0,r1 /* Set flag if caches not enabled */ + l.bf restart_with_caches_enabled + l.nop + +test_ok: + l.movhi r3,0x8000 + l.ori r3,r3,0x000d + l.nop 2 + l.or r3,r0,r0 + l.nop 1 + +test_fail: + l.movhi r3,0xbaaa + l.ori r3,r3,0xaaad + l.nop 2 + l.ori r3,r0,1 + l.nop 1 + +restart_with_caches_enabled: + + /* Disable IMMU before restart*/ + l.mfspr r3,r0,SPR_SR + l.xori r3,r3,SPR_SR_IME + l.mtspr r0,r3,SPR_ESR_BASE + l.movhi r9,hi(.L1) + l.ori r9,r9,lo(.L1) + l.mtspr r0,r9,SPR_EPCR_BASE + l.rfe +.L1: + l.jal _cache_init + l.nop + + /* Actually we won't want dcache enabled as we'll be reading + and writing instructions around the shop so will not want them + being cached */ + l.mfspr r3,r0,SPR_SR + l.xori r3,r3,SPR_SR_DCE + l.mtspr r0,r3,SPR_SR + + l.j _start + l.nop + + /* A simple function, which we will copy the instructions of + to different parts of memory */ +ljr9_function: + l.jr r9 + l.nop + _______________________________________________ OpenRISC mailing list [email protected] http://lists.openrisc.net/listinfo/openrisc
