diff options
author | Ranjith Kumaran <ranjith@cygnus.com> | 2000-03-18 01:48:54 +0300 |
---|---|---|
committer | Ranjith Kumaran <ranjith@cygnus.com> | 2000-03-18 01:48:54 +0300 |
commit | 03261851a10dd2d6900a0a00a7515a0a46fb5d76 (patch) | |
tree | 7c22ac6cbbc99fd5cd1b5426853be8d4fd7bfcf1 /libgloss/mips/vr4300.S | |
parent | fae4c299f14fc23e2829c8656992eba21f79242a (diff) |
20000317 sourceware import
Diffstat (limited to 'libgloss/mips/vr4300.S')
-rw-r--r-- | libgloss/mips/vr4300.S | 341 |
1 files changed, 341 insertions, 0 deletions
diff --git a/libgloss/mips/vr4300.S b/libgloss/mips/vr4300.S new file mode 100644 index 000000000..2fc576ed3 --- /dev/null +++ b/libgloss/mips/vr4300.S @@ -0,0 +1,341 @@ +/* + * vr4300.S -- CPU specific support routines + * + * Copyright (c) 1995,1996 Cygnus Support + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + */ + +#ifndef __mips64 + .set mips3 +#endif +#ifdef __mips16 +/* This file contains 32 bit assembly code. */ + .set nomips16 +#endif + +#include "regs.S" + + .text + .align 2 + + # Taken from "R4300 Preliminary RISC Processor Specification + # Revision 2.0 January 1995" page 39: "The Count + # register... increments at a constant rate... at one-half the + # PClock speed." + # We can use this fact to provide small polled delays. + .globl __cpu_timer_poll + .ent __cpu_timer_poll +__cpu_timer_poll: + .set noreorder + # in: a0 = (unsigned int) number of PClock ticks to wait for + # out: void + + # The Vr4300 counter updates at half PClock, so divide by 2 to + # get counter delta: + bnezl a0, 1f # continue if delta non-zero + srl a0, a0, 1 # divide ticks by 2 {DELAY SLOT} + # perform a quick return to the caller: + j ra + nop # {DELAY SLOT} +1: + mfc0 v0, $9 # C0_COUNT: get current counter value + nop + nop + # We cannot just do the simple test, of adding our delta onto + # the current value (ignoring overflow) and then checking for + # equality. The counter is incrementing every two PClocks, + # which means the counter value can change between + # instructions, making it hard to sample at the exact value + # desired. + + # However, we do know that our entry delta value is less than + # half the number space (since we divide by 2 on entry). This + # means we can use a difference in signs to indicate timer + # overflow. + addu a0, v0, a0 # unsigned add (ignore overflow) + # We know have our end value (which will have been + # sign-extended to fill the 64bit register value). +2: + # get current counter value: + mfc0 v0, $9 # C0_COUNT + nop + nop + # This is an unsigned 32bit subtraction: + subu v0, a0, v0 # delta = (end - now) {DELAY SLOT} + bgtzl v0, 2b # looping back is most likely + nop + # We have now been delayed (in the foreground) for AT LEAST + # the required number of counter ticks. + j ra # return to caller + nop # {DELAY SLOT} + .set reorder + .end __cpu_timer_poll + + # Flush the processor caches to memory: + + .globl __cpu_flush + .ent __cpu_flush +__cpu_flush: + .set noreorder + # NOTE: The Vr4300 *CANNOT* have any secondary cache (bit 17 + # of the CONFIG registered is hard-wired to 1). We just + # provide code to flush the Data and Instruction caches. + + # Even though the Vr4300 has hard-wired cache and cache line + # sizes, we still interpret the relevant Config register + # bits. This allows this code to be used for other conforming + # MIPS architectures if desired. + + # Get the config register + mfc0 a0, C0_CONFIG + nop + nop + li a1, 1 # a useful constant + # + srl a2, a0, 9 # bits 11..9 for instruction cache size + andi a2, a2, 0x7 # 3bits of information + add a2, a2, 12 # get full power-of-2 value + sllv a2, a1, a2 # instruction cache size + # + srl a3, a0, 6 # bits 8..6 for data cache size + andi a3, a3, 0x7 # 3bits of information + add a3, a3, 12 # get full power-of-2 value + sllv a3, a1, a3 # data cache size + # + li a1, (1 << 5) # check IB (instruction cache line size) + and a1, a0, a1 # mask against the CONFIG register value + beqz a1, 1f # branch on result of delay slot operation + nop + li a1, 32 # non-zero, then 32bytes + j 2f # continue + nop +1: + li a1, 16 # 16bytes +2: + # + li t0, (1 << 4) # check DB (data cache line size) + and a0, a0, t0 # mask against the CONFIG register value + beqz a0, 3f # branch on result of delay slot operation + nop + li a0, 32 # non-zero, then 32bytes + j 4f # continue + nop +3: + li a0, 16 # 16bytes +4: + # + # a0 = data cache line size + # a1 = instruction cache line size + # a2 = instruction cache size + # a3 = data cache size + # + lui t0, ((K0BASE >> 16) & 0xFFFF) + ori t0, t0, (K0BASE & 0xFFFF) + addu t1, t0, a2 # end cache address + subu t2, a1, 1 # line size mask + not t2 # invert the mask + and t3, t0, t2 # get start address + addu t1, -1 + and t1, t2 # get end address +5: + cache INDEX_INVALIDATE_I,0(t3) + bne t3, t1, 5b + addu t3, a1 + # + addu t1, t0, a3 # end cache address + subu t2, a0, 1 # line size mask + not t2 # invert the mask + and t3, t0, t2 # get start address + addu t1, -1 + and t1, t2 # get end address +6: + cache INDEX_WRITEBACK_INVALIDATE_D,0(t3) + bne t3, t1, 6b + addu t3, a0 + # + j ra # return to the caller + nop + .set reorder + .end __cpu_flush + + # NOTE: This variable should *NOT* be addressed relative to + # the $gp register since this code is executed before $gp is + # initialised... hence we leave it in the text area. This will + # cause problems if this routine is ever ROMmed: + + .globl __buserr_cnt +__buserr_cnt: + .word 0 + .align 3 +__k1_save: + .word 0 + .word 0 + .align 2 + + .ent __buserr + .globl __buserr +__buserr: + .set noat + .set noreorder + # k0 and k1 available for use: + mfc0 k0,C0_CAUSE + nop + nop + andi k0,k0,0x7c + sub k0,k0,7 << 2 + beq k0,$0,__buserr_do + nop + # call the previous handler + la k0,__previous + jr k0 + nop + # +__buserr_do: + # TODO: check that the cause is indeed a bus error + # - if not then just jump to the previous handler + la k0,__k1_save + sd k1,0(k0) + # + la k1,__buserr_cnt + lw k0,0(k1) # increment counter + addu k0,1 + sw k0,0(k1) + # + la k0,__k1_save + ld k1,0(k0) + # + mfc0 k0,C0_EPC + nop + nop + addu k0,k0,4 # skip offending instruction + mtc0 k0,C0_EPC # update EPC + nop + nop + eret +# j k0 +# rfe + .set reorder + .set at + .end __buserr + +__exception_code: + .set noreorder + lui k0,%hi(__buserr) + daddiu k0,k0,%lo(__buserr) + jr k0 + nop + .set reorder +__exception_code_end: + + .data +__previous: + .space (__exception_code_end - __exception_code) + # This subtracting two addresses is working + # but is not garenteed to continue working. + # The assemble reserves the right to put these + # two labels into different frags, and then + # cant take their difference. + + .text + + .ent __default_buserr_handler + .globl __default_buserr_handler +__default_buserr_handler: + .set noreorder + # attach our simple bus error handler: + # in: void + # out: void + mfc0 a0,C0_SR + nop + li a1,SR_BEV + and a1,a1,a0 + beq a1,$0,baseaddr + lui a0,0x8000 # delay slot + lui a0,0xbfc0 + daddiu a0,a0,0x0200 +baseaddr: + daddiu a0,a0,0x0180 + # a0 = base vector table address + la a1,__exception_code_end + la a2,__exception_code + subu a1,a1,a2 + la a3,__previous + # there must be a better way of doing this???? +copyloop: + lw v0,0(a0) + sw v0,0(a3) + lw v0,0(a2) + sw v0,0(a0) + daddiu a0,a0,4 + daddiu a2,a2,4 + daddiu a3,a3,4 + subu a1,a1,4 + bne a1,$0,copyloop + nop + la a0,__buserr_cnt + sw $0,0(a0) + j ra + nop + .set reorder + .end __default_buserr_handler + + .ent __restore_buserr_handler + .globl __restore_buserr_handler +__restore_buserr_handler: + .set noreorder + # restore original (monitor) bus error handler + # in: void + # out: void + mfc0 a0,C0_SR + nop + li a1,SR_BEV + and a1,a1,a0 + beq a1,$0,res_baseaddr + lui a0,0x8000 # delay slot + lui a0,0xbfc0 + daddiu a0,a0,0x0200 +res_baseaddr: + daddiu a0,a0,0x0180 + # a0 = base vector table address + la a1,__exception_code_end + la a3,__exception_code + subu a1,a1,a3 + la a3,__previous + # there must be a better way of doing this???? +res_copyloop: + lw v0,0(a3) + sw v0,0(a0) + daddiu a0,a0,4 + daddiu a3,a3,4 + subu a1,a1,4 + bne a1,$0,res_copyloop + nop + j ra + nop + .set reorder + .end __restore_buserr_handler + + .ent __buserr_count + .globl __buserr_count +__buserr_count: + .set noreorder + # restore original (monitor) bus error handler + # in: void + # out: unsigned int __buserr_cnt + la v0,__buserr_cnt + lw v0,0(v0) + j ra + nop + .set reorder + .end __buserr_count + +/* EOF vr4300.S */ |