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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-newlib/] [newlib-1.17.0/] [libgloss/] [mips/] [vr5xxx.S] - Blame information for rev 9

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 9 jlechner
/*
2
 * vr5xxx.S -- CPU specific support routines
3
 *
4
 * Copyright (c) 1999 Cygnus Solutions
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
/* This file cloned from vr4300.S by dlindsay@cygnus.com
18
 * and recoded to suit Vr5432 and Vr5000.
19
 * Should be no worse for Vr43{00,05,10}.
20
 * Specifically, __cpu_flush() has been changed (a) to allow for the hardware
21
 * difference (in set associativity) between the Vr5432 and Vr5000,
22
 * and (b) to flush the optional secondary cache of the Vr5000.
23
 */
24
 
25
/* Processor Revision Identifier (PRID) Register: Implementation Numbers */
26
#define IMPL_VR5432     0x54
27
 
28
/* Cache Constants not determinable dynamically */
29
#define VR5000_2NDLINE 32       /* secondary cache line size */
30
#define VR5432_LINE 32          /* I,Dcache line sizes */
31
#define VR5432_SIZE (16*1024)   /* I,Dcache half-size */
32
 
33
 
34
#ifndef __mips64
35
        .set mips3
36
#endif
37
#ifdef __mips16
38
/* This file contains 32 bit assembly code.  */
39
        .set nomips16
40
#endif
41
 
42
#include "regs.S"
43
 
44
        .text
45
        .align  2
46
 
47
        # Taken from "R4300 Preliminary RISC Processor Specification
48
        # Revision 2.0 January 1995" page 39: "The Count
49
        # register... increments at a constant rate... at one-half the
50
        # PClock speed."
51
        # We can use this fact to provide small polled delays.
52
        .globl  __cpu_timer_poll
53
        .ent    __cpu_timer_poll
54
__cpu_timer_poll:
55
        .set    noreorder
56
        # in:   a0 = (unsigned int) number of PClock ticks to wait for
57
        # out:  void
58
 
59
        # The Vr4300 counter updates at half PClock, so divide by 2 to
60
        # get counter delta:
61
        bnezl   a0, 1f          # continue if delta non-zero
62
        srl     a0, a0, 1       # divide ticks by 2             {DELAY SLOT}
63
        # perform a quick return to the caller:
64
        j       ra
65
        nop                     #                               {DELAY SLOT}
66
1:
67
        mfc0    v0, C0_COUNT    # get current counter value
68
        nop
69
        nop
70
        # We cannot just do the simple test, of adding our delta onto
71
        # the current value (ignoring overflow) and then checking for
72
        # equality. The counter is incrementing every two PClocks,
73
        # which means the counter value can change between
74
        # instructions, making it hard to sample at the exact value
75
        # desired.
76
 
77
        # However, we do know that our entry delta value is less than
78
        # half the number space (since we divide by 2 on entry). This
79
        # means we can use a difference in signs to indicate timer
80
        # overflow.
81
        addu    a0, v0, a0      # unsigned add (ignore overflow)
82
        # We know have our end value (which will have been
83
        # sign-extended to fill the 64bit register value).
84
2:
85
        # get current counter value:
86
        mfc0    v0, C0_COUNT
87
        nop
88
        nop
89
        # This is an unsigned 32bit subtraction:
90
        subu    v0, a0, v0      # delta = (end - now)           {DELAY SLOT}
91
        bgtzl   v0, 2b          # looping back is most likely
92
        nop
93
        # We have now been delayed (in the foreground) for AT LEAST
94
        # the required number of counter ticks.
95
        j       ra              # return to caller
96
        nop                     #                               {DELAY SLOT}
97
        .set    reorder
98
        .end    __cpu_timer_poll
99
 
100
        # Flush the processor caches to memory:
101
 
102
        .globl  __cpu_flush
103
        .ent    __cpu_flush
104
__cpu_flush:
105
        .set    noreorder
106
        # NOTE: The Vr4300 and Vr5432 *CANNOT* have any secondary cache.
107
        # On those, SC (bit 17 of CONFIG register) is hard-wired to 1,
108
        # except that email from Dennis_Han@el.nec.com says that old
109
        # versions of the Vr5432 incorrectly hard-wired this bit to 0.
110
        # The Vr5000 has an optional direct-mapped secondary cache,
111
        # and the SC bit correctly indicates this.
112
 
113
        # So, for the 4300 and 5432 we want to just
114
        # flush the primary Data and Instruction caches.
115
        # For the 5000 it is desired to flush the secondary cache too.
