Source to machdep/ppc/lowmem_vectors.s
/*
* Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
* Reserved. This file contains Original Code and/or Modifications of
* Original Code as defined in and that are subject to the Apple Public
* Source License Version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. Please obtain a copy of the
* License at http://www.apple.com/publicsource and read it before using
* this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License."
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* Low-memory exception vector code for PowerPC MACH
*
* These are the only routines that are ever run with
* VM instruction translation switched off.
*
* The PowerPC is quite strange in that rather than having a set
* of exception vectors, the exception handlers are installed
* in well-known addresses in low memory. This code must be loaded
* at ZERO in physical memory. We do this by putting this code
* into a special segment (__VECTORS) and giving the segment
* a -segaddr of zero in the 'ld' command line.
*
* When this code is loaded into memory, it is loaded at physical
* address zero.
*
* This code handles all powerpc exceptions and is always entered
* in supervisor mode with translation off. It saves the minimum
* processor state before switching back on translation and
* jumping to the approprate routine.
*
* Vectors from 0x100 to 0x2fff occupy 0x100 bytes each (64 instructions)
*
* We use some of this space to decide which stack to use, and where to
* save the context etc, before jumping to a generic handler.
*/
#include <assym.h>
#include <debug.h>
#include <cpus.h>
#include <mach_debug.h>
#include <machdep/ppc/asm.h>
#include <machdep/ppc/proc_reg.h>
#include <machdep/ppc/exception.h>
#include <mach/ppc/vm_param.h>
#include <machdep/ppc/nkdefs.h>
#include <ppc/pcb_flags.h>
/* Kernel origin point. Keep this in sync with the makefiles!
See MASTER.ppc and MAKEFILE.ppc!
*/
#define RELOC 0x10000
/*
* Define a couple of macros to make the Handler macro simpler
*/
#if __STDC__
#define LHL(x) LCL(_handler ## x)
#define LOC(y) 0x ## y
#else /* __STDC__ */
#define LHL(x) LCL(_handler/**/x)
#define LOC(y) 0x/**/y
#endif /* __STDC__ */
/*
* Almost all handlers do exactly the same thing:
* save r1-r3 into sprg1-3
* load r3 with a value indicating which trap
* load r2 with the per-processor save area pointer
* branch to the generic entry code.
*/
#define HANDLER2(a,v,l) LHL(a): @ \
. = LOC(a) @ \
mtsprg 3, r3 @ \
mtsprg 2, r2 @ \
li r3, v @ \
mtsprg 1, r1 @ \
mfsprg r2, 0 @ \
b LCL(l)
#define HANDLER(a,v) HANDLER2(a, v, _exception_entry)
/*
* Here are the vectors
*/
.section __VECTORS, __interrupts
.align 2
.globl _ExceptionVectorsStart
_ExceptionVectorsStart: /* Used if relocating the exception vectors */
/*
* System reset - call debugger
*/
HANDLER(100, EXC_RESET)
/*
* Machine check (physical bus error) - call debugger
*/
HANDLER(200, EXC_MACHINE_CHECK)
/*
* Data access - page fault, invalid memory rights for operation
*/
HANDLER2(300, EXC_DATA_ACCESS, _MMU)
/*
* Instruction access - as for data access
*/
HANDLER2(400,EXC_INSTRUCTION_ACCESS, _MMU)
/*
* External interrupt
*/
HANDLER(500,EXC_INTERRUPT)
/*
* Alignment - many reasons
*/
HANDLER(600,EXC_ALIGNMENT)
/*
* Program - floating point exception, illegal inst, priv inst, user trap
*/
HANDLER2(700, EXC_PROGRAM, _BLUE_FAST_TRAP)
/*
* Program - floating point disabled, illegal inst, priv inst, user trap
*/
HANDLER(800,EXC_FP_UNAVAILABLE)
/*
* Decrementer - DEC register has passed zero.
*/
HANDLER(900,EXC_DECREMENTER)
/*
* I/O controller interface error - MACH does not use this
* (601 only)
*/
HANDLER(a00,EXC_IO_ERROR)
/*
* Reserved
*/
HANDLER(b00,EXC_RESERVED_0B)
/*
* System call - generated by the sc instruction
*/
HANDLER(c00,EXC_SYSTEM_CALL)
/*
* Trace - generated by single stepping
* (603, 603e and 604)
*/
HANDLER(d00,EXC_TRACE)
/*
* Floating point assist
*/
HANDLER(e00,EXC_FP_ASSIST)
/*
* Performance monitoring interrupt (Not implemented yet)
* (604)
*/
HANDLER(f00,EXC_PERFORMANCE_MON)
/*
* Instruction translation miss - we inline this code.
* (603, 603e only)
*
* Upon entry (done for us by the machine):
* srr0 : addr of instruction that missed
* srr1 : bits 0-3 = saved CR0
* 4 = lru way bit
* 16-31 = saved msr
* msr[tgpr] = 1 (so gpr0-3 become our temporary variables)
* imiss: ea that missed
* icmp : the compare value for the va that missed
* hash1: pointer to first hash pteg
* hash2: pointer to 2nd hash pteg
*
* Register usage:
* tmp0: saved counter
* tmp1: junk
* tmp2: pointer to pteg
* tmp3: current compare value
*
* This code is taken from the 603e User's Manual with
* some bugfixes and minor improvements to save bytes and cycles
*/
L_handler1000:
. = 0x1000
mfspr tmp2, hash1
mfctr tmp0 /* use tmp0 to save ctr */
mfspr tmp3, icmp
.L_imiss_find_pte_in_pteg:
li tmp1, 8 /* count */
subi tmp2, tmp2, 8 /* offset for lwzu */
mtctr tmp1 /* count... */
.L_imiss_pteg_loop:
lwz tmp1, 8(tmp2) /* check pte0 for match... */
addi tmp2, tmp2, 8
cmpw CR0, tmp1, tmp3
#if 0
bdnzf+ CR0+lt, .L_imiss_pteg_loop
#else
bc 0, 2, .L_imiss_pteg_loop
#endif
beq+ CR0, .L_imiss_found_pte
/* Not found in PTEG, we must scan 2nd then give up */
andi. tmp1, tmp3, MASK(PTE0_HASH_ID)
bne- .L_imiss_do_no_hash_exception /* give up */
mfspr tmp2, hash2
ori tmp3, tmp3, MASK(PTE0_HASH_ID)
b .L_imiss_find_pte_in_pteg
.L_imiss_found_pte:
lwz tmp1, 4(tmp2) /* get pte1_t */
andi. tmp3, tmp1, MASK(PTE1_WIMG_GUARD) /* Fault? */
bne- .L_imiss_do_prot_exception /* Guarded - illegal */
/* Ok, we've found what we need to, restore and rfi! */
mtctr tmp0 /* restore ctr */
mfsrr1 tmp3
mfspr tmp0, imiss
mtcrf 0x80, tmp3 /* Restore CR0 */
mtspr rpa, tmp1 /* set the pte */
ori tmp1, tmp1, MASK(PTE1_REFERENCED) /* set referenced */
tlbli tmp0
sth tmp1, 6(tmp2)
rfi
.L_imiss_do_prot_exception:
/* set up srr1 to indicate protection exception... */
mfsrr1 tmp3
andi. tmp2, tmp3, 0xffff
addis tmp2, tmp2, MASK(SRR1_TRANS_PROT) >> 16
b .L_imiss_do_exception
.L_imiss_do_no_hash_exception:
/* clean up registers for protection exception... */
mfsrr1 tmp3
andi. tmp2, tmp3, 0xffff
addis tmp2, tmp2, MASK(SRR1_TRANS_HASH) >> 16
/* And the entry into the usual instruction fault handler ... */
.L_imiss_do_exception:
mtctr tmp0 /* Restore ctr */
mtsrr1 tmp2 /* Set up srr1 */
mfmsr tmp0
xoris tmp0, tmp0, MASK(MSR_TGPR)>>16 /* no TGPR */
mtcrf 0x80, tmp3 /* Restore CR0 */
mtmsr tmp0 /* reset MSR[TGPR] */
ba 0x400 /* Instr Access */
/*
* Data load translation miss
* (603, 603e only)
*
* Upon entry (done for us by the machine):
* srr0 : addr of instruction that missed
* srr1 : bits 0-3 = saved CR0
* 4 = lru way bit
* 5 = 1 if store
* 16-31 = saved msr
* msr[tgpr] = 1 (so gpr0-3 become our temporary variables)
* dmiss: ea that missed
* dcmp : the compare value for the va that missed
* hash1: pointer to first hash pteg
* hash2: pointer to 2nd hash pteg
*
* Register usage:
* tmp0: saved counter
* tmp1: junk
* tmp2: pointer to pteg
* tmp3: current compare value
*
* This code is taken from the 603e User's Manual with
* some bugfixes and minor improvements to save bytes and cycles
*/
L_handler1100:
. = 0x1100
mfspr tmp2, hash1
mfctr tmp0 /* use tmp0 to save ctr */
mfspr tmp3, dcmp
.L_dlmiss_find_pte_in_pteg:
li tmp1, 8 /* count */
subi tmp2, tmp2, 8 /* offset for lwzu */
mtctr tmp1 /* count... */
.L_dlmiss_pteg_loop:
lwz tmp1, 8(tmp2) /* check pte0 for match... */
addi tmp2, tmp2, 8
cmpw CR0, tmp1, tmp3
#if 0
bdnzf+ CR0+lt, .L_dlmiss_pteg_loop
#else
bc 0,2, .L_dlmiss_pteg_loop
#endif
beq+ CR0, .L_dmiss_found_pte
/* Not found in PTEG, we must scan 2nd then give up */
andi. tmp1, tmp3, MASK(PTE0_HASH_ID) /* already at 2nd? */
bne- .L_dmiss_do_no_hash_exception /* give up */
mfspr tmp2, hash2
ori tmp3, tmp3, MASK(PTE0_HASH_ID)
b .L_dlmiss_find_pte_in_pteg
.L_dmiss_found_pte:
lwz tmp1, 4(tmp2) /* get pte1_t */
/* Ok, we've found what we need to, restore and rfi! */
mtctr tmp0 /* restore ctr */
mfsrr1 tmp3
mfspr tmp0, dmiss
mtcrf 0x80, tmp3 /* Restore CR0 */
mtspr rpa, tmp1 /* set the pte */
ori tmp1, tmp1, MASK(PTE1_REFERENCED) /* set referenced */
tlbld tmp0 /* load up tlb */
sth tmp1, 6(tmp2) /* sth is faster? */
rfi
/* This code is shared with data store translation miss */
.L_dmiss_do_no_hash_exception:
/* clean up registers for protection exception... */
mfsrr1 tmp3
/* prepare to set DSISR_WRITE_BIT correctly from srr1 info */
rlwinm tmp1, tmp3, 9, 6, 6
addis tmp1, tmp1, MASK(SRR1_TRANS_NO_PTE) >> 16
/* And the entry into the usual data fault handler ... */
mtctr tmp0 /* Restore ctr */
andi. tmp2, tmp3, 0xffff /* Clean up srr1 */
mtsrr1 tmp2 /* Set srr1 */
mtdsisr tmp1
mfspr tmp2, dmiss
mtdar tmp2
mfmsr tmp0
xoris tmp0, tmp0, MASK(MSR_TGPR)>>16 /* no TGPR */
mtcrf 0x80, tmp3 /* Restore CR0 */
sync
mtmsr tmp0 /* reset MSR[TGPR] */
ba 0x300 /* Data Access */
/*
* Data store translation miss (similar to data load)
* (603, 603e only)
*
* Upon entry (done for us by the machine):
* srr0 : addr of instruction that missed
* srr1 : bits 0-3 = saved CR0
* 4 = lru way bit
* 5 = 1 if store
* 16-31 = saved msr
* msr[tgpr] = 1 (so gpr0-3 become our temporary variables)
* dmiss: ea that missed
* dcmp : the compare value for the va that missed
* hash1: pointer to first hash pteg
* hash2: pointer to 2nd hash pteg
*
* Register usage:
* tmp0: saved counter
* tmp1: junk
* tmp2: pointer to pteg
* tmp3: current compare value
*
* This code is taken from the 603e User's Manual with
* some bugfixes and minor improvements to save bytes and cycles
*/
L_handler1200:
. = 0x1200
mfspr tmp2, hash1
mfctr tmp0 /* use tmp0 to save ctr */
mfspr tmp3, dcmp
.L_dsmiss_find_pte_in_pteg:
li tmp1, 8 /* count */
subi tmp2, tmp2, 8 /* offset for lwzu */
mtctr tmp1 /* count... */
.L_dsmiss_pteg_loop:
lwz tmp1, 8(tmp2) /* check pte0 for match... */
addi tmp2, tmp2, 8
cmpw CR0, tmp1, tmp3
#if 0
bdnzf+ CR0+lt, .L_dsmiss_pteg_loop
#else
bc 0,2, .L_dsmiss_pteg_loop
#endif
beq+ CR0, .L_dsmiss_found_pte
/* Not found in PTEG, we must scan 2nd then give up */
andi. tmp1, tmp3, MASK(PTE0_HASH_ID) /* already at 2nd? */
bne- .L_dmiss_do_no_hash_exception /* give up */
mfspr tmp2, hash2
ori tmp3, tmp3, MASK(PTE0_HASH_ID)
b .L_dsmiss_find_pte_in_pteg
.L_dsmiss_found_pte:
lwz tmp1, 4(tmp2) /* get pte1_t */
andi. tmp3, tmp1, MASK(PTE1_CHANGED) /* unchanged, check? */
beq- .L_dsmiss_check_prot /* yes, check prot */
.L_dsmiss_resolved:
/* Ok, we've found what we need to, restore and rfi! */
mtctr tmp0 /* restore ctr */
mfsrr1 tmp3
mfspr tmp0, dmiss
mtcrf 0x80, tmp3 /* Restore CR0 */
mtspr rpa, tmp1 /* set the pte */
tlbld tmp0 /* load up tlb */
rfi
.L_dsmiss_check_prot:
/* PTE is unchanged, we must check that we can write */
rlwinm. tmp3, tmp1, 30, 0, 1 /* check PP[1] */
bge- .L_dsmiss_check_prot_user_kern
andi. tmp3, tmp1, 1 /* check PP[0] */
beq+ .L_dsmiss_check_prot_ok
.L_dmiss_do_prot_exception:
/* clean up registers for protection exception... */
mfsrr1 tmp3
/* prepare to set DSISR_WRITE_BIT correctly from srr1 info */
rlwinm tmp1, tmp3, 9, 6, 6
addis tmp1, tmp1, MASK(SRR1_TRANS_NO_PTE) >> 16
/* And the entry into the usual data fault handler ... */
mtctr tmp0 /* Restore ctr */
andi. tmp2, tmp3, 0xffff /* Clean up srr1 */
mtsrr1 tmp2 /* Set srr1 */
mtdsisr tmp1
mfspr tmp2, dmiss
mtdar tmp2
mfmsr tmp0
xoris tmp0, tmp0, MASK(MSR_TGPR)>>16 /* no TGPR */
mtcrf 0x80, tmp3 /* Restore CR0 */
sync
mtmsr tmp0 /* reset MSR[TGPR] */
ba 0x300 /* Data Access */
/* NB - if we knew we were on a 603e we could test just the MSR_KEY bit */
.L_dsmiss_check_prot_user_kern:
mfsrr1 tmp3
andi. tmp3, tmp3, MASK(MSR_PR)
beq+ .L_dsmiss_check_prot_kern
mfspr tmp3, dmiss /* check user privs */
mfsrin tmp3, tmp3 /* get excepting SR */
andis. tmp3, tmp3, 0x2000 /* Test SR ku bit */
beq+ .L_dsmiss_check_prot_ok
b .L_dmiss_do_prot_exception
.L_dsmiss_check_prot_kern:
mfspr tmp3, dmiss /* check kern privs */
mfsrin tmp3, tmp3
andis. tmp3, tmp3, 0x4000 /* Test SR Ks bit */
bne- .L_dmiss_do_prot_exception
.L_dsmiss_check_prot_ok:
/* Ok, mark as referenced and changed before resolving the fault */
ori tmp1, tmp1, (MASK(PTE1_REFERENCED)|MASK(PTE1_CHANGED))
sth tmp1, 6(tmp2)
b .L_dsmiss_resolved
/*
* Instruction address breakpoint
* (603, 603e and 604)
*
*/
HANDLER(1300,EXC_INSTRUCTION_BKPT)
/*
* System management interrupt
* (603, 603e and 604)
*/
HANDLER(1400,EXC_SYSTEM_MANAGEMENT)
/*
* There is now a large gap of reserved traps
*/
HANDLER(1500,EXC_RESERVED_15)
HANDLER(1600,EXC_RESERVED_16)
HANDLER(1700,EXC_RESERVED_17)
HANDLER(1800,EXC_RESERVED_18)
HANDLER(1900,EXC_RESERVED_19)
HANDLER(1a00,EXC_RESERVED_1A)
HANDLER(1b00,EXC_RESERVED_1B)
HANDLER(1c00,EXC_RESERVED_1C)
HANDLER(1d00,EXC_RESERVED_1D)
HANDLER(1e00,EXC_RESERVED_1E)
HANDLER(1f00,EXC_RESERVED_1F)
/*
* Run mode/ trace exception - single stepping on 601 processors
* (601 only)
*/
HANDLER(2000,EXC_RUNMODE_TRACE)
/*
* There is another large gap of reserved traps
*/
HANDLER(2100,EXC_RESERVED_21)
HANDLER(2200,EXC_RESERVED_22)
HANDLER(2300,EXC_RESERVED_23)
HANDLER(2400,EXC_RESERVED_24)
HANDLER(2500,EXC_RESERVED_25)
HANDLER(2600,EXC_RESERVED_26)
HANDLER(2700,EXC_RESERVED_27)
HANDLER(2800,EXC_RESERVED_28)
HANDLER(2900,EXC_RESERVED_29)
HANDLER(2a00,EXC_RESERVED_2A)
HANDLER(2b00,EXC_RESERVED_2B)
HANDLER(2c00,EXC_RESERVED_2C)
HANDLER(2d00,EXC_RESERVED_2D)
HANDLER(2e00,EXC_RESERVED_2E)
HANDLER(2f00,EXC_RESERVED_2F)
/* Remember that at 0x3000 is just past the end of the trap table */
. = 0x3000
/*
* L_exception_entry(type)
*
* This is the common exception handling routine called by any
* type of system exception. (except 603 translation miss exceptions)
*
* Entry: via a system exception handler, thus interrupts off, VM off.
* Entry r1-r3 have been saved in sprg1-3.
* r2 - byte offset into per_proc_info of this CPU
* r3 - contains the exception number.
*
* Exit: srr0 and srr1 saved in per_proc_info structure
* r3 (supplied) saved in per_proc_info structure
* cr saved in per_proc_info structure
* original r1-3 saved in sprg1-3.
* r1 - is scratch
* r2 - byte offset into per_proc_info of this CPU
* r3 -contains exception info as for entry
*
* The exception handler is entered with
* VM on, interrupts still switched off
*/
L_exception_entry:
/* Save SRR0 and SRR1 plus cr and r3 into PER_PROC structure */
stw r3, PP_SAVE_EXCEPTION_TYPE(r2)
mfsrr0 r1
mfsrr1 r3
stw r1, PP_SAVE_SRR0(r2)
stw r3, PP_SAVE_SRR1(r2)
mfdar r1
mfdsisr r3
stw r1, PP_SAVE_DAR(r2)
stw r3, PP_SAVE_DSISR(r2)
mfcr r1
stw r1, PP_SAVE_CR(r2)
.L_Common:
/* Remap the kernel using seg reg 0, and I/O via seg reg 5 */
lis r3, (KERNEL_SEG_REG0_VALUE >> 16)
#if PPC_SID_KERNEL != 0
/* if PPC_SID_KERNEL == 0, then bottom 16 bits are 0,
* so save an instruction - big deal
*/
ori r3, r3, (KERNEL_SEG_REG0_VALUE & 0xFFFF)
#endif
mtsr sr0, r3 /* Kernel SR0 */
ori r1, r3, 1 /* Kernel SR1 */
mtsr sr1, r1
ori r1, r3, 2
mtsr sr2, r1
ori r1, r3, 3
mtsr sr3, r1
/* jump into main handler code switching on VM at the same time */
/* We assume kernel data is mapped contiguously in physical
* memory, otherwise we need to switch on (at least) virtual data.
*/
lwz r3, PP_SAVE_EXCEPTION_TYPE(r2)
lwz r1, PP_PHYS_EXCEPTION_HANDLERS(r2)
lwzx r1, r1, r3
lwz r2, PP_VIRT_PER_PROC(r2)
mtsrr0 r1
li r1, MSR_SUPERVISOR_INT_OFF
mtsrr1 r1
rfi /* into the exception handler with VM on */
/*
* exception_exit(sr0,srr0,srr1)
*
* This is the trampoline code used when exiting into a foreign
* address space.
*
* NMGS TODO - can't we skip exception_exit by relying on translations
* NMGS TODO even after we've loaded sr0? Docs aren't clear. Using
* NMGS TODO 1-1 kernel text mapping would definately avoid this need.
*
* Entry : entry via rfi, MSR = MSR_VM_OFF
* r1-3 saved in sprg1-3
* r1 = user's sr0 - used to construct sr1 too
* r2 = user's srr0 (instruction pointer)
* r3 = user's srr1 (msr)
*
* Exit : this routine restores the users' space and rfis.
*/
.data
.align ALIGNMENT
.globl EXT(exception_exit)
EXT(exception_exit):
.long exception_exit_fn /* phys addr of fn */
.section __VECTORS, __interrupts
.align 2
exception_exit_fn:
mtsrr0 r2
mtsrr1 r3
mtsr sr0, r1 /* Restore user space SR0 */
ori r2, r1, 1
mtsr sr1, r2 /* Restore user space SR1 */
ori r2, r1, 2
mtsr sr2, r2
ori r2, r1, 3
mtsr sr3, r2
mfsprg r1, 1
mfsprg r2, 2
mfsprg r3, 3
rfi
/*
** Blue Box Fast Trap entry
**
** Entry: VM switched OFF
** Interrupts OFF
** Data/Inst Relocation OFF
** r1-r3 have been saved in sprg1-3.
** r2 - ptr to per_proc_info of this CPU
** r3 - contains the exception number.
**
**
*/
.align 5
L_BLUE_FAST_TRAP:
mfcr r1
stw r1, PP_SAVE_CR(r2)
/* Check for Trap program exception */
mfsrr1 r1
mtcrf 0x70, r1
// bt+ 12, EmulateUnimplementedInstructions
// bt 13, EmulatePrivilegedInstructions
bf 14, 1f
/* check for bluebox enabled */
lwz r1, PP_CPU_DATA(r2)
lwz r1, CPU_FLAGS(r1)
rlwinm. r1,r1,0,PCB_BB_BIT,PCB_BB_BIT
beq 1f /* exit if bb not enabled */
/* Now save some state for working room */
stw r4, PP_SAVE_R4(r2)
stw r5, PP_SAVE_R5(r2)
stw r6, PP_SAVE_R6(r2)
stw r7, PP_SAVE_R7(r2)
/* Turn on Data Reloction to get instruction */
mfmsr r1
ori r5, r1, MASK(MSR_DR)
mtmsr r5
isync
/* read in offending instruction */
mfsrr0 r6
lwz r7, 0(r6)
/* turn Data Relocation back off*/
mtmsr r1
isync
/* check the trap instruction */
xoris r6, r7, 0xFFF
cmplwi cr7, r6, 17
bge cr7, 2f
/*
** Once here
** r1-r3 -> sprg1-3
** r4-r7 -> PP_SAVE_R4-7
** cr -> PP_SAVE_CR
** r2 -> Per Processor Info Block
** r3 -> exception type
*/
stw r0, PP_SAVE_R0(r2)
mfspr r0, srr0
stw r0, PP_SAVE_SRR0(r2)
mfspr r0, srr1
stw r0, PP_SAVE_SRR1(r2)
mfsprg r0, 1
stw r0, PP_SAVE_R1(r2)
mfsprg r0, 2
stw r0, PP_SAVE_R2(r2)
mfsprg r0, 3
stw r0, PP_SAVE_R3(r2)
stw r8, PP_SAVE_R8(r2)
stw r9, PP_SAVE_R9(r2)
stw r10, PP_SAVE_R10(r2)
stw r11, PP_SAVE_R11(r2)
stw r12, PP_SAVE_R12(r2)
/*
** functions 0-15 -> Call
** 16 -> Exit
*/
cmplwi cr7, r6, 16
beq cr7, .L_ExitPseudoKernel
/*QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ
* void CallPseudoKernel ( void )
*
* This op provides a means of invoking the BlueBox PseudoKernel from a
* system (68k) or native (PPC) context while changing BlueBox interruption
* state atomically. As an added bonus, this op clobbers only r0 while leaving
* the rest of PPC user state registers intact.
*
* This op is invoked as follows:
* li r0, kCallPseudoKernelNumber // load this op's firmware call number
* sc // invoke CallPseudoKernel
* dc.l CallPseudoKernelDescriptorPtr // static pointer to CallPseudoK
ernelDescriptor
*
* NOTE: The CallPseudoKernelDescriptor and the word pointed to by
* intControlAddr must be locked, else this op will crash the kernel.
*
QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ*/
// word following the twi is the descriptor's address
lwz r3, PP_SAVE_SRR0(r2)
lwz r10, PP_SAVE_CR(r2) // setup r10 with CR
/* Turn on Data Relocation */
mtmsr r5
isync
lwz r3, 4(r3) // get descriptor's address
lwz r11, CPKD_INTCONTROLADDR(r3)
lwz r4, CPKD_PC(r3)
lwz r6, CPKD_NEWSTATE(r3)
lwz r7, CPKD_INTSTATEMASK(r3)
lwz r8, 0(r11) // get current interruption control word
// lwz r5, CPKD_GPR0(r3)
lwz r12, CPKD_SYSCONTEXTSTATE(r3)
andc r9, r8, r7 // remove current state
and r8, r8, r7 // extract current state
cmplw r8, r12 // test for entry from system context
or r9, r9, r6 // insert new state
bne .L_CallFromAlternateContext
.L_CallFromSystemContext:
lwz r6, CPKD_INTCR2SHIFT(r3)
lwz r7, CPKD_INTCR2MASK(r3)
srw r10, r10, r6 // position live CR2 from cr register as required
andc r9, r9, r7 // remove old backup CR2
and r10, r10, r7 // mask live CR2
or r9, r9, r10 // insert CR2 into backup CR2
b .L_CallContinue
.L_CallFromAlternateContext:
.L_CallContinue:
stw r9, 0(r11) // update interruption control word
/* turn Data Relocation back off*/
mtmsr r1
isync
/* introduce new pc and gr0 contents */
lwz r6, PP_SAVE_SRR1(r2)
stw r4, PP_SAVE_SRR0(r2)
// stw r5, PP_SAVE_R0(r2)
// insert updated fe0, fe1, se, and be bits into user msr
rlwimi r6, r6, 0, MSR_FE1_BIT, MSR_FE0_BIT
/* Disable FPU */
rlwinm r6, r6, 0, MSR_FP_BIT+1, MSR_FP_BIT-1
/* zero single step and branch step control in user msr */
stw r6, PP_SAVE_SRR1(r2) // update user msr
.L_BlueBoxCommonExit:
/*
** Restore State for Exit
*/
lwz r4, PP_SAVE_CR(r2)
stwcx. r4, 0, r2 /* clear existing reservation */
mtcr r4 /* update cr, it is live */
/* the trampoline code takes r1-r3 from sprg1-3, and uses r1-3
* as arguments */
lwz r0, PP_SAVE_R1(r2)
mtsprg 1, r0
lwz r0, PP_SAVE_R2(r2)
mtsprg 2, r0
lwz r0, PP_SAVE_R3(r2)
mtsprg 3, r0
lwz r0, PP_SAVE_R0(r2)
lwz r4, PP_SAVE_R4(r2)
lwz r5, PP_SAVE_R5(r2)
lwz r6, PP_SAVE_R6(r2)
lwz r7, PP_SAVE_R7(r2)
lwz r8, PP_SAVE_R8(r2)
lwz r9, PP_SAVE_R9(r2)
lwz r10, PP_SAVE_R10(r2)
lwz r11, PP_SAVE_R11(r2)
lwz r12, PP_SAVE_R12(r2)
/*
** Setup parameters for exit code
*/
mfsr r1, sr0
lwz r3, PP_SAVE_SRR1(r2) /* load the last register... */
lwz r2, PP_SAVE_SRR0(r2) /* For trampoline */
b exception_exit_fn
2:
lwz r7, PP_SAVE_R7(r2)
lwz r6, PP_SAVE_R6(r2)
lwz r5, PP_SAVE_R5(r2)
lwz r4, PP_SAVE_R4(r2)
1:
lwz r1, PP_SAVE_CR(r2)
mtcr r1
b L_exception_entry
/*QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ
* void ExitPseudoKernel ( ExitPseudoKernelDescriptorPtr exitDescriptor )
*
* This op provides a means of exiting from the BlueBox PseudoKernel to a
* user context while changing the BlueBox interruption state atomically.
* It also allows all of the user state PPC registers to be loaded.
*
* This op is invoked as follows:
* lwz r3, ExitPseudoKernelDescriptorPtr
* li r0, kCallPseudoKernelNumber // load this op's firmware call number
* sc // invoke CallPseudoKernel
*
QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ*/
.L_ExitPseudoKernel:
/* Turn on Data Relocation */
mtmsr r5
isync
/* start of actual routine */
//mfspr r9, srr1
lwz r9, PP_SAVE_SRR1(r2)
//mfsprg r3, 3 // restore r3, it is exitdescptr
lwz r3, PP_SAVE_R3(r2)
lwz r8, EPKD_CR(r3)
lwz r11, EPKD_INTCONTROLADDR(r3)
lwz r4, EPKD_PC(r3)
lwz r7, EPKD_NEWSTATE(r3)
lwz r10, EPKD_INTSTATEMASK(r3)
lwz r5, 0(r11) // get current interruption control word
lwz r0, EPKD_SYSCONTEXTSTATE(r3)
andc r12, r5, r10 // remove current state
cmplw r7, r0 // test for exit to system context
or r12, r12, r7 // insert new state
lwz r0, EPKD_MSRUPDATE(r3)
beq .L_ExitToSystemContext
.L_ExitToAlternateContext:
lwz r5, EPKD_INTPENDINGMASK(r3)
lwz r6, EPKD_INTPENDINGPC(r3)
and. r7, r12, r5 // test for pending 'rupt in backup cr2
beq .L_ExitUpdateRuptControlWord // and enter alternate context if none pending
mr r4, r6 // otherwise, introduce entry abort pc
b .L_ExitNoUpdateRuptControlWord // and prepare to reenter pseudokernel
.L_ExitToSystemContext:
lwz r5, EPKD_INTCR2SHIFT(r3)
lwz r6, EPKD_INTCR2MASK(r3)
slw r7, r12, r5 // position backup cr2
and r7, r7, r6 // and mask it
or r8, r8, r7 // then or it into the live cr2
// ...fall through into system context
.L_ExitUpdateRuptControlWord:
rlwimi r9, r0, 0, MSR_FE0_BIT, MSR_FE1_BIT
/* Disable FPU */
rlwinm r9, r9, 0, MSR_FP_BIT+1, MSR_FP_BIT-1
// insert updated fe0, fe1, se, and be bits into user msr
stw r12, 0(r11) // update interruption control word
.L_ExitNoUpdateRuptControlWord:
lwz r5, EPKD_GPR0(r3)
lwz r6, EPKD_SP(r3)
lwz r7, EPKD_GPR3(r3)
/* turn Data Relocation back off */
mtmsr r1
isync
// load caller's new register content
stw r4, PP_SAVE_SRR0(r2)
stw r5, PP_SAVE_R0(r2)
stw r6, PP_SAVE_R1(r2)
stw r7, PP_SAVE_R3(r2)
stw r8, PP_SAVE_CR(r2)
stw r9, PP_SAVE_SRR1(r2)
b .L_BlueBoxCommonExit
#if 1
/*
** EmulateUnimplementedInstructions
**
** Entry r1-r3 have been saved in sprg1-3.
** r2 - byte offset into per_proc_info of this CPU
** r3 - contains the exception number.
** cr saved in per_proc_info structure
**
*/
EmulatePrivilegedInstructions:
EmulateUnimplementedInstructions:
stw r0,PP_SAVE_R0+( 0*4)(r2)
stmw r4,PP_SAVE_R0+( 4*4)(r2)
//la UnimpMQptr,RegMQ(ContextPtr)
//lwz ContextPtr,XCP_GPR_0_31+(ContextPtr*4)(KernelDataPtr)
#if CountExceptions
// Assume that the instruction will be emulated, so increment the count.
//lwz DataTemp,NI+EmulatedUnimpInstCount(KernelDataPtr)
//lwz MemProcPtr,MemProcBasePtr(KernelDataPtr)
//addi DataTemp,DataTemp,1
//stw DataTemp,NI+EmulatedUnimpInstCount(KernelDataPtr)
#else
//lwz MemProcPtr,MemProcBasePtr(KernelDataPtr)
#endif
mfmsr MSR_Disabled
//ori MSR_Enabled,MSR_Disabled,msr_dr
ori MSR_Enabled,MSR_Disabled,MASK(MSR_DR)
mtmsr MSR_Enabled // enable Data Relocation
isync
lwz MemInstr,0(SavedSRR0) // read the faulty instruction
mtmsr MSR_Disabled // disable data relocation
isync
//rlwinm DataTemp,MemInstr,6,0x000003F // get Opcode field
rlwinm DataTemp,MemInstr,6,26,31 // get Opcode field
cmpwi cr6,DataTemp,9
cmpwi cr0,DataTemp,22
cmpwi cr1,DataTemp,31
//lwz MemDataH,UnimpDefaults(KernelDataPtr)
lis MemDataH,0xFFFF
ori MemDataH,MemDataH,0xFFFF
//rlwinm MemDataL,MemCtxFlags,b_CtxFlagEmulatePowerCompatible-b_EmulatePOWERmaskLSB,1<<(31-b_EmulatePOWERmaskLSB)
rlwinm MemDataL,MemCtxFlags,b_CtxFlagEmulatePowerCompatible-b_EmulatePOWERmaskLSB,14,14)
neg MemDataL,MemDataL
//rlwimi MemDataL,MemCtxFlags,b_CtxFlagEmulateOptionalInstr-b_EmulateOptional,1<<(31-b_EmulateOptional)
rlwimi MemDataL,MemCtxFlags,b_CtxFlagEmulateOptionalInstr-b_EmulateOptional,16,16)
or MemDataL,MemDataL,MemDataH
//rlwimi MemDataL,MemInstr,0,0x000007FF
rlwimi MemDataL,MemInstr,0,21,31
//rlwimi MemCtxFlags,MemCtxFlags,(b_CtxFlagStepTraceEnabled-b_CtxFlagTracePending)&0x1F,1<<(31-b_CtxFlagTracePending)
rlwimi MemCtxFlags,MemCtxFlags,(b_CtxFlagStepTraceEnabled-b_CtxFlagTracePending)&0x1F,b_CtxFlagTracePending,b_CtxFlagTracePending)
//rlwinm UnimpRSRT,MemInstr,13+0,0x0000007C
rlwinm UnimpRSRT,MemInstr,13+0,25,29
//rlwinm UnimpRA,MemInstr,13+5,0x0000007C
rlwinm UnimpRA,MemInstr,13+5,25,29
// 001001 rt-rt ra-ra si-si si-si si-si s dozi rt,ra,si
beq cr6,EmulateDOZI
mtcrf 0x3F,MemDataL
//rlwinm UnimpRB,MemInstr,13+10,0x0000007C
rlwinm UnimpRB,MemInstr,13+10,25,29
// 010110 rs-rs ra-ra rb-rb mb-mb me-me . rlmi[.] ra,rs,rb,mb,me
beq cr0,EmulateRLMI
bne cr1,EmulateOp31done
//rlwinm MemDataL,MemInstr,2,0x000000F8 // low 5 bits of XO field * 8
rlwinm MemDataL,MemInstr,2,24,28 // low 5 bits of XO field * 8
add MemDataL,MemDataL,MemProcPtr
// lwz MemDataH,EmulateOp31Lookup+0-MemProcBase(MemDataL)
//rlwinm DataTemp,MemInstr,26,0x0000001F // high 5 bits of XO field
rlwinm DataTemp,MemInstr,26,27,31 // high 5 bits of XO field
// lwz MemDataL,EmulateOp31Lookup+4-MemProcBase(MemDataL)
rotlw. MemDataH,MemDataH,DataTemp // see if supported XO field
add MemDataL,MemDataL,MemProcPtr // compute routine address
mtlr MemDataL
bltlr // dispatch to supported proc
EmulateOp31done:
// 100001 rt-rt ra-ra d---d d---d d---d d lwzu rt,d(ra)
// 100011 rt-rt ra-ra d---d d---d d---d d lbzu rt,d(ra)
// 100101 rs-rs ra-ra d---d d---d d---d d stwu rs,d(ra)
// 100111 rs-rs ra-ra d---d d---d d---d d stbu rs,d(ra)
// 101001 rt-rt ra-ra d---d d---d d---d d lhzu rt,d(ra)
// 101011 rt-rt ra-ra d---d d---d d---d d lhau rt,d(ra)
// 101101 rs-rs ra-ra d---d d---d d---d d sthu rs,d(ra)
// 101110 rt-rt ra-ra d---d d---d d---d d lmw rt,d(ra)
// 110001 ft-ft ra-ra d---d d---d d---d d lfsu ft,d(ra)
// 110011 ft-ft ra-ra d---d d---d d---d d lfdu ft,d(ra)
// 110101 fs-fs ra-ra d---d d---d d---d d stfsu fs,d(ra)
// 110111 fs-fs ra-ra d---d d---d d---d d stfdu fs,d(ra)
ble cr1,EmulateILLEGAL // primary opcode <= 31 are illegal
lis MemDataH,0x55565500>>16 // mask for valid primary opcodes
ori MemDataH,MemDataH,0x55565500&0xFFFF
rotlw. MemDataH,MemDataH,DataTemp // see if this opcode is legal
blt EmulatePowerMemoryInvalidForm // if legal opcode, must be invalid form
EmulateILLEGAL:
EmulateDisabledPowerMQ:
EmulateDisabledPowerRTC:
EmulateDisabledPowerDEC:
EmulateDisabledPowerComplex:
EmulateDisabledInvalidSPR:
EmulateDisabledPowerCLCS:
EmulateDisabledPowerMemory:
EmulateDisabledOptional:
mtcrf 0x70,SavedSRR1 // test SRR1 flags for original cause
li Tmp1,ecInvalidInstr // invalid instruction
bf 13,GenerateInvalidInstructionException // If not privileged, use ecInvalidInstr
EmulatePRIVILEGED:
mtcrf 0x0F,SavedSRR1 // test SRR1 flags for PR bit
li Tmp1,ecInvalidInstr // invalid instruction
// bf b_msr_pr,GenerateInvalidInstructionException // If privileged, use ecInvalidInstr
li Tmp1,ecPrivilegedInstr // privileged instruction
GenerateInvalidInstructionException:
#if CountExceptions
// The instruction was really invalid, so decrement the emulated instruction count.
//lwz Tmp2,NI+EmulatedUnimpInstCount(KernelDataPtr)
//lmw r14,XCP_GPR_0_31+(14*4)(KernelDataPtr)
subi Tmp2,Tmp2,1
//stw Tmp2,NI+EmulatedUnimpInstCount(KernelDataPtr)
#else
//lmw r14,XCP_GPR_0_31+(14*4)(KernelDataPtr)
#endif
// lwz ContextPtr,ActiveContextPtr(KernelDataPtr)
// lwz ContextStateFlags,ActiveCtxFlags(KernelDataPtr)
b GenerateException // call the exception handler
EmulateOp31Lookup:
.long 0x00000000,EmulateILLEGAL-MemProcBase // 00
.long 0x00000000,EmulateILLEGAL-MemProcBase // 01
.long 0x00000000,EmulateILLEGAL-MemProcBase // 02
.long 0x00000000,EmulateILLEGAL-MemProcBase // 03
.long 0x00000000,EmulateILLEGAL-MemProcBase // 04
.long 0x00000000,EmulateILLEGAL-MemProcBase // 05
.long 0x00000000,EmulateILLEGAL-MemProcBase // 06
.long 0x00000000,EmulateILLEGAL-MemProcBase // 07
// 011111 rt-rt ra-ra rb-rb 01000 01000 . doz[.] rt,ra,rb
// 011111 rt-rt ra-ra xxxxx 01011 01000 . abs[.] rt,ra
// 011111 rt-rt ra-ra xxxxx 01111 01000 . nabs[.] rt,ra
// 011111 rt-rt ra-ra rb-rb 11000 01000 . dozo[.] rt,ra,rb
// 011111 rt-rt ra-ra xxxxx 11011 01000 . abso[.] rt,ra
// 011111 rt-rt ra-ra xxxxx 11111 01000 . nabso[.] rt,ra
.long 0x00910091,EmulateDOZ_ABS_NABS-MemProcBase // 08
.long 0x00000000,EmulateILLEGAL-MemProcBase // 09
.long 0x00000000,EmulateILLEGAL-MemProcBase // 0A
// 011111 rt-rt ra-ra rb-rb 00011 01011 . mul[.] rt,ra,rb
// 011111 rt-rt ra-ra rb-rb 01010 01011 . div[.] rt,ra,rb
// 011111 rt-rt ra-ra rb-rb 01011 01011 . divs[.] rt,ra,rb
// 011111 rt-rt ra-ra rb-rb 10011 01011 . mulo[.] rt,ra,rb
// 011111 rt-rt ra-ra rb-rb 11010 01011 . divo[.] rt,ra,rb
// 011111 rt-rt ra-ra rb-rb 11011 01011 . divso[.] rt,ra,rb
.long 0x10301030,EmulateMUL_DIV_DIVS-MemProcBase // 0B
.long 0x00000000,EmulateILLEGAL-MemProcBase // 0C
.long 0x00000000,EmulateILLEGAL-MemProcBase // 0D
.long 0x00000000,EmulateILLEGAL-MemProcBase // 0E
.long 0x00000000,EmulateILLEGAL-MemProcBase // 0F
.long 0x00000000,EmulateILLEGAL-MemProcBase // 10
.long 0x00000000,EmulateILLEGAL-MemProcBase // 11
.long 0x00000000,EmulateILLEGAL-MemProcBase // 12
// 011111 rt-rt 00000 xxxxx 01010 10011 x mfmq rt
// 011111 rt-rt 00001 xxxxx 01010 10011 x mfxer rt
// 011111 rt-rt 00010 xxxxx 01010 10011 x mfspr rt,0x2
// 011111 rt-rt 00011 xxxxx 01010 10011 x mfspr rt,0x3
// 011111 rt-rt 00100 xxxxx 01010 10011 x mfrtcu rt
// 011111 rt-rt 00101 xxxxx 01010 10011 x mfrtcl rt
// 011111 rt-rt 00110 xxxxx 01010 10011 x mfdec rt
// 011111 rt-rt 00111 xxxxx 01010 10011 x mfspr rt,0x7
// 011111 rt-rt 01000 xxxxx 01010 10011 x mflr rt
// 011111 rt-rt 01001 xxxxx 01010 10011 x mfctr rt
// 011111 rt-rt 01010 xxxxx 01010 10011 x mfspr rt,0xA
// 011111 rt-rt 01011 xxxxx 01010 10011 x mfspr rt,0xB
// 011111 rt-rt 01100 xxxxx 01010 10011 x mfspr rt,0xC
// 011111 rt-rt 01101 xxxxx 01010 10011 x mfspr rt,0xD
// 011111 rt-rt 01110 xxxxx 01010 10011 x mfspr rt,0xE
// 011111 rt-rt 01111 xxxxx 01010 10011 x mfspr rt,0xF
// 011111 rt-rt 11111 01000 01010 10011 x mfspr rt,287
// 011111 rt-rt 11000 11101 01010 10011 x mfspr rt,952
// 011111 rt-rt 11001 11101 01010 10011 x mfspr rt,953
// 011111 rt-rt 11010 11101 01010 10011 x mfspr rt,954
// 011111 rt-rt 11011 11101 01010 10011 x mfspr rt,955
// 011111 rt-rt 11100 11101 01010 10011 x mfspr rt,956
// 011111 rt-rt 11101 11101 01010 10011 x mfspr rt,957
// 011111 rt-rt 11110 11101 01010 10011 x mfspr rt,958
// 011111 rt-rt 11111 11101 01010 10011 x mfspr rt,959
// 011111 rt-rt 01100 01000 01011 10011 x mftb rt
// 011111 rt-rt 01101 01000 01011 10011 x mftbu rt
// 011111 rs-rs 00000 xxxxx 01110 10011 x mtmq rs
// 011111 rs-rs 00001 xxxxx 01110 10011 x mtxer rs
// 011111 rs-rs 00010 xxxxx 01110 10011 x mtspr 0x2,rs
// 011111 rs-rs 00011 xxxxx 01110 10011 x mtspr 0x3,rs
// 011111 rs-rs 00100 xxxxx 01110 10011 x mtspr 0x4,rs
// 011111 rs-rs 00101 xxxxx 01110 10011 x mtspr 0x5,rs
// 011111 rs-rs 00110 xxxxx 01110 10011 x mtspr 0x6,rs
// 011111 rs-rs 00111 xxxxx 01110 10011 x mtspr 0x7,rs
// 011111 rs-rs 01000 xxxxx 01110 10011 x mtlr rs
// 011111 rs-rs 01001 xxxxx 01110 10011 x mtctr rs
// 011111 rs-rs 01010 xxxxx 01110 10011 x mtspr 0xA,rs
// 011111 rs-rs 01011 xxxxx 01110 10011 x mtspr 0xB,rs
// 011111 rs-rs 01100 xxxxx 01110 10011 x mtspr 0xC,rs
// 011111 rs-rs 01101 xxxxx 01110 10011 x mtspr 0xD,rs
// 011111 rs-rs 01110 xxxxx 01110 10011 x mtspr 0xE,rs
// 011111 rs-rs 01111 xxxxx 01110 10011 x mtspr 0xF,rs
// 011111 rs-rs 11000 11101 01110 10011 x mtspr 952,rs
// 011111 rs-rs 11001 11101 01110 10011 x mtspr 953,rs
// 011111 rs-rs 11010 11101 01110 10011 x mtspr 954,rs
// 011111 rs-rs 11011 11101 01110 10011 x mtspr 955,rs
// 011111 rs-rs 11100 11101 01110 10011 x mtspr 956,rs
// 011111 rs-rs 11101 11101 01110 10011 x mtspr 957,rs
// 011111 rs-rs 11110 11101 01110 10011 x mtspr 958,rs
// 011111 rs-rs 11111 11101 01110 10011 x mtspr 959,rs
// 011111 rt-rt ra-ra xxxxx 10000 10011 x clcs rt,ra
.long 0x00328000,EmulateMFSPR_MFTB_MTSPR_CLCS-MemProcBase // 13
.long 0x00000000,EmulateILLEGAL-MemProcBase // 14
// 011111 rt-rt ra-ra rb-rb 01000 10101 . lscbx[.] rt,ra,rb
// 011111 rt-rt ra-ra rb-rb 10000 10101 x lswx rt,ra,rb
// 011111 rt-rt ra-ra nb-nb 10010 10101 x lswi rt,ra,nb
.long 0x0080A000,EmulatePowerMemoryInvalidForm-MemProcBase // 15
.long 0x00000000,EmulateILLEGAL-MemProcBase // 16
// 011111 rt-rt ra-ra rb-rb 00001 10111 x lwzux rt,ra,rb
// 011111 rt-rt ra-ra rb-rb 00011 10111 x lbzux rt,ra,rb
// 011111 rs-rs ra-ra rb-rb 00101 10111 x stwux rs,ra,rb
// 011111 rs-rs ra-ra rb-rb 00111 10111 x stbux rs,ra,rb
// 011111 rt-rt ra-ra rb-rb 01001 10111 x lhzux rt,ra,rb
// 011111 rt-rt ra-ra rb-rb 01011 10111 x lhaux rt,ra,rb
// 011111 rs-rs ra-ra rb-rb 01101 10111 x sthux rs,ra,rb
// 011111 ft-ft ra-ra rb-rb 10001 10111 x lfsux ft,ra,rb
// 011111 ft-ft ra-ra rb-rb 10011 10111 x lfdux ft,ra,rb
// 011111 fs-fs ra-ra rb-rb 10101 10111 x stfsux fs,ra,rb
// 011111 fs-fs ra-ra rb-rb 10111 10111 x stfdux fs,ra,rb
// 011111 fs-fs ra-ra rb-rb 11110 10111 x stfiwx fs,ra,rb
.long 0x55545502,EmulateUpdateMemOps_STFIWX-MemProcBase // 17
// 011111 rs-rs ra-ra rb-rb 00100 11000 . slq[.] ra,rs,rb
// 011111 rs-rs ra-ra sh-sh 00101 11000 . sliq[.] ra,rs,sh
// 011111 rs-rs ra-ra rb-rb 00110 11000 . sllq[.] ra,rs,rb
// 011111 rs-rs ra-ra sh-sh 00111 11000 . slliq[.] ra,rs,sh
// 011111 rs-rs ra-ra rb-rb 10100 11000 . srq[.] ra,rs,rb
// 011111 rs-rs ra-ra sh-sh 10101 11000 . sriq[.] ra,rs,sh
// 011111 rs-rs ra-ra rb-rb 10110 11000 . srlq[.] ra,rs,rb
// 011111 rs-rs ra-ra sh-sh 10111 11000 . srliq[.] ra,rs,sh
// 011111 rs-rs ra-ra rb-rb 11100 11000 . sraq[.] ra,rs,rb
// 011111 rs-rs ra-ra sh-sh 11101 11000 . sraiq[.] ra,rs,sh
.long 0x0F000F0C,EmulateSHIFTQ-MemProcBase // 18
// 011111 rs-rs ra-ra rb-rb 00100 11001 . sle[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 00110 11001 . sleq[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 10000 11001 . rrib[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 10100 11001 . sre[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 10110 11001 . sreq[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 11100 11001 . srea[.] ra,rs,rb
.long 0x0A008A08,EmulateRRIB_SHIFTE-MemProcBase // 19
.long 0x00000000,EmulateILLEGAL-MemProcBase // 1A
.long 0x00000000,EmulateILLEGAL-MemProcBase // 1B
.long 0x00000000,EmulateILLEGAL-MemProcBase // 1C
// 011111 rs-rs ra-ra rb-rb 00000 11101 . maskg[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 10000 11101 . maskir[.] ra,rs,rb
.long 0x80008000,EmulateMASKG_MASKIR-MemProcBase // 1D
.long 0x00000000,EmulateILLEGAL-MemProcBase // 1E
.long 0x00000000,EmulateILLEGAL-MemProcBase // 1F
EmulateUpdateRT_cr0_xer_mq:
stw MemDataH,0(UnimpMQptr) // update MQ in context block
EmulateUpdateRT_cr0_xer: // update XER (live XER already updated)
EmulateUpdateRT_cr0:
bf 31,EmulateUpdateRT // test the Rc bit
mfcr DataTemp // get current CR0
//rlwimi SavedCR,DataTemp,0,0xF0000000 // update saved CR0
rlwimi SavedCR,DataTemp,0,0,3 // update saved CR0
EmulateUpdateRT:
stwx MemDataL,KernelDataPtr,UnimpRT // update RT
b CompleteMemOpDone // instruction emulation complete
EmulateDOZ_ABS_NABS:
// 1 11111 11112 22222 22223 3
// 012345 67890 12345 67890 12345 67890 1
// ------ ----- ----- ----- ----- ----- -
// 011111 rt-rt ra-ra rb-rb 01000 01000 . doz[.] rt,ra,rb
// 011111 rt-rt ra-ra xxxxx 01011 01000 . abs[.] rt,ra
// 011111 rt-rt ra-ra xxxxx 01111 01000 . nabs[.] rt,ra
// 011111 rt-rt ra-ra rb-rb 11000 01000 . dozo[.] rt,ra,rb
// 011111 rt-rt ra-ra xxxxx 11011 01000 . abso[.] rt,ra
// 011111 rt-rt ra-ra xxxxx 11111 01000 . nabso[.] rt,ra
bf b_EmulatePowerComplex,EmulateDisabledPowerComplex
lwzx UnimpRA,KernelDataPtr,UnimpRA // get RA
bf 24,EmulateDOZ
EmulateABS_NABS:
// 011111 rt-rt ra-ra xxxxx 01011 01000 . abs[.] rt,ra
// 011111 rt-rt ra-ra xxxxx 01111 01000 . nabs[.] rt,ra
// 011111 rt-rt ra-ra xxxxx 11011 01000 . abso[.] rt,ra
// 011111 rt-rt ra-ra xxxxx 11111 01000 . nabso[.] rt,ra
bt 21,EmulateABSO_NABSO
// 011111 rt-rt ra-ra xxxxx 01011 01000 . abs[.] rt,ra
// 011111 rt-rt ra-ra xxxxx 01111 01000 . nabs[.] rt,ra
mr. MemDataL,UnimpRA // get operand, update cr0
// crxor 23,23,lt // exchange abs with nabs if negative
crxor 23,23,lt_b // exchange abs with nabs if negative
bf 23,EmulateUpdateRT_cr0 // return unchanged result
neg. MemDataL,UnimpRA // negate operand, update cr0
b EmulateUpdateRT_cr0 // return negated result
EmulateABSO_NABSO:
// 011111 rt-rt ra-ra xxxxx 11011 01000 . abso[.] rt,ra
// 011111 rt-rt ra-ra xxxxx 11111 01000 . nabso[.] rt,ra
li MemDataL,0
addo. MemDataL,UnimpRA,MemDataL // get operand, clear OV, cr0
// crxor 23,23,lt // exchange abs with nabs if negative
crxor 23,23,lt_b // exchange abs with nabs if negative
bf 23,EmulateUpdateRT_cr0_xer // return unchanged result
nego. MemDataL,UnimpRA // negate operand, update OV, cr0
b EmulateUpdateRT_cr0_xer // return negated result
EmulateDOZI:
// 001001 rt-rt ra-ra si-si si-si si-si s dozi rt,ra,si
mtcrf 0x3F,MemDataL
bf b_EmulatePowerComplex,EmulateDisabledPowerComplex
lwzx UnimpRA,KernelDataPtr,UnimpRA // get RA
extsh UnimpRB,MemInstr // get SI
cmpw cr1,UnimpRB,UnimpRA // see if SI < RA
sub MemDataL,MemDataL,MemDataL // assume zero
blt cr1,EmulateUpdateRT // return zero when difference < zero
sub MemDataL,UnimpRB,UnimpRA // compute difference
b EmulateUpdateRT // return difference when >= zero
EmulateDOZ:
// 011111 rt-rt ra-ra rb-rb 01000 01000 . doz[.] rt,ra,rb
// 011111 rt-rt ra-ra rb-rb 11000 01000 . dozo[.] rt,ra,rb
lwzx UnimpRB,KernelDataPtr,UnimpRB // get RB
bt 21,EmulateDOZO
// 011111 rt-rt ra-ra rb-rb 01000 01000 . doz[.] rt,ra,rb
cmpw cr1,UnimpRB,UnimpRA // see if RB < RA
sub. MemDataL,MemDataL,MemDataL // assume zero
blt cr1,EmulateUpdateRT_cr0 // return zero when difference < zero
sub. MemDataL,UnimpRB,UnimpRA // compute difference
b EmulateUpdateRT_cr0 // return difference when >= zero
EmulateDOZO:
// 011111 rt-rt ra-ra rb-rb 11000 01000 . dozo[.] rt,ra,rb
cmpw cr1,UnimpRB,UnimpRA // see if RB < RA
subo. MemDataL,MemDataL,MemDataL // assume zero
blt cr1,EmulateUpdateRT_cr0_xer // return zero when difference < zero
subo. MemDataL,UnimpRB,UnimpRA // compute difference
b EmulateUpdateRT_cr0_xer // return difference when >= zero
EmulateMUL_DIV_DIVS:
// 1 11111 11112 22222 22223 3
// 012345 67890 12345 67890 12345 67890 1
// ------ ----- ----- ----- ----- ----- -
// 011111 rt-rt ra-ra rb-rb 00011 01011 . mul[.] rt,ra,rb
// 011111 rt-rt ra-ra rb-rb 01010 01011 . div[.] rt,ra,rb
// 011111 rt-rt ra-ra rb-rb 01011 01011 . divs[.] rt,ra,rb
// 011111 rt-rt ra-ra rb-rb 10011 01011 . mulo[.] rt,ra,rb
// 011111 rt-rt ra-ra rb-rb 11010 01011 . divo[.] rt,ra,rb
// 011111 rt-rt ra-ra rb-rb 11011 01011 . divso[.] rt,ra,rb
bf b_EmulatePowerMQ,EmulateDisabledPowerMQ
lwzx UnimpRB,KernelDataPtr,UnimpRB // get RB
lwzx UnimpRA,KernelDataPtr,UnimpRA // get RA
bf 22,EmulateMUL
// 011111 rt-rt ra-ra rb-rb 01010 01011 . div[.] rt,ra,rb
// 011111 rt-rt ra-ra rb-rb 01011 01011 . divs[.] rt,ra,rb
// 011111 rt-rt ra-ra rb-rb 11010 01011 . divo[.] rt,ra,rb
// 011111 rt-rt ra-ra rb-rb 11011 01011 . divso[.] rt,ra,rb
cmpwi cr1,UnimpRB,0 // anything / 00000000 is undefined
bt 25,EmulateDIVS
// 011111 rt-rt ra-ra rb-rb 01010 01011 . div[.] rt,ra,rb
// 011111 rt-rt ra-ra rb-rb 11010 01011 . divo[.] rt,ra,rb
lwz UnimpMQtmp,0(UnimpMQptr) // get MQ from context block
srwi MemDataL,UnimpMQtmp,31 // get Sign(MQ)
add. MemDataL,MemDataL,UnimpRA // see if RA=Sign(MQ)
bne EmulateDIV // perform complex 64 bit divide when RA<>Sign(MQ)
mr UnimpRA,UnimpMQtmp // perform 32 bit DIVS (MQ/RB) when RA=Sign(MQ)
EmulateDIVS:
// 011111 rt-rt ra-ra rb-rb 01011 01011 . divs[.] rt,ra,rb
// 011111 rt-rt ra-ra rb-rb 11011 01011 . divso[.] rt,ra,rb
cmpwi cr0,UnimpRB,-1 // 80000000 / FFFFFFFF is undefined
bt 21,EmulateDIVSO
// 011111 rt-rt ra-ra rb-rb 01011 01011 . divs[.] rt,ra,rb
beq cr0,EmulateDIVS_neg_one // handle RA / FFFFFFFF (just negate)
beq cr1,EmulateDIVS_zero // handle RA / 00000000
divw MemDataL,UnimpRA,UnimpRB // quotient <- RA / RB
EmulateDIVS_rem_calc:
mullw MemDataH,MemDataL,UnimpRB // quotient * RB
sub. MemDataH,UnimpRA,MemDataH // remainder <- RA - (quotient * RB)
b EmulateUpdateRT_cr0_xer_mq
EmulateDIVS_neg_one:
neg MemDataL,UnimpRA // quotient <- -RA
sub. MemDataH,UnimpRA,UnimpRA // remainder <- 00000000
b EmulateUpdateRT_cr0_xer_mq
EmulateDIVSO:
// 011111 rt-rt ra-ra rb-rb 11011 01011 . divso[.] rt,ra,rb
divwo MemDataL,UnimpRA,UnimpRB // quotient <- RA / RB, compute OV bit
beq cr0,EmulateDIVS_neg_one // handle RA / FFFFFFFF (just negate)
bne cr1,EmulateDIVS_rem_calc // compute remainder, unless RA / 00000000
EmulateDIVS_zero:
//rlwinm DataTemp,UnimpRA,2,0x00000002 // quotient <- 00000001 when RA < 0
rlwinm DataTemp,UnimpRA,2,30,30// quotient <- 00000001 when RA < 0
subi MemDataL,DataTemp,1 // quotient <- FFFFFFFF when RA >= 0
mr. MemDataH,UnimpRA // remainder <- RA
b EmulateUpdateRT_cr0_xer_mq
EmulateDIV:
mfxer UnimpXERtmp // save XER CA bit
beq cr1,EmulateDIV_zero // handle RA / 00000000
cmpwi cr0,UnimpRB,0 // test sign of RB
cmpwi cr1,UnimpRA,0 // test sign of RA
// crxor (cr1*4)+so,(cr0*4)+lt,(cr1*4)+lt// compute sign of quotient
crxor (rcr1*4)+so_b,(rcr0*4)+lt_b,(rcr1*4)+lt_b// compute sign of quotient
bge cr0,EmulateDIV_denom_ok // compute abs (RB)
neg UnimpRB,UnimpRB // UnimpRB <- abs (32 bit denom)
EmulateDIV_denom_ok:
bge cr1,EmulateDIV_numer_ok // compute abs (RA||MQ)
subfic UnimpMQtmp,UnimpMQtmp,0 // UnimpRA/UnimpMQtmp <- abs (64 bit numerator)
subfze UnimpRA,UnimpRA
EmulateDIV_numer_ok:
cmplw UnimpRA,UnimpRB // see if abs(quotient) fits in 32 bits
bge EmulateDIV_initial_ovfl // handle overflow
#if 0
// Slower, but smaller divide algorithm
mfctr DataTemp // save the CTR register
li MemDataL,32 // loop for 32 bits
mtctr MemDataL // setup the counter
EmulateDIV_shift:
slwi UnimpRA,UnimpRA,1 // shift 64 bit remainder
//rlwimi UnimpRA,UnimpMQtmp,1,0x00000001 // shift in MSB of low 32 bits
rlwimi UnimpRA,UnimpMQtmp,1,31,31 // shift in MSB of low 32 bits
cmplw UnimpRA,UnimpRB // Q = remainder >= denominator
slwi UnimpMQtmp,UnimpMQtmp,1 // shift in the quotient bit (assume Q=0)
blt EmulateDIV_q0 // branch when Q=0
EmulateDIV_q1:
sub UnimpRA,UnimpRA,UnimpRB // subtract denom from remainder
ori UnimpMQtmp,UnimpMQtmp,1 // set the quotient bit (Q=1)
EmulateDIV_q0:
bdnz EmulateDIV_shift // loop for 32 bits
mtctr DataTemp // restore the CTR register
mr MemDataH,UnimpRA // MemDataH <- remainder
#else
// about 1.5x faster, but bigger divide algorithm
cntlzw MemDataL,UnimpRB // MemDataL <- denominator shift amount
xor UnimpRA,UnimpRA,UnimpMQtmp // merge numerator halves for left shift
slw UnimpRB,UnimpRB,MemDataL // UnimpRB <- normalized denom
rotlw UnimpRA,UnimpRA,MemDataL // rotate numer.high xor numer.low
slw UnimpMQtmp,UnimpMQtmp,MemDataL // shift numer.low
xor UnimpRA,UnimpRA,UnimpMQtmp// UnimpRA/UnimpMQtmp <- left shifted numer.high/low
srwi DataTemp,UnimpRB,16 // get upper 16 bits of normalized denom
divwu MemDataH,UnimpRA,DataTemp // compute first 16 bits of quotient estimate
mullw DataTemp,MemDataH,DataTemp // quotient * upper(denom)
sub UnimpRA,UnimpRA,DataTemp// compute remainder using upper 16 bits of denom
slwi UnimpRA,UnimpRA,16 // shift remainder left by 16 bit
//rlwimi UnimpRA,UnimpMQtmp,16,0x0000FFFF
rlwimi UnimpRA,UnimpMQtmp,16,16,31
slwi UnimpMQtmp,UnimpMQtmp,16
//rlwinm DataTemp,UnimpRB,0,0x0000FFFF // get lower 16 bits of normalized denom
rlwinm DataTemp,UnimpRB,0,16,31// get lower 16 bits of normalized denom
mullw DataTemp,MemDataH,DataTemp // quotient * lower(denom)
subfc UnimpRA,DataTemp,UnimpRA // compute remainder using lower 16 bits of denom
subfe. DataTemp,DataTemp,DataTemp // compute borrow
add UnimpMQtmp,UnimpMQtmp,MemDataH // shift in quotient
bge EmulateDIV_compute_low
EmulateDIV_correct_high:
addc UnimpRA,UnimpRA,UnimpRB
addze. DataTemp,DataTemp
subi UnimpMQtmp,UnimpMQtmp,1
blt EmulateDIV_correct_high
EmulateDIV_compute_low:
srwi DataTemp,UnimpRB,16 // get upper 16 bits of normalized denom
divwu MemDataH,UnimpRA,DataTemp // compute next 16 bits of quotient estimate
mullw DataTemp,MemDataH,DataTemp // quotient * upper(denom)
sub UnimpRA,UnimpRA,DataTemp // compute remainder using upper 16 bits of denom
slwi UnimpRA,UnimpRA,16 // shift remainder left by 16 bit
//rlwimi UnimpRA,UnimpMQtmp,16,0x0000FFFF
rlwimi UnimpRA,UnimpMQtmp,16,16,31
slwi UnimpMQtmp,UnimpMQtmp,16
//rlwinm DataTemp,UnimpRB,0,0x0000FFFF // get lower 16 bits of normalized denom
rlwinm DataTemp,UnimpRB,0,16,31 // get lower 16 bits of normalized denom
mullw DataTemp,MemDataH,DataTemp // quotient * lower(denom)
subfc UnimpRA,DataTemp,UnimpRA // compute remainder using lower 16 bits of denom
subfe. DataTemp,DataTemp,DataTemp // compute borrow
add UnimpMQtmp,UnimpMQtmp,MemDataH // shift in quotient
bge EmulateDIV_low_done
EmulateDIV_correct_low:
addc UnimpRA,UnimpRA,UnimpRB
addze. DataTemp,DataTemp
subi UnimpMQtmp,UnimpMQtmp,1
blt EmulateDIV_correct_low
EmulateDIV_low_done:
srw MemDataH,UnimpRA,MemDataL // MemDataH <- remainder
#endif
EmulateDIV_correct_signs:
mr. MemDataL,UnimpMQtmp // MemDataL <- quotient
bge cr1,EmulateDIV_r_done
neg MemDataH,MemDataH
EmulateDIV_r_done:
bns cr1,EmulateDIV_q_done
neg. MemDataL,MemDataL
EmulateDIV_q_done:
bf 21,EmulateDIV_xer_done
// crxor (cr0*4)+lt,(cr0*4)+lt,(cr1*4)+so
crxor (rcr0*4)+lt_b,(rcr0*4)+lt_b,(rcr1*4)+so_b
//rlwinm UnimpXERtmp,UnimpXERtmp,0,0xBFFFFFFF// clear OV bit
rlwinm UnimpXERtmp,UnimpXERtmp,0,2,0 // clear OV bit
bge EmulateDIV_xer_done
oris UnimpXERtmp,UnimpXERtmp,0xC000 // set SO and OV bits
EmulateDIV_xer_done:
mtxer UnimpXERtmp // restore XER
mr. MemDataH,MemDataH
b EmulateUpdateRT_cr0_xer_mq
EmulateDIV_initial_ovfl:
// I can't figure out the 601 algorithm for undefined overflow quo/rem.
// Instead, return the values that would be computed for divide by zero.
EmulateDIV_zero:
bf 21,EmulateDIV_zero_xer_done
oris UnimpXERtmp,UnimpXERtmp,0xC000 // set SO and OV bits
EmulateDIV_zero_xer_done:
mtxer UnimpXERtmp // restore XER
not MemDataL,UnimpRA
srwi DataTemp,UnimpRA,31
mr. MemDataH,UnimpMQtmp
add MemDataL,DataTemp,MemDataL
b EmulateUpdateRT_cr0_xer_mq
EmulateMUL:
// 011111 rt-rt ra-ra rb-rb 00011 01011 . mul[.] rt,ra,rb
// 011111 rt-rt ra-ra rb-rb 10011 01011 . mulo[.] rt,ra,rb
mulhw MemDataL,UnimpRA,UnimpRB // RT <- low 32 bits of product
bt 21,EmulateMULO
// 011111 rt-rt ra-ra rb-rb 00011 01011 . mul[.] rt,ra,rb
mullw. MemDataH,UnimpRA,UnimpRB // MQ <- high 32 bits of product
b EmulateUpdateRT_cr0_xer_mq
EmulateMULO:
// 011111 rt-rt ra-ra rb-rb 10011 01011 . mulo[.] rt,ra,rb
mullwo. MemDataH,UnimpRA,UnimpRB // MQ <- high 32 bits of product (update OV)
b EmulateUpdateRT_cr0_xer_mq
EmulateMFSPR_MFTB_MTSPR_CLCS:
// 1 11111 11112 22222 22223 3
// 012345 67890 12345 67890 12345 67890 1
// ------ ----- ----- ----- ----- ----- -
// 011111 rt-rt 00000 xxxxx 01010 10011 x mfmq rt
// 011111 rt-rt 00001 xxxxx 01010 10011 x mfxer rt
// 011111 rt-rt 00010 xxxxx 01010 10011 x mfspr rt,0x2
// 011111 rt-rt 00011 xxxxx 01010 10011 x mfspr rt,0x3
// 011111 rt-rt 00100 xxxxx 01010 10011 x mfrtcu rt
// 011111 rt-rt 00101 xxxxx 01010 10011 x mfrtcl rt
// 011111 rt-rt 00110 xxxxx 01010 10011 x mfdec rt
// 011111 rt-rt 00111 xxxxx 01010 10011 x mfspr rt,0x7
// 011111 rt-rt 01000 xxxxx 01010 10011 x mflr rt
// 011111 rt-rt 01001 xxxxx 01010 10011 x mfctr rt
// 011111 rt-rt 01010 xxxxx 01010 10011 x mfspr rt,0xA
// 011111 rt-rt 01011 xxxxx 01010 10011 x mfspr rt,0xB
// 011111 rt-rt 01100 xxxxx 01010 10011 x mfspr rt,0xC
// 011111 rt-rt 01101 xxxxx 01010 10011 x mfspr rt,0xD
// 011111 rt-rt 01110 xxxxx 01010 10011 x mfspr rt,0xE
// 011111 rt-rt 01111 xxxxx 01010 10011 x mfspr rt,0xF
// 011111 rt-rt 11111 01000 01010 10011 x mfspr rt,287
// 011111 rt-rt 11000 11101 01010 10011 x mfspr rt,952
// 011111 rt-rt 11001 11101 01010 10011 x mfspr rt,953
// 011111 rt-rt 11010 11101 01010 10011 x mfspr rt,954
// 011111 rt-rt 11011 11101 01010 10011 x mfspr rt,955
// 011111 rt-rt 11100 11101 01010 10011 x mfspr rt,956
// 011111 rt-rt 11101 11101 01010 10011 x mfspr rt,957
// 011111 rt-rt 11110 11101 01010 10011 x mfspr rt,958
// 011111 rt-rt 11111 11101 01010 10011 x mfspr rt,959
// 011111 rt-rt 01100 01000 01011 10011 x mftb rt
// 011111 rt-rt 01101 01000 01011 10011 x mftbu rt
// 011111 rs-rs 00000 xxxxx 01110 10011 x mtmq rs
// 011111 rs-rs 00001 xxxxx 01110 10011 x mtxer rs
// 011111 rs-rs 00010 xxxxx 01110 10011 x mtspr 0x2,rs
// 011111 rs-rs 00011 xxxxx 01110 10011 x mtspr 0x3,rs
// 011111 rs-rs 00100 xxxxx 01110 10011 x mtspr 0x4,rs
// 011111 rs-rs 00101 xxxxx 01110 10011 x mtspr 0x5,rs
// 011111 rs-rs 00110 xxxxx 01110 10011 x mtspr 0x6,rs
// 011111 rs-rs 00111 xxxxx 01110 10011 x mtspr 0x7,rs
// 011111 rs-rs 01000 xxxxx 01110 10011 x mtlr rs
// 011111 rs-rs 01001 xxxxx 01110 10011 x mtctr rs
// 011111 rs-rs 01010 xxxxx 01110 10011 x mtspr 0xA,rs
// 011111 rs-rs 01011 xxxxx 01110 10011 x mtspr 0xB,rs
// 011111 rs-rs 01100 xxxxx 01110 10011 x mtspr 0xC,rs
// 011111 rs-rs 01101 xxxxx 01110 10011 x mtspr 0xD,rs
// 011111 rs-rs 01110 xxxxx 01110 10011 x mtspr 0xE,rs
// 011111 rs-rs 01111 xxxxx 01110 10011 x mtspr 0xF,rs
// 011111 rs-rs 11000 11101 01110 10011 x mtspr 952,rs
// 011111 rs-rs 11001 11101 01110 10011 x mtspr 953,rs
// 011111 rs-rs 11010 11101 01110 10011 x mtspr 954,rs
// 011111 rs-rs 11011 11101 01110 10011 x mtspr 955,rs
// 011111 rs-rs 11100 11101 01110 10011 x mtspr 956,rs
// 011111 rs-rs 11101 11101 01110 10011 x mtspr 957,rs
// 011111 rs-rs 11110 11101 01110 10011 x mtspr 958,rs
// 011111 rs-rs 11111 11101 01110 10011 x mtspr 959,rs
// 011111 rt-rt ra-ra xxxxx 10000 10011 x clcs rt,ra
bt 25,EmulateMFTB
bt 21,EmulateCLCS
cmpwi cr0,UnimpRA,0x10*4 // test for 1xxxx, privileged
cmpwi cr1,UnimpRA,0*4
cmpwi cr6,UnimpRA,1*4
bt 23,EmulateMTSPR
EmulateMFSPR:
bge EmulatePrivilegedMFSPR // privileged SPR
// 011111 rt-rt 00000 xxxxx 01010 10011 x mfmq rt
// 011111 rt-rt 00001 xxxxx 01010 10011 x mfxer rt
// 011111 rt-rt 00010 xxxxx 01010 10011 x mfspr rt,0x2
// 011111 rt-rt 00011 xxxxx 01010 10011 x mfspr rt,0x3
// 011111 rt-rt 00100 xxxxx 01010 10011 x mfrtcu rt
// 011111 rt-rt 00101 xxxxx 01010 10011 x mfrtcl rt
// 011111 rt-rt 00110 xxxxx 01010 10011 x mfdec rt
// 011111 rt-rt 00111 xxxxx 01010 10011 x mfspr rt,0x7
// 011111 rt-rt 01000 xxxxx 01010 10011 x mflr rt
// 011111 rt-rt 01001 xxxxx 01010 10011 x mfctr rt
// 011111 rt-rt 01010 xxxxx 01010 10011 x mfspr rt,0xA
// 011111 rt-rt 01011 xxxxx 01010 10011 x mfspr rt,0xB
// 011111 rt-rt 01100 xxxxx 01010 10011 x mfspr rt,0xC
// 011111 rt-rt 01101 xxxxx 01010 10011 x mfspr rt,0xD
// 011111 rt-rt 01110 xxxxx 01010 10011 x mfspr rt,0xE
// 011111 rt-rt 01111 xxxxx 01010 10011 x mfspr rt,0xF
// CR0 is set as follows:
// 0,1,5,6,8,9 - lt,gt,eq cleared, so set based upon xer
// 2,3,4,7,A,B,C,D,E,F - based upon add. ra,rb
crclr lt_b
beq cr1,EmulateMFMQ // SPR=0, MFMQ
beq cr6,EmulateMFXER // SPR=1, MFXER
cmpwi cr1,UnimpRA,5*4
cmpwi cr6,UnimpRA,6*4
beq cr1,EmulateMFRTC // SPR=5, MFRTCL
beq cr6,EmulateMFDEC // SPR=6, MFDEC
cmpwi cr1,UnimpRA,8*4
cmpwi cr6,UnimpRA,9*4
beq cr1,EmulateMFLR // SPR=8, MFLR
beq cr6,EmulateMFCTR // SPR=9, MFCTR
// compute CR0 for RTCU and invalid SPR encodings
cmpwi cr6,UnimpRA,4*4
lwzx UnimpRA,KernelDataPtr,UnimpRA // get RA
lwzx UnimpRB,KernelDataPtr,UnimpRB // get RB
add. MemDataL,UnimpRA,UnimpRB // cr0 based upon RA+RB
beq cr6,EmulateMFRTC // SPR=4, MFRTCU
bf b_EmulateInvalidSPR,EmulateDisabledInvalidSPR
b EmulateUpdateCR0
EmulateMFMQ:
// 011111 rt-rt 00000 xxxxx 01010 10011 x mfmq rt
bf b_EmulatePowerMQ,EmulateDisabledPowerMQ
lwz MemDataL,0(UnimpMQptr) // get MQ from context block
b EmulateUpdateRT_cr0
EmulateMFXER:
// 011111 rt-rt 00001 xxxxx 01010 10011 x mfxer rt
bf b_EmulateInvalidSPR,EmulateDisabledInvalidSPR
mtcrf 0x80,SavedCR // restore CR0
//.long (31<<26)+(MemDataL<<21)+(sprXER<<16)+(339<<1)+(1<<0) // mfxer. MemDataL
.long (31<<26)+(dMemDataL<<21)+(sprXER<<16)+(339<<1)+(1<<0) // mfxer. MemDataL
b EmulateUpdateRT_cr0
EmulateMFRTC:
// 011111 rt-rt 00100 xxxxx 01010 10011 x mfrtcu rt
// 011111 rt-rt 00101 xxxxx 01010 10011 x mfrtcl rt
bf b_EmulatePowerRTC,EmulateDisabledPowerRTC
RetryMFRTC:
mftbu MemDataH // read the 64 bit Time Base register
mftb MemDataL
mftbu DataTemp
cmplw cr1,DataTemp,MemDataH
bne- cr1,RetryMFRTC // retry if high half changed
//lwz DataTemp,TBtoRTCmult(KernelDataPtr) // TBtoRTCmult
//lbz UnimpRA,TBtoRTCshL(KernelDataPtr) // TBtoRTCshL
//lbz UnimpRB,TBtoRTCshR(KernelDataPtr) // TBtoRTCshR
mullw UnimpMQptr,MemDataH,DataTemp // TBU*TBtoRTCmult (L)
mulhwu UnimpMQtmp,MemDataL,DataTemp // TBL*TBtoRTCmult (H)
add UnimpMQptr,UnimpMQptr,UnimpMQtmp // TBU*TBtoRTCmult (L) + TBL*TBtoRTCmult (H)
bne cr6,EmulateMFRTCL
EmulateMFRTCU:
// 011111 rt-rt 00100 xxxxx 01010 10011 x mfrtcu rt
cmplw cr1,UnimpMQptr,UnimpMQtmp // test for carry out
srw UnimpMQptr,UnimpMQptr,UnimpRB
mulhwu MemDataL,MemDataH,DataTemp // TBU*TBtoRTCmult (upper 32 bits)
bge+ cr1,$+8
addi MemDataL,MemDataL,1 // add in carry out
slw MemDataL,MemDataL,UnimpRA // TBU*TBtoRTCmult (H) left shifted by TBtoRTCshL
add MemDataL,MemDataL,UnimpMQptr // 32 bit integer seconds
b EmulateUpdateRT_cr0
EmulateMFRTCL:
// 011111 rt-rt 00101 xxxxx 01010 10011 x mfrtcl rt
mullw MemDataL,MemDataL,DataTemp // TBL*TBtoRTCmult (L)
srw MemDataL,MemDataL,UnimpRB // TBL*TBtoRTCmult (L) right shifted by TBtoRTCshR
slw UnimpMQptr,UnimpMQptr,UnimpRA
add MemDataL,MemDataL,UnimpMQptr // 32 bit fractional seconds
lis DataTemp,1000000000>>16
ori DataTemp,DataTemp,1000000000&0xFFFF
mulhwu MemDataL,MemDataL,DataTemp // convert fraction to nanoseconds
b EmulateUpdateRT_cr0
EmulateMFDEC:
// 011111 rt-rt 00110 xxxxx 01010 10011 x mfdec rt
bf b_EmulatePowerDEC,EmulateDisabledPowerDEC
mfspr MemDataL,fromDEC // get DEC
b EmulateUpdateRT_cr0
EmulateMFLR:
// 011111 rt-rt 01000 xxxxx 01010 10011 x mflr rt
bf b_EmulateInvalidSPR,EmulateDisabledInvalidSPR
mtcrf 0x80,SavedCR // restore CR0
mtlr SavedLR // get LR
//.long (31<<26)+(MemDataL<<21)+(sprLR<<16)+(339<<1)+(1<<0) // mflr. MemDataL
.long (31<<26)+(dMemDataL<<21)+(sprLR<<16)+(339<<1)+(1<<0) // mflr. MemDataL
b EmulateUpdateRT_cr0
EmulateMFCTR:
// 011111 rt-rt 01001 xxxxx 01010 10011 x mfctr rt
bf b_EmulateInvalidSPR,EmulateDisabledInvalidSPR
mtcrf 0x80,SavedCR // restore CR0
//.long (31<<26)+(MemDataL<<21)+(sprCTR<<16)+(339<<1)+(1<<0)// mfctr. MemDataL
.long (31<<26)+(dMemDataL<<21)+(sprCTR<<16)+(339<<1)+(1<<0)// mfctr. MemDataL
b EmulateUpdateRT_cr0
// the following registers are specific to the 604 and allow
// performance monitoring for the entire system.
// For now the access to these privileged registers is allowed to
// let people do their thing. tjm
//
// The registers are:
// MMCR0: SPR - 952
// PMC1: SPR - 953
// PMC2: SPR - 954
// SIA: SPR - 955
// MMCR1: SPR - 956
// PMC3: SPR - 957
// PMC4: SPR - 958
// SDA: SPR - 959
//
// PVR: SPR - 287
EmulatePrivilegedMFSPR:
// 011111 rt-rt 11111 01000 01010 10011 x mfspr rt,287
// 011111 rt-rt 11000 11101 01010 10011 x mfspr rt,952
// 011111 rt-rt 11001 11101 01010 10011 x mfspr rt,953
// 011111 rt-rt 11010 11101 01010 10011 x mfspr rt,954
// 011111 rt-rt 11011 11101 01010 10011 x mfspr rt,955
// 011111 rt-rt 11100 11101 01010 10011 x mfspr rt,956
// 011111 rt-rt 11101 11101 01010 10011 x mfspr rt,957
// 011111 rt-rt 11110 11101 01010 10011 x mfspr rt,958
// 011111 rt-rt 11111 11101 01010 10011 x mfspr rt,959
mtcrf 0x80,SavedCR // restore CR0
//rlwinm UnimpRB,MemInstr,11+10,0x000003FF // get SPR field
rlwinm UnimpRB,MemInstr,11+10,22,31 // get SPR field
cmplwi cr1,UnimpRB,((287&0x1F)<<5)|(287>>5)// test for PVR Register
beq cr1,EmulateMFPVR // SPR=287, MFPVR
bf b_EmulatePrivSPRperf0,EmulatePRIVILEGED
// 604 and Sirocco
cmplwi cr1,UnimpRB,((sprMMCR0&0x1F)<<5)|(sprMMCR0>>5) // test for MMCR0 Register
beq cr1,EmulateMFMMCR0 // SPR=952, MFMMCR0
cmplwi cr1,UnimpRB,((sprPMC1&0x1F)<<5)|(sprPMC1>>5) // test for PMC1 Register
beq cr1,EmulateMFPMC1 // SPR=953, MFPMC1
cmplwi cr1,UnimpRB,((sprPMC2&0x1F)<<5)|(sprPMC2>>5) // test for PMC2 Register
beq cr1,EmulateMFPMC2 // SPR=954, MFPMC2
cmplwi cr1,UnimpRB,((sprSIA&0x1F)<<5)|(sprSIA>>5) // test for SIA Register
beq cr1,EmulateMFSIA // SPR=955, MFSIA
bf b_EmulatePrivSPRperf,EmulatePrivilegedMFSPRNoSDA
// 604 and Sirocco
cmplwi cr1,UnimpRB,((sprSDA&0x1F)<<5)|(sprSDA>>5) // test for SDA Register
beq cr1,EmulateMFSDA // SPR=959, MFSDA
EmulatePrivilegedMFSPRNoSDA:
bf b_EmulatePrivSPRperf2,EmulatePRIVILEGED
// Sirocco only
cmplwi cr1,UnimpRB,((sprMMCR1&0x1F)<<5)|(sprMMCR1>>5) // test for MMCR1 Register
beq cr1,EmulateMFMMCR1 // SPR=956, MFMMCR1
cmplwi cr1,UnimpRB,((sprPMC3&0x1F)<<5)|(sprPMC3>>5) // test for PMC3 Register
beq cr1,EmulateMFPMC3 // SPR=957, MFPMC3
cmplwi cr1,UnimpRB,((sprPMC4&0x1F)<<5)|(sprPMC4>>5) // test for PMC4 Register
beq cr1,EmulateMFPMC4 // SPR=958, MFPMC4
b EmulatePRIVILEGED
EmulateMFPVR:
// 011111 rt-rt 11111 01000 01010 10011 x mfspr rt,287
bf b_EmulatePrivMFPVR,EmulatePRIVILEGED
//.long (31<<26)+(MemDataL<<21)+((sprPVR&0x1F)<<16)+((sprPVR>>5)<<11)+(339<<1)+(1<<0)
.long (31<<26)+(dMemDataL<<21)+((sprPVR&0x1F)<<16)+((sprPVR>>5)<<11)+(339<<1)+(1<<0)
b EmulateUpdateRT_cr0
EmulateMFMMCR0:
// 011111 rt-rt 11000 11101 01010 10011 x mfspr rt,952
//.long (31<<26)+(MemDataL<<21)+((sprMMCR0&0x1F)<<16)+((sprMMCR0>>5)<<11)+(339<<1)+(1<<0)
.long (31<<26)+(dMemDataL<<21)+((sprMMCR0&0x1F)<<16)+((sprMMCR0>>5)<<11)+(339<<1)+(1<<0)
b EmulateUpdateRT_cr0
EmulateMFPMC1:
// 011111 rt-rt 11001 11101 01010 10011 x mfspr rt,953
//.long (31<<26)+(MemDataL<<21)+((sprPMC1&0x1F)<<16)+((sprPMC1>>5)<<11)+(339<<1)+(1<<0)
.long (31<<26)+(dMemDataL<<21)+((sprPMC1&0x1F)<<16)+((sprPMC1>>5)<<11)+(339<<1)+(1<<0)
b EmulateUpdateRT_cr0
EmulateMFPMC2:
// 011111 rt-rt 11010 11101 01010 10011 x mfspr rt,954
//.long (31<<26)+(MemDataL<<21)+((sprPMC2&0x1F)<<16)+((sprPMC2>>5)<<11)+(339<<1)+(1<<0)
.long (31<<26)+(dMemDataL<<21)+((sprPMC2&0x1F)<<16)+((sprPMC2>>5)<<11)+(339<<1)+(1<<0)
b EmulateUpdateRT_cr0
EmulateMFSIA:
// 011111 rt-rt 11011 11101 01010 10011 x mfspr rt,955
//.long (31<<26)+(MemDataL<<21)+((sprSIA&0x1F)<<16)+((sprSIA>>5)<<11)+(339<<1)+(1<<0)
.long (31<<26)+(dMemDataL<<21)+((sprSIA&0x1F)<<16)+((sprSIA>>5)<<11)+(339<<1)+(1<<0)
b EmulateUpdateRT_cr0
EmulateMFMMCR1:
// 011111 rt-rt 11000 11101 01010 10011 x mfspr rt,956
//.long (31<<26)+(MemDataL<<21)+((sprMMCR1&0x1F)<<16)+((sprMMCR1>>5)<<11)+(339<<1)+(1<<0)
.long (31<<26)+(dMemDataL<<21)+((sprMMCR1&0x1F)<<16)+((sprMMCR1>>5)<<11)+(339<<1)+(1<<0)
b EmulateUpdateRT_cr0
EmulateMFPMC3:
// 011111 rt-rt 11001 11101 01010 10011 x mfspr rt,957
//.long (31<<26)+(MemDataL<<21)+((sprPMC3&0x1F)<<16)+((sprPMC3>>5)<<11)+(339<<1)+(1<<0)
.long (31<<26)+(dMemDataL<<21)+((sprPMC3&0x1F)<<16)+((sprPMC3>>5)<<11)+(339<<1)+(1<<0)
b EmulateUpdateRT_cr0
EmulateMFPMC4:
// 011111 rt-rt 11010 11101 01010 10011 x mfspr rt,958
//.long (31<<26)+(MemDataL<<21)+((sprPMC4&0x1F)<<16)+((sprPMC4>>5)<<11)+(339<<1)+(1<<0)
.long (31<<26)+(dMemDataL<<21)+((sprPMC4&0x1F)<<16)+((sprPMC4>>5)<<11)+(339<<1)+(1<<0)
b EmulateUpdateRT_cr0
EmulateMFSDA:
// 011111 rt-rt 11111 11101 01010 10011 x mfspr rt,959
//.long (31<<26)+(MemDataL<<21)+((sprSDA&0x1F)<<16)+((sprSDA>>5)<<11)+(339<<1)+(1<<0)
.long (31<<26)+(dMemDataL<<21)+((sprSDA&0x1F)<<16)+((sprSDA>>5)<<11)+(339<<1)+(1<<0)
b EmulateUpdateRT_cr0
EmulateMFTB:
// 011111 rt-rt 01100 01000 01011 10011 x mftb rt
// 011111 rt-rt 01101 01000 01011 10011 x mftbu rt
//rlwinm DataTemp,MemInstr,6+5+10,0x000003FF // get the TBR field
rlwinm DataTemp,MemInstr,6+5+10,22,31 // get the TBR field
cmplwi cr1,DataTemp,((268&0x1F)<<5)|(268>>5) // test for MFTBl
cmplwi cr6,DataTemp,((269&0x1F)<<5)|(269>>5) // test for MFTBu
// cror cr0*4+eq,cr1*4+eq,cr6*4+eq // see if valid TBR field
cror rcr0*4+eq_b,rcr1*4+eq_b,rcr6*4+eq_b // see if valid TBR field
bne cr0,EmulateILLEGAL // invalid TBR field
RetryMFTB:
mfspr MemDataH,fromRTCU // assuming 601, read Power RTC timer
mfspr MemDataL,fromRTCL
mfspr DataTemp,fromRTCU
xor. DataTemp,DataTemp,MemDataH
bne- RetryMFTB // retry if high half changed
lis DataTemp,1000000000>>16
ori DataTemp,DataTemp,1000000000&0xFFFF
mfspr UnimpMQtmp,sprMQ // preserve MQ from 601 multiply ops
// 011111 rt-rt 01100 01000 01011 10011 x mftb rt
mullw UnimpRB,MemDataH,DataTemp // convert Power timer to PowerPC timer
mtspr sprMQ,UnimpMQtmp // restore MQ after 601 multiply ops
add MemDataL,MemDataL,UnimpRB // compute TBL
beq cr1,EmulateUpdateRT // update RT register, when TBL
// 011111 rt-rt 01101 01000 01011 10011 x mftbu rt
cmplw MemDataL,UnimpRB // test for carry out
mulhwu MemDataL,MemDataH,DataTemp // compute TBU
mtspr sprMQ,UnimpMQtmp // restore MQ after 601 multiply ops
bge EmulateUpdateRT // update RT register, when TBU, no carry out
addi MemDataL,MemDataL,1 // add in carry out
b EmulateUpdateRT // update RT register, when TBU, carry out
EmulateMTSPR:
lwzx UnimpRS,KernelDataPtr,UnimpRS // get RS
bge EmulatePrivilegedMTSPR // privileged SPR
// 011111 rs-rs 00000 xxxxx 01110 10011 x mtmq rs
// 011111 rs-rs 00001 xxxxx 01110 10011 x mtxer rs
// 011111 rs-rs 00010 xxxxx 01110 10011 x mtspr 0x2,rs
// 011111 rs-rs 00011 xxxxx 01110 10011 x mtspr 0x3,rs
// 011111 rs-rs 00100 xxxxx 01110 10011 x mtspr 0x4,rs
// 011111 rs-rs 00101 xxxxx 01110 10011 x mtspr 0x5,rs
// 011111 rs-rs 00110 xxxxx 01110 10011 x mtspr 0x6,rs
// 011111 rs-rs 00111 xxxxx 01110 10011 x mtspr 0x7,rs
// 011111 rs-rs 01000 xxxxx 01110 10011 x mtlr rs
// 011111 rs-rs 01001 xxxxx 01110 10011 x mtctr rs
// 011111 rs-rs 01010 xxxxx 01110 10011 x mtspr 0xA,rs
// 011111 rs-rs 01011 xxxxx 01110 10011 x mtspr 0xB,rs
// 011111 rs-rs 01100 xxxxx 01110 10011 x mtspr 0xC,rs
// 011111 rs-rs 01101 xxxxx 01110 10011 x mtspr 0xD,rs
// 011111 rs-rs 01110 xxxxx 01110 10011 x mtspr 0xE,rs
// 011111 rs-rs 01111 xxxxx 01110 10011 x mtspr 0xF,rs
mr. UnimpRS,UnimpRS // cr0 based upon RS
beq cr1,EmulateMTMQ // SPR=0, MTMQ
bf b_EmulateInvalidSPR,EmulateDisabledInvalidSPR
beq cr6,EmulateMTXER // SPR=1, MTXER
cmpwi cr1,UnimpRA,8*4
cmpwi cr6,UnimpRA,9*4
beq cr1,EmulateMTLR // SPR=8, MTLR
beq cr6,EmulateMTCTR // SPR=9, MTCTR
b EmulateUpdateCR0
EmulateMTMQ:
// 011111 rs-rs 00000 xxxxx 01110 10011 x mtmq rs
bf b_EmulatePowerMQ,EmulateDisabledPowerMQ
stw UnimpRS,0(UnimpMQptr) // update MQ in context block
b EmulateUpdateCR0
EmulateMTXER:
// 011111 rs-rs 00001 xxxxx 01110 10011 x mtxer rs
mtcrf 0x80,SavedCR // restore CR0
//.long (31<<26)+(UnimpRS<<21)+(0x01<<16)+(467<<1)+(1<<0) // mtxer. UnimpRS
.long (31<<26)+(dUnimpRS<<21)+(0x01<<16)+(467<<1)+(1<<0) // mtxer. UnimpRS
b EmulateUpdateCR0
EmulateMTLR:
// 011111 rs-rs 01000 xxxxx 01110 10011 x mtlr rs
mtcrf 0x80,SavedCR // restore CR0
mr SavedLR,UnimpRS // update LR
//.long (31<<26)+(UnimpRS<<21)+(0x08<<16)+(467<<1)+(1<<0) // mtlr. UnimpRS
.long (31<<26)+(dUnimpRS<<21)+(0x08<<16)+(467<<1)+(1<<0) // mtlr. UnimpRS
b EmulateUpdateCR0
EmulateMTCTR:
// 011111 rs-rs 01001 xxxxx 01110 10011 x mtctr rs
mtcrf 0x80,SavedCR // restore CR0
//.long (31<<26)+(UnimpRS<<21)+(0x09<<16)+(467<<1)+(1<<0) // mtctr. UnimpRS
.long (31<<26)+(dUnimpRS<<21)+(0x09<<16)+(467<<1)+(1<<0) // mtctr. UnimpRS
b EmulateUpdateCR0
EmulatePrivilegedMTSPR:
// 011111 rs-rs 11000 11101 01110 10011 x mtspr 952,rs
// 011111 rs-rs 11001 11101 01110 10011 x mtspr 953,rs
// 011111 rs-rs 11010 11101 01110 10011 x mtspr 954,rs
// 011111 rs-rs 11011 11101 01110 10011 x mtspr 955,rs
// 011111 rs-rs 11100 11101 01110 10011 x mtspr 956,rs
// 011111 rs-rs 11101 11101 01110 10011 x mtspr 957,rs
// 011111 rs-rs 11110 11101 01110 10011 x mtspr 958,rs
// 011111 rs-rs 11111 11101 01110 10011 x mtspr 959,rs
bf b_EmulatePrivSPRperf0,EmulatePRIVILEGED
mtcrf 0x80,SavedCR // restore CR0
//rlwinm UnimpRB,MemInstr,11+10,0x000003FF // get SPR field
rlwinm UnimpRB,MemInstr,11+10,22,31 // get SPR field
// 604 and Sirocco
cmplwi cr1,UnimpRB,((sprMMCR0&0x1F)<<5)|(sprMMCR0>>5) // test for MMCR0 Register
beq cr1,EmulateMTMMCR0 // SPR=952, MTMMCR0
cmplwi cr1,UnimpRB,((sprPMC1&0x1F)<<5)|(sprPMC1>>5) // test for PMC1 Register
beq cr1,EmulateMTPMC1 // SPR=953, MTPMC1
cmplwi cr1,UnimpRB,((sprPMC2&0x1F)<<5)|(sprPMC2>>5) // test for PMC2 Register
beq cr1,EmulateMTPMC2 // SPR=954, MTPMC2
cmplwi cr1,UnimpRB,((sprSIA&0x1F)<<5)|(sprSIA>>5) // test for SIA Register
beq cr1,EmulateMTSIA // SPR=955, MTSIA
bf b_EmulatePrivSPRperf,EmulatePrivilegedMTSPRNoSDA
// Sirocco only
cmplwi cr1,UnimpRB,((sprSDA&0x1F)<<5)|(sprSDA>>5) // test for SDA Register
beq cr1,EmulateMTSDA // SPR=959, MTSDA
EmulatePrivilegedMTSPRNoSDA:
bf b_EmulatePrivSPRperf2,EmulatePRIVILEGED
// Sirocco only
cmplwi cr1,UnimpRB,((sprMMCR1&0x1F)<<5)|(sprMMCR1>>5) // test for MMCR1 Register
beq cr1,EmulateMTMMCR1 // SPR=956, MTMMCR1
cmplwi cr1,UnimpRB,((sprPMC3&0x1F)<<5)|(sprPMC3>>5) // test for PMC3 Register
beq cr1,EmulateMTPMC3 // SPR=957, MTPMC3
cmplwi cr1,UnimpRB,((sprPMC4&0x1F)<<5)|(sprPMC4>>5) // test for PMC4 Register
beq cr1,EmulateMTPMC4 // SPR=958, MTPMC4
b EmulatePRIVILEGED
EmulateMTMMCR0:
// 011111 rs-rs 11000 11101 01110 10011 x mtspr 952,rs
//.long (31<<26)+(UnimpRS<<21)+((sprMMCR0&0x1F)<<16)+((sprMMCR0>>5)<<11)+(467<<1)+(1<<0)
.long (31<<26)+(dUnimpRS<<21)+((sprMMCR0&0x1F)<<16)+((sprMMCR0>>5)<<11)+(467<<1)+(1<<0)
b EmulateUpdateCR0
EmulateMTPMC1:
// 011111 rs-rs 11001 11101 01110 10011 x mtspr 953,rs
//.long (31<<26)+(UnimpRS<<21)+((sprPMC1&0x1F)<<16)+((sprPMC1>>5)<<11)+(467<<1)+(1<<0)
.long (31<<26)+(dUnimpRS<<21)+((sprPMC1&0x1F)<<16)+((sprPMC1>>5)<<11)+(467<<1)+(1<<0)
b EmulateUpdateCR0
EmulateMTPMC2:
// 011111 rs-rs 11010 11101 01110 10011 x mtspr 954,rs
//.long (31<<26)+(UnimpRS<<21)+((sprPMC2&0x1F)<<16)+((sprPMC2>>5)<<11)+(467<<1)+(1<<0)
.long (31<<26)+(dUnimpRS<<21)+((sprPMC2&0x1F)<<16)+((sprPMC2>>5)<<11)+(467<<1)+(1<<0)
b EmulateUpdateCR0
EmulateMTSIA:
// 011111 rs-rs 11011 11101 01110 10011 x mtspr 955,rs
//.long (31<<26)+(UnimpRS<<21)+((sprSIA&0x1F)<<16)+((sprSIA>>5)<<11)+(467<<1)+(1<<0)
.long (31<<26)+(dUnimpRS<<21)+((sprSIA&0x1F)<<16)+((sprSIA>>5)<<11)+(467<<1)+(1<<0)
b EmulateUpdateCR0
EmulateMTMMCR1:
// 011111 rs-rs 11000 11101 01110 10011 x mtspr 956,rs
//.long (31<<26)+(UnimpRS<<21)+((sprMMCR1&0x1F)<<16)+((sprMMCR1>>5)<<11)+(467<<1)+(1<<0)
.long (31<<26)+(dUnimpRS<<21)+((sprMMCR1&0x1F)<<16)+((sprMMCR1>>5)<<11)+(467<<1)+(1<<0)
b EmulateUpdateCR0
EmulateMTPMC3:
// 011111 rs-rs 11001 11101 01110 10011 x mtspr 957,rs
//.long (31<<26)+(UnimpRS<<21)+((sprPMC3&0x1F)<<16)+((sprPMC3>>5)<<11)+(467<<1)+(1<<0)
.long (31<<26)+(dUnimpRS<<21)+((sprPMC3&0x1F)<<16)+((sprPMC3>>5)<<11)+(467<<1)+(1<<0)
b EmulateUpdateCR0
EmulateMTPMC4:
// 011111 rs-rs 11010 11101 01110 10011 x mtspr 958,rs
//.long (31<<26)+(UnimpRS<<21)+((sprPMC4&0x1F)<<16)+((sprPMC4>>5)<<11)+(467<<1)+(1<<0)
.long (31<<26)+(dUnimpRS<<21)+((sprPMC4&0x1F)<<16)+((sprPMC4>>5)<<11)+(467<<1)+(1<<0)
b EmulateUpdateCR0
EmulateMTSDA:
// 011111 rs-rs 11111 11101 01110 10011 x mtspr 959,rs
//.long (31<<26)+(UnimpRS<<21)+((sprSDA&0x1F)<<16)+((sprSDA>>5)<<11)+(467<<1)+(1<<0)
.long (31<<26)+(dUnimpRS<<21)+((sprSDA&0x1F)<<16)+((sprSDA>>5)<<11)+(467<<1)+(1<<0)
b EmulateUpdateCR0
EmulateCLCS:
// 011111 rt-rt ra-ra xxxxx 10000 10011 x clcs rt,ra
bf b_EmulatePowerCLCS,EmulateDisabledPowerCLCS
//rlwinm. UnimpRA,MemInstr,11+5,0x0000000F // cr0 based upon low 4 bits of RA field
rlwinm. UnimpRA,MemInstr,11+5,28,31 // cr0 based upon low 4 bits of RA field
//rlwinm MemDataL,MemInstr,11+5,0x0000000E // setup to test for inst/data cache size
rlwinm MemDataL,MemInstr,11+5,28,30 // setup to test for inst/data cache size
cmpwi cr1,MemDataL,0xA // inst/data cache sizes are special cases
// la UnimpRA,EmulateCLCS_info-MemProcBase(UnimpRA)
lbzx UnimpRA,MemProcPtr,UnimpRA // get the offset within ProcessorInfo
//la MemDataL,PI+ProcessorInfoStart(KernelDataPtr)
beq cr1,EmulateCLCS_word // inst/data cache size is 4 bytes
lhzx MemDataL,MemDataL,UnimpRA // all others are 2 bytes
b EmulateUpdateRT_cr0
EmulateCLCS_word:
lwzx MemDataL,MemDataL,UnimpRA // get the 4 byte inst/data cache size
b EmulateUpdateRT_cr0
EmulateCLCS_info:
#if 0
.byte DataCacheLineSize-ProcessorInfoStart // x0000 : 64 - undefined
.byte DataCacheLineSize-ProcessorInfoStart // x0001 : 64 - undefined
.byte DataCacheLineSize-ProcessorInfoStart // x0010 : 64 - undefined
.byte DataCacheLineSize-ProcessorInfoStart // x0011 : 64 - undefined
.byte DataCacheBlockSizeTouch-ProcessorInfoStart // x0100 : 32 - touch cache sector size
.byte InstCacheBlockSize-ProcessorInfoStart // x0101 : 32 - inst cache sector size
.byte DataCacheBlockSize-ProcessorInfoStart // x0110 : 32 - data cache sector size
.byte CombinedCaches-ProcessorInfoStart // x0111 : 1 - combined cache
.byte InstCacheAssociativity-ProcessorInfoStart // x1000 : 8 - inst cache set associativity
.byte DataCacheAssociativity-ProcessorInfoStart // x1001 : 8 - data cache set associativity
.byte InstCacheTotalSize-ProcessorInfoStart // x1010 : 32768 - inst cache size
.byte DataCacheTotalSize-ProcessorInfoStart // x1011 : 32768 - data cache size
.byte InstCacheLineSize-ProcessorInfoStart // x1100 : 64 - inst cache line size
.byte DataCacheLineSize-ProcessorInfoStart // x1101 : 64 - data cache line size
.byte DataCacheLineSize-ProcessorInfoStart // x1110 : 64 - min line size
.byte DataCacheLineSize-ProcessorInfoStart // x1111 : 64 - max line size
#endif
EmulateRRIB_SHIFTE:
// 1 11111 11112 22222 22223 3
// 012345 67890 12345 67890 12345 67890 1
// ------ ----- ----- ----- ----- ----- -
// 011111 rs-rs ra-ra rb-rb 00100 11001 . sle[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 00110 11001 . sleq[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 10000 11001 . rrib[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 10100 11001 . sre[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 10110 11001 . sreq[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 11100 11001 . srea[.] ra,rs,rb
lwzx UnimpRB,KernelDataPtr,UnimpRB // get RB
//rlwinm UnimpRB,UnimpRB,0,0x1F // just use low 5 bits of RB
rlwinm UnimpRB,UnimpRB,0,27,31 // just use low 5 bits of RB
bt 23,EmulateSHIFT
EmulateRRIB:
// 011111 rs-rs ra-ra rb-rb 10000 11001 . rrib[.] ra,rs,rb
bf b_EmulatePowerComplex,EmulateDisabledPowerComplex
lwzx UnimpRS,KernelDataPtr,UnimpRS // get RS
lis DataTemp,0xFFFF8000 // mask for bit 0
lwzx MemDataL,KernelDataPtr,UnimpRA // get RA
srw DataTemp,DataTemp,UnimpRB // mask for bit specified by RB
srw UnimpRS,UnimpRS,UnimpRB // position data to be inserted
b EmulateUpdateRA_cr0_insert // insert the bit
EmulateSHIFTQ:
// 1 11111 11112 22222 22223 3
// 012345 67890 12345 67890 12345 67890 1
// ------ ----- ----- ----- ----- ----- -
// 011111 rs-rs ra-ra rb-rb 00100 11000 . slq[.] ra,rs,rb
// 011111 rs-rs ra-ra sh-sh 00101 11000 . sliq[.] ra,rs,sh
// 011111 rs-rs ra-ra rb-rb 00110 11000 . sllq[.] ra,rs,rb
// 011111 rs-rs ra-ra sh-sh 00111 11000 . slliq[.] ra,rs,sh
// 011111 rs-rs ra-ra rb-rb 10100 11000 . srq[.] ra,rs,rb
// 011111 rs-rs ra-ra sh-sh 10101 11000 . sriq[.] ra,rs,sh
// 011111 rs-rs ra-ra rb-rb 10110 11000 . srlq[.] ra,rs,rb
// 011111 rs-rs ra-ra sh-sh 10111 11000 . srliq[.] ra,rs,sh
// 011111 rs-rs ra-ra rb-rb 11100 11000 . sraq[.] ra,rs,rb
// 011111 rs-rs ra-ra sh-sh 11101 11000 . sraiq[.] ra,rs,sh
bt 25,EmulateSHIFT_imm
// 011111 rs-rs ra-ra rb-rb 00100 11000 . slq[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 00110 11000 . sllq[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 10100 11000 . srq[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 10110 11000 . srlq[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 11100 11000 . sraq[.] ra,rs,rb
lwzx UnimpRB,KernelDataPtr,UnimpRB // get RB
//rlwinm UnimpRB,UnimpRB,0,0x3F // just use low 6 bits of RB
rlwinm UnimpRB,UnimpRB,0,26,31 // just use low 6 bits of RB
bf 24,EmulateSHIFT
// 011111 rs-rs ra-ra rb-rb 00110 11000 . sllq[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 10110 11000 . srlq[.] ra,rs,rb
cmpwi cr0,UnimpRB,31
crnot 23,23 // clear bit 23, don't update MQ
ble EmulateSHIFT
bf b_EmulatePowerMQ,EmulateDisabledPowerMQ
// 011111 rs-rs ra-ra rb-rb 00110 11000 . sllq[.] ra,rs,rb (rb>31)
// 011111 rs-rs ra-ra rb-rb 10110 11000 . srlq[.] ra,rs,rb (rb>31)
lwz MemDataH,0(UnimpMQptr) // get MQ from context block
li DataTemp,-1
//rlwinm UnimpRB,UnimpRB,0,0x1F // just use low 5 bits of RB
rlwinm UnimpRB,UnimpRB,0,27,31 // just use low 5 bits of RB
bt 21,EmulateSHIFT_srlq
EmulateSHIFT_sllq:
// 011111 rs-rs ra-ra rb-rb 00110 11000 . sllq[.] ra,rs,rb (rb>31)
slw DataTemp,DataTemp,UnimpRB
and. MemDataL,MemDataH,DataTemp
b EmulateUpdateRA_cr0
EmulateSHIFT_srlq:
// 011111 rs-rs ra-ra rb-rb 10110 11000 . srlq[.] ra,rs,rb (rb>31)
srw DataTemp,DataTemp,UnimpRB
and. MemDataL,MemDataH,DataTemp
b EmulateUpdateRA_cr0
EmulateSHIFT_imm:
// 011111 rs-rs ra-ra sh-sh 00101 11000 . sliq[.] ra,rs,sh
// 011111 rs-rs ra-ra sh-sh 00111 11000 . slliq[.] ra,rs,sh
// 011111 rs-rs ra-ra sh-sh 10101 11000 . sriq[.] ra,rs,sh
// 011111 rs-rs ra-ra sh-sh 10111 11000 . srliq[.] ra,rs,sh
// 011111 rs-rs ra-ra sh-sh 11101 11000 . sraiq[.] ra,rs,sh
//rlwinm UnimpRB,MemInstr,11+10,0x0000001F // get SH
rlwinm UnimpRB,MemInstr,11+10,27,31 // get SH
EmulateSHIFT:
// 011111 rs-rs ra-ra rb-rb 00100 11000 . slq[.] ra,rs,rb
// 011111 rs-rs ra-ra sh-sh 00101 11000 . sliq[.] ra,rs,sh
// 011111 rs-rs ra-ra rb-rb 00110 11000 . sllq[.] ra,rs,rb (rb<32)
// 011111 rs-rs ra-ra sh-sh 00111 11000 . slliq[.] ra,rs,sh
// 011111 rs-rs ra-ra rb-rb 10100 11000 . srq[.] ra,rs,rb
// 011111 rs-rs ra-ra sh-sh 10101 11000 . sriq[.] ra,rs,sh
// 011111 rs-rs ra-ra rb-rb 10110 11000 . srlq[.] ra,rs,rb (rb<32)
// 011111 rs-rs ra-ra sh-sh 10111 11000 . srliq[.] ra,rs,sh
// 011111 rs-rs ra-ra rb-rb 11100 11000 . sraq[.] ra,rs,rb
// 011111 rs-rs ra-ra sh-sh 11101 11000 . sraiq[.] ra,rs,sh
// 011111 rs-rs ra-ra rb-rb 00100 11001 . sle[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 00110 11001 . sleq[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 10100 11001 . sre[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 10110 11001 . sreq[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 11100 11001 . srea[.] ra,rs,rb
bf b_EmulatePowerMQ,EmulateDisabledPowerMQ
lwzx UnimpRS,KernelDataPtr,UnimpRS // get RS
bt 21,EmulateSHIFT_right
EmulateSHIFT_left_logical:
// 011111 rs-rs ra-ra rb-rb 00100 11000 . slq[.] ra,rs,rb
// 011111 rs-rs ra-ra sh-sh 00101 11000 . sliq[.] ra,rs,sh
// 011111 rs-rs ra-ra rb-rb 00110 11000 . sllq[.] ra,rs,rb (rb<32)
// 011111 rs-rs ra-ra sh-sh 00111 11000 . slliq[.] ra,rs,sh
// 011111 rs-rs ra-ra rb-rb 00100 11001 . sle[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 00110 11001 . sleq[.] ra,rs,rb
slw. MemDataL,UnimpRS,UnimpRB // RA <- RS shifted left by RB bits
rotlw MemDataH,UnimpRS,UnimpRB // MQ <- RS rotated left by RB bits
bf 24,EmulateUpdateRA_cr0_mq
// 011111 rs-rs ra-ra rb-rb 00110 11000 . sllq[.] ra,rs,rb (rb<32)
// 011111 rs-rs ra-ra sh-sh 00111 11000 . slliq[.] ra,rs,sh
// 011111 rs-rs ra-ra rb-rb 00110 11001 . sleq[.] ra,rs,rb
li DataTemp,-1
slw DataTemp,DataTemp,UnimpRB
EmulateUpdateRA_cr0_mq_merge:
// 011111 rs-rs ra-ra rb-rb 00110 11000 . sllq[.] ra,rs,rb (rb<32)
// 011111 rs-rs ra-ra sh-sh 00111 11000 . slliq[.] ra,rs,sh
// 011111 rs-rs ra-ra rb-rb 10110 11000 . srlq[.] ra,rs,rb (rb<32)
// 011111 rs-rs ra-ra sh-sh 10111 11000 . srliq[.] ra,rs,sh
// 011111 rs-rs ra-ra rb-rb 00110 11001 . sleq[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 10110 11001 . sreq[.] ra,rs,rb
lwz UnimpRB,0(UnimpMQptr) // get MQ from context block
andc DataTemp,UnimpRB,DataTemp
or. MemDataL,MemDataL,DataTemp
bf 23,EmulateUpdateRA_cr0
EmulateUpdateRA_cr0_mq:
// 011111 rs-rs ra-ra sh-sh 00111 11000 . slliq[.] ra,rs,sh
// 011111 rs-rs ra-ra sh-sh 10111 11000 . srliq[.] ra,rs,sh
// 011111 rs-rs ra-ra rb-rb 00110 11001 . sleq[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 10110 11001 . sreq[.] ra,rs,rb
stw MemDataH,0(UnimpMQptr) // update MQ in context block
EmulateUpdateRA_cr0:
stwx MemDataL,KernelDataPtr,UnimpRA // update RA
EmulateUpdateCR0:
bf 31,CompleteMemOpDone
mfcr DataTemp // get CR0
//rlwimi SavedCR,DataTemp,0,0xF0000000 // update CR0
rlwimi SavedCR,DataTemp,0,0,3 // update CR0
b CompleteMemOpDone
EmulateSHIFT_right:
// 011111 rs-rs ra-ra rb-rb 10100 11000 . srq[.] ra,rs,rb
// 011111 rs-rs ra-ra sh-sh 10101 11000 . sriq[.] ra,rs,sh
// 011111 rs-rs ra-ra rb-rb 10110 11000 . srlq[.] ra,rs,rb(rb<32)
// 011111 rs-rs ra-ra sh-sh 10111 11000 . srliq[.] ra,rs,sh
// 011111 rs-rs ra-ra rb-rb 11100 11000 . sraq[.] ra,rs,rb
// 011111 rs-rs ra-ra sh-sh 11101 11000 . sraiq[.] ra,rs,sh
// 011111 rs-rs ra-ra rb-rb 10100 11001 . sre[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 10110 11001 . sreq[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 11100 11001 . srea[.] ra,rs,rb
neg MemDataH,UnimpRB// convert right rotate count to left
rotlw MemDataH,UnimpRS,MemDataH// MQ <- RS rotated right by RB bits
bt 22,EmulateSHIFT_right_arith
EmulateSHIFT_right_logical:
// 011111 rs-rs ra-ra rb-rb 10100 11000 . srq[.] ra,rs,rb
// 011111 rs-rs ra-ra sh-sh 10101 11000 . sriq[.] ra,rs,sh
// 011111 rs-rs ra-ra rb-rb 10110 11000 . srlq[.] ra,rs,rb (rb<32)
// 011111 rs-rs ra-ra sh-sh 10111 11000 . srliq[.] ra,rs,sh
// 011111 rs-rs ra-ra rb-rb 10100 11001 . sre[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 10110 11001 . sreq[.] ra,rs,rb
srw. MemDataL,UnimpRS,UnimpRB// RA <- RS shifted righ by RB bits
bf 24,EmulateUpdateRA_cr0_mq
// 011111 rs-rs ra-ra rb-rb 10110 11000 . srlq[.] ra,rs,rb(rb<32)
// 011111 rs-rs ra-ra sh-sh 10111 11000 . srliq[.] ra,rs,sh
// 011111 rs-rs ra-ra rb-rb 10110 11001 . sreq[.] ra,rs,rb
li DataTemp,-1
srw DataTemp,DataTemp,UnimpRB
b EmulateUpdateRA_cr0_mq_merge
EmulateSHIFT_right_arith:
// 011111 rs-rs ra-ra rb-rb 11100 11000 . sraq[.] ra,rs,rb
// 011111 rs-rs ra-ra sh-sh 11101 11000 . sraiq[.] ra,rs,sh
// 011111 rs-rs ra-ra rb-rb 11100 11001 . srea[.] ra,rs,rb
sraw. MemDataL,UnimpRS,UnimpRB // updates live copy of XER
b EmulateUpdateRA_cr0_mq
EmulateMASKG_MASKIR:
// 1 11111 11112 22222 22223 3
// 012345 67890 12345 67890 12345 67890 1
// ------ ----- ----- ----- ----- ----- -
// 011111 rs-rs ra-ra rb-rb 00000 11101 . maskg[.] ra,rs,rb
// 011111 rs-rs ra-ra rb-rb 10000 11101 . maskir[.] ra,rs,rb
bf b_EmulatePowerComplex,EmulateDisabledPowerComplex
lwzx UnimpRB,KernelDataPtr,UnimpRB // get RB
lwzx UnimpRS,KernelDataPtr,UnimpRS // get RS
bt 21,EmulateMASKIR
EmulateMASKG:
// 011111 rs-rs ra-ra rb-rb 00000 11101 . maskg[.] ra,rs,rb
li MemDataL,-1 // initial mask
sub UnimpRB,UnimpRB,UnimpRS // end - start
not UnimpRB,UnimpRB // 31 - (end - start) (number of zeros)
//rlwinm UnimpRB,UnimpRB,0,0x1F // mask to 5 bits
rlwinm UnimpRB,UnimpRB,0,27,31 // mask to 5 bits
neg UnimpRS,UnimpRS // setup to right rotate field mask by RS
slw MemDataL,MemDataL,UnimpRB// left aligned field mask
rotlw. MemDataL,MemDataL,UnimpRS // position the field mask
b EmulateUpdateRA_cr0
EmulateMASKIR:
// 011111 rs-rs ra-ra rb-rb 10000 11101 . maskir[.] ra,rs,rb
lwzx MemDataL,KernelDataPtr,UnimpRA // get RA
and UnimpRS,UnimpRS,UnimpRB // get new bits to insert
andc MemDataL,MemDataL,UnimpRB // clear old bits to be overwritten
or. MemDataL,MemDataL,UnimpRS// insert new bits
b EmulateUpdateRA_cr0
EmulateRLMI:
// 010110 rs-rs ra-ra rb-rb mb-mb me-me . rlmi[.] ra,rs,rb,mb,me
bf b_EmulatePowerComplex,EmulateDisabledPowerComplex
lwzx UnimpRS,KernelDataPtr,UnimpRS // get RS
//rlwinm MemDataH,MemInstr,21+5,0x1F // get MB
rlwinm MemDataH,MemInstr,21+5,27,31 // get MB
lwzx UnimpRB,KernelDataPtr,UnimpRB // get RB
//rlwinm MemDataL,MemInstr,21+10,0x1F // get ME
rlwinm MemDataL,MemInstr,21+10,27,31 // get ME
li DataTemp,-1 // initial mask
sub MemDataL,MemDataL,MemDataH // ME - MB
not MemDataL,MemDataL // 31 - (ME - MB)
//rlwinm MemDataL,MemDataL,0,0x1F// mask to 5 bits
rlwinm MemDataL,MemDataL,0,27,31 // mask to 5 bits
neg MemDataH,MemDataH // setup to right rotate field mask by MB
slw DataTemp,DataTemp,MemDataL // left aligned field mask
lwzx MemDataL,KernelDataPtr,UnimpRA // get RA
rotlw DataTemp,DataTemp,MemDataH // position the field mask
rotlw UnimpRS,UnimpRS,UnimpRB // position the RS data to be inserted
EmulateUpdateRA_cr0_insert:
and UnimpRS,UnimpRS,DataTemp // get new bits to insert
andc MemDataL,MemDataL,DataTemp // clear old bits to be overwritten
or. MemDataL,MemDataL,UnimpRS // insert new bits
b EmulateUpdateRA_cr0
EmulatePowerMemoryInvalidForm:
// 011111 rt-rt ra-ra rb-rb 01000 10101 . lscbx[.] rt,ra,rb
// 011111 rt-rt ra-ra rb-rb 10000 10101 x lswx rt,ra,rb
// 011111 rt-rt ra-ra nb-nb 10010 10101 x lswi rt,ra,nb
// 011111 rt-rt ra-ra rb-rb 00001 10111 x lwzux rt,ra,rb
// 011111 rt-rt ra-ra rb-rb 00011 10111 x lbzux rt,ra,rb
// 011111 rs-rs ra-ra rb-rb 00101 10111 x stwux rs,ra,rb
// 011111 rs-rs ra-ra rb-rb 00111 10111 x stbux rs,ra,rb
// 011111 rt-rt ra-ra rb-rb 01001 10111 x lhzux rt,ra,rb
// 011111 rt-rt ra-ra rb-rb 01011 10111 x lhaux rt,ra,rb
// 011111 rs-rs ra-ra rb-rb 01101 10111 x sthux rs,ra,rb
// 011111 ft-ft ra-ra rb-rb 10001 10111 x lfsux ft,ra,rb
// 011111 ft-ft ra-ra rb-rb 10011 10111 x lfdux ft,ra,rb
// 011111 fs-fs ra-ra rb-rb 10101 10111 x stfsux fs,ra,rb
// 011111 fs-fs ra-ra rb-rb 10111 10111 x stfdux fs,ra,rb
// 100001 rt-rt ra-ra d---d d---d d---d d lwzu rt,d(ra)
// 100011 rt-rt ra-ra d---d d---d d---d d lbzu rt,d(ra)
// 100101 rs-rs ra-ra d---d d---d d---d d stwu rs,d(ra)
// 100111 rs-rs ra-ra d---d d---d d---d d stbu rs,d(ra)
// 101001 rt-rt ra-ra d---d d---d d---d d lhzu rt,d(ra)
// 101011 rt-rt ra-ra d---d d---d d---d d lhau rt,d(ra)
// 101101 rs-rs ra-ra d---d d---d d---d d sthu rs,d(ra)
// 101110 rt-rt ra-ra d---d d---d d---d d lmw rt,d(ra)
// 110001 ft-ft ra-ra d---d d---d d---d d lfsu ft,d(ra)
// 110011 ft-ft ra-ra d---d d---d d---d d lfdu ft,d(ra)
// 110101 fs-fs ra-ra d---d d---d d---d d stfsu fs,d(ra)
// 110111 fs-fs ra-ra d---d d---d d---d d stfdu fs,d(ra)
bf b_EmulatePowerMemory,EmulateDisabledPowerMemory
b DSI_Decode // emulate the memory reference
EmulateUpdateMemOps_STFIWX:
// 011111 rt-rt ra-ra rb-rb 00001 10111 x lwzux rt,ra,rb
// 011111 rt-rt ra-ra rb-rb 00011 10111 x lbzux rt,ra,rb
// 011111 rs-rs ra-ra rb-rb 00101 10111 x stwux rs,ra,rb
// 011111 rs-rs ra-ra rb-rb 00111 10111 x stbux rs,ra,rb
// 011111 rt-rt ra-ra rb-rb 01001 10111 x lhzux rt,ra,rb
// 011111 rt-rt ra-ra rb-rb 01011 10111 x lhaux rt,ra,rb
// 011111 rs-rs ra-ra rb-rb 01101 10111 x sthux rs,ra,rb
// 011111 ft-ft ra-ra rb-rb 10001 10111 x lfsux ft,ra,rb
// 011111 ft-ft ra-ra rb-rb 10011 10111 x lfdux ft,ra,rb
// 011111 fs-fs ra-ra rb-rb 10101 10111 x stfsux fs,ra,rb
// 011111 fs-fs ra-ra rb-rb 10111 10111 x stfdux fs,ra,rb
// 011111 fs-fs ra-ra rb-rb 11110 10111 x stfiwx fs,ra,rb
bt 25,EmulatePowerMemoryInvalidForm // update forms may be invalid forms
EmulateSTFIWX:
// 011111 fs-fs ra-ra rb-rb 11110 10111 x stfiwx fs,ra,rb
bf b_EmulateOptional,EmulateDisabledOptional
b DSI_Decode // emulate the memory reference
.align 8
MemProcBase:
// The Setup routines expect the following register contents:
//
// KernelDataPtr Points to base of KernelData page, XCP_GPR_0_31 must be first
// SavedSRR0 The address of the instruction that caused the exception
// SavedSRR1 The MSR at the time of the exception (low 16 bits)
// SavedLR The Link Register at the time of the exception
// SavedCR The Condition Register at the time of the exception
// SavedVBR The contents of VectorBaseSPRG at the time of the exception
// MemCmdInfo 6/MemOp,5/RT,5/RA,10/0,5/size,1/RW
// MemUpdateEA The effective address generated by the memory reference
// MemAddress Don't care
// MemDataH Don't care
// MemDataL High 3 bytes must be zero, low byte is don't care
// MemProcPtr High 22 bits point to MemProcBase, low 10 bits don't care
// MemSetupInfo Low byte, completion routine index
// MemCtxFlags Copy of ActiveCtxFlags
// MSR_Enabled Data to load into MSR to enable DR
// MSR_Disabled Data to load into MSR to disable DR and possibly enable FP
// jMemInstr The entire instruction that caused the exception (If FlagReadInstr)
// MemByteCount Don't care
// RegIndex Don't care
// DataTemp Don't care
// PTEaddr unused
// PTEu unused
// PTEl unused
// LR Points to setup routine
// CR CR3 contains the 4 flag bits
// gpr 0..31 are saved in XCP_GPR_0_31
// gpr 0,2..9 are same as saved copy
// The Completion routines expect the following register contents:
//
// KernelDataPtr Points to base of KernelData page, XCP_GPR_0_31 must be first
// SavedSRR0 The address of the instruction that caused the exception
// SavedSRR1 The MSR at the time of the exception (low 16 bits)
// SavedLR The Link Register at the time of the exception
// SavedCR The Condition Register at the time of the exception
// SavedVBR The contents of VectorBaseSPRG at the time of the exception
// MemCmdInfo 6/MemOp,5/RT,5/RA,10/MemOpSpecific,5/size,1/RW
// MemUpdateEA The effective address for updating, or other completion purposes
// MemAddress Address of byte just past end of data
// MemDataH High 4 bytes of data that was read/written
// MemDataL Low 4 bytes of data that was read/written
// MemProcPtr High 22 bits point to MemProcBase, low 10 bits don't care
// MemSetupInfo Low byte, completion routine index
// MemCtxFlags Copy of ActiveCtxFlags
// MSR_Enabled Data to load into MSR to enable DR
// MSR_Disabled Data to load into MSR to disable DR and possibly enable FP
// MemInstr Don't care
// MemByteCount Don't care
// RegIndex Don't care
// DataTemp Don't care
// PTEaddr unused
// PTEu unused
// PTEl unused
// LR Points to completion routine
// CR CR3 contains the low 2 flag bits
// gpr 0..31 are saved in XCP_GPR_0_31
//gpr 0,2..9 are same as saved copy, iff b_FlagRegModified=0
SetupLDAR:
Setup0000010:
Setup0000011:
Setup0000100:
Setup0000101:
Setup0000110:
Setup0000111:
Setup0001000:
Setup0001001:
Setup0001010:
Setup0001011:
Setup0001111:
Setup0010000:
Setup0010001:
Setup0010010:
Setup0010011:
Setup0010100:
Setup0010101:
Setup0010110:
Setup0010111:
Setup0011000:
Setup0011001:
Setup0011010:
Setup0011011:
SetupLMD:
SetupSTMD:
Setup0100001:
Setup0100011:
Setup0100110:
Setup0100111:
Setup0101100:
Setup0101101:
Setup0101110:
Setup0101111:
Setup0110001:
Setup0110011:
Setup0110100:
Setup0110110:
Setup0110111:
Setup0111000:
Setup0111001:
Setup0111010:
Setup0111011:
Setup0111100:
Setup0111101:
Setup0111110:
Setup0111111:
Setup1000000:
SetupSTDCX:
Setup1000101:
Setup1000110:
SetupDCBI:
SetupSYNC:
Setup1001011:
SetupEIEIO:
SetupCLF:
Setup1010010:
Setup1010101:
SetupCLI:
Setup1011000:
SetupDCLST:
Setup1011010:
Setup1011011:
Setup1011100:
Setup1011101:
Setup1011110:
SetupLFQX:
Setup1101101:
SetupSTFQX:
SetupLFQUX:
Setup1111101:
SetupSTFQUX:
Setup1111111:
bl KernelCrash // invalid memory exception opcode
#if 0
Complete0001_00:
Complete0001_11:
Complete0010_00:
Complete0010_11:
Complete0011_00:
Complete0011_01:
CompleteLDAR:
CompleteSTDC_:
Complete0110_00:
Complete0110_01:
CompleteLMD:
Complete0111_00:
Complete0111_01:
CompleteSTMD:
Complete1100_01:
Complete1100_10:
Complete1100_11:
Complete1101_00:
Complete1101_01:
Complete1101_10:
Complete1101_11:
Complete1110_00:
Complete1110_01:
Complete1110_10:
Complete1110_11:
Complete1111_00:
Complete1111_01:
CompleteIllegal:
b CompleteForceEx
SetupSTFSX: rlwinm MemCmdInfo,MemCmdInfo,0,0xFFE0FFFF // RA <- 0, no update
SetupSTFSUX:crclr 31 // indicate single precision
b SetupFloatStore
SetupSTFDX:
SetupSTFIWX:rlwinm MemCmdInfo,MemCmdInfo,0,0xFFE0FFFF // RA <- 0, no update
SetupSTFDUX:crset 31 // indicate double precision
SetupFloatStore:
rlwinm MemAddress,MemProcPtr,0,0xFFFFFC00 // clear low bits
rlwimi MemAddress,MemCmdInfo,6+5+3,0xF8 // get index of FRS register
la MemAddress,StoreFPreg-MemProcBase(MemAddress)
mtlr MemAddress // setup to get FRS
rlwimi MSR_Disabled,SavedSRR1,0,msr_fp // setup to enable FP regs
mtmsr MSR_Disabled // enable FP regs, if they were valid
isync
blr // FP reg -> DataConvertBuffer
SetupFloatStoreDone:
ori SavedSRR1,SavedSRR1,msr_fp // FP regs are now valid
lwz MemDataH,DataConvertBuffer+0(KernelDataPtr) // get upper half of data
lwz MemDataL,DataConvertBuffer+4(KernelDataPtr) // get lower half of data
bt 31,SetupDone // all done if double prec
rlwinm DataTemp,MemDataH,12,0x07FF // get DP exponent, test for zero
cmpwi DataTemp,896 // check for denorm
rlwimi MemDataH,MemDataH,3,0x3FFFFFF8 // convert dp to sp
rlwimi MemDataH,MemDataL,3,0x00000007 // convert dp to sp
mr MemDataL,MemDataH // setup 32 bits to be stored
bgt SetupDone // all done if normalized single
cmpwi DataTemp,874 // check for denorm to zero
rlwinm MemDataL,MemDataH,0,0x80000000 // retain sign, exp/frac <- 0
blt SetupDone // all done if denorm to zero
oris MemDataH,MemDataH,0x0080 // insert msb
neg DataTemp,DataTemp // shift amount 0
22 (low 6 bits)
rlwinm MemDataH,MemDataH,0,0x00FFFFFF // clear high bits
srw MemDataH,MemDataH,DataTemp // denormalize the data
rlwimi MemDataL,MemDataH,31,0x007FFFFF // insert the shifted fraction
b SetupDone // all done
SetupSTWBRX:
rlwinm RegIndex,MemCmdInfo,6+5+2,0x7C // get index of RS register
lwbrx MemDataL,KernelDataPtr,RegIndex // get register RS, data to store
b SetupDoneClearRA
SetupSTHBRX:
rlwinm RegIndex,MemCmdInfo,6+5+2,0x7C // get index of RS register
la MemDataL,2(KernelDataPtr)
lhbrx MemDataL,MemDataL,RegIndex // get register RS, data to store
b SetupDoneClearRA
SetupSTMW:
SetupSTBUX:
SetupSTHUX:
SetupSTWUX:
SetupSTDUX:
SetupSTDU:
rlwinm RegIndex,MemCmdInfo,6+5+2,0x7C // get index of RS register
lwzx MemDataL,KernelDataPtr,RegIndex // get register RS, data to store
b SetupDone
SetupSTBX:
SetupSTHX:
SetupSTWX:
SetupSTWCX_:
SetupSTDX:
SetupSTD:
SetupECOWX:
rlwinm RegIndex,MemCmdInfo,6+5+2,0x7C // get index of RS register
lwzx MemDataL,KernelDataPtr,RegIndex // get register RS, data to store
SetupLBZX:
SetupLHZX:
SetupLHAX:
SetupLWZX:
SetupLWA:
SetupLWAX:
SetupLWAR:
SetupLFSX:
SetupLD:
SetupLDX:
SetupLFDX:
SetupECIWX:
SetupDoneClearRA:
rlwinm MemCmdInfo,MemCmdInfo,0,0xFFE0FFFF // RA <- 0, no update
SetupDCBF:
SetupDCBT:
SetupICBI:
SetupDCBST:
SetupDCBTST:
SetupLBZUX:
SetupLHZUX:
SetupLHAUX:
SetupLHBRX:
SetupLWZUX:
SetupLWAUX:
SetupLWBRX:
SetupLMW:
SetupLFSUX:
SetupLDU:
SetupLDUX:
SetupLFDUX:
SetupDone:
rlwinm. MemByteCount,MemCmdInfo,31,0x0F // get byte count, test for zero
add MemAddress,MemUpdateEA,MemByteCount // point past end of data
RetryStart:
rlwinm MemProcPtr,MemProcPtr,0,0xFFFFFC00 // setup to insert alignment info
rlwimi MemProcPtr,MemAddress,1,0x0E // insert low 3 bits of end address
rlwimi MemProcPtr,MemCmdInfo,4,0xF0 // insert len, r/w
lha MemByteCount,RetryLookup-MemProcBase(MemProcPtr)
la DataTemp,VectorTableDSI(KernelDataPtr)
add MemByteCount,MemByteCount,MemProcPtr
mtlr MemByteCount
mtsprg VectorBaseSPRG,DataTemp // setup to catch nested DSIs
mtmsr MSR_Enabled
isync
rlwimi MemProcPtr,MemSetupInfo,2,0x03FC // insert completion routine index
bnelr // read/write the bytes if count <> 0
b RetryDone // nothing to retry if count = 0
W4_22: srwi DataTemp,MemDataL,16
sth DataTemp,-4(MemAddress)
addi MemCmdInfo,MemCmdInfo,2*MemCmdSizeDec
sth MemDataL,-2(MemAddress)
b RetryDone
R4_22: lhz DataTemp,-4(MemAddress)
addi MemCmdInfo,MemCmdInfo,2*MemCmdSizeDec
rlwimi MemDataL,DataTemp,16,0xFFFF0000
R2_2: lhz DataTemp,-2(MemAddress)
rlwimi MemDataL,DataTemp, 0,0x0000FFFF
RetryDoneNoData:
RetryDone: bl WaitBusIdle
rlwinm. RegIndex,MemCmdInfo,16+2,0x7C // get RA register index, test RA=0
mtlr MemProcPtr // point to completion routine
cror eq,eq,b_FlagNoUpdate
mtsprg VectorBaseSPRG,SavedVBR // restore previous exception vectors
beqlr // run completion proc if no update
crset b_FlagRegModified // indicate that saved registers are modified
stwx MemUpdateEA,KernelDataPtr,RegIndex // update RA register
blr // run completion proc
CompleteLHA:
extsh MemDataL,MemDataL // sign extend the data
CompleteLBZ:
CompleteLHZ:
CompleteLWZ:
CompleteLWA:
CompleteLD:
rlwinm RegIndex,MemCmdInfo,11+2,0x7C // get RT register index
crset b_FlagRegModified // indicate that saved registers are modified
stwx MemDataL,KernelDataPtr,RegIndex // update RT register
CompleteSTB:
CompleteSTH:
CompleteSTW:
CompleteSTD:
CompleteMemOpDone:
andi. DataTemp,MemCtxFlags,1<<(31-b_CtxFlagTracePending) // see if trace pending
la SavedSRR0,4(SavedSRR0) // skip over the faulting instr
mtsrr0 SavedSRR0
mtsrr1 SavedSRR1
bne CompleteTracePending
mtlr SavedLR
// when b_FlagRegModified = 0, gpr 0,2
9 are still valid, gpr 0
31 are saved in XCP_GPR_0_31
// when b_FlagRegModified = 1, gpr 0,2
9 may be invalid, gpr 0
31 are saved in XCP_GPR_0_31
bf b_FlagRegModified,CompleteReturnMin
CompleteReturnMax:
mtcr SavedCR
lmw r2,XCP_GPR_0_31+(2*4)(KernelDataPtr)
lwz r0,XCP_GPR_0_31+(0*4)(KernelDataPtr)
lwz r1,XCP_GPR_0_31+(1*4)(KernelDataPtr)
rfi
CompleteReturnMin:
mtcr SavedCR
lmw r10,XCP_GPR_0_31+(10*4)(KernelDataPtr)
lwz r1,XCP_GPR_0_31+( 1*4)(KernelDataPtr)
rfi
CompleteTracePending:
mfsprg SavedVBR,VectorBaseSPRG
mtsprg lrSaveSPRG,SavedLR
rlwinm MemCtxFlags,MemCtxFlags,0,~(1<<(31-b_CtxFlagTracePending))
lwz SavedLR,0x0D00>>6(SavedVBR) // get the trace handler
stw MemCtxFlags,ActiveCtxFlags(KernelDataPtr)
mtcr SavedCR
mtlr SavedLR
lmw r2,XCP_GPR_0_31+(2*4)(KernelDataPtr)
lwz r0,XCP_GPR_0_31+(0*4)(KernelDataPtr)
lwz r1,XCP_GPR_0_31+(1*4)(KernelDataPtr)
mtsprg r1SaveSPRG,r1
blrl
CompleteLHBR:
slwi MemDataL,MemDataL,16 // shift bytes into high half, zero fill
CompleteLWBR:
rlwinm RegIndex,MemCmdInfo,11+2,0x7C // get RT register index
crset b_FlagRegModified // indicate that saved registers are modified
stwbrx MemDataL,KernelDataPtr,RegIndex // update RT register
b CompleteMemOpDone
CompleteLFS:rlwinm MemDataH,MemDataL,0,0x80000000 // copy the sign bit
xor. MemDataL,MemDataH,MemDataL // clear sign, test for +/- zero
beq CompleteLFD // If all zero, all done
rlwinm. DataTemp,MemDataL,16,0x00007F80 // get the exponent, test for zero
addi DataTemp,DataTemp,0x0080 // setup to extend exp=255
rlwimi MemDataH,MemDataL,32-3,0x07FFFFFF // convert sp to dp
extsh DataTemp,DataTemp // fill with FFFF if exp=255
rlwimi MemDataH,MemDataL,0,0x40000000 // update bit 1
slwi MemDataL,MemDataL,32-3 // convert sp to dp
subi DataTemp,DataTemp,0x4080 // compute bits 2
4
rlwimi MemDataH,DataTemp,0,0x38000000 // convert sp to dp
bne CompleteLFD // all done if not denorm
srwi MemDataL,MemDataL,20 // reassemble fraction
rlwimi MemDataL,MemDataH,12,0xFFFFF000 // reassemble fraction
cntlzw DataTemp,MemDataL // setup to normalize
slw MemDataL,MemDataL,DataTemp // normalize fraction
neg DataTemp,DataTemp // setup to compute exponent
rlwimi MemDataH,MemDataL,1+20,0x000FFFFF // convert sp to dp
addi DataTemp,DataTemp,1023-127 // compute dp exponent
slwi MemDataL,MemDataL,1+20 // convert sp to dp
rlwimi MemDataH,DataTemp,20,0x7FF00000 // insert exponent
CompleteLFD:rlwinm DataTemp,MemProcPtr,0,0xFFFFFC00 // clear low bits
rlwimi DataTemp,MemCmdInfo,6+5+3,0xF8 // get index of FRT register
la DataTemp,LoadFPreg-MemProcBase(DataTemp)
mtlr DataTemp // setup to get FRT
stw MemDataH,DataConvertBuffer+0(KernelDataPtr) // save upper half of data
stw MemDataL,DataConvertBuffer+4(KernelDataPtr) // save lower half of data
rlwimi MSR_Disabled,SavedSRR1,0,msr_fp // setup to enable FP regs
mtmsr MSR_Disabled // enable FP regs, if they were valid
isync
ori SavedSRR1,SavedSRR1,msr_fp // FP regs will become valid
blr // FP reg <- DataConvertBuffer
CompleteLMW:rlwinm. RegIndex,MemCmdInfo,6+5+2,0x7C // get RT register index, test zero
rlwinm DataTemp,MemCmdInfo,6+5+5+2,0x7C // get RA index, to compare to RT
cmpw cr7,RegIndex,DataTemp // see if RT=RA
addis MemCmdInfo,MemCmdInfo,1<<5 // increment RT
beq CompleteLMWupdateRT // always update if RT=0
beq cr7,CompleteLMWskipRT // dont update if RT=RA
CompleteLMWupdateRT:
stwx MemDataL,KernelDataPtr,RegIndex // update RT register
CompleteLMWskipRT:
cmpwi RegIndex,31*4 // check RT=31
li MemByteCount,(4<<1)+1 // read 4 bytes
rlwimi MemCmdInfo,MemByteCount,0,0x3F // insert byte count, r/w
la MemAddress,4(MemAddress) // point past end of data
bne RetryStart // continue until RT=31
b CompleteMemOpDone // all done when RT=31
CompleteSTMW:
addis MemCmdInfo,MemCmdInfo,1<<5 // increment RS
rlwinm. RegIndex,MemCmdInfo,6+5+2,0x7C // get index of RS register, check wrap
beq CompleteMemOpDone // all done when 31 wraps to 0
lwzx MemDataL,KernelDataPtr,RegIndex // get register RS, data to store
li MemByteCount,(4<<1)+0 // write 4 bytes
rlwimi MemCmdInfo,MemByteCount,0,0x3F // insert byte count, r/w
la MemAddress,4(MemAddress) // point past end of data
b RetryStart // store the next register
SetupDCBZ: lhz MemDataL,PI+DataCacheBlockSize(KernelDataPtr)
neg MemDataL,MemDataL // form mask
and MemAddress,MemUpdateEA,MemDataL // align address to start of cache block
b CompleteDCBZnext // start zeroing
CompleteDCBZ:
lhz MemDataL,PI+DataCacheBlockSize(KernelDataPtr)
subi MemDataL,MemDataL,8 // DCBZ size - 8
and. MemByteCount,MemAddress,MemDataL // check for wrap into next cache block
rlwinm MemAddress,MemAddress,0,-8 // align address to next 8 bytes
beq CompleteMemOpDone // all done when 31 wraps to 0
CompleteDCBZnext:
li MemByteCount,(8<<1)+0 // write 8 bytes
rlwimi. MemCmdInfo,MemByteCount,0,0x3F // insert byte count, r/w force ne for RetryStart
la MemAddress,8(MemAddress) // point past end of data
li MemDataH,0 // store 8 bytes of zeros at a time
li MemDataL,0 // store 8 bytes of zeros at a time
b RetryStart // store the next register
CompleteLWAR:
rlwinm RegIndex,MemCmdInfo,11+2,0x7C // get RT register index
crset b_FlagRegModified // indicate that saved registers are modified
stwx MemDataL,KernelDataPtr,RegIndex // update RT register
stwcx. MemDataL,KernelDataPtr,RegIndex // clear the reservation
b CompleteMemOpDone // complete the load
CompleteSTWC_: // perform a rd instead of wr to update HTAB
stwcx. r0,0,KernelDataPtr // XCP_GPR_0_31+(0*4)(KernelDataPtr), clear reservation
mfcr DataTemp // get CR0 (especially updated SO bit)
rlwinm DataTemp,DataTemp,0,0xDFFFFFFF // clear the EQ bit, indicate store not performed
rlwimi SavedCR,DataTemp,0,0xF0000000 // update saved CR0
b CompleteMemOpDone // complete the operation
CompleteTouchRd:
rlwinm MemCtxFlags,MemCtxFlags,0,~((1<<(31-b_CtxFlagTracePending))|(1<<(31-b_CtxFlagMemInfoValid)))
la SavedSRR0,-4(SavedSRR0) // re-execute the instruction
stw MemCtxFlags,ActiveCtxFlags(KernelDataPtr) // clear pending exceptions
b CompleteMemOpDone // retry the operation
CompleteForceEx:
li Tmp1,ecDataInvalidAddress // there are no legal addresses for this op
b GenerateMemException // Invalid Address, Mem Exception
SetupSTSWI: subi MemByteCount,MemInstr,1<<11 // get NB field - 1
rlwinm MemByteCount,MemByteCount,21,0x1F // get count - 1
b SetupSTSW // join common code
SetupSTSWX: mfxer MemByteCount // get byte count
andi. MemByteCount,MemByteCount,0x7F // test for zero, clear unused bits
subi MemByteCount,MemByteCount,1 // get count - 1
beq CompleteMemOpDone // all done if count=0
SetupSTSW: rlwimi MemCmdInfo,MemByteCount,4,0x07C0 // insert register count
not MemByteCount,MemByteCount // compute ending byte number
rlwimi MemCmdInfo,MemByteCount,26,0x0C000000 // modify low 2 bits of memop
mr MemAddress,MemUpdateEA // point to start of data
b CompleteSTSWnext // store the next register
CompleteSTSW_4:
CompleteSTSW_3:
CompleteSTSW_2:
CompleteSTSW_1:
andi. MemByteCount,MemCmdInfo,0x07C0 // see if all done
addis RegIndex,MemCmdInfo,1<<5 // increment RS, may wrap around
rlwimi MemCmdInfo,RegIndex,0,0x03E00000 // insert incremented RS field
subi MemCmdInfo,MemCmdInfo,0x0040 // decrement reg count field
bne CompleteSTSWnext // continue if count<>0
b CompleteMemOpDone // all done if count=0
SetupLSWI: subi MemByteCount,MemInstr,1<<11 // get NB field - 1
rlwinm MemByteCount,MemByteCount,21,0x1F // get count - 1
addis RegIndex,MemInstr,0x1F<<5 // get RT field - 1
rlwimi MemCmdInfo,RegIndex,22,0x0000F800 // create RB field = RT-1
b SetupLSW // join common code
SetupLSWX: mfxer MemByteCount // get byte count
andi. MemByteCount,MemByteCount,0x7F // test for zero, clear unused bits
rlwimi MemCmdInfo,MemInstr,0,0x0000F800 // insert RB field
subi MemByteCount,MemByteCount,1 // get count - 1
beq CompleteMemOpDone // all done if count=0
SetupLSW: andis. DataTemp,MemCmdInfo,0x001F // see if RA=0
rlwimi MemCmdInfo,MemByteCount,4,0x07C0 // insert register count
not MemByteCount,MemByteCount // compute ending byte number
rlwimi MemCmdInfo,MemByteCount,26,0x0C000000 // modify low 2 bits of memop
mr MemAddress,MemUpdateEA // point to start of data
bne CompleteLSWnext // load the next register (RA<>0)
rlwimi MemCmdInfo,MemCmdInfo,5,0x001F0000 // Use RB for RA when RA=0
b CompleteLSWnext // load the next register
CompleteLSW_4:
CompleteLSW_3:
CompleteLSW_2:
CompleteLSW_1:
andi. MemByteCount,MemCmdInfo,0x07C0 // see if last register
rlwinm RegIndex,MemCmdInfo,6+5+2,0x7C // get index of RT register
bne CompleteLSWnoShift // don't shift data unless last register
rlwinm MemByteCount,MemCmdInfo,9,0x18 // get the shift amount
slw MemDataL,MemDataL,MemByteCount // left align the data
b CompleteLSWnoShift // join common code
CompleteLSCB_4:
CompleteLSCB_3:
CompleteLSCB_2:
CompleteLSCB_1:
CompleteLSCB__4:
CompleteLSCB__3:
CompleteLSCB__2:
CompleteLSCB__1:
rlwinm. MemByteCount,MemCmdInfo,32-4,0x07C // see if last register
rlwinm RegIndex,MemCmdInfo,6+5+2,0x7C // get index of RT register
bne CompleteLSCBnoShift // don't shift data unless last register
rlwinm DataTemp,MemCmdInfo,9,0x18 // get the shift amount
slw MemDataL,MemDataL,DataTemp // left align the data
b CompleteLSCBnoShift // join common code
SetupLSCBX: mfxer MemByteCount // get byte count
andi. MemByteCount,MemByteCount,0x7F // test for zero, clear unused bits
rlwimi MemCmdInfo,MemInstr,0,0x0000F800 // insert RB field
rlwimi MemCmdInfo,MemInstr,28,0x10000000 // insert RC bit
cmpw cr7,MemInstr,MemByteCount // force CR7 to NE condition
beq CompleteLSCBend // all done if count=0
subi MemByteCount,MemByteCount,1 // get count - 1
andis. DataTemp,MemCmdInfo,0x001F // see if RA=0
rlwimi MemCmdInfo,MemByteCount,4,0x07C0 // insert register count
not MemByteCount,MemByteCount // compute ending byte number
rlwimi MemCmdInfo,MemByteCount,26,0x0C000000 // modify low 2 bits of memop
mr MemAddress,MemUpdateEA // point to start of data
bne CompleteLSCBnext // load the next register (RA<>0)
rlwimi MemCmdInfo,MemCmdInfo,5,0x001F0000 // Use RB for RA when RA=0
b CompleteLSCBnext // load the next register
// NOTE: All of the Setup/Complete entry points must reside in the 1024 byte range
// starting at MemProcBase. To make sure that they all fit, some of the longer routines
// have been split up, and are continued here, which can be outside of the 1024 byte range.
CompleteSTSWnext:
andi. DataTemp,MemCmdInfo,0x07C0 // see if last register
rlwinm RegIndex,MemCmdInfo,6+5+2,0x7C // get index of RS register
lwzx MemDataL,KernelDataPtr,RegIndex // get register RS, data to store
li MemByteCount,(4<<1)+0 // write 4 bytes
rlwimi MemCmdInfo,MemByteCount,0,0x3F // insert byte count, r/w
la MemAddress,4(MemAddress) // point past end of data
bne RetryStart // store the next register
rlwinm MemByteCount,MemCmdInfo,9,0x18 // get the shift amount
srw MemDataL,MemDataL,MemByteCount // right align the data
rlwinm MemByteCount,MemCmdInfo,6,0x03 // get the remaining byte count
neg MemByteCount,MemByteCount // setup for subtraction
add MemAddress,MemAddress,MemByteCount // adjust the ending address
addi MemByteCount,MemByteCount,4 // compute number of bytes to write
rlwimi. MemCmdInfo,MemByteCount,1,0x3E // insert byte count, force ne for RetryStart
b RetryStart // store the last register
CompleteLSWnoShift:
rlwinm DataTemp,MemCmdInfo,6+5+5+2,0x7C // get RA index, to compare to RT
cmpw cr7,RegIndex,DataTemp // see if RT=RA
rlwinm DataTemp,MemCmdInfo,6+5+5+5+2,0x7C // get RB index, to compare to RT
cmpw cr6,RegIndex,DataTemp // see if RT=RB
beq cr7,CompleteLSWupdateDone // skip register if RT=RA
beq cr6,CompleteLSWupdateDone // skip register if RT=RB
stwx MemDataL,KernelDataPtr,RegIndex // update register RT
CompleteLSWupdateDone:
addis RegIndex,MemCmdInfo,1<<5 // increment RT, may wrap around
rlwimi MemCmdInfo,RegIndex,0,0x03E00000 // insert incremented RT field
subi MemCmdInfo,MemCmdInfo,0x0040 // decrement reg count field
beq CompleteMemOpDone // all done if count=0
CompleteLSCBnext:
CompleteLSWnext:
andi. DataTemp,MemCmdInfo,0x07C0 // see if last register
li MemByteCount,(4<<1)+1 // read 4 bytes
rlwimi MemCmdInfo,MemByteCount,0,0x3F // insert byte count, r/w
la MemAddress,4(MemAddress) // point past end of data
bne RetryStart // read the next word
rlwinm MemByteCount,MemCmdInfo,6,0x03 // get the remaining byte count
neg MemByteCount,MemByteCount // setup for subtraction
add MemAddress,MemAddress,MemByteCount // adjust the ending address
addi MemByteCount,MemByteCount,4 // compute number of bytes to read
rlwimi. MemCmdInfo,MemByteCount,1,0x3E // insert byte count, force ne for RetryStart
b RetryStart // store the last register
CompleteLSCBnoShift:
rlwinm DataTemp,MemCmdInfo,6+5+5+2,0x7C // get RA index, to compare to RT
cmpw cr7,RegIndex,DataTemp // see if RT=RA
rlwinm DataTemp,MemCmdInfo,6+5+5+5+2,0x7C // get RB index, to compare to RT
cmpw cr6,RegIndex,DataTemp // see if RT=RB
beq cr7,CompleteLSCBupdateDone // skip register if RT=RA
beq cr6,CompleteLSCBupdateDone // skip register if RT=RB
stwx MemDataL,KernelDataPtr,RegIndex // update register RT
CompleteLSCBupdateDone:
addis RegIndex,MemCmdInfo,1<<5 // increment RT, may wrap around
rlwimi MemCmdInfo,RegIndex,0,0x03E00000 // insert incremented RT field
subi MemCmdInfo,MemCmdInfo,0x0040 // decrement reg count field
not MemByteCount,MemByteCount // setup to compute negative count
rlwimi MemByteCount,MemCmdInfo,6,0x03 // insert low 2 bits
li RegIndex,1 // setup to increment neg count
mfxer DataTemp // get byte to compare to
rlwinm DataTemp,DataTemp,32-8,0xFF // right align it
rlwinm MemDataH,MemDataL,8,0xFF // get byte 0
cmpw cr7,MemDataH,DataTemp // check for match
add. MemByteCount,MemByteCount,RegIndex // count the byte, check for end
beq cr7,CompleteLSCBmatch // exit if match found
beq CompleteLSCBend // exit if end of string reached
rlwinm MemDataH,MemDataL,16,0xFF // get byte 1
cmpw cr7,MemDataH,DataTemp // check for match
add. MemByteCount,MemByteCount,RegIndex // count the byte, check for end
beq cr7,CompleteLSCBmatch // exit if match found
beq CompleteLSCBend // exit if end of string reached
rlwinm MemDataH,MemDataL,24,0xFF // get byte 2
cmpw cr7,MemDataH,DataTemp // check for match
add. MemByteCount,MemByteCount,RegIndex // count the byte, check for end
beq cr7,CompleteLSCBmatch // exit if match found
beq CompleteLSCBend // exit if end of string reached
rlwinm MemDataH,MemDataL,0,0xFF // get byte 3
cmpw cr7,MemDataH,DataTemp // check for match
add. MemByteCount,MemByteCount,RegIndex // count the byte, check for end
beq cr7,CompleteLSCBmatch // exit if match found
bne CompleteLSCBnext // continue reading if more bytes
CompleteLSCBend:
CompleteLSCBmatch:
rlwinm. RegIndex,MemCmdInfo,0,0x10000000 // test the RC bit
mfxer DataTemp // get string length
add MemByteCount,MemByteCount,DataTemp // compute number of bytes compared
rlwimi DataTemp,MemByteCount,0,0x7F // insert into XER
mtxer DataTemp // restore XER
beq CompleteMemOpDone // all done if RC=0
mfcr DataTemp // get the match/so bits
rlwinm DataTemp,DataTemp,0,0x03 // clear the lt/gt bits
rlwimi SavedCR,DataTemp,28,0xF0000000 // update the saved CR0 field
b CompleteMemOpDone // all done
R8_1241: lbz DataTemp,-8(MemAddress)
addi MemCmdInfo,MemCmdInfo,1*MemCmdSizeDec
rlwimi MemDataH,DataTemp,24,0xFF000000
R7_241: lhz DataTemp,-7(MemAddress)
addi MemCmdInfo,MemCmdInfo,2*MemCmdSizeDec
rlwimi MemDataH,DataTemp, 8,0x00FFFF00
b R5_41
R6_141: lbz DataTemp,-6(MemAddress)
addi MemCmdInfo,MemCmdInfo,1*MemCmdSizeDec
rlwimi MemDataH,DataTemp, 8,0x0000FF00
R5_41: lwz DataTemp,-5(MemAddress)
addi MemCmdInfo,MemCmdInfo,4*MemCmdSizeDec
rlwimi MemDataH,DataTemp, 8,0x000000FF
rlwimi MemDataL,DataTemp, 8,0xFFFFFF00
b R1_1
R8_1421: lbz DataTemp,-8(MemAddress)
addi MemCmdInfo,MemCmdInfo,1*MemCmdSizeDec
rlwimi MemDataH,DataTemp,24,0xFF000000
R7_421: lwz DataTemp,-7(MemAddress)
addi MemCmdInfo,MemCmdInfo,4*MemCmdSizeDec
rlwimi MemDataH,DataTemp,24,0x00FFFFFF
rlwimi MemDataL,DataTemp,24,0xFF000000
b R3_21
R6_1221: lbz DataTemp,-6(MemAddress)
addi MemCmdInfo,MemCmdInfo,1*MemCmdSizeDec
rlwimi MemDataH,DataTemp, 8,0x0000FF00
R5_221: lhz DataTemp,-5(MemAddress)
addi MemCmdInfo,MemCmdInfo,2*MemCmdSizeDec
rlwimi MemDataH,DataTemp,24,0x000000FF
rlwimi MemDataL,DataTemp,24,0xFF000000
b R3_21
R4_121: lbz DataTemp,-4(MemAddress)
addi MemCmdInfo,MemCmdInfo,1*MemCmdSizeDec
rlwimi MemDataL,DataTemp,24,0xFF000000
R3_21: lhz DataTemp,-3(MemAddress)
addi MemCmdInfo,MemCmdInfo,2*MemCmdSizeDec
rlwimi MemDataL,DataTemp, 8,0x00FFFF00
b R1_1
R2_11: lbz DataTemp,-2(MemAddress)
addi MemCmdInfo,MemCmdInfo,1*MemCmdSizeDec
rlwimi MemDataL,DataTemp, 8,0x0000FF00
R1_1: lbz DataTemp,-1(MemAddress)
rlwimi MemDataL,DataTemp, 0,0x000000FF
b RetryDone
R8_242: lhz DataTemp,-8(MemAddress)
addi MemCmdInfo,MemCmdInfo,2*MemCmdSizeDec
rlwimi MemDataH,DataTemp,16,0xFFFF0000
b R6_42
R7_142: lbz DataTemp,-7(MemAddress)
addi MemCmdInfo,MemCmdInfo,1*MemCmdSizeDec
rlwimi MemDataH,DataTemp,16,0x00FF0000
R6_42: lwz DataTemp,-6(MemAddress)
addi MemCmdInfo,MemCmdInfo,4*MemCmdSizeDec
rlwimi MemDataH,DataTemp,16,0x0000FFFF
rlwimi MemDataL,DataTemp,16,0xFFFF0000
b R2_2
R5_122: lbz DataTemp,-5(MemAddress)
addi MemCmdInfo,MemCmdInfo,1*MemCmdSizeDec
rlwimi MemDataH,DataTemp, 0,0x000000FF
b R4_22
R3_12: lbz DataTemp,-3(MemAddress)
addi MemCmdInfo,MemCmdInfo,1*MemCmdSizeDec
rlwimi MemDataL,DataTemp,16,0x00FF0000
b R2_2
R8_44: lwz MemDataH,-8(MemAddress)
addi MemCmdInfo,MemCmdInfo,4*MemCmdSizeDec
lwz MemDataL,-4(MemAddress)
b RetryDone
R7_124: lbz DataTemp,-7(MemAddress)
addi MemCmdInfo,MemCmdInfo,1*MemCmdSizeDec
rlwimi MemDataH,DataTemp,16,0x00FF0000
R6_24: lhz DataTemp,-6(MemAddress)
addi MemCmdInfo,MemCmdInfo,2*MemCmdSizeDec
rlwimi MemDataH,DataTemp, 0,0x0000FFFF
lwz MemDataL,-4(MemAddress)
b RetryDone
R5_14: lbz DataTemp,-5(MemAddress)
addi MemCmdInfo,MemCmdInfo,1*MemCmdSizeDec
rlwimi MemDataH,DataTemp, 0,0x000000FF
R4_4: lwz MemDataL,-4(MemAddress)
b RetryDone
R8_8: lwz MemDataH,-8(MemAddress)
lwz MemDataL,-4(MemAddress)
b RetryDone
W8_1241: srwi DataTemp,MemDataH,24
stb DataTemp,-8(MemAddress)
addi MemCmdInfo,MemCmdInfo,1*MemCmdSizeDec
W7_241: srwi DataTemp,MemDataH,8
sth DataTemp,-7(MemAddress)
addi MemCmdInfo,MemCmdInfo,2*MemCmdSizeDec
b W5_41
W6_141: srwi DataTemp,MemDataH,8
stb DataTemp,-6(MemAddress)
addi MemCmdInfo,MemCmdInfo,1*MemCmdSizeDec
W5_41: srwi DataTemp,MemDataL,8
rlwimi DataTemp,MemDataH,24,0xFF000000
stw DataTemp,-5(MemAddress)
addi MemCmdInfo,MemCmdInfo,4*MemCmdSizeDec
stb MemDataL,-1(MemAddress)
b RetryDone
W8_1421: srwi DataTemp,MemDataH,24
stb DataTemp,-8(MemAddress)
addi MemCmdInfo,MemCmdInfo,1*MemCmdSizeDec
W7_421: srwi DataTemp,MemDataL,24
rlwimi DataTemp,MemDataH, 8,0xFFFFFF00
stw DataTemp,-7(MemAddress)
addi MemCmdInfo,MemCmdInfo,4*MemCmdSizeDec
b W3_21
W6_1221: srwi DataTemp,MemDataH,8
stb DataTemp,-6(MemAddress)
addi MemCmdInfo,MemCmdInfo,1*MemCmdSizeDec
W5_221: srwi DataTemp,MemDataL,24
rlwimi DataTemp,MemDataH, 8,0x0000FF00
sth DataTemp,-5(MemAddress)
addi MemCmdInfo,MemCmdInfo,2*MemCmdSizeDec
b W3_21
W4_121: srwi DataTemp,MemDataL,24
stb DataTemp,-4(MemAddress)
addi MemCmdInfo,MemCmdInfo,1*MemCmdSizeDec
W3_21: srwi DataTemp,MemDataL,8
sth DataTemp,-3(MemAddress)
addi MemCmdInfo,MemCmdInfo,2*MemCmdSizeDec
stb MemDataL,-1(MemAddress)
b RetryDone
W2_11: srwi DataTemp,MemDataL,8
stb DataTemp,-2(MemAddress)
addi MemCmdInfo,MemCmdInfo,1*MemCmdSizeDec
W1_1: stb MemDataL,-1(MemAddress)
b RetryDone
W8_242: srwi DataTemp,MemDataH,16
sth DataTemp,-8(MemAddress)
addi MemCmdInfo,MemCmdInfo,2*MemCmdSizeDec
b W6_42
W7_142: srwi DataTemp,MemDataH,16
stb DataTemp,-7(MemAddress)
addi MemCmdInfo,MemCmdInfo,1*MemCmdSizeDec
W6_42: srwi DataTemp,MemDataL,16
rlwimi DataTemp,MemDataH,16,0xFFFF0000
stw DataTemp,-6(MemAddress)
addi MemCmdInfo,MemCmdInfo,4*MemCmdSizeDec
sth MemDataL,-2(MemAddress)
b RetryDone
W5_122: stb MemDataH,-5(MemAddress)
addi MemCmdInfo,MemCmdInfo,1*MemCmdSizeDec
b W4_22
W3_12: srwi DataTemp,MemDataL,16
stb DataTemp,-3(MemAddress)
addi MemCmdInfo,MemCmdInfo,1*MemCmdSizeDec
W2_2: sth MemDataL,-2(MemAddress)
b RetryDone
W8_44: stw MemDataH,-8(MemAddress)
addi MemCmdInfo,MemCmdInfo,4*MemCmdSizeDec
stw MemDataL,-4(MemAddress)
b RetryDone
W7_124: srwi DataTemp,MemDataH,16
stb DataTemp,-7(MemAddress)
addi MemCmdInfo,MemCmdInfo,1*MemCmdSizeDec
W6_24: sth MemDataH,-6(MemAddress)
addi MemCmdInfo,MemCmdInfo,2*MemCmdSizeDec
stw MemDataL,-4(MemAddress)
b RetryDone
W5_14: stb MemDataH,-5(MemAddress)
addi MemCmdInfo,MemCmdInfo,1*MemCmdSizeDec
W4_4: stw MemDataL,-4(MemAddress)
b RetryDone
W8_8: stw MemDataH,-8(MemAddress)
stw MemDataL,-4(MemAddress)
b RetryDone
#endif /* 0 */
/*
** HACK! Assembler fixups!
*/
CompleteMemOpDone:
DSI_Decode:
GenerateException:
KernelCrash:
rfi
#endif
/* ---------------------------------------------------------------------------
L_MMU(type)
Adopted from Nukernel technology.
This is the exception handling routine branched to by a DSI or ISI
type of system exception.
An extension of the data access and instruction access exception handlers
installed in the hardware vectors. Satisfies the fault, if possible, from
the overflow hash table or by generating the PTE from static information.
NOTE: Must be called in the access exception path before data relocation has been
re-enabled. Instruction relocation is OK only if these routines are entirely BAT
mapped. Avoiding relocated references is a requirement for being able to move
*any* PTE out to the overflow table. Otherwise, it would be possible to "overflow
fault" inside the overflow fault handler.
This routine acts as a safety valve to handle cases when too many virtual
addresses fall in a PTE hash class (aka a PTE group or PTEG). Though the PMAP
support allows pagable entries to be tossed and reconstituted later, wired
page frames cannot be handled in this manner. This firmware function extends
the apparent size of the PTEGs by creating a software overflow list that can
house extra PTEs. When a DSI or ISI is recognized, this function checks the
overflow list for the related PTE and upon finding it, places it in its
appropriate PTEG. This may cause a PTE to be vacated into the overflow list.
Once the PTE is reinstated, control is passed directly back to the interrupted
instruction. Upon failing to find the related PTE, control is passed to the
common exit handler to propagate the DSI or ISI to the upper kernel layer for
the usual page fault resolution.
Other firmware functions replace some of the PMAP equivalent functions to
ensure searches and/or deletions include the PTEs in the overflow list.
These functions are accesed via fast path system calls.
Entry: via a system exception handler, thus interrupts off, VM off.
Entry r1-r3 have been saved in sprg1-3.
r2 - byte offset into per_proc_info of this CPU
r3 - contains the exception number.
Exit: If the PTE miss is resolved by finding the related PTE in
the overflow list, control passes directly to the exception
point. Otherwise, the exception is propagated to the usual
common exception handler.
*/
#define noErr 0
#define kernelInUseErr -1
#define kernelAlreadyFreeErr -2
.section __VECTORS, __interrupts
.align ALIGNMENT
/* Globals used by the MMU support functions to manage
the overflow hash table.
*/
.gOverflowHashTable: .long 0
.gFreeOverflowPTEs: .long 0
.gOverflowPTEGSeed: .long 0
.gOverflowTossCount: .long 0
.gOverflowReloadCount: .long 0
/* Globals used to track autogen capable areas (a nukernel area
is similar to a mach region). Areas that are autogen capable
have physically contiguous pages and are resident (wired).
*/
.gAutogenAreaList: .long 0
.gAutogenReloadCount: .long 0
.gAutogenTossCount: .long 0
L_MMU:
/* Save SRR0 and SRR1 plus cr and r3 into PER_PROC structure.
*/
stw r3, PP_SAVE_EXCEPTION_TYPE(r2)
mfsrr0 r1
mfsrr1 r3
stw r1, PP_SAVE_SRR0(r2)
stw r3, PP_SAVE_SRR1(r2)
mfdar r1
mfdsisr r3
stw r1, PP_SAVE_DAR(r2)
stw r3, PP_SAVE_DSISR(r2)
mfcr r1
stw r1, PP_SAVE_CR(r2)
/* Save registers we'll use into the per-processor buffer.
*/
stw r0, PP_SAVE_R0(r2)
stw r4, PP_SAVE_R4(r2)
stw r5, PP_SAVE_R5(r2)
stw r6, PP_SAVE_R6(r2)
stw r7, PP_SAVE_R7(r2)
stw r8, PP_SAVE_R8(r2)
stw r9, PP_SAVE_R9(r2)
stw r10, PP_SAVE_R10(r2)
stw r11, PP_SAVE_R11(r2)
stw r12, PP_SAVE_R12(r2)
mflr r0
lwz r3, PP_SAVE_EXCEPTION_TYPE(r2)
stw r0, PP_SAVE_LR(r2)
ReloadPTE:
/* Check the OverflowHashTable and AutogenAreaList,
reloading if possible.
*/
cmpwi r3, EXC_INSTRUCTION_ACCESS
mfspr r4, srr0 // fault address is PC
beq HaveFaultAddress
mfdar r4 // fault address is DAR
HaveFaultAddress:
li r3, 0 // pass "current address space"
bl LookupPTE
// EndHashTableSection r2
/* Check result and restore the registers. If extended PTE lookup worked
(r4 == noErr), rfi to resume faultee's execution. If it didn't work,
continue to process the exception as a page fault.
*/
cmpwi r4, noErr // check LookupPTE result
lwz r3, PP_SAVE_CR(r2)
lwz r5, PP_SAVE_LR(r2)
lwz r0, PP_SAVE_R0(r2)
mtlr r5
lwz r4, PP_SAVE_R4(r2)
lwz r5, PP_SAVE_R5(r2)
lwz r6, PP_SAVE_R6(r2)
lwz r7, PP_SAVE_R7(r2)
lwz r8, PP_SAVE_R8(r2)
lwz r9, PP_SAVE_R9(r2)
lwz r10, PP_SAVE_R10(r2)
lwz r11, PP_SAVE_R11(r2)
lwz r12, PP_SAVE_R12(r2)
beq- DoRFI // LookupPTE worked?
mtcr r3
b .L_Common
/* Restore the faultee's r1-r3, then rfi back with the PTE mapped! Pad (at
least) the remainder of the rfi instruction's cache line with benign values
to prevent prefetch enigmas as we transition from instruction relocation off
back to instruction relocation on. This is a problem on 601s.
*/
DoRFI: mtcr r3
mfsprg r1, 1
mfsprg r2, 2
mfsprg r3, 3
rfi
.long 0 // Safety padding
.long 0 // Safety padding
.long 0 // Safety padding
.long 0 // Safety padding
.long 0 // Safety padding
.long 0 // Safety padding
.long 0 // Safety padding
.long 0 // Safety padding
#if 0 /* WIP ================================================================== */
/*
-------------------------------------------------------------------------------------
AllocateOverflowPTE.
Inputs: r3 == PTEG address
r4 == PTE hash information word
r5 == PTE attributes word
Outputs: (none)
Changes: r3 - r6
Description.
NOTE: This routine is called with interrupts and data relocation disabled.
-------------------------------------------------------------------------------------
*/
AllocateOverflowPTE:
/* Get an entry from the overflow PTE free list.
*/
lwz r6, .gFreeOverflowPTEs(0)
stw r3, OverflowPTE.ptegAddress(r6)
lwz r3, OverflowPTE.pNextOverflowPTE(r6)
stw r3, .gFreeOverflowPTEs(0)
/* Copy thePTEG and thePTEValue into overflow PTE with pteValid set to one.
r6 == OverflowPTE, r3 == thePTEG, r4 == hash info.
*/
oris r4, r4, PTE_validMaskS
stw r4, OverflowPTE.pteValue+PTE.hashInfoWord(r6)
stw r5, OverflowPTE.pteValue+PTE.attributesWord(r6)
/* Place overflow PTE into proper hash table list head.
The hash function is the abbreviated page index (api).
r6 == OverflowPTE, r4 == hash information word
*/
rlwinm r4, r4, PTE_apiShiftOut, PTE_apiMaskOut
slwi r4, r4, 2
addi r3, r4, .gOverflowHashTable
lwz r4, 0(r3)
stw r4, OverflowPTE.pNextOverflowPTE(r6)
stw r6, 0(r3)
blr
/* -----------------------------------------------------------------------------------
void DeallocateOverflowPTE (OverflowPTE * theOverflowPTE)
Inputs: r3 == OverflowPTE to deallocate
Outputs: (none)
Changes: r3 - r5
Description.
-------------------------------------------------------------------------------------
*/
DeallocateOverflowPTE:
/* Hash function is the abbreviated page index.
*/
lwz r5, OverflowPTE.pteValue+PTE.hashInfoWord(r3)
rlwinm r5, r5, PTE_apiShiftOut, PTE_apiMaskOut
slwi r5, r5, 2
addi r4, r5, .gOverflowHashTable
/* Locate the element previous to the one being deallocated
r4 == address of current element of which to check link
r3 == address of target element.
*/
DeallocateLoop:
lwz r5, OverflowPTE.pNextOverflowPTE(r4)
cmplw r5, r3
beq DeallocateFound
mr r4, r5
b DeallocateLoop
/* Delink target element from previous element
r3 == address of target element
r4 == address of previous element in list, or the list head itself.
*/
DeallocateFound:
lwz r5, OverflowPTE.pNextOverflowPTE(r3)
stw r5, OverflowPTE.pNextOverflowPTE(r4)
/* For viewing from the debugger: Make the upper nibble of the
ptegAddress be 0xF so we can easily recognize freed elements
with all the information intact (PTEG addresses are physical,
and are most likely very low so the high 0xF does not disturb anything).
*/
#ifdef DEBUG
lwz r5, OverflowPTE.ptegAddress(r3)
oris r5, r5, 0xF000
stw r5, OverflowPTE.ptegAddress(r3)
#endif /* DEBUG */
/* Link target element into the free list. Normally, put it at
the head. For debugger viewing, put it at the end so we have
a little history.
r3 == address of target element.
*/
#ifdef DEBUG
lwz r4, .gFreeOverflowPTEs(0)
FindEnd:
lwz r5, OverflowPTE.pNextOverflowPTE(r4)
cmpwi r5, 0
beq FoundEnd
mr r4, r5
b FindEnd
FoundEnd:
stw r5, OverflowPTE.pNextOverflowPTE(r3)
stw r3, OverflowPTE.pNextOverflowPTE(r4)
#else /* DEBUG */
lwz r4, .gFreeOverflowPTEs(0)
stw r4, OverflowPTE.pNextOverflowPTE(r3)
stw r3, .gFreeOverflowPTEs(0)
#endif /* DEBUG */
blr
/* ----------------------------------------------------------------------------------
AllocateFromPTEG.
Inputs: r3 == PTEG address
r4 == PTE hash information word
r5 == PTE page attributes word
Outputs: r3 == PTE address, nil if there was no room
Changes: r3 - r6
Description.
NOTE: This routine is called with interrupts and data relocation disabled.
-------------------------------------------------------------------------------------
*/
AllocateFromPTEG:
/* Loop to find entry with pteValid == 0
*/
AllocateFromPTEGLoop:
lwz r6, PTE.hashInfoWord(r3)
andis. r6, r6, PTE_validMaskS // check PTE valid
beq FoundFreePTE // if clear, go use this PTE
addi r3, r3, PTE.sizeof // else, move to next PTE in PTEG
andi. r6, r3, kPTEGSize-1 // off end of PTEG now?
bne AllocateFromPTEGLoop // if not, loop to check PTE
/* No free entry in this PTEG.
*/
li r3, 0 // return nil
b AllocateFromPTEGDone // bye
/* Free PTE found. r3 == PTE address
*/
FoundFreePTE:
oris r4, r4, PTE_validMaskS
stw r5, PTE.attributesWord(r3)
sync
stw r4, PTE.hashInfoWord(r3)
/* Common exit path
r3 == PTE address or nil
*/
AllocateFromPTEGDone:
blr
/* -----------------------------------------------------------------------------------
LookupExistingPTEfromVSID.
Inputs: r3 == VSID.
r4 == logical address
Outputs: same as LookupExistingPTE
NOTE: This routine is called with interrupts and data relocation disabled.
-------------------------------------------------------------------------------------
*/
LookupExistingPTEfromVSID:
/* Use gSDR1 and specified VSID for theSpace.
r3 == VSID, r4 == logical address
*/
lwz r8, .gSDR1(rtoc) // r8 = memory system's SDR1
lwz r8, 0(r8)
b HaveMMUInformation
/* -----------------------------------------------------------------------------------
LookupExistingPTE.
Inputs: r3 == address space description or nil (meaning current)
r4 == logical address
Outputs: r3 == PTE address or nil
r4 == Iff r3 is nil: OverflowPTE address, or nil
r12 == msr value to restore when out of critical section
Changes: r3 - r10, r12
Exits in hash table critical section
Return the address of the PageTableEntry or OverflowPTE that map the specified
logical address. A nil AddressSpace specifies the current MMU mappings.
NOTE: This routine is called with interrupts and data relocation disabled.
-------------------------------------------------------------------------------------
*/
LookupExistingPTE:
/* Check whether caller specified a particular space, or current mappings
*/
cmpwi r3, 0 // theSpace specified?
bne UseSpecifiedSpace // if so, go use it
/* Use gSDR1 and SegmentRegister from current MMU state.
*/
mfsrin r3, r4 // r3 = SegmentRegister value
mfsdr1 r8 // r8 = SDR1
b HaveMMUInformation
/* Use gSDR1 and SegmentRegister for theSpace.
r3 == AddressSpace pointer, r4 == logical address.
*/
UseSpecifiedSpace:
lwz r3, OpaqueAddressSpacePtr.mmuInfo+MMUSpaceDesc.segmentRegisters(r3)
rlwinm r5, r4, EA_segmentNumberShiftOut+2, (EA_segmentNumberMaskOut << 2) // extract and multiply segment number
add r3, r3, r5 // make byte offset into register file
lwz r3, 0(r3) // r3 = SegmentRegister value
lwz r8, .gSDR1(rtoc) // r8 = memory system's SDR1
lwz r8, 0(r8)
/* Calculate value to match with entry's hashInfoWord
((1 << 31) | (segment ID << 7) | (theHashType << 6) | api)
r3 == SegmentRegister value, r4 == logical address, r8 == SDR1
*/
HaveMMUInformation:
rlwinm r6, r3, SR_segmentIDShiftOut+7, (SR_segmentIDMaskOut << 7) // extract, rotate segment ID
rlwinm r5, r4, EA_apiShiftOut, EA_apiMaskOut // extract abbreviated page index
or r5, r6, r5 // combine segment ID and api
oris r10, r5, PTE_validMaskS // r10 = hashInfoWord to match
/* Calculate hash values.
*/
rlwinm r5, r4, EA_virtualPageShiftOut+kLog2PTEGSize, (EA_virtualPageMaskOut << kLog2PTEGSize) // calculate (virtual page ID * kPTEGSize)
rlwinm r6, r3, SR_VSIDShiftOut+kLog2PTEGSize, (SR_VSIDMaskOut << kLog2PTEGSize) // calculate (19-bit-VSID * kPTEGSize)
xor r3, r5, r6 // calculate primary hash value
not r5, r3 // calculate secondary hash value
/* Turn off interrupts and data translation
*/
BeginHashTableSection r4, r6, r7
/* Calculate PTEG address from hash value and SDR1
r3 == primary hash value, r5 == secondary hash value,
r8 == SDR1, r10 == hashInfoWord to match.
*/
HaveHashValue:
rlwinm r6, r8, SDR1_HTABmaskShiftOut+SDR1_HTABorgShiftIn, (SDR1_HTABmaskMaskOut << SDR1_HTABorgShiftIn) // extract table mask and ...
ori r6, r6, ((-SDR1_HTABorgMask-1) & -kPTEGSize) // ... ones-fill to make mask
and r3, r3, r6 // mask the hash value
rlwinm r6, r8, 0, SDR1_HTABorgMask // isolate physical base of hash table
or r3, r6, r3 // sum base and masked hash value to get PTEG
/* Search the PTEG for matching entry
r3 == PTEG address, r10 == hashInfoWord to match.
*/
SearchPTEGLoop:
lwz r6, PTE.hashInfoWord(r3)
cmplw r6, r10 // check this PTE
beq PTELookupDone // if matched, go return it
addi r3, r3, PTE.sizeof // move to next PTE in PTEG
andi. r6, r3, kPTEGSize-1 // off end of PTEG?
bne SearchPTEGLoop // if not, go check this PTE
andi. r6, r10, PTE_hashTypeMask // tried both PTEGs now?
bne LookupOverflowPTE // if so, go try overflow
subi r9, r3, kPTEGSize // remember primary PTEG address
/* Calculate secondary hash value
*/
ori r10, r10, PTE_hashTypeMask // switch match for secondary PTEG
mr r3, r5 // get secondary hash value
b HaveHashValue // and retry
/* PTE not in main hash table, try the overflow table
r3 == secondary PTEG address + PTEGSize,
r9 == primary PTEG address,
r10 == hashInfoWord to match
*/
LookupOverflowPTE:
subi r8, r3, kPTEGSize // remember secondary PTEG address
rlwinm r10, r10, 0, ~PTE_hashTypeMask // use hash type for primary PTEG
rlwinm r6, r10, PTE_apiShiftOut+2, (PTE_apiMaskOut << 2) // multiply API by sizeof(OverflowPTE *)
addi r5, r6, .gOverflowHashTable // sum base and offset to get list head
TryAgain:
lwz r4, 0(r5) // get first OverflowPTE in list
SearchOverflowLoop:
cmpwi r4, 0 // nil OverflowPTE pointer?
beq OverflowLoopNotFound // if so, nothing found
lwz r6, OverflowPTE.ptegAddress(r4) // get PTEG from OverflowPTE
cmplw r6, r9 // matching PTEG address?
bne ContinueOverflowLoop // if not, continue loop
lwz r6, OverflowPTE.pteValue+PTE.hashInfoWord(r4)
cmplw r6, r10 // matching hash information?
beq OverflowLoopDone // if so, found OverflowPTE!
ContinueOverflowLoop:
lwz r4, OverflowPTE.pNextOverflowPTE(r4)
b SearchOverflowLoop
OverflowLoopNotFound:
cmplw r8, r9 // tried secondary already?
mr r9, r8 // switch to secondary PTEG
ori r10, r10, PTE_hashTypeMask // switch match for secondary PTEG
bne TryAgain // go look again
/* Overflow loop exited one way or the other.
r4 == OverflowPTE address, or nil.
*/
OverflowLoopDone:
#ifdef DEBUG
cmpwi r4, 0
beq DoneIncOverflowReloadCount
lwz r3, .gOverflowReloadCount(0)
addi r3, r3, 1
stw r3, .gOverflowReloadCount(0)
DoneIncOverflowReloadCount:
#endif /* DEBUG */
li r3, 0 // make nil PTE address
/* Common exit.
r3 == PTE address, or nil.
If nil, r4 == OverflowPTE address, or nil.
*/
PTELookupDone:
blr
/* -----------------------------------------------------------------------------------
GeneratePTE.
Inputs: r3 == theLogicalAddress
Outputs: r3 == primary PTEG address, or nil
r4 == primary PTE hash information word (with pteValid == 0)
r5 == PTE page attributes word
r6 == secondary PTEG address
Changes: r3 - r7
Reconstitute a PageTableEntry for the specified logical address in the current
address space, based on the AutogenArea list.
NOTE: This routine is called with interrupts and data relocation disabled.
-------------------------------------------------------------------------------------
*/
GeneratePTE:
/* Locate AutogenArea element for the specified logical address
*/
lwz r7, .gAutogenAreaList(0)
GeneratePTELoop:
cmpwi r7, 0
beq CantGenerate
lwz r4, AutogenArea.lowestBackedAddress(r7)
cmplw r4, r3 // lowest <= theLogicalAddress?
bgt ContinueGeneratePTELoop // if not, continue
lwz r4, AutogenArea.highestBackedAddress(r7)
cmplw r3, r4 // theLogicalAddress <= highest?
ble FoundAutogenArea // if so, we can generate the PTE
ContinueGeneratePTELoop:
lwz r7, AutogenArea.pNextAutogenArea(r7)
b GeneratePTELoop
/* Found an autogen area for address. Carry on.
r3 == logical address, r7 == address of autogen area
*/
FoundAutogenArea:
/* Generate hash information word
r3 == logical address
((1 << 31) | (segment ID << 7) | (theHashType << 6) | api)
*/
mfsrin r4, r3 // get segment register value
rlwinm r4, r4, PTE_segmentIDShiftIn, PTE_segmentIDMask // extract, rotate segment ID
rlwinm r5, r3, EA_apiShiftOut, EA_apiMaskOut // extract abbreviated page index
or r4, r4, r5 // combine segment ID and api
oris r4, r4, PTE_validMaskS // turn on pteValid
/* Generate page attributes word
*/
lwz r5, AutogenArea.lowestBackedAddress(r7)
sub r5, r3, r5
rlwinm r5, r5, 0, kPageAlignMask
lwz r6, AutogenArea.physicalBase(r7)
add r5, r5, r6
lwz r6, AutogenArea.pageProtection(r7)
rlwimi r5, r6, PTE_protectionShiftIn, PTE_protectionMask
lwz r6, AutogenArea.pageCacheMode(r7)
rlwimi r5, r6, PTE_cacheControlShiftIn, PTE_cacheControlMask
/* Calculate PTEG addresses
*/
mfsrin r7, r3 // get segment register value
rlwinm r6, r3, EA_virtualPageShiftOut+kLog2PTEGSize, (EA_virtualPageMaskOut << kLog2PTEGSize) // calculate (virtual page ID * kPTEGSize)
rlwinm r7, r7, SR_VSIDShiftOut+kLog2PTEGSize, (SR_VSIDMaskOut << kLog2PTEGSize) // calculate (19-bit-VSID * kPTEGSize)
xor r3, r6, r7 // calculate primary hash value
not r6, r3 // calculate secondary hash value
mfsdr1 r7 // get hash table register
rlwinm r7, r7, SDR1_HTABmaskShiftOut+SDR1_HTABorgShiftIn, (SDR1_HTABmaskMaskOut << SDR1_HTABorgShiftIn) // extract table mask and ...
ori r7, r7, ((-SDR1_HTABorgMask-1) & -kPTEGSize) // ... ones-fill to make mask
and r3, r3, r7 // mask the primary hash value
and r6, r6, r7 // mask the secondary hash value
mfsdr1 r7 // get hash table register
rlwinm r7, r7, 0, SDR1_HTABorgMask // isolate physical base of hash table
or r3, r7, r3 // r3 = primary PTEG address
or r6, r7, r6 // r6 = secondary PTEG address
#ifdef DEBUG
lwz r7, .gAutogenReloadCount(0)
addi r7, r7, 1
stw r7, .gAutogenReloadCount(0)
#endif
b GeneratePTEDone
CantGenerate:
li r3, 0
GeneratePTEDone:
blr
#endif /* WIP ================================================================== */
/* -----------------------------------------------------------------------------------
LookupPTE
Inputs: r3 == address space description or nil
r4 == theLogicalAddress
Outputs: r3 == thePTE
r4 == zero iff page was in main hash table
r12 == value for EndHashTableSection to restore msr
Changes: r0, r3 - r12
msr = hardware interrupts and data translation disabled
Map, if possible, the specified current logical address into the main hash table by
either bringing it in from the overflow hash table, or generating the PTE on-the-fly.
Exits still inside the hash table critical section so caller can access the returned
PTE address. While in the critical section, hardware interrupts and data relocation
are disabled. Caller must EndHashTableSection when done with the PTE.
NOTE: When called with r3 == nil, this routine must assume data translation is
already disabled.
-------------------------------------------------------------------------------------
*/
LookupPTE:
/* Temp stub. Indicate we didn't find a PTE in the overflow
list to propagate the exception upward.
*/
li r4, kernelInUseErr // status saying no reload
blr
#if 0 /* WIP ================================================================== */
/* save link register so we can make calls.
*/
mflr r0
/* Check the hash table and overflow table. Return error if the page is
in the main hash table, because the exception must be for some other
problem, like access level violation.
*/
mr r11, r4 // r11 = logical address
bl LookupExistingPTE // locate PTE or OverflowPTE
cmpwi r3, 0 // found PTE?
beq TryOverflow // no, what about OverflowPTE?
li r4, kernelInUseErr // status saying no reload
b LookupPTEDone // return PTE address and status
/* No overflow means we can try generating the PTE on-the-fly
*/
TryOverflow:
cmpwi r4, 0 // found OverflowPTE?
beq TryGeneratingPTE // if not, go try making PTE
/* Retrieve mapping information from, and free, the OverflowPTE
*/
lwz r8, OverflowPTE.ptegAddress(r4)
lwz r9, OverflowPTE.pteValue+PTE.hashInfoWord(r4)
lwz r10, OverflowPTE.pteValue+PTE.attributesWord(r4)
mr r3, r4
bl DeallocateOverflowPTE
mr r7, r8 // PTEG address for overflow
mr r4, r9 // hash information word
b ReloadIt
/* Not in main hash table or in overflow table.
Try to generate a PTE.
*/
TryGeneratingPTE:
mr r3, r11 // pass logical address
bl GeneratePTE
cmpwi r3, 0 // check result
bne GenerateWorked
li r3, 0 // nil PTE address
li r4, kernelAlreadyFreeErr // status saying no PTE at all
b LookupPTEDone // bye
/* PTE was generated. Try primary PTEG. Fall back to secondary PTEG.
r3 == primary PTEG, r4 == hash information, r5 == attributes,
r6 == secondary PTEG
*/
GenerateWorked:
mr r7, r3 // keep PTEG address for overflow
mr r8, r6 // keep secondary PTEG address for retry
mr r9, r4 // keep hash information word for retry
mr r10, r5 // keep attributes word for retry
bl AllocateFromPTEG
cmpwi r3, 0
bne ReloadWorked
ori r4, r9, PTE_hashTypeMask // hash information word for secondary PTEG
rlwinm r9, r9, 0, ~PTE_hashTypeMask // hash information word for overflow
/* Search specified PTEG.
r8 == PTEG to check,
r4 == PTE hash information word,
r10 == PTE page attribute word
r7 == PTEG address for overflow,
r9 == PTE hash information word for overflow.
*/
ReloadIt:
mr r3, r8 // pass PTEG address
mr r5, r10 // pass attributes word
bl AllocateFromPTEG
cmpwi r3, 0 // check result
bne ReloadWorked // if it worked, we're done
/* No room in primary or secondary PTEG.
Select an existing PTE to swap out from the primary PTEG.
*/
lwz r4, .gOverflowPTEGSeed(0) // get current seed value
addi r3, r4, 1 // increment it
cmpwi r3, kPTEsPerPTEG // check for wrap
blt SetNewSeed // if none, store value
li r3, 0 // else cut back to zero
SetNewSeed:
stw r3, .gOverflowPTEGSeed(0) // store updated seed value
slwi r4, r4, kLog2PTESize // multiply seed by element size
add r8, r7, r4 // r8 = PTE address to swap out
#if 0
/*
!!! Don't do this until I/O system agrees with implied restrictions. !!!
Use the PTE we located. Don't waste an OverflowPTE on PTE that can be
regenerated instead. The address needs to be with an AutogenArea,
and the page's cache mode must be the same as the area's.
NOTE: Because the AutogenArea lookup is based on the physical address,
the cache mode check might be inaccurate if there are more than one
AutogenArea containing that physical address. Therefore, SetProcessorCacheMode
disallows AutogenArea cache mode changes if there are any aliased pages, and
we are safe. The idea is that there should be an area per cache mode for
AutogenArea-type areas.
r7 == PTEG address, r8 == PTE address
*/
lwz r3, PTE.attributesWord(r8) // get attributes word
rlwinm r3, r3, 0, PTE_pageMask // mask to physical address
lwz r5, .gAutogenAreaList(0)
IsAutogenAddressLoop:
cmpwi r5, 0
beq SaveInOverflowTable
lwz r4, AutogenArea.physicalBase(r5)
cmplw r4, r3 // physical base <= page address?
bgt ContinueIsAutogenAddressLoop // if not, continue
lwz r4, AutogenArea.lowestBackedAddress(r5)
lwz r6, AutogenArea.highestBackedAddress(r5)
sub r6, r6, r4
lwz r4, AutogenArea.physicalBase(r5)
add r4, r4, r6
cmplw r3, r4 // page address <= highest?
ble IsAutogenAddress // if so, r5 == the AutogenArea
ContinueIsAutogenAddressLoop:
lwz r5, AutogenArea.pNextAutogenArea(r5)
b IsAutogenAddressLoop
IsAutogenAddress:
lwz r4, PTE.hashInfoWord(r8)
rlwinm r3, r4, PTE_cacheControlShiftOut, PTE_cacheControlMaskOut
lwz r5, AutogenArea.pageCacheMode(r5) // get area's cache mode
#ifdef DEBUG
cmplw r3, r5
bne SaveInOverflowTable
lwz r4, .gAutogenTossCount(0)
addi r4, r4, 1
stw r4, .gAutogenTossCount(0)
#endif /* DEBUG */
cmplw r3, r5 // matching cache mode?
beq SwapOutPTE // if so, we can regenerate the PTE
/* Copy the PTE's contents into an element in the overflow table.
r7 == PTEG address, r8 == PTE address.
*/
SaveInOverflowTable:
#endif /* 0 */
#ifdef DEBUG
lwz r3, .gOverflowTossCount(0)
addi r3, r3, 1
stw r3, .gOverflowTossCount(0)
#endif /* DEBUG */
mr r3, r7 // pass PTEG address
lwz r4, PTE.hashInfoWord(r8) // pass hash information word
lwz r5, PTE.attributesWord(r8) // pass attributes word
bl AllocateOverflowPTE
/* Map the new page in place of the old. A tlbie is not necessary
because no effective-to-physical mapping is being undone. Rather,
the PTE is just moving to the overflow list (i.e. the tlb information
still applies). Changes to the tlb entry happen only as a result of a
page fault (e.g. setting the "modified" bit), so tlb cast out has no
requirement that the PTE be in the main hash table.
r8 == PTE,
r9 == hash information word,
r10 == attributes
*/
SwapOutPTE:
li r3, 0 // zero word
stw r3, PTE.hashInfoWord(r8) // invalidate the PTE
sync // synchronize
stw r10, PTE.attributesWord(r8) // store new attributes
sync // synchronize
stw r9, PTE.hashInfoWord(r8) // store new hash information
mr r3, r8 // r3 == PTE address
/* Page was successfully mapped
r3 == PTE address or nil
*/
ReloadWorked:
li r4, noErr // status saying reload happened
/* r3 == PTE address or nil,
r4 == noErr iff reload happened
*/
LookupPTEDone:
mtlr r0
blr
#endif /* WIP ================================================================== */
/* ------------------------------------------------------------------------------
*/
.globl _ExceptionVectorsEnd
_ExceptionVectorsEnd: /* Used if relocating the exception vectors */
/* The entirety of the lowmem area has to fit in the space assigned to it.
The kernel start point is defined in to places: the makefile.ppc and
MASTER.ppc files.
*/
#if (_ExceptionVectorsEnd - _ExceptionVectorsStart) > RELOC
#warning **** lowmem overflows into kernel space ****
#endif