1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
|
/*
* Creation Date: <2001/01/26 21:21:53 samuel>
* Time-stamp: <2001/06/21 14:27:35 samuel>
*
* <mainloop.S>
*
* Main loop
*
* Copyright (C) 2000, 2001 Samuel Rydh (samuel@ibrium.se)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation
*
*/
#include "mol_config.h"
#include "rvec.h"
#include "multiplexer.h"
#include "processor.h"
#include "asm_offsets.h"
#include "asmdefs.h"
#include "mac_registers.h"
//#define DEBUG
//#define DEBUG_REGISTERS // Always save gprs/fprs
////////////////////////////////////////////////////////////////////////
//
// This file depends upon the register conventions of the platform.
// Linux/PPC uses the System V ABI:
//
// Altered by function calls:
// r0,r3-r12,(r2 ?)
// fr0-fr13
// cr[0,1,5,6,7]
// ctr
// xer
// certain bits of fpscr
//
// Not altered by function calls:
// r13-r31
// cr[2,3,4]
// fr14-fr31
// certain bits of fpscr
//
// The AltiVec implementation makes the assumption that *NO*
// altivec registers (including VRSAVE) is touched except by us.
//
////////////////////////////////////////////////////////////////////////
/************************************************************************/
/* DEBUG */
/************************************************************************/
.macro DBG_ASSERT_RVF_BIT bit scr
#ifdef DEBUG
lwz \scr,STACK_DBG_RVEC(r1)
rlwinm \scr,\scr,0,\bit,\bit
beq error_detected
#endif
.endm
#ifdef DEBUG
.print "**************** DEBUG ENABLED IN mainloop_asm.S ***************"
error_detected:
li r3,RVEC_INTERNAL_ERROR
lwz r4,STACK_DBG_RVEC(r1)
b do_rvec_jump
#endif
.macro DEBUG_IN_KERNEL val, scr1, scr2
#ifdef DEBUG
lwz \scr1,STACK_MREGS(r1)
li \scr2,\val
stw \scr2,xDBG_IN_MAC_MODE(\scr1)
#endif
.endm
/************************************************************************/
/* MACROS */
/************************************************************************/
.macro SETVEC, name, rvec, func, scr, scr2
bl 1f
.ascii "\name\0"
.balign 4,0
1:
LOADI \scr,gRVECtable
LOADI \scr2,\func
stw \scr2,((\rvec & RVEC_MASK) * RVEC_ESIZE) (\scr)
mflr \scr2
stw \scr2,((\rvec & RVEC_MASK) * RVEC_ESIZE + 8) (\scr)
.endm
/************************************************************************/
/* mainloop_asm_init */
/************************************************************************/
// This could be done in C, but we do it here for the sake
// of modularity.
GLOBL( mainloop_asm_init ):
mflr r5
SETVEC "Init -", RVEC_INITIALIZE, rvec_initialize, /**/ r3,r4
SETVEC "NOP -", RVEC_NOP, loop, /**/ r3,r4
SETVEC "Exit -", RVEC_EXIT, mainloop_out, /**/ r3,r4
SETVEC "EnableFPU -", RVEC_ENABLE_FPU, rvec_enable_fpu, /**/ r3,r4
SETVEC "EnableAltivec -", RVEC_ENABLE_ALTIVEC, rvec_enable_altivec, /**/ r3,r4
mtlr r5
blr
/************************************************************************/
/* mainloop */
/************************************************************************/
///////////////////////////////////////////////////////////////
// mainloop( rvec, mregs, session_magic )
// The following registers hold mac-values:
//
// r13-r31
// fr0-fr12 (if fpu_state == FPU_DIRTY)
// fr14-fr31
//
// In particular, fr13 and fpscr *never* hold mac values.
// (We can't touch fpscr since that might trigger a FPU exception)
.set STACK_SPACE, 416
.set STACK_LR, STACK_SPACE+4
.set STACK_RESERVED, 0 // 8 bytes
.set STACK_DUMMY_FP, 8 // 8 bytes
.set STACK_MREGS, 16 // 4 bytes
#ifdef DEBUG
.set STACK_DBG_RVEC, 20 // 4 bytes
#endif
.set STACK_SESSION_MAGIC, 24 // 4 bytes
.set STACK_FPRS, 32 // 256 bytes
.set STACK_GPRS, 288 // 128 bytes
GLOBL( mainloop ):
// Push stackframe
stwu r1,-STACK_SPACE(r1)
mflr r0
mfxer r11 // XER (uncertain about this one)
mfcr r12 // CR (cr1-cr7 needs to be saved?)
mffs fr3
stfd fr3,xEMULATOR_FPSCR-4(r1) // Save emulator fpscr
STORE_GPR_RANGE r11,r31,STACK_GPRS,r1 // don't touch r13-r31 (and f14-f31)
STORE_GPR_RANGE r2,r2,STACK_GPRS,r1 // probably not necessary
STORE_FPR_RANGE fr14,fr31,STACK_FPRS,r1 // don't touch fp14-fp31
stw r0,STACK_LR(r1)
stw r4,STACK_MREGS(r1)
stw r5,STACK_SESSION_MAGIC(r1)
lwz r11,xALTIVEC_USED(r4) // Only touch the AltiVec unit if we know
cmpwi r11,0 // we have one.
beq 1f
xVEC_LOAD r4, /**/ r11
1: xLOAD_FULL_FPU r4 // loads everything (except fr13 and fpscr)
xGPR_LOAD_RANGE 13,31,r4 // r4 = mbase
b do_rvec_jump
loop:
lwz r6,STACK_MREGS(r1)
lwz r7,xINTERRUPT(r6)
cmpwi r7,0
bne- mol_interrupt
li r4,MOL_ENTRY_R4_MAGIC
li r5,MOL_ENTRY_R5_MAGIC
// Any privileged instruction
switch_magic:
DEBUG_IN_KERNEL 1, /**/ r10,r11
lwz r7,STACK_SESSION_MAGIC(r1)
MOL_KERNEL_ENTRY_MAGIC // Only r1, r2 and rvec parameters are valid afterwards
DEBUG_IN_KERNEL 0, /**/ r10,r11
do_rvec_jump:
#ifdef DEBUG_REGISTERS
bl save_fpu
bl save_gprs
#endif
// Return point, r3=rvec#, r4+=arguments
rlwinm. r0,r3,0,RVF_fb,RVF_lb // Any RVEC flags?
bne- handle_rvec_flags // Mod r0,r9-r12
do_rvec_jump_:
LOADI r9,gRVECtable // Jump to return vector
rlwinm r10,r3, RVEC_ESIZE_LOG2, 31-(NRVECS_LOG2-1)-RVEC_ESIZE_LOG2, 31-RVEC_ESIZE_LOG2
lwzx r0,r9,r10
mtlr r0
#ifdef COLLECT_RVEC_STATISTICS
addi r10,r10,4
lwzx r11,r9,r10
addi r0,r11,1
stwx r0,r9,r10
#endif
#ifdef DEBUG
lwz r9,STACK_MREGS(r1)
stw r3,xDBG_LAST_RVEC(r9)
stw r3,STACK_DBG_RVEC(r1)
#endif
blrl
cmpwi r3,0
beq+ loop
mtcr r3 // Bit 0-3 (cr0) not used for flags
lwz r4,STACK_MREGS(r1)
btl- kRVecGPRsModifiedBit, gprs_modified
btl- kRVecFPRsModifiedBit, fprs_modified
bt- kRVecExitBit, mainloop_out
b loop
mol_interrupt:
li r3,RVEC_INTERRUPT
b do_rvec_jump
mainloop_out:
bl save_altivec // save altivec (for session-save/debug)
bl save_fpu // save fpu registers (if necessary)
lwz r4,STACK_MREGS(r1)
xGPR_SAVE_RANGE 13,31,r4 // save xGPR13-xGPR31
// Pop stackframe
lwz r0,STACK_LR(r1)
LOAD_GPR_RANGE r11,r31,STACK_GPRS,r1
LOAD_FPR_RANGE fr14,fr31,STACK_FPRS,r1
mtxer r11
mtcr r12
mtlr r0
addi r1,r1,STACK_SPACE
blr
/////////////////////////////////////////////////////////////////
// kernel_call_return
//
// r3 RVEC number
//
// If our low-level asm kernel code calls C-kernel code directly,
// then the return point is set to kernel_call_return rather than
// do_rvec_jump. This allows the C-kernel code to pass parameters
// to rvec functions by storing them in xRVEC_PARAM.
kernel_call_return:
lwz r8,STACK_MREGS(r1)
lwz r4,xRVEC_PARAM0(r8)
lwz r5,xRVEC_PARAM1(r8)
lwz r6,xRVEC_PARAM2(r8)
b do_rvec_jump
////////////////////////////////////////////////////////////////
// handle_rvec_flags
//
// r0 flags (upper 16 bits; top 4 bits unused)
// r3-rX rvec call
//
// safe to modify: r0, r9-r12
handle_rvec_flags:
mtcr r0
btl RVF_USES_FPRS_BIT, save_fpu // should go before RVF_FPU_UNSAFE_VECTOR
btl RVF_FPU_UNSAFE_BIT, save_low_fpu
btl RVF_USES_GPRS_BIT, save_gprs
b do_rvec_jump_
// Make sure the complete FPU is stored in mregs
// Modifies r9-r11
save_fpu:
lwz r10,STACK_MREGS(r1)
lwz r9,xFPU_STATE(r10)
cmpwi r9,FPU_STATE_SAVED // If the FPU is already saved, do nothing
beqlr+
li r11,FPU_STATE_SAVED
stw r11,xFPU_STATE(r10)
crclr RVF_FPU_UNSAFE_BIT
xSAVE_TOPHALF_FPU r10 // Save top half of the FPU
cmpwi r9,FPU_STATE_DIRTY // and the lower half of FPU if its dirty
bnelr
xSAVE_LOW_FPU r10 // save all of the FPU
blr
// Save low FPU registers (if the FPU is dirty). We must do this before
// taking a vector that might touch the FPU.
// Modifies r9-r11
save_low_fpu:
lwz r10,STACK_MREGS(r1)
lwz r9,xFPU_STATE(r10)
cmpwi r9,FPU_STATE_DIRTY // Save FPU if its dirty
bnelr+
li r11,FPU_STATE_HALF_SAVED
xSAVE_LOW_FPU r10 // r10 = mregs
stw r11,xFPU_STATE(r10)
blr
// Make sure all GPRs are stored in mregs
save_gprs:
lwz r10,STACK_MREGS(r1)
xGPR_SAVE_RANGE 13,31,r10 // r10=mregs, save xGPR13-xGPR31
blr
save_altivec:
lwz r10,STACK_MREGS(r1)
lwz r9,xALTIVEC_USED(r10)
cmpwi r9,0
beqlr
xVEC_SAVE r10, /**/ r9
blr
///////////////////////////////////////////////////////////////////
// rvec return flags
//
// r3: return code
// r4: mregs
//
// Safe to modify: r0,r5-r12, lr, ctr
// called if kRVecGPRsModified was return by the rvector
gprs_modified:
DBG_ASSERT_RVF_BIT RVF_USES_GPRS_BIT, /**/ r12
xGPR_LOAD_RANGE 13,31,r4 // r4 = mbase
blr
// called kRVecFPRsModified was return by the rvector
fprs_modified:
DBG_ASSERT_RVF_BIT RVF_USES_FPRS_BIT, /**/ r12
xLOAD_TOPHALF_FPU r4 // we only need to reload the top half of the fpu.
blr
/************************************************************************/
/* Miscellaneous rvecs */
/************************************************************************/
rvec_initialize:
LOADI r6,kernel_call_return
li r4,MOL_INITIALIZE_R4_MAGIC
li r5,MOL_INITIALIZE_R5_MAGIC
b switch_magic
rvec_enable_fpu:
stfd fr0,STACK_DUMMY_FP(r1) // enable the fpu
b loop
rvec_enable_altivec:
li r3,1
lwz r4,STACK_MREGS(r1)
stw r3,xALTIVEC_USED(r4) // Useful for AltiVec detection
.long 0x10000484 // vor v0,v0,v0
b loop
|