116
        # There is an operation difference worth noting.
117
        # The 4300 and 5000 primary caches use VA bit 14 to choose cache set,
118
        # whereas 5432 primary caches use VA bit 0.
119
 
120
        # This code interprets the relevant Config register bits as
121
        # much as possible, except for the 5432.
122
        # The code therefore has some portability.
123
        # However, the associativity issues mean you should not just assume
124
        # that this code works anywhere. Also, the secondary cache set
125
        # size is hardwired, since the 5000 series does not define codes
126
        # for variant sizes.
127
 
128
        # Note: this version of the code flushes D$ before I$.
129
        #   It is difficult to construct a case where that matters,
130
        #   but it cant hurt.
131
 
132
        mfc0    a0, C0_PRID     # a0 = Processor Revision register
133
        nop                     # dlindsay: unclear why the nops, but
134
        nop                     # vr4300.S had such so I do too.
135
        srl     a2, a0, PR_IMP  # want bits 8..15
136
        andi    a2, a2, 0x255   # mask: now a2 = Implementation # field
137
        li      a1, IMPL_VR5432
138
        beq     a1, a2, 8f      # use Vr5432-specific flush algorithm
139
        nop
140
 
141
        # Non-Vr5432 version of the code.
142
        # (The distinctions being: CONFIG is truthful about secondary cache,
143
        # and we act as if the primary Icache and Dcache are direct mapped.)
144
 
145
        mfc0    t0, C0_CONFIG   # t0 = CONFIG register
146
        nop
147
        nop
148
        li      a1, 1           # a1=1, a useful constant
149
 
150
        srl     a2, t0, CR_IC   # want IC field of CONFIG
151
        andi    a2, a2, 0x7     # mask: now a2= code for Icache size
152
        add     a2, a2, 12      # +12
153
        sllv    a2, a1, a2      # a2=primary instruction cache size in bytes
154
 
155
        srl     a3, t0, CR_DC   # DC field of CONFIG
156
        andi    a3, a3, 0x7     # mask: now a3= code for Dcache size
157
        add     a3, a3, 12      # +12
158
        sllv    a3, a1, a3      # a3=primary data cache size in bytes
159
 
160
        li      t2, (1 << CR_IB) # t2=mask over IB boolean
161
        and     t2, t2, t0      # test IB field of CONFIG register value
162
        beqz    t2, 1f          #
163
        li      a1, 16          # 16 bytes (branch shadow: always loaded.)
164
        li      a1, 32          # non-zero, then 32bytes
165
1:
166
 
167
        li      t2, (1 << CR_DB) # t2=mask over DB boolean
168
        and     t2, t2, t0      # test BD field of CONFIG register value
169
        beqz    t2, 2f          #
170
        li      a0, 16          # 16bytes (branch shadow: always loaded.)
171
        li      a0, 32          # non-zero, then 32bytes
172
2:
173
        lui     t1, ((K0BASE >> 16) & 0xFFFF)
174
        ori     t1, t1, (K0BASE & 0xFFFF)
175
 
176
        # At this point,
177
        # a0 = primary Dcache line size in bytes
178
        # a1 = primary Icache line size in bytes
179
        # a2 = primary Icache size in bytes
180
        # a3 = primary Dcache size in bytes
181
        # t0 = CONFIG value
182
        # t1 = a round unmapped cached base address (we are in kernel mode)
183
        # t2,t3 scratch
184
 
185
        addi    t3, t1, 0       # t3=t1=start address for any cache
186
        add     t2, t3, a3      # t2=end adress+1 of Dcache
187
        sub     t2, t2, a0      # t2=address of last line in Dcache
188
3:
189
        cache   INDEX_WRITEBACK_INVALIDATE_D,0(t3)
190
        bne     t3, t2, 3b      #
191
        addu    t3, a0          # (delay slot) increment by Dcache line size
192
 
193
 
194
        # Now check CONFIG to see if there is a secondary cache
195
        lui     t2, (1 << (CR_SC-16)) # t2=mask over SC boolean
196
        and     t2, t2, t0      # test SC in CONFIG
197
        bnez    t2, 6f
198
 
199
        # There is a secondary cache. Find out its sizes.
200
 
201
        srl     t3, t0, CR_SS   # want SS field of CONFIG
202
        andi    t3, t3, 0x3     # mask: now t3= code for cache size.
203
        beqz    t3, 4f
204
        lui     a3, ((512*1024)>>16)    # a3= 512K, code was 0
205
        addu    t3, -1                  # decrement code
