OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [newlib-1.10.0/] [libgloss/] [mips/] [vr4300.S] - Rev 1005

Go to most recent revision | Compare with Previous | Blame | View Log

/*
 * 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 */

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.