[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} |
---|
| 49 | 1: |
---|
| 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). |
---|
| 67 | 2: |
---|
| 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 |
---|
| 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 */ |
---|