206
        beqz    t3, 4f
207
        lui     a3, ((1024*1024)>>16)   # a3= 1 M, code  1
208
        addu    t3, -1                  # decrement code
209
        beqz    t3, 4f
210
        lui     a3, ((2*1024*1024)>>16) # a3= 2 M, code 2
211
        j       6f                      # no secondary cache, code 3
212
 
213
4:      # a3 = secondary cache size in bytes
214
        li      a0, VR5000_2NDLINE      # no codes assigned for other than 32
215
 
216
        # At this point,
217
        # a0 = secondary cache line size in bytes
218
        # a1 = primary Icache line size in bytes
219
        # a2 = primary Icache size in bytes
220
        # a3 = secondary cache size in bytes
221
        # t1 = a round unmapped cached base address (we are in kernel mode)
222
        # t2,t3 scratch
223
 
224
        addi    t3, t1, 0       # t3=t1=start address for any cache
225
        add     t2, t3, a3      # t2=end address+1 of secondary cache
226
        sub     t2, t2, a0      # t2=address of last line in secondary cache
227
5:
228
        cache   INDEX_WRITEBACK_INVALIDATE_SD,0(t3)
229
        bne     t3, t2, 5b
230
        addu    t3, a0          # (delay slot) increment by line size
231
 
232
 
233
6:      # Any optional secondary cache done.  Now do I-cache and return.
234
 
235
        # At this point,
236
        # a1 = primary Icache line size in bytes
237
        # a2 = primary Icache size in bytes
238
        # t1 = a round unmapped cached base address (we are in kernel mode)
239
        # t2,t3 scratch
240
 
241
        add     t2, t1, a2      # t2=end adress+1 of Icache
242
        sub     t2, t2, a1      # t2=address of last line in Icache
243
7:
244
        cache   INDEX_INVALIDATE_I,0(t1)
245
        bne     t1, t2, 7b
246
        addu    t1, a1          # (delay slot) increment by Icache line size
247
 
248
        j       ra      # return to the caller
249
        nop
250
 
251
8:
252
 
253
# Vr5432 version of the cpu_flush code.
254
# (The distinctions being: CONFIG can not be trusted about secondary
255
# cache (which does not exist). The primary caches use Virtual Address Bit 0
256
# to control set selection.
257
 
258
# Code does not consult CONFIG about cache sizes: knows the hardwired sizes.
259
# Since both I and D have the same size and line size, uses a merged loop.
260
 
261
        li      a0, VR5432_LINE
262
        li      a1, VR5432_SIZE
263
        lui     t1, ((K0BASE >> 16) & 0xFFFF)
264
        ori     t1, t1, (K0BASE & 0xFFFF)
265
 
266
        # a0 = cache line size in bytes
267
        # a1 = 1/2 cache size in bytes
268
        # t1 = a round unmapped cached base address (we are in kernel mode)
269
 
270
        add     t2, t1, a1      # t2=end address+1
271
        sub     t2, t2, a0      # t2=address of last line in Icache
272
 
273
9:
274
        cache   INDEX_WRITEBACK_INVALIDATE_D,0(t1)      # set 0
275
        cache   INDEX_WRITEBACK_INVALIDATE_D,1(t1)      # set 1
276
        cache   INDEX_INVALIDATE_I,0(t1)        # set 0
277
        cache   INDEX_INVALIDATE_I,1(t1)        # set 1
278
        bne     t1, t2, 9b
279
        addu    t1, a0
280
 
281
        j       ra      # return to the caller
282
        nop
283
        .set    reorder
284
        .end    __cpu_flush
285
 
286
        # NOTE: This variable should *NOT* be addressed relative to
287
        # the $gp register since this code is executed before $gp is
288
        # initialised... hence we leave it in the text area. This will
289
        # cause problems if this routine is ever ROMmed:
290
 
291
        .globl  __buserr_cnt
292
__buserr_cnt:
293
        .word   0
294
        .align  3
295
__k1_save:
296
        .word   0
297
        .word   0
298
        .align  2
299
 
300
        .ent __buserr
301
        .globl __buserr
302
__buserr:
303
        .set noat
304
        .set noreorder
305
        # k0 and k1 available for use:
306
        mfc0    k0,C0_CAUSE
307
        nop
308
        nop
309
        andi    k0,k0,0x7c
310
        sub     k0,k0,7 << 2
311
        beq     k0,$0,__buserr_do
312
        nop
313
        # call the previous handler
314
        la      k0,__previous
315
        jr      k0
316
        nop
317
        #
