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/sw
- from Rev 530 to Rev 535
- ↔ Reverse comparison
Rev 530 → Rev 535
/tests/or1200/board/or1200-rfemmu.S
0,0 → 1,533
/* |
Test of return from execption and MMU behavior |
|
For now, just a simple test confirming that the instructions we l.rfe |
to are executed OK. |
|
In this test we are checking that execution of instructions after |
l.rfe enabling the MMU occurs OK. |
|
Mainly this is to test what happens when the first virtual address |
after a l.rfe is a cache "hit" - ensuring this instruction is not |
executed. |
|
Test method: |
Relocate a simple looping function to an unused page in memory, at |
offset 0xf00 within that page. Translate virtual page 0 to this page |
and execute it, with timer interrupts occuring, ensuring the l.rfe is |
being called regularly. |
|
Whenever the function in virtual space is so be resumed, code at the |
address matching the virtual space is executed before the l.rfe, |
ensuring it is in cache. If any of these instructions in the physical |
address are executed, then the code running in virtual space will |
detect this and crash. |
|
In this instance, the test function is only about 30 instructions |
long. It is mapped to virtual address 0xf00. The physical address |
0xf00 has the same number of instructions, setting r31 to -1 (0xfffffff) |
This string of 32 instructions is executed before any l.rfe back to the |
function running with MMUs on in the virtual page address. The last |
instruction before the l.rfe clears r31, so if any of the instructions |
in the physical address space get executed, r31 will return to |
0xffffffff and this can be detected by the code. |
|
The test finishes when the test function, running in virtual address |
space, has incremented a value in memory beyond the alue defined by |
TEST_LOOPS. |
|
The test has the possibility of being restarted and run with |
caches enabled. |
|
Julius Baxter, ORSoC AB, julius.baxter@orsoc.se |
|
|
*/ |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2010 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" |
#include "or1200-defines.h" |
|
#define ONCE_THROUGH_WITH_CACHE_ENABLED 1 |
|
#define TEST_LOOPS 0xffff |
|
#define PAGE_ADR_SHIFT 13 |
|
// Should be at least 0x1000 |
#define PAGE_OFFSET_FOR_TEST 0xf00 |
|
#define TIMER_CYCLES_RATE 1000 |
|
#define LOAD_SYMBOL_2_GPR(gpr,symbol) \ |
l.movhi gpr, hi(symbol) ; \ |
l.ori gpr, gpr, lo(symbol) |
|
/* =================================================== [ 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 |
|
/* Jump to program initialisation code */ |
.global _start |
l.movhi r4, hi(_start) |
l.ori r4, r4, lo(_start) |
l.jr r4 |
l.nop |
|
/* ---[ 0x400: itlb fault ]--------------------------------------------- */ |
.org 0x400 |
l.ori r3,r0,0xa00 |
l.nop 0x2 |
l.movhi r3,0xbaaa |
l.ori r3,r3,0xaaad |
l.nop 0x2 |
l.nop 0x1 /* We should never have a itlb miss */ |
|
/* ---[ 0x500: timer exception ]---------------------------------------- */ |
.org 0x500 |
/* check test loop counter to see if test is over */ |
LOAD_SYMBOL_2_GPR(r3,function_global) |
l.lwz r3,0(r3) |
l.sfgeui r3,TEST_LOOPS |
l.bf check_for_restart |
l.nop |
/* Write to TTMR again to clear TTMR[IP] bit */ |
l.jal timer_load |
l.nop |
|
l.j call_rfe /* continue execution */ |
l.nop |
|
.org 0x600 |
l.j fail |
l.nop |
|
.org 0x700 |
l.j fail |
l.nop |
|
.org 0x800 |
l.j fail |
l.nop |
|
|
/* ---[ 0xa00: itlb miss ]---------------------------------------------- */ |
.org 0xa00 |
l.ori r3,r0,0xa00 |
l.nop 0x2 |
l.movhi r3,0xbaaa |
l.ori r3,r3,0xaaad |
l.nop 0x2 |
l.j 0 |
l.nop 0x1 /* We should never have a itlb miss */ |
|
/* ---[ 0xc00: system call ]-------------------------------------------- */ |
.org 0xc00 |
l.movhi r3,0xbaaa |
l.ori r3,r3,0xaaad |
l.nop 0x2 /* Simulation report */ |
l.j 0 /* Loop here */ |
l.nop 0x1 /* End simulation */ |
|
/* ---[ 0xE00: TRAP exception ]----------------------------------------- */ |
.org 0xe00 |
l.j 0 |
l.nop 0x1 |
|
/* ---[ reserved space ]------------------------------------ */ |
.org PAGE_OFFSET_FOR_TEST |
call_rfe: |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.movhi r31,0 |
l.rfe |
|
|
/* =================================================== [ text ] === */ |
.section .data |
immu_sets: |
.long -1 |
immu_ways: |
.long -1 |
dmmu_sets: |
.long -1 |
dmmu_ways: |
.long -1 |
test_page_num: |
.long -1 |
function_global: |
.long 0 |
|
|
/* =================================================== [ text ] === */ |
.section .text |
|
/* =================================================== [ start ] === */ |
|
.global _start |
_start: |
|
#if ONCE_THROUGH_WITH_CACHE_ENABLED==1 |
l.jal _cache_init |
l.nop |
#endif |
|
// Kick off test |
l.jal _main |
l.nop |
|
/* =================================================== [ main ] === */ |
.global _main |
_main: |
// Get MMU configuration |
l.jal immu_get_config |
l.nop |
l.jal dmmu_get_config |
l.nop |
|
// Clear IMMU |
l.jal immu_clear |
l.nop |
// Clear DMMU |
l.jal dmmu_clear |
l.nop |
|
// Set up stack pointer, but kind of don't need it |
LOAD_SYMBOL_2_GPR(r1,_stack) |
|
// What is next page above stack? |
l.srli r4,r1,PAGE_ADR_SHIFT |
l.addi r4,r4,1 /* Next page past */ |
LOAD_SYMBOL_2_GPR(r5,test_page_num) |
l.sw 0(r5),r4 /* We will do tests with code in this PPN */ |
|
|
LOAD_SYMBOL_2_GPR(r2,test_function) |
LOAD_SYMBOL_2_GPR(r3,test_function_end) |
/* Convert physical page number back to physical address */ |
l.slli r4,r4,PAGE_ADR_SHIFT |
/* r4 has physical address of where we'll relocate our test program to |
but we want it at an offset of PAGE_OFFSET_FOR_TEST inside that page. |
*/ |
|
l.addi r4,r4,PAGE_OFFSET_FOR_TEST |
program_relocate_loop: |
l.lwz r5,0(r2) |
l.sw 0(r4),r5 |
l.sfeq r2,r3 |
l.mtspr r0,r4,SPR_DCBIR /* flush dcache */ |
l.addi r4,r4,4 /* increment dest ptr */ |
l.bnf program_relocate_loop |
l.addi r2,r2,4 /* increment src ptr */ |
|
mmu_setup: |
/* Program relocated, setup MMU mappings */ |
/* Physical page number of test-code is in test_page_num. We need |
to set up a mapping for this page in the MMU, then launch execution |
of it. |
*/ |
LOAD_SYMBOL_2_GPR(r5,test_page_num) |
l.lwz r5,0(r5) |
/* Basically should be match-PPN of 0 translates to page |
number test_page_num. |
Set up entry 0, then, and have translate address to test_page_num*/ |
// Match register |
l.ori r3,r0,SPR_ITLBMR_V /* Just this */ |
l.mtspr r0,r3,SPR_ITLBMR_BASE(0) |
// Setup TR page number |
l.slli r3,r5,PAGE_ADR_SHIFT //r5 = page number of target page |
l.ori r3,r3,ITLB_PR_NOLIMIT |
l.mtspr r0,r3,SPR_ITLBTR_BASE(0) |
|
timer_setup: |
/* Init timer to fire at rate of TIMER_CYCLES_RATE */ |
l.jal timer_load |
l.nop |
|
sr_setup: |
// Start test - set up EPCR to jump to PAGE_OFFSET_FOR_TEST |
l.ori r3,r0,PAGE_OFFSET_FOR_TEST |
l.mtspr r0,r3,SPR_EPCR_BASE |
|
l.mfspr r3,r0,SPR_SR |
l.ori r3,r3,(SPR_SR_IME|SPR_SR_TEE) /* IMMU, tick timer enable */ |
l.mtspr r0,r3,SPR_ESR_BASE |
|
// Ensure global counter variable is zero |
LOAD_SYMBOL_2_GPR(r3,function_global) |
l.sw 0(r3),r0 |
|
// Call function entry point, check bug doesn't occur |
l.j call_rfe |
l.nop |
|
// Should never get here - test is detected as finished from the |
// timer interrupt. |
|
check_for_restart: |
l.mfspr r4,r0,SPR_SR |
l.andi r4,r4,SPR_SR_ICE /* is instruction cache enabled? */ |
l.sfgtu r4,r0 |
l.bnf restart_with_caches |
l.nop |
|
finish: |
l.movhi r3,0x8000 |
l.ori r3,r3,0x000d |
l.nop 0x2 |
l.j 0 |
l.nop 0x1 |
|
fail: |
l.movhi r3,0xbaaa |
l.ori r3,r3,0xaaad |
l.nop 0x2 |
l.j 0 |
l.nop 0x1 |
|
|
/* A stilly test function - doing some loads/stores, and some |
branches |
only touches r13 and r14*/ |
/* Should be relocatable */ |
test_function: |
// Check for error - r31 should be 0 |
l.sfne r31,r0 |
l.bf test_function_fail |
|
LOAD_SYMBOL_2_GPR(r13,function_global) |
l.lwz r14,0(r13) /* Load value of global */ |
l.addi r14,r14,1 |
l.sw 0(r13),r14 /* Store it back */ |
l.mtspr r0,r13,SPR_DCBIR /* flush dcache */ |
/* Every 8, branch away and back */ |
l.andi r14,r14,0xf |
l.sfeq r14,r0 |
l.bf test_function_sub |
l.nop |
l.j test_function |
l.nop |
|
test_function_sub: |
l.j test_function |
l.nop |
|
test_function_fail: |
l.sys 0 /* Bail out with syscall */ |
|
test_function_end: |
l.nop 0x1 |
|
|
|
restart_with_caches: |
l.jal _cache_init |
l.nop |
l.movhi r4, hi(_start) |
l.ori r4, r4, lo(_start) |
l.jr r4 |
l.nop |
|
|
/* MMU configuration functions */ |
|
immu_get_config: |
l.mfspr r3,r0,SPR_IMMUCFGR |
// Number of ways |
l.andi r4,r3,SPR_IMMUCFGR_NTW |
l.addi r4,r4,1 |
// Store the ways in immu_ways |
l.movhi r5,hi(immu_ways) |
l.ori r5,r5,lo(immu_ways) |
l.sw 0(r5),r4 |
// Number of sets |
l.andi r4,r3,SPR_IMMUCFGR_NTS |
l.srli r4,r4,SPR_IMMUCFGR_NTS_OFF |
l.ori r6,r0,1 |
l.sll r4,r6,r4 |
// Store the ways in immu_ways |
l.movhi r5,hi(immu_sets) |
l.ori r5,r5,lo(immu_sets) |
l.jr r9 // Return |
l.sw 0(r5),r4 |
|
dmmu_get_config: |
l.mfspr r3,r0,SPR_DMMUCFGR |
// Number of ways |
l.andi r4,r3,SPR_DMMUCFGR_NTW |
l.addi r4,r4,1 |
// Store the ways in dmmu_ways |
l.movhi r5,hi(dmmu_ways) |
l.ori r5,r5,lo(dmmu_ways) |
l.sw 0(r5),r4 |
// Number of sets |
l.andi r4,r3,SPR_DMMUCFGR_NTS |
l.srli r4,r4,SPR_DMMUCFGR_NTS_OFF |
l.ori r6,r0,1 |
l.sll r4,r6,r4 |
// Store the ways in dmmu_ways |
l.movhi r5,hi(dmmu_sets) |
l.ori r5,r5,lo(dmmu_sets) |
l.jr r9 // Return |
l.sw 0(r5),r4 |
|
|
immu_clear: |
// r3 - immu_ways |
// r4 - immu_sets |
// r5 - work |
// r6 - ways counter |
// r7 - sets counter |
// r10 - match regs spr address |
// r11 - translate regs spr address |
|
/* Clear all IMMU match/translate register pairs */ |
l.movhi r5,hi(immu_ways) |
l.ori r5,r5,lo(immu_ways) |
l.lwz r3,0(r5) |
l.movhi r5,hi(immu_sets) |
l.ori r5,r5,lo(immu_sets) |
l.lwz r4,0(r5) |
|
l.movhi r6, 0 // Clear ways counters |
|
immu_clear_set: |
l.movhi r7, 0 // Clear sets counter |
// Calculate base of IMMU match & translate registers |
l.ori r10,r0,SPR_ITLBMR_BASE(0) |
l.ori r11,r0,SPR_ITLBTR_BASE(0) |
l.slli r5,r6,8 /* Multiply ways by 256 (ways<<8) */ |
l.add r10,r10,r5 |
l.add r11,r11,r5 |
immu_clear_set_loop: |
l.mtspr r10,r0,0 /* ITLBMR_BASE(way) + set = 0 */ |
l.mtspr r11,r0,0 /* ITLBTR_BASE(way) + set = 0 */ |
l.addi r7,r7,1 |
l.sfne r4,r7 |
l.addi r10,r10,1 |
l.bf immu_clear_set_loop |
l.addi r11,r11,1 |
|
l.addi r6,r6,1 /* Increment ways counter */ |
l.sfne r3,r6 /* Cleared all ways? */ |
l.bf immu_clear_set |
l.nop |
|
/* Finished */ |
l.jr r9 |
l.nop |
|
dmmu_clear: |
// r3 - dmmu_ways |
// r4 - dmmu_sets |
// r5 - work |
// r6 - ways counter |
// r7 - sets counter |
// r10 - match regs spr address |
// r11 - translate regs spr address |
|
/* Clear all DMMU match/translate register pairs */ |
l.movhi r5,hi(dmmu_ways) |
l.ori r5,r5,lo(dmmu_ways) |
l.lwz r3,0(r5) |
l.movhi r5,hi(dmmu_sets) |
l.ori r5,r5,lo(dmmu_sets) |
l.lwz r4,0(r5) |
|
l.movhi r6, 0 // Clear ways counters |
|
dmmu_clear_set: |
l.movhi r7, 0 // Clear sets counter |
// Calculate base of DMMU match & translate registers |
l.ori r10,r0,SPR_DTLBMR_BASE(0) |
l.ori r11,r0,SPR_DTLBTR_BASE(0) |
l.slli r5,r6,8 /* Multiply ways by 256 (ways<<8) */ |
l.add r10,r10,r5 |
l.add r11,r11,r5 |
dmmu_clear_set_loop: |
l.mtspr r10,r0,0 /* ITLBMR_BASE(way) + set = 0 */ |
l.mtspr r11,r0,0 /* ITLBTR_BASE(way) + set = 0 */ |
l.addi r7,r7,1 |
l.sfne r4,r7 |
l.addi r10,r10,1 |
l.bf dmmu_clear_set_loop |
l.addi r11,r11,1 |
|
l.addi r6,r6,1 /* Increment ways counter */ |
l.sfne r3,r6 /* Cleared all ways? */ |
l.bf dmmu_clear_set |
l.nop |
|
/* Finished */ |
l.jr r9 |
l.nop |
|
|
|
#define TTMR_RELOAD_VALUE (SPR_TTMR_IE | SPR_TTMR_RT | TIMER_CYCLES_RATE) |
timer_load: |
l.movhi r3,hi(TTMR_RELOAD_VALUE) |
l.ori r3,r3,lo(TTMR_RELOAD_VALUE) |
l.jr r9 |
l.mtspr r0,r3,SPR_TTMR |
/tests/or1200/sim/or1200-rfe.S
0,0 → 1,157
/* |
Test of return from execption behavior |
|
For now, just a simple test confirming that the instructions we l.rfe |
to are executed OK. |
|
In this test we just increment a counter and confirm this occurred. |
|
Julius Baxter, ORSoC AB, julius.baxter@orsoc.se |
|
Register usage: |
|
r1: function call address |
r2: SR when function is called |
r3: test counter |
r4: temp register |
r5: temp register |
|
*/ |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2010 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" |
#include "or1200-defines.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 |
|
/* Jump to program initialisation code */ |
.global _start |
l.movhi r4, hi(_start) |
l.ori r4, r4, lo(_start) |
l.jr r4 |
l.nop |
|
/* ---[ 0xE00: TRAP exception ]----------------------------------------- */ |
.org 0xe00 |
/* Traps occur when we want to call a function - function address will |
be in r1, desired SR will be in r2. |
Put EPCR+4 into r9 - link register, function will return |
that way*/ |
l.mfspr r9,r0,SPR_EPCR_BASE |
l.addi r9,r9,4 /* One instruction past l.trap that got us here */ |
l.mtspr r0,r1,SPR_EPCR_BASE |
l.mtspr r0,r2,SPR_ESR_BASE |
l.rfe |
/* An unsupported instruction in delay slot, which should not be |
executed */ |
lf.add.d r1,r2,r3 |
|
/* =================================================== [ text ] === */ |
.section .text |
|
/* =================================================== [ start ] === */ |
|
.global _start |
_start: |
|
// Kick off test |
l.jal _main |
l.nop |
|
/* =================================================== [ main ] === */ |
|
/* Call a function with l.rfe */ |
#define CALL_FN_WITH_RFE(fn) \ |
l.movhi r1,hi(fn) ;\ |
l.ori r1,r1,lo(fn) ;\ |
l.mfspr r2,r0,SPR_SR ;\ |
l.trap 15 |
|
.global _main |
_main: |
/* First test, call some functions by l.rfe'ing */ |
l.movhi r3,0 /* r3 = function call counter */ |
|
CALL_FN_WITH_RFE(function1) |
CALL_FN_WITH_RFE(function1) |
|
|
#define EXPECTED_RESULT 2 |
/* Check result in r3 against the define */ |
l.sfnei r3,EXPECTED_RESULT |
l.bf fail |
l.nop |
|
check_for_restart: |
l.mfspr r4,r0,SPR_SR |
l.andi r4,r4,SPR_SR_ICE /* is instruction cache enabled? */ |
l.sfgtu r4,r0 |
l.bnf restart_with_caches |
l.nop |
|
finish: |
l.movhi r3,0x8000 |
l.ori r3,r3,0x000d |
l.nop 0x2 |
l.movhi r3,0 |
l.nop 0x2 |
l.nop 0x1 |
l.nop |
|
fail: |
l.movhi r3,0xbaaa |
l.ori r3,r3,0xaaad |
l.nop 0x2 |
l.nop 0x1 |
|
function1: |
l.addi r3,r3,1 /* Increment function call counter */ |
l.jr r9 |
l.nop 0x2 /* Report value */ |
|
restart_with_caches: |
l.jal _cache_init |
l.nop |
l.movhi r4, hi(_start) |
l.ori r4, r4, lo(_start) |
l.jr r4 |
l.nop |
|
|
/tests/or1200/sim/or1200-rfemmu.S
0,0 → 1,533
/* |
Test of return from execption and MMU behavior |
|
For now, just a simple test confirming that the instructions we l.rfe |
to are executed OK. |
|
In this test we are checking that execution of instructions after |
l.rfe enabling the MMU occurs OK. |
|
Mainly this is to test what happens when the first virtual address |
after a l.rfe is a cache "hit" - ensuring this instruction is not |
executed. |
|
Test method: |
Relocate a simple looping function to an unused page in memory, at |
offset 0xf00 within that page. Translate virtual page 0 to this page |
and execute it, with timer interrupts occuring, ensuring the l.rfe is |
being called regularly. |
|
Whenever the function in virtual space is so be resumed, code at the |
address matching the virtual space is executed before the l.rfe, |
ensuring it is in cache. If any of these instructions in the physical |
address are executed, then the code running in virtual space will |
detect this and crash. |
|
In this instance, the test function is only about 30 instructions |
long. It is mapped to virtual address 0xf00. The physical address |
0xf00 has the same number of instructions, setting r31 to -1 (0xfffffff) |
This string of 32 instructions is executed before any l.rfe back to the |
function running with MMUs on in the virtual page address. The last |
instruction before the l.rfe clears r31, so if any of the instructions |
in the physical address space get executed, r31 will return to |
0xffffffff and this can be detected by the code. |
|
The test finishes when the test function, running in virtual address |
space, has incremented a value in memory beyond the alue defined by |
TEST_LOOPS. |
|
The test has the possibility of being restarted and run with |
caches enabled. |
|
Julius Baxter, ORSoC AB, julius.baxter@orsoc.se |
|
|
*/ |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2010 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" |
#include "or1200-defines.h" |
|
#define ONCE_THROUGH_WITH_CACHE_ENABLED 0 |
|
#define TEST_LOOPS 15 |
|
#define PAGE_ADR_SHIFT 13 |
|
// Should be at least 0x1000 |
#define PAGE_OFFSET_FOR_TEST 0xf00 |
|
#define TIMER_CYCLES_RATE 1000 |
|
#define LOAD_SYMBOL_2_GPR(gpr,symbol) \ |
l.movhi gpr, hi(symbol) ; \ |
l.ori gpr, gpr, lo(symbol) |
|
/* =================================================== [ 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 |
|
/* Jump to program initialisation code */ |
.global _start |
l.movhi r4, hi(_start) |
l.ori r4, r4, lo(_start) |
l.jr r4 |
l.nop |
|
/* ---[ 0x400: itlb fault ]--------------------------------------------- */ |
.org 0x400 |
l.ori r3,r0,0xa00 |
l.nop 0x2 |
l.movhi r3,0xbaaa |
l.ori r3,r3,0xaaad |
l.nop 0x2 |
l.nop 0x1 /* We should never have a itlb miss */ |
|
/* ---[ 0x500: timer exception ]---------------------------------------- */ |
.org 0x500 |
/* check test loop counter to see if test is over */ |
LOAD_SYMBOL_2_GPR(r3,function_global) |
l.lwz r3,0(r3) |
l.sfgeui r3,TEST_LOOPS |
l.bf check_for_restart |
l.nop 2 |
/* Write to TTMR again to clear TTMR[IP] bit */ |
l.jal timer_load |
l.nop |
|
l.j call_rfe /* continue execution */ |
l.nop |
|
.org 0x600 |
l.j fail |
l.nop |
|
.org 0x700 |
l.j fail |
l.nop |
|
.org 0x800 |
l.j fail |
l.nop |
|
|
/* ---[ 0xa00: itlb miss ]---------------------------------------------- */ |
.org 0xa00 |
l.ori r3,r0,0xa00 |
l.nop 0x2 |
l.movhi r3,0xbaaa |
l.ori r3,r3,0xaaad |
l.nop 0x2 |
l.j 0 |
l.nop 0x1 /* We should never have a itlb miss */ |
|
/* ---[ 0xc00: system call ]-------------------------------------------- */ |
.org 0xc00 |
l.movhi r3,0xbaaa |
l.ori r3,r3,0xaaad |
l.nop 0x2 /* Simulation report */ |
l.j 0 /* Loop here */ |
l.nop 0x1 /* End simulation */ |
|
/* ---[ 0xE00: TRAP exception ]----------------------------------------- */ |
.org 0xe00 |
l.j 0 |
l.nop 0x1 |
|
/* ---[ reserved space ]------------------------------------ */ |
.org PAGE_OFFSET_FOR_TEST |
call_rfe: |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.addi r31,r0,-1 |
l.movhi r31,0 |
l.rfe |
|
|
/* =================================================== [ text ] === */ |
.section .data |
immu_sets: |
.long -1 |
immu_ways: |
.long -1 |
dmmu_sets: |
.long -1 |
dmmu_ways: |
.long -1 |
test_page_num: |
.long -1 |
function_global: |
.long 0 |
|
|
/* =================================================== [ text ] === */ |
.section .text |
|
/* =================================================== [ start ] === */ |
|
.global _start |
_start: |
|
#if ONCE_THROUGH_WITH_CACHE_ENABLED==1 |
l.jal _cache_init |
l.nop |
#endif |
|
// Kick off test |
l.jal _main |
l.nop |
|
/* =================================================== [ main ] === */ |
.global _main |
_main: |
// Get MMU configuration |
l.jal immu_get_config |
l.nop |
l.jal dmmu_get_config |
l.nop |
|
// Clear IMMU |
l.jal immu_clear |
l.nop |
// Clear DMMU |
l.jal dmmu_clear |
l.nop |
|
// Set up stack pointer, but kind of don't need it |
LOAD_SYMBOL_2_GPR(r1,_stack) |
|
// What is next page above stack? |
l.srli r4,r1,PAGE_ADR_SHIFT |
l.addi r4,r4,1 /* Next page past */ |
LOAD_SYMBOL_2_GPR(r5,test_page_num) |
l.sw 0(r5),r4 /* We will do tests with code in this PPN */ |
|
|
LOAD_SYMBOL_2_GPR(r2,test_function) |
LOAD_SYMBOL_2_GPR(r3,test_function_end) |
/* Convert physical page number back to physical address */ |
l.slli r4,r4,PAGE_ADR_SHIFT |
/* r4 has physical address of where we'll relocate our test program to |
but we want it at an offset of PAGE_OFFSET_FOR_TEST inside that page. |
*/ |
|
l.addi r4,r4,PAGE_OFFSET_FOR_TEST |
program_relocate_loop: |
l.lwz r5,0(r2) |
l.sw 0(r4),r5 |
l.sfeq r2,r3 |
l.mtspr r0,r4,SPR_DCBIR /* flush dcache */ |
l.addi r4,r4,4 /* increment dest ptr */ |
l.bnf program_relocate_loop |
l.addi r2,r2,4 /* increment src ptr */ |
|
mmu_setup: |
/* Program relocated, setup MMU mappings */ |
/* Physical page number of test-code is in test_page_num. We need |
to set up a mapping for this page in the MMU, then launch execution |
of it. |
*/ |
LOAD_SYMBOL_2_GPR(r5,test_page_num) |
l.lwz r5,0(r5) |
/* Basically should be match-PPN of 0 translates to page |
number test_page_num. |
Set up entry 0, then, and have translate address to test_page_num*/ |
// Match register |
l.ori r3,r0,SPR_ITLBMR_V /* Just this */ |
l.mtspr r0,r3,SPR_ITLBMR_BASE(0) |
// Setup TR page number |
l.slli r3,r5,PAGE_ADR_SHIFT //r5 = page number of target page |
l.ori r3,r3,ITLB_PR_NOLIMIT |
l.mtspr r0,r3,SPR_ITLBTR_BASE(0) |
|
timer_setup: |
/* Init timer to fire at rate of TIMER_CYCLES_RATE */ |
l.jal timer_load |
l.nop |
|
sr_setup: |
// Start test - set up EPCR to jump to PAGE_OFFSET_FOR_TEST |
l.ori r3,r0,PAGE_OFFSET_FOR_TEST |
l.mtspr r0,r3,SPR_EPCR_BASE |
|
l.mfspr r3,r0,SPR_SR |
l.ori r3,r3,(SPR_SR_IME|SPR_SR_TEE) /* IMMU, tick timer enable */ |
l.mtspr r0,r3,SPR_ESR_BASE |
|
// Ensure global counter variable is zero |
LOAD_SYMBOL_2_GPR(r3,function_global) |
l.sw 0(r3),r0 |
|
// Call function entry point, check bug doesn't occur |
l.j call_rfe |
l.nop |
|
// Should never get here - test is detected as finished from the |
// timer interrupt. |
|
check_for_restart: |
l.mfspr r4,r0,SPR_SR |
l.andi r4,r4,SPR_SR_ICE /* is instruction cache enabled? */ |
l.sfgtu r4,r0 |
l.bnf restart_with_caches |
l.nop |
|
finish: |
l.movhi r3,0x8000 |
l.ori r3,r3,0x000d |
l.nop 0x2 |
l.j 0 |
l.nop 0x1 |
|
fail: |
l.movhi r3,0xbaaa |
l.ori r3,r3,0xaaad |
l.nop 0x2 |
l.j 0 |
l.nop 0x1 |
|
|
/* A stilly test function - doing some loads/stores, and some |
branches |
only touches r13 and r14*/ |
/* Should be relocatable */ |
test_function: |
// Check for error - r31 should be 0 |
l.sfne r31,r0 |
l.bf test_function_fail |
|
LOAD_SYMBOL_2_GPR(r13,function_global) |
l.lwz r14,0(r13) /* Load value of global */ |
l.addi r14,r14,1 |
l.sw 0(r13),r14 /* Store it back */ |
l.mtspr r0,r13,SPR_DCBIR /* flush dcache */ |
/* Every 8, branch away and back */ |
l.andi r14,r14,0xf |
l.sfeq r14,r0 |
l.bf test_function_sub |
l.nop |
l.j test_function |
l.nop |
|
test_function_sub: |
l.j test_function |
l.nop |
|
test_function_fail: |
l.sys 0 /* Bail out with syscall */ |
|
test_function_end: |
l.nop 0x1 |
|
|
|
restart_with_caches: |
l.jal _cache_init |
l.nop |
l.movhi r4, hi(_start) |
l.ori r4, r4, lo(_start) |
l.jr r4 |
l.nop |
|
|
/* MMU configuration functions */ |
|
immu_get_config: |
l.mfspr r3,r0,SPR_IMMUCFGR |
// Number of ways |
l.andi r4,r3,SPR_IMMUCFGR_NTW |
l.addi r4,r4,1 |
// Store the ways in immu_ways |
l.movhi r5,hi(immu_ways) |
l.ori r5,r5,lo(immu_ways) |
l.sw 0(r5),r4 |
// Number of sets |
l.andi r4,r3,SPR_IMMUCFGR_NTS |
l.srli r4,r4,SPR_IMMUCFGR_NTS_OFF |
l.ori r6,r0,1 |
l.sll r4,r6,r4 |
// Store the ways in immu_ways |
l.movhi r5,hi(immu_sets) |
l.ori r5,r5,lo(immu_sets) |
l.jr r9 // Return |
l.sw 0(r5),r4 |
|
dmmu_get_config: |
l.mfspr r3,r0,SPR_DMMUCFGR |
// Number of ways |
l.andi r4,r3,SPR_DMMUCFGR_NTW |
l.addi r4,r4,1 |
// Store the ways in dmmu_ways |
l.movhi r5,hi(dmmu_ways) |
l.ori r5,r5,lo(dmmu_ways) |
l.sw 0(r5),r4 |
// Number of sets |
l.andi r4,r3,SPR_DMMUCFGR_NTS |
l.srli r4,r4,SPR_DMMUCFGR_NTS_OFF |
l.ori r6,r0,1 |
l.sll r4,r6,r4 |
// Store the ways in dmmu_ways |
l.movhi r5,hi(dmmu_sets) |
l.ori r5,r5,lo(dmmu_sets) |
l.jr r9 // Return |
l.sw 0(r5),r4 |
|
|
immu_clear: |
// r3 - immu_ways |
// r4 - immu_sets |
// r5 - work |
// r6 - ways counter |
// r7 - sets counter |
// r10 - match regs spr address |
// r11 - translate regs spr address |
|
/* Clear all IMMU match/translate register pairs */ |
l.movhi r5,hi(immu_ways) |
l.ori r5,r5,lo(immu_ways) |
l.lwz r3,0(r5) |
l.movhi r5,hi(immu_sets) |
l.ori r5,r5,lo(immu_sets) |
l.lwz r4,0(r5) |
|
l.movhi r6, 0 // Clear ways counters |
|
immu_clear_set: |
l.movhi r7, 0 // Clear sets counter |
// Calculate base of IMMU match & translate registers |
l.ori r10,r0,SPR_ITLBMR_BASE(0) |
l.ori r11,r0,SPR_ITLBTR_BASE(0) |
l.slli r5,r6,8 /* Multiply ways by 256 (ways<<8) */ |
l.add r10,r10,r5 |
l.add r11,r11,r5 |
immu_clear_set_loop: |
l.mtspr r10,r0,0 /* ITLBMR_BASE(way) + set = 0 */ |
l.mtspr r11,r0,0 /* ITLBTR_BASE(way) + set = 0 */ |
l.addi r7,r7,1 |
l.sfne r4,r7 |
l.addi r10,r10,1 |
l.bf immu_clear_set_loop |
l.addi r11,r11,1 |
|
l.addi r6,r6,1 /* Increment ways counter */ |
l.sfne r3,r6 /* Cleared all ways? */ |
l.bf immu_clear_set |
l.nop |
|
/* Finished */ |
l.jr r9 |
l.nop |
|
dmmu_clear: |
// r3 - dmmu_ways |
// r4 - dmmu_sets |
// r5 - work |
// r6 - ways counter |
// r7 - sets counter |
// r10 - match regs spr address |
// r11 - translate regs spr address |
|
/* Clear all DMMU match/translate register pairs */ |
l.movhi r5,hi(dmmu_ways) |
l.ori r5,r5,lo(dmmu_ways) |
l.lwz r3,0(r5) |
l.movhi r5,hi(dmmu_sets) |
l.ori r5,r5,lo(dmmu_sets) |
l.lwz r4,0(r5) |
|
l.movhi r6, 0 // Clear ways counters |
|
dmmu_clear_set: |
l.movhi r7, 0 // Clear sets counter |
// Calculate base of DMMU match & translate registers |
l.ori r10,r0,SPR_DTLBMR_BASE(0) |
l.ori r11,r0,SPR_DTLBTR_BASE(0) |
l.slli r5,r6,8 /* Multiply ways by 256 (ways<<8) */ |
l.add r10,r10,r5 |
l.add r11,r11,r5 |
dmmu_clear_set_loop: |
l.mtspr r10,r0,0 /* ITLBMR_BASE(way) + set = 0 */ |
l.mtspr r11,r0,0 /* ITLBTR_BASE(way) + set = 0 */ |
l.addi r7,r7,1 |
l.sfne r4,r7 |
l.addi r10,r10,1 |
l.bf dmmu_clear_set_loop |
l.addi r11,r11,1 |
|
l.addi r6,r6,1 /* Increment ways counter */ |
l.sfne r3,r6 /* Cleared all ways? */ |
l.bf dmmu_clear_set |
l.nop |
|
/* Finished */ |
l.jr r9 |
l.nop |
|
|
|
#define TTMR_RELOAD_VALUE (SPR_TTMR_IE | SPR_TTMR_RT | TIMER_CYCLES_RATE) |
timer_load: |
l.movhi r3,hi(TTMR_RELOAD_VALUE) |
l.ori r3,r3,lo(TTMR_RELOAD_VALUE) |
l.jr r9 |
l.mtspr r0,r3,SPR_TTMR |
/drivers/or1200/or1200-mmu.S
File deleted
/drivers/or1200/mmu.S
0,0 → 1,21
#include "spr-defs.h" |
|
/* MMU enable functions */ |
.global lo_dmmu_en |
lo_dmmu_en: |
l.mfspr r3,r0,SPR_SR |
l.ori r3,r3,SPR_SR_DME |
l.mtspr r0,r3,SPR_ESR_BASE |
l.mtspr r0,r9,SPR_EPCR_BASE |
l.rfe |
l.nop |
|
.global lo_immu_en |
lo_immu_en: |
l.mfspr r3,r0,SPR_SR |
l.ori r3,r3,SPR_SR_IME |
l.mtspr r0,r3,SPR_ESR_BASE |
l.mtspr r0,r9,SPR_EPCR_BASE |
l.rfe |
l.nop |
|
/drivers/or1200/include/spr-defs.h
281,7 → 281,7
#define SPR_DTLBMR_PL1 0x00000002 /* Page Level 1 (if 0 then PL2) */ |
#define SPR_DTLBMR_CID 0x0000003c /* Context ID */ |
#define SPR_DTLBMR_LRU 0x000000c0 /* Least Recently Used */ |
#define SPR_DTLBMR_VPN 0xfffff000 /* Virtual Page Number */ |
#define SPR_DTLBMR_VPN 0xffffe000 /* Virtual Page Number */ |
|
/* |
* Bit definitions for the Data TLB Translate Register |
297,7 → 297,7
#define SPR_DTLBTR_UWE 0x00000080 /* User Write Enable */ |
#define SPR_DTLBTR_SRE 0x00000100 /* Supervisor Read Enable */ |
#define SPR_DTLBTR_SWE 0x00000200 /* Supervisor Write Enable */ |
#define SPR_DTLBTR_PPN 0xfffff000 /* Physical Page Number */ |
#define SPR_DTLBTR_PPN 0xffffe000 /* Physical Page Number */ |
|
#define DTLB_PR_NOLIMIT ( SPR_DTLBTR_URE | \ |
SPR_DTLBTR_UWE | \ |
312,7 → 312,7
#define SPR_ITLBMR_PL1 0x00000002 /* Page Level 1 (if 0 then PL2) */ |
#define SPR_ITLBMR_CID 0x0000003c /* Context ID */ |
#define SPR_ITLBMR_LRU 0x000000c0 /* Least Recently Used */ |
#define SPR_ITLBMR_VPN 0xfffff000 /* Virtual Page Number */ |
#define SPR_ITLBMR_VPN 0xffffe000 /* Virtual Page Number */ |
|
/* |
* Bit definitions for the Instruction TLB Translate Register |
326,7 → 326,7
#define SPR_ITLBTR_D 0x00000020 /* Dirty */ |
#define SPR_ITLBTR_SXE 0x00000040 /* User Read Enable */ |
#define SPR_ITLBTR_UXE 0x00000080 /* User Write Enable */ |
#define SPR_ITLBTR_PPN 0xfffff000 /* Physical Page Number */ |
#define SPR_ITLBTR_PPN 0xffffe000 /* Physical Page Number */ |
|
#define ITLB_PR_NOLIMIT ( SPR_ITLBTR_SXE | \ |
SPR_ITLBTR_UXE ) |
/drivers/or1200/Makefile
1,7 → 1,7
SW_ROOT=../.. |
|
# Sources to go into the liborpsoc.a support library |
COMPILE_SRCS=exceptions.c int.c or1200-mmu.S or1200-utils.c cache.S |
COMPILE_SRCS=exceptions.c int.c mmu.S or1200-utils.c cache.S |
|
include $(SW_ROOT)/Makefile.inc |
|