]> sourceware.org Git - newlib-cygwin.git/blob - libgloss/mips/vr4300.S
If -mfp32, do not enable 64-bit FPR registers on mips3
[newlib-cygwin.git] / libgloss / mips / vr4300.S
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}
49 1:
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.
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).
67 2:
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
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
121 1:
122 li a1, 16 # 16bytes
123 2:
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
132 3:
133 li a0, 16 # 16bytes
134 4:
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
149 5:
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
160 6:
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
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
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
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
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 */
This page took 0.050899 seconds and 5 git commands to generate.