URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
Compare Revisions
- This comparison shows the changes necessary to convert path
/openrisc/trunk/orpsocv2
- from Rev 805 to Rev 807
- ↔ Reverse comparison
Rev 805 → Rev 807
/rtl/verilog/or1200/or1200_sprs.v
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]} : |
/rtl/verilog/or1200/or1200_cpu.v
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) |
); |
|
// |
/rtl/verilog/or1200/or1200_except.v
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,6 → 587,7
wb_pc : delayed1_ex_dslot ? |
dl_pc : delayed2_ex_dslot ? |
id_pc : ex_pc; |
dsx <= ex_dslot; |
end |
`endif |
`ifdef OR1200_EXCEPT_FLOAT |
579,6 → 594,7
14'b00_0000_0000_01??: begin |
except_type <= `OR1200_EXCEPT_FLOAT; |
epcr <= id_pc; |
dsx <= ex_dslot; |
end |
`endif |
`ifdef OR1200_EXCEPT_INT |
585,6 → 601,7
14'b00_0000_0000_001?: begin |
except_type <= `OR1200_EXCEPT_INT; |
epcr <= id_pc; |
dsx <= ex_dslot; |
end |
`endif |
`ifdef OR1200_EXCEPT_TICK |
591,6 → 608,7
14'b00_0000_0000_0001: begin |
except_type <= `OR1200_EXCEPT_TICK; |
epcr <= id_pc; |
dsx <= ex_dslot; |
end |
`endif |
default: |
/sim/bin/Makefile
67,6 → 67,8
or1200-cy \ |
or1200-ov \ |
or1200-sf \ |
or1200-dsx \ |
or1200-dsxinsn \ |
or1200-ffl1 \ |
or1200-linkregtest \ |
or1200-tick \ |
/sw/tests/or1200/sim/or1200-dsx.S
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 <juliusbaxter@gmail.com> |
|
*/ |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// 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 |
/sw/tests/or1200/sim/or1200-dsxinsn.S
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 <juliusbaxter@gmail.com> |
|
*/ |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// 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 |
|