318
__buserr_do:
319
        # TODO: check that the cause is indeed a bus error
320
        # - if not then just jump to the previous handler
321
        la      k0,__k1_save
322
        sd      k1,0(k0)
323
        #
324
        la      k1,__buserr_cnt
325
        lw      k0,0(k1)        # increment counter
326
        addu    k0,1
327
        sw      k0,0(k1)
328
        #
329
        la      k0,__k1_save
330
        ld      k1,0(k0)
331
        #
332
        mfc0    k0,C0_EPC
333
        nop
334
        nop
335
        addu    k0,k0,4         # skip offending instruction
336
        mtc0    k0,C0_EPC       # update EPC
337
        nop
338
        nop
339
        eret
340
#        j       k0
341
#        rfe
342
        .set reorder
343
        .set at
344
        .end __buserr
345
 
346
__exception_code:
347
        .set noreorder
348
        lui     k0,%hi(__buserr)
349
        daddiu  k0,k0,%lo(__buserr)
350
        jr      k0
351
        nop
352
        .set reorder
353
__exception_code_end:
354
 
355
        .data
356
__previous:
357
        .space  (__exception_code_end - __exception_code)
358
        # This subtracting two addresses is working
359
        # but is not garenteed to continue working.
360
        # The assemble reserves the right to put these
361
        # two labels into different frags, and then
362
        # cant take their difference.
363
 
364
        .text
365
 
366
        .ent    __default_buserr_handler
367
        .globl  __default_buserr_handler
368
__default_buserr_handler:
369
        .set noreorder
370
        # attach our simple bus error handler:
371
        # in:  void
372
        # out: void
373
        mfc0    a0,C0_SR
374
        nop
375
        li      a1,SR_BEV
376
        and     a1,a1,a0
377
        beq     a1,$0,baseaddr
378
        lui     a0,0x8000       # delay slot
379
        lui     a0,0xbfc0
380
        daddiu  a0,a0,0x0200
381
baseaddr:
382
        daddiu  a0,a0,0x0180
383
        # a0 = base vector table address
384
        la      a1,__exception_code_end
385
        la      a2,__exception_code
386
        subu    a1,a1,a2
387
        la      a3,__previous
388
        # there must be a better way of doing this????
389
copyloop:
390
        lw      v0,0(a0)
391
        sw      v0,0(a3)
392
        lw      v0,0(a2)
393
        sw      v0,0(a0)
394
        daddiu  a0,a0,4
395
        daddiu  a2,a2,4
396
        daddiu  a3,a3,4
397
        subu    a1,a1,4
398
        bne     a1,$0,copyloop
399
        nop
400
        la      a0,__buserr_cnt
401
        sw      $0,0(a0)
402
        j       ra
403
        nop
404
        .set reorder
405
        .end    __default_buserr_handler
406
 
407
        .ent    __restore_buserr_handler
408
        .globl  __restore_buserr_handler
409
__restore_buserr_handler:
410
        .set noreorder
411
        # restore original (monitor) bus error handler
412
        # in:  void
413
        # out: void
414
        mfc0    a0,C0_SR
415
        nop
416
        li      a1,SR_BEV
417
        and     a1,a1,a0
418
        beq     a1,$0,res_baseaddr
419
        lui     a0,0x8000       # delay slot
420
        lui     a0,0xbfc0
421
        daddiu  a0,a0,0x0200
422
res_baseaddr:
423
        daddiu  a0,a0,0x0180
424
        # a0 = base vector table address
425
        la      a1,__exception_code_end
426
        la      a3,__exception_code
427
        subu    a1,a1,a3
428
        la      a3,__previous
429
        # there must be a better way of doing this????
430
res_copyloop:
431
        lw      v0,0(a3)
432
        sw      v0,0(a0)
433
        daddiu  a0,a0,4
434
        daddiu  a3,a3,4
435
        subu    a1,a1,4
436
        bne     a1,$0,res_copyloop
437
        nop
438
        j       ra
439
        nop
440
        .set reorder
441
        .end    __restore_buserr_handler
442
 
443
        .ent    __buserr_count
444
        .globl  __buserr_count
445
__buserr_count:
446
        .set noreorder
447
        # restore original (monitor) bus error handler
448
        # in:  void
449
        # out: unsigned int __buserr_cnt
450
        la      v0,__buserr_cnt
451
        lw      v0,0(v0)
452
        j       ra
453
        nop
454
        .set reorder
455
        .end    __buserr_count
456
 
457
/* EOF vr5xxx.S */

powered by: WebSVN 2.1.0

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