source: trunk/libs/newlib/src/libgloss/mips/vr5xxx.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: 12.4 KB
Line 
1/*
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}
661:
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).
842:
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
1651:
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
1722:
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
1883:
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
2134:      # 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
2275:
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       
2336:      # 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
2437:
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
2518:
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
2739:
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
381baseaddr:
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????
389copyloop:
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
422res_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????
430res_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 */
Note: See TracBrowser for help on using the repository browser.