Files
Arquivotheca.AIX-4.1.3/bos/kernel/ml/POWER/power_emul_ppc.m4
seta75D d6fe8fe829 Init
2021-10-11 22:19:34 -03:00

547 lines
18 KiB
Plaintext

# @(#)74 1.3 src/bos/kernel/ml/POWER/power_emul_ppc.m4, sysml, bos411, 9430C411a 7/27/94 02:34:42
#****************************************************************************
#
# COMPONENT_NAME: (SYSML) Kernel Assembler Code
#
# FUNCTIONS: power_asm_emulate
#
# ORIGINS: 27, 83
#
# IBM CONFIDENTIAL -- (IBM Confidential Restricted when
# combined with the aggregated modules for this product)
# SOURCE MATERIALS
# (C) COPYRIGHT International Business Machines Corp. 1989, 1994
# All Rights Reserved
#
# US Government Users Restricted Rights - Use, duplication or
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
#
# Copyright (C) Bull S.A. 1994
# LEVEL 1, 5 Years Bull Confidential Information
#
#****************************************************************************
.set OE, 21 # update XER if OE bit is set in opcode
.set Rc, 31 # update CR if Rc bit is set in opcode
.machine "ppc"
#****************************************************************************
#
# Try C emulation: call power_emul()
#
#****************************************************************************
call_c_emul:
# Restore initial context and r15 with ppda addr.
# r15 is already saved in SPRG1.
# get SRR0,SRR1,LR,CR,XER from savearea
lwz r27, SAVE_SRR0(r25) # load SRR0
lwz r28, SAVE_SRR1(r25) # load SRR1
lwz r29, SAVE_LR(r25) # load LR
lwz r30, SAVE_CR(r25) # load CR
lwz r31, SAVE_XER(r25) # load XER
mtspr SRR0, r27 # restore SRR0
mtspr SRR1, r28 # restore SRR1
mtlr r29 # restore LR
mtcr r30 # restore CR
mtxer r31 # restore XER
mr r15, r25 # move ppda addr to r15
# restore r26-r31
lwz r26, SAVE_R26(r25) # restore r26
lwz r27, SAVE_R27(r25) # restore r27
lwz r28, SAVE_R28(r25) # restore r28
lwz r29, SAVE_R29(r25) # restore r29
lwz r30, SAVE_R30(r25) # restore r30
lwz r31, SAVE_R31(r25) # restore r31
lwz r25, SAVE_R25(r15) # restore r25
# Part of pr_flih() code duplicated here.
mfspr r0, LR # do full state save
bl ENTRY(state_save)
.extern ENTRY(state_save)
# Set new interrupt priority; perform interrupt setup processing
li r3, PR_LEVEL
li r4, INTMAX*256
bl ENTRY(begin_interrupt)
.extern ENTRY(begin_interrupt)
# Compute the code to pass to p_slih to indicate type of interrupt
lwz r12, mstmsr(INTR_MST) # Fetch SRR1=flags set by hdwe, old MSR
cntlzw r5, r12 # Bit number of first '1' bit
la r5, (EXCEPT_FLOAT-11)(r5) # Convert bit number to code (parm 3):
# 00000000001000... => FLOAT
# 00000000000100... => INV_OP
# 00000000000010... => PRIV_OP
# 00000000000001... => TRAP
# Note that hardware spec guarantees that top 11 bits will be '0' and
# that exactly one of the next four will be '1'.
# No support for imprecise interrupt yet
rlwinm. r12, r12, 0, SRR_PR_IMPRE # check for imprecise interrupt
beq+ cr0, not_fp_imp # branch if not imprecise
sync # sync floating point unit
li r5, EXCEPT_FLOAT_IMPRECISE # imprecise exception code
not_fp_imp:
# Call power_emul() with p_slih() parameters.
mr r3, INTR_MST # offending mst
lwz r4, mstiar(INTR_MST) # excepting old IAR
lwz r6, ppda_curthread(PPDA_ADDR) # current thread pointer
.extern ENTRY(power_emul)
bl ENTRY(power_emul)
# Finish interrupt processing; resume interrupted program
b ENTRY(finish_interrupt)
.extern ENTRY(finish_interrupt)
#****************************************************************************
#
# Final stage of power_asm_emulate(): store result, update XER and CR
# then go to "al_ret" label in al_flih.m4 code.
#
#****************************************************************************
pr_st:
# store r31 into RT
rlwinm r30, r26, 14, 0xF8 # r30 = bits(6-10) of opcode, RT*8
.using low, r30
la r30, loadtab(r30)
.drop r30
mtlr r30 # LR = branch addr in loadtab
mfcr r29 # save CR
blrl # store r31 into RT
# is OE bit set
mtcr r26
bc+ false, OE, pr_Rc
mfxer r31
stw r31, SAVE_XER(r25) # OE=1: store XER back to save area
pr_Rc:
# is Rc bit set
bc+ false, Rc, pr_ret # leave if RC=0
lwz r31, SAVE_CR(r25) # Rc=1: load CR from save area
lwz r30, SAVE_XER(r25) # load XER from save area
rlwimi r31, r29, 0, 0xe0000000 # insert LT, GT, EQ bits in CR0
rlwimi r31, r30, 29, 0x10000000 # insert XER[SO] bit in CR0[SO]
stw r31, SAVE_CR(r25) # store new CR in save area
pr_ret:
# update statistics counter and return
mr r31, r2 # save r2
lwz r2, DATA(g_toc) # load kernel toc
LTOC(r30, emulate_count, data)
lwz r29, 0(r30) # load,
addi r29, r29, 1 # incremente and
stw r29, 0(r30) # store counter
mr r2, r31 # restore r2
b al_ret # restore and return.
#******************************************************************************
#
# power_asm_emulate
#
# The power_asm_emulate is only called from pr_flih_ppc() and perform
# the power emulation. If assembler emulation fail then call emulation
# written in C : power_emul().
#
# Upon entry:
# r15 restored
# r25 = address of the PPDA
# r26 = opcode of the faulting instruction
# r27 = address of the faulting instruction
# MSR = r28 = MSR:DR=0
# r29 = MSR:DR=1
# r30 = scratch
# r31 = scratch
#
#******************************************************************************
DATA(power_asm_emulate):
.globl DATA(power_asm_emulate)
# get primary opcode
rlwinm r31, r26, 6, 0x3f
cmpi cr0, r31, 9
cmpi cr7, r31, 31
beq- cr0, emul_dozi # asm emulation for dozi instruction
bne- cr7, call_c_emul # try C emulation
#****************************************************************************
# Try to find extended opcode for primary opcode = 31
# r25 = save area addr
# r26 = opcode faulting instruction
# r27 = SRR0 = faulting instruction addr
# MSR = r28 = MSR:DR=0
# r29 = MSR:DR=1
# r30 = scratch
# r31 = primary opcode
#****************************************************************************
rlwinm r30, r26, 31, 0x3ff # extended opcode and OE tested
cmpi cr0, r30, 0x115 # lscbx lscbx.
cmpi cr7, r30, 0x153 # mfspr
beq+ cr0, emul_lscbx
cmpi cr6, r30, 0x1d3 # mtspr
beq+ cr7, emul_mfspr
beq+ cr6, emul_mtspr
rlwinm r30, r26, 31, 0x1ff # extended opcode without OE
cmpi cr0, r30, 0x06b # mul mul. mulo mulo.
cmpi cr7, r30, 0x14b # div div. divo divo.
beq+ cr0, emul_mul
beq+ cr7, emul_div
cmpi cr0, r30, 0x16b # divs divs. divso divso.
cmpi cr7, r30, 0x108 # doz doz. dozo dozo.
beq+ cr0, emul_divs
beq+ cr7, emul_doz
cmpi cr0, r30, 0x168 # abs abs. abso abso.
cmpi cr7, r30, 0x1e8 # nabs nabs. nabso nabso.
beq+ cr0, emul_abs
beq+ cr7, emul_nabs
b call_c_emul # call C code emulation
#****************************************************************************
# Emulation code
#****************************************************************************
emul_mul:
# get content of RA
rlwinm r30, r26, 19, 0xF8 # r30 = bits(11-15) of opcode, RA*8
mfsr r27, sr2
.using low, r30
la r30, stortab(r30) # r30 = branch addr in stortab for RA
.drop r30
stw r27, SAVE_WORK1(r25) # save original sr2
mtlr r30 # LR = branch address in stortab
rlwinm r27, r27, 0, ~SR_KsKp # clear "k" bit(s)
blrl # set r31 = (RA)
mr r28, r31 # save (RA)
# get content of RB
rlwinm r30, r26, 24, 0xF8 # r30 = bits(16-20) of opcode, RB*8
mtsr sr2, r27 # ensure r/w access to mst
.using low, r30
la r30, stortab(r30) # r30 = branch addr in stortab for RB
.drop r30
lwz r27, ppda_csa(r25) # mst address
mtlr r30 # LR = branch address in stortab
blrl # set r31 = RB
# compute low order 32 bits of result
mullwo. r30, r31, r28 # low order 32 bits and set CR0 & XER
mtmsr r29 # turn on Data Relocation
isync
xori r29, r29, MSR_DR # toggle DR
stw r30, mstmq(r27) # low order 32 bits in MQ emulation
mtmsr r29 # turn off Data Relocation
isync
lwz r30, SAVE_WORK1(r25) # load original sr2 value
mulhw r31, r31, r28 # compute high order 32 bits of result
mtsr sr2, r30 # restore sr2
b pr_st # store into RT
emul_doz:
# get content of RA -> r31
rlwinm r30, r26, 19, 0xF8 # r30 = bits(11-15) of opcode, RA*8
.using low, r30
la r30, stortab(r30) # r30 = branch addr in stortab for RA
.drop r30
mtlr r30 # LR = branch address in stortab
blrl # set r31=(RA)
# get content of RB -> r31
rlwinm r30, r26, 24, 0xF8 # r30 = bits(16-20) of opcode, RB*8
mr r29, r31 # save (RA)
.using low, r30
la r30, stortab(r30) # r30 = branch addr in stortab for RB
.drop r30
mtlr r30 # LR = branch address in stortab
blrl # set r31 = RB
cmp 0, r29, r31 # if RA > RB
li r28, 0 # return (RT)=0
bgt+ doz_pos
subfo. r31, r29, r31 # compute (RT), set CR0 & XER
b pr_st # and store
doz_pos:
addo. r31, r28, r28 # set CR0 & XER
b pr_st
emul_lscbx:
# update statistics counter: don't modify r29 here
# because alignment use it.
mr r31, r2 # save r2
lwz r2, DATA(g_toc) # load kernel toc
LTOC(r30, emulate_count, data)
lwz r28, 0(r30) # load,
addi r28, r28, 1 # incremente and
stw r28, 0(r30) # store counter
mr r2, r31 # restore r2
# Reuse code from al_flih.m4
# Compute effective addr (pseudo dar) in r27 and
# emulate code between "l_str_cmp" and "next" label.
# Then branch in al_flih.m4 at "next" label
# get content of RB -> r31
rlwinm r30, r26, 24, 0xF8 # r30 = bits(16-20) of opcode, RB*8
stb r30, SAVE_RB(r25) # save RB
.using low, r30
la r30, stortab(r30) # r30 = branch addr in stortab for RB
.drop r30
mtlr r30 # LR = branch address in stortab
blrl # set r31 = (RB)
rlwinm r30, r26, 19, 0xF8 # r30 = bits(11-15) of opcode, RA*8
stb r30, SAVE_RA(r25) # save RA
cmpi cr0, r30, 0 # branch if RA = r0
mr r27, r31 # save (RB)
beq- lscbx_pos # DAR = (RB)
.using low, r30 # else get content of RA -> r31
la r30, stortab(r30) # r30 = branch addr in stortab for RA
.drop r30
mtlr r30 # LR = branch address in stortab
blrl # set r31=RA
add r27, r27, r31 # DAR = (RA) + (RB)
lscbx_pos:
# l_str_cmp code emulation with DAR modification
stw r26, SAVE_WORK1(r25) # save original instruction to scratch
stw r27, SAVE_WORK2(r25) # save DAR
lwz r31, SAVE_XER(r25) # load XER from save area
andi. r30, r31, 0x7F # mask off to get byte count
cmpi 0, r30, 0 # if byte count <= 0
ble- get_out # then go to get_out in al_flih.m4
rlwinm r28, r31, 24, 0xFF # get match byte
stb r28, SAVE_MATCH(r25) # save match byte
addi r27, r27, -1 # prepare DAR for update loads
add r30, r30, r27 # get address of last load
rlwinm r26, r26, 14, 0xF8 # r26 = bits(6-10) of opcode, RT*8
stb r26, SAVE_RT(r25) # save copy of RT
b next # branch in al_flih.m4 code
emul_div:
# upon entry: r25 = save area addr
# r26 = opcode faulting instruction
# r27 = SRR0 = faulting instruction addr
# MSR = r28 = MSR:DR=0
# r29 = MSR:DR=1
# r30 = scratch
# r31 = primary opcode
#
# emulation for: div RD,RA,RB
#
# if (RA)=0 and (RB)>0
# then
# divwuo RD,MQ,RB /* to clear XER[OV] */
# compute remainder
# else
# call C code and use divi64()
#
# Note: work is done with MSR_DR=1 and sr2 access enable
#
# get content of RA
rlwinm r30, r26, 19, 0xF8 # r30 = bits(11-15) of opcode, RA*8
.using low, r30
la r30, stortab(r30) # r30 = branch addr in stortab for RA
.drop r30
mtlr r30 # LR = branch address in stortab
blrl # set r31=RA
mfsr r27, sr2
cmpi cr0, r31, 0 # if (RA) <> 0
rlwinm r30, r26, 24, 0xF8 # r30 = bits(16-20) of opcode, RB*8
bne- call_c_emul # call C emulation
# get content of RB
.using low, r30
la r30, stortab(r30) # r30 = branch addr in stortab for RB
.drop r30
stw r27, SAVE_WORK1(r25) # save original sr2
mtlr r30 # LR = branch address in stortab
rlwinm r27, r27, 0, ~SR_KsKp # clear "k" bit(s)
blrl # set r31 = RB
mtsr sr2, r27 # ensure r/w access to mst
cmpi cr0, r31, 0 # if (RB) < 0
lwz r27, ppda_csa(r25)
blt- call_c_emul # call C emulation
mtmsr r29 # turn on Data Relocation
isync
lwz r30, mstmq(r27) # get content of emulated MQ
divwuo r29, r30, r31 # compute quotient MQ/RB and update XER
mullw r31, r31, r29 # compute (MQ/RB)*RB
subfc. r30, r31, r30 # compute remainder MQ-((MQ/RB)*RB) and set CR0
stw r30, mstmq(r27) # save remainder in MQ
mtmsr r28 # turn off Data Relocation
isync
lwz r30, SAVE_WORK1(r25) # load original sr2 value
mr r31, r29 # r31=quotient and
mtsr sr2, r30 # restore sr2
b pr_st # store into RT
emul_abs:
# get content of RA
rlwinm r30, r26, 19, 0xF8 # r30 = bits(11-15) of opcode, RA*8
.using low, r30
la r30, stortab(r30) # r30 = branch addr in stortab for RA
.drop r30
mtlr r30 # LR = branch address in stortab
blrl # set r31=(RA)
cmpi cr0, r31, 0
li r30, 0
bge abs_pos # branch if (RA) >= 0
nego. r31, r31 # set CR0 & XER
b pr_st
abs_pos:
addo. r31, r30, r31 # set CR0 & XER
b pr_st
emul_divs:
# get content of RB
rlwinm r30, r26, 24, 0xF8 # r30 = bits(16-20) of opcode, RB*8
mfsr r27, sr2
.using low, r30
la r30, stortab(r30) # r30 = branch addr in stortab for RB
.drop r30
stw r27, SAVE_WORK1(r25) # save original sr2
mtlr r30 # LR = branch address in stortab
rlwinm r27, r27, 0, ~SR_KsKp # clear "k" bit(s)
blrl # set r31 = (RB)
# get content of RA -> r31
rlwinm r30, r26, 19, 0xF8 # r30 = bits(11-15) of opcode, RA*8
mr r28, r31 # save (RB)
.using low, r30
la r30, stortab(r30) # r30 = branch addr in stortab for RA
.drop r30
mtsr sr2, r27 # ensure r/w access to mst
mtlr r30 # LR = branch address in stortab
lwz r27, ppda_csa(r25) # for access to emulated MQ
blrl # set r31 = (RA)
cmpi cr0, r28, -1 # divw return undefined RD
mtmsr r29 # turn on Data Relocation
isync
xori r29, r29, MSR_DR # toggle DR
bne+ cr0, divs_pos # branch if (RA) <> -1
rlwinm r30, r31, 1, -1 # rotate RB
cmpi cr0, r30, 1 # compare RB with -2**31
bne+ cr0, divs_pos # branch if (RB) <> -2**31
li r28, 0 # emulate -2**31/-1
divwo r30, r31, r28 # RT=-2**31; overflow in XER
cmpi cr0, r28, 0 # MQ=0; update CR0
stw r28, mstmq(r27) # save (MQ)=0 in mst
mtmsr r29 # turn off Data Relocation
isync
lwz r30, SAVE_WORK1(r25) # load original sr2 value
mtsr sr2, r30 # restore sr2
b pr_st # store r31=-2**31 into RT
divs_pos:
divwo r30, r31, r28 # compute quotient & detect overflow
mullw r28, r30, r28 # compute remainder RB = RA - ((RA/RB) * RB)
subf. r28, r28, r31 # and update CR0
ori r31, r30, 0x0 # quotient to correct reg.
stw r28, mstmq(r27) # save r28=(MQ) in mst
mtmsr r29 # turn off Data Relocation
isync
lwz r30, SAVE_WORK1(r25) # load original sr2 value
mtsr sr2, r30 # restore sr2
b pr_st # store r31 into RT
emul_nabs:
# get content of RA -> r31
rlwinm r30, r26, 19, 0xF8 # r30 = bits(11-15) of opcode, RA*8
.using low, r30
la r30, stortab(r30) # r30 = branch addr in stortab for RA
.drop r30
mtlr r30 # LR = branch address in stortab
blrl # set r31=RA
mfxer r30 # clear XER[OV] in case OE is set
rlwinm r30, r30, 0, 0xbfffffff
cmpi cr0, r31, 0
mtxer r30
ble nabs_pos # branch if RA <= 0
neg. r31, r31 # set CR0
b pr_st
nabs_pos:
li r30, 0
add. r31, r30, r31 # set CR0
b pr_st
emul_dozi:
# get content of RA -> r31
rlwinm r30, r26, 19, 0xF8 # r30 = bits(11-15) of opcode, RA*8
.using low, r30
la r30, stortab(r30) # r30 = branch addr in stortab for RA
.drop r30
mtlr r30 # LR = branch address in stortab
blrl # set r31=RA
# get immediate field -> r30
andi. r30, r26, 0xFFFF # mask off to get SIMM
extsh r30, r30 # extend 32 bits
cmp 0, r31, r30 # if RA > SIMM
li r29, 0 # return RT=0
bgt- dozi_pos
subf r29, r31, r30 # compute RT
dozi_pos:
mr r31, r29 # load r31
rlwinm r30, r26, 14, 0xF8 # r30 = bits(6-10) of opcode, RT*8
.using low, r30
la r30, loadtab(r30) # r30 = branch addr in loadtab for RT
.drop r30 #
mtlr r30 # LR = branch addr in loadtab
blrl # store r31 into RT
b pr_ret # restore and return
emul_mfspr:
# get SPR field -> r27
rlwinm r27, r26, 21, 0x3FF # r27 = bits(11-20) of opcode
mfsr r31, sr2
cmpi cr0, r27, 0 # if MQ encoding
mr r30, r31 # save original sr2 in r30
lwz r27, ppda_csa(r25)
rlwinm r31, r31, 0, ~SR_KsKp # clear "k" bit(s)
bne- cr0, call_c_emul # call C code emulation
mtsr sr2, r31 # ensure r/w access to mst
# get content of emulated MQ
mtmsr r29 # turn on Data Relocation
isync
lwz r31, mstmq(r27) # load MQ from mst
mtmsr r28 # turn off Data Relocation
isync
mtsr sr2, r30 # restore sr2
b pr_st # store r31 into RT :OE and Rc always null
# so is correct to branch to pr_st
emul_mtspr:
# get SPR field -> r30
rlwinm r30, r26, 21, 0x3FF # r30 = bits(11-20) of opcode
mfsr r28, sr2
cmpi cr0, r30, 0 # if MQ encoding
mr r27, r28 # save original sr2 in r27
rlwinm r30, r26, 14, 0xF8 # r30 = bits(6-10) of opcode, RT*8
bne- cr0, call_c_emul # call C code emulation
# get content of RT -> r31
.using low, r30
la r30, stortab(r30) # r30 = branch addr in stortab for RT
.drop r30
mtlr r30 # LR = branch addr in stortab
rlwinm r28, r28, 0, ~SR_KsKp # clear "k" bit(s)
blrl # set r31 = RT
mtsr sr2, r28 # ensure r/w access to mst
lwz r30, ppda_csa(r25)
# store r31 in MQ emulation
mtmsr r29 # turn on Data Relocation
isync
xori r29, r29, MSR_DR # toggle DR
stw r31, mstmq(r30)
mtmsr r29 # turn off Data Relocation
isync
lwz r30, SAVE_WORK1(r25) # load original sr2 value
mtsr sr2, r27 # restore sr2
b pr_ret # restore and return
include(i_machine.m4)
include(except.m4)