fixes for host gcc 4.6.1
[zpugcc/jano.git] / toolchain / gcc / libgloss / mips / vr4300.S
blob2fc576ed3f9e9f71472fe1141be5fcf59cdcef33
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  */
17 #ifndef __mips64
18         .set mips3
19 #endif
20 #ifdef __mips16
21 /* This file contains 32 bit assembly code.  */
22         .set nomips16
23 #endif
25 #include "regs.S"
27         .text
28         .align  2
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
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}
50         mfc0    v0, $9          # 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.
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).
68         # get current counter value:
69         mfc0    v0, $9  # 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
83         # Flush the processor caches to memory:
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.
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.
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
122         li      a1, 16          # 16bytes
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
133         li      a0, 16          # 16bytes
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
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
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
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:
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
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
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:
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.
248         .text
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
265 baseaddr:
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????
273 copyloop:
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
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
306 res_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????
314 res_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
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
341 /* EOF vr4300.S */