source: trunk/libs/newlib/src/libgloss/mips/vr4300.S @ 686

Last change on this file since 686 was 444, checked in by satin@…, 7 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 8.0 KB
RevLine 
[444]1/*
2 * vr4300.S -- CPU specific support routines
3 *
4 * Copyright (c) 1995,1996 Cygnus Support
5 *
6 * The authors hereby grant permission to use, copy, modify, distribute,
7 * and license this software and its documentation for any purpose, provided
8 * that existing copyright notices are retained in all copies and that this
9 * notice is included verbatim in any distributions. No written agreement,
10 * license, or royalty fee is required for any of the authorized uses.
11 * Modifications to this software may be copyrighted by their authors
12 * and need not follow the licensing terms described here, provided that
13 * the new terms are clearly indicated on the first page of each file where
14 * they apply.
15 */
16
17#ifndef __mips64
18        .set mips3
19#endif
20#ifdef __mips16
21/* This file contains 32 bit assembly code.  */
22        .set nomips16
23#endif
24
25#include "regs.S"
26
27        .text
28        .align  2
29
30        # Taken from "R4300 Preliminary RISC Processor Specification
31        # Revision 2.0 January 1995" page 39: "The Count
32        # register... increments at a constant rate... at one-half the
33        # PClock speed."
34        # We can use this fact to provide small polled delays.
35        .globl  __cpu_timer_poll
36        .ent    __cpu_timer_poll
37__cpu_timer_poll:
38        .set    noreorder
39        # in:   a0 = (unsigned int) number of PClock ticks to wait for
40        # out:  void
41
42        # The Vr4300 counter updates at half PClock, so divide by 2 to
43        # get counter delta:
44        bnezl   a0, 1f          # continue if delta non-zero
45        srl     a0, a0, 1       # divide ticks by 2             {DELAY SLOT}
46        # perform a quick return to the caller:
47        j       ra
48        nop                     #                               {DELAY SLOT}
491:
50        mfc0    v0, C0_COUNT    # get current counter value
51        nop
52        nop
53        # We cannot just do the simple test, of adding our delta onto
54        # the current value (ignoring overflow) and then checking for
55        # equality. The counter is incrementing every two PClocks,
56        # which means the counter value can change between
57        # instructions, making it hard to sample at the exact value
58        # desired.
59
60        # However, we do know that our entry delta value is less than
61        # half the number space (since we divide by 2 on entry). This
62        # means we can use a difference in signs to indicate timer
63        # overflow.
64        addu    a0, v0, a0      # unsigned add (ignore overflow)
65        # We know have our end value (which will have been
66        # sign-extended to fill the 64bit register value).
672:
68        # get current counter value:
69        mfc0    v0, C0_COUNT
70        nop
71        nop
72        # This is an unsigned 32bit subtraction:
73        subu    v0, a0, v0      # delta = (end - now)           {DELAY SLOT}
74        bgtzl   v0, 2b          # looping back is most likely
75        nop
76        # We have now been delayed (in the foreground) for AT LEAST
77        # the required number of counter ticks.
78        j       ra              # return to caller
79        nop                     #                               {DELAY SLOT}
80        .set    reorder
81        .end    __cpu_timer_poll
82
83        # Flush the processor caches to memory:
84
85        .globl  __cpu_flush
86        .ent    __cpu_flush
87__cpu_flush:
88        .set    noreorder
89        # NOTE: The Vr4300 *CANNOT* have any secondary cache (bit 17
90        # of the CONFIG registered is hard-wired to 1). We just
91        # provide code to flush the Data and Instruction caches.
92
93        # Even though the Vr4300 has hard-wired cache and cache line
94        # sizes, we still interpret the relevant Config register
95        # bits. This allows this code to be used for other conforming
96        # MIPS architectures if desired.
97
98        # Get the config register
99        mfc0    a0, C0_CONFIG
100        nop
101        nop
102        li      a1, 1           # a useful constant
103        #
104        srl     a2, a0, 9       # bits 11..9 for instruction cache size
105        andi    a2, a2, 0x7     # 3bits of information
106        add     a2, a2, 12      # get full power-of-2 value
107        sllv    a2, a1, a2      # instruction cache size
108        #
109        srl     a3, a0, 6       # bits 8..6 for data cache size
110        andi    a3, a3, 0x7     # 3bits of information
111        add     a3, a3, 12      # get full power-of-2 value
112        sllv    a3, a1, a3      # data cache size
113        #
114        li      a1, (1 << 5)    # check IB (instruction cache line size)
115        and     a1, a0, a1      # mask against the CONFIG register value
116        beqz    a1, 1f          # branch on result of delay slot operation
117        nop
118        li      a1, 32          # non-zero, then 32bytes
119        j       2f              # continue
120        nop
1211:
122        li      a1, 16          # 16bytes
1232:
124        #
125        li      t0, (1 << 4)    # check DB (data cache line size)
126        and     a0, a0, t0      # mask against the CONFIG register value
127        beqz    a0, 3f          # branch on result of delay slot operation
128        nop
129        li      a0, 32          # non-zero, then 32bytes
130        j       4f              # continue
131        nop
1323:
133        li      a0, 16          # 16bytes
1344:
135        #
136        # a0 = data cache line size
137        # a1 = instruction cache line size
138        # a2 = instruction cache size
139        # a3 = data cache size
140        #
141        lui     t0, ((K0BASE >> 16) & 0xFFFF)
142        ori     t0, t0, (K0BASE & 0xFFFF)
143        addu    t1, t0, a2      # end cache address
144        subu    t2, a1, 1       # line size mask
145        not     t2              # invert the mask
146        and     t3, t0, t2      # get start address
147        addu    t1, -1
148        and     t1, t2          # get end address
1495:
150        cache   INDEX_INVALIDATE_I,0(t3)
151        bne     t3, t1, 5b
152        addu    t3, a1
153        #
154        addu    t1, t0, a3      # end cache address
155        subu    t2, a0, 1       # line size mask
156        not     t2              # invert the mask
157        and     t3, t0, t2      # get start address
158        addu    t1, -1
159        and     t1, t2          # get end address
1606:
161        cache   INDEX_WRITEBACK_INVALIDATE_D,0(t3)
162        bne     t3, t1, 6b
163        addu    t3, a0
164        #
165        j       ra      # return to the caller
166        nop
167        .set    reorder
168        .end    __cpu_flush
169
170        # NOTE: This variable should *NOT* be addressed relative to
171        # the $gp register since this code is executed before $gp is
172        # initialised... hence we leave it in the text area. This will
173        # cause problems if this routine is ever ROMmed:
174
175        .globl  __buserr_cnt
176__buserr_cnt:
177        .word   0
178        .align  3
179__k1_save:
180        .word   0
181        .word   0
182        .align  2
183
184        .ent __buserr
185        .globl __buserr
186__buserr:
187        .set noat
188        .set noreorder
189        # k0 and k1 available for use:
190        mfc0    k0,C0_CAUSE
191        nop
192        nop
193        andi    k0,k0,0x7c
194        sub     k0,k0,7 << 2
195        beq     k0,$0,__buserr_do
196        nop
197        # call the previous handler
198        la      k0,__previous
199        jr      k0
200        nop
201        #
202__buserr_do:
203        # TODO: check that the cause is indeed a bus error
204        # - if not then just jump to the previous handler
205        la      k0,__k1_save
206        sd      k1,0(k0)
207        #
208        la      k1,__buserr_cnt
209        lw      k0,0(k1)        # increment counter
210        addu    k0,1
211        sw      k0,0(k1)
212        #
213        la      k0,__k1_save
214        ld      k1,0(k0)
215        #
216        mfc0    k0,C0_EPC
217        nop
218        nop
219        addu    k0,k0,4         # skip offending instruction
220        mtc0    k0,C0_EPC       # update EPC
221        nop
222        nop
223        eret
224#        j       k0
225#        rfe
226        .set reorder
227        .set at
228        .end __buserr
229
230__exception_code:
231        .set noreorder
232        lui     k0,%hi(__buserr)
233        daddiu  k0,k0,%lo(__buserr)
234        jr      k0
235        nop
236        .set reorder
237__exception_code_end:
238
239        .data
240__previous:
241        .space  (__exception_code_end - __exception_code)
242        # This subtracting two addresses is working
243        # but is not garenteed to continue working.
244        # The assemble reserves the right to put these
245        # two labels into different frags, and then
246        # cant take their difference.
247
248        .text
249
250        .ent    __default_buserr_handler
251        .globl  __default_buserr_handler
252__default_buserr_handler:
253        .set noreorder
254        # attach our simple bus error handler:
255        # in:  void
256        # out: void
257        mfc0    a0,C0_SR
258        nop
259        li      a1,SR_BEV
260        and     a1,a1,a0
261        beq     a1,$0,baseaddr
262        lui     a0,0x8000       # delay slot
263        lui     a0,0xbfc0
264        daddiu  a0,a0,0x0200
265baseaddr:
266        daddiu  a0,a0,0x0180
267        # a0 = base vector table address
268        la      a1,__exception_code_end
269        la      a2,__exception_code
270        subu    a1,a1,a2
271        la      a3,__previous
272        # there must be a better way of doing this????
273copyloop:
274        lw      v0,0(a0)
275        sw      v0,0(a3)
276        lw      v0,0(a2)
277        sw      v0,0(a0)
278        daddiu  a0,a0,4
279        daddiu  a2,a2,4
280        daddiu  a3,a3,4
281        subu    a1,a1,4
282        bne     a1,$0,copyloop
283        nop
284        la      a0,__buserr_cnt
285        sw      $0,0(a0)
286        j       ra
287        nop
288        .set reorder
289        .end    __default_buserr_handler
290
291        .ent    __restore_buserr_handler
292        .globl  __restore_buserr_handler
293__restore_buserr_handler:
294        .set noreorder
295        # restore original (monitor) bus error handler
296        # in:  void
297        # out: void
298        mfc0    a0,C0_SR
299        nop
300        li      a1,SR_BEV
301        and     a1,a1,a0
302        beq     a1,$0,res_baseaddr
303        lui     a0,0x8000       # delay slot
304        lui     a0,0xbfc0
305        daddiu  a0,a0,0x0200
306res_baseaddr:
307        daddiu  a0,a0,0x0180
308        # a0 = base vector table address
309        la      a1,__exception_code_end
310        la      a3,__exception_code
311        subu    a1,a1,a3
312        la      a3,__previous
313        # there must be a better way of doing this????
314res_copyloop:
315        lw      v0,0(a3)
316        sw      v0,0(a0)
317        daddiu  a0,a0,4
318        daddiu  a3,a3,4
319        subu    a1,a1,4
320        bne     a1,$0,res_copyloop
321        nop
322        j       ra
323        nop
324        .set reorder
325        .end    __restore_buserr_handler
326
327        .ent    __buserr_count
328        .globl  __buserr_count
329__buserr_count:
330        .set noreorder
331        # restore original (monitor) bus error handler
332        # in:  void
333        # out: unsigned int __buserr_cnt
334        la      v0,__buserr_cnt
335        lw      v0,0(v0)
336        j       ra
337        nop
338        .set reorder
339        .end    __buserr_count
340
341/* EOF vr4300.S */
Note: See TracBrowser for help on using the repository browser.