#include <sys/cdefs.h>
#include <mips/asm.h>
#include <mips/trap.h>
#include <mips/cpuregs.h>
#include "assym.h"
.set reorder
#define REG_REGMASK (0x1f << REG_SCALESHIFT)
LEAF(mips_emul_branchdelayslot)
REG_PROLOGUE
REG_S zero, TF_REG_ZERO(a1) # ensure zero has value 0
REG_EPILOGUE
move t3, ra # need to save this locally
srl t0, a0, 26-PTR_SCALESHIFT
andi t0, 0x3F << PTR_SCALESHIFT
PTR_L t9, bcemul_optbl(t0)
jr t9
.rdata
bcemul_optbl:
PTR_WORD bcemul_special # 000 SPECIAL
PTR_WORD bcemul_sigill # 001 REGIMM
PTR_WORD bcemul_sigill # 002 J
PTR_WORD bcemul_sigill # 003 JAL
PTR_WORD bcemul_sigill # 004 BEQ
PTR_WORD bcemul_sigill # 005 BNE
PTR_WORD bcemul_sigill # 006 BLEZ
PTR_WORD bcemul_sigill # 007 BGTZ
PTR_WORD bcemul_addi # 010 ADDI
PTR_WORD bcemul_addiu # 011 ADDIU
PTR_WORD bcemul_slti # 012 SLTI
PTR_WORD bcemul_sltiu # 013 SLTIU
PTR_WORD bcemul_andi # 014 ANDI
PTR_WORD bcemul_ori # 015 ORI
PTR_WORD bcemul_xori # 016 XORI
PTR_WORD bcemul_lui # 017 LUI
PTR_WORD bcemul_sigill # 020 COP0
PTR_WORD _C_LABEL(mips_emul_fp) # 021 COP1
PTR_WORD bcemul_sigill # 022 COP2
PTR_WORD bcemul_sigill # 023 COP1X
PTR_WORD bcemul_sigill # 024 BEQL
PTR_WORD bcemul_sigill # 025 BNEL
PTR_WORD bcemul_sigill # 026 BNEZL
PTR_WORD bcemul_sigill # 027 BGTZL
#ifdef __mips_o32
PTR_WORD bcemul_sigill # 030 DADDI (*)
PTR_WORD bcemul_sigill # 031 DADDIU (*)
PTR_WORD bcemul_sigill # 030 LDL (*)
PTR_WORD bcemul_sigill # 031 LDR (*)
#else
PTR_WORD bcemul_daddi # 030 DADDI (*)
PTR_WORD bcemul_daddiu # 031 DADDIU (*)
PTR_WORD _C_LABEL(mips_emul_ldl) # 032 LDL (*)
PTR_WORD _C_LABEL(mips_emul_ldr) # 033 LDR (*)
#endif
PTR_WORD bcemul_sigill # 034 SPECIAL2
PTR_WORD bcemul_sigill # 035 JALX
PTR_WORD bcemul_sigill # 036 MDMX
PTR_WORD bcemul_sigill # 037 SPECIAL3
PTR_WORD _C_LABEL(mips_emul_lb) # 040 LB
PTR_WORD _C_LABEL(mips_emul_lh) # 041 LH
PTR_WORD _C_LABEL(mips_emul_lwl) # 042 LWL
PTR_WORD _C_LABEL(mips_emul_lw) # 043 LW
PTR_WORD _C_LABEL(mips_emul_lbu) # 044 LBU
PTR_WORD _C_LABEL(mips_emul_lhu) # 045 LHU
PTR_WORD _C_LABEL(mips_emul_lwr) # 046 LWR
#ifdef __mips_o32
PTR_WORD bcemul_sigill # 047 LWU (*)
#else
PTR_WORD _C_LABEL(mips_emul_lwu) # 047 LWU (*)
#endif
PTR_WORD _C_LABEL(mips_emul_sb) # 050 SB
PTR_WORD _C_LABEL(mips_emul_sh) # 051 SH
PTR_WORD _C_LABEL(mips_emul_swl) # 052 SWL
PTR_WORD _C_LABEL(mips_emul_sw) # 053 SW
#ifdef __mips_o32
PTR_WORD bcemul_sigill # 054 SDL (*)
PTR_WORD bcemul_sigill # 055 SDR (*)
#else
PTR_WORD _C_LABEL(mips_emul_sdl) # 054 SDL (*)
PTR_WORD _C_LABEL(mips_emul_sdr) # 055 SDR (*)
#endif
PTR_WORD _C_LABEL(mips_emul_swr) # 056 SWR
PTR_WORD bcemul_sigill # 057 CACHE
PTR_WORD bcemul_sigill # 060 LL
PTR_WORD _C_LABEL(mips_emul_lwc1) # 061 LWC1
PTR_WORD bcemul_sigill # 062 LWC2
PTR_WORD bcemul_sigill # 063 PREF
PTR_WORD bcemul_sigill # 064 LLD (*)
PTR_WORD _C_LABEL(mips_emul_ldc1) # 065 LDC
PTR_WORD bcemul_sigill # 066 LDC2
#ifdef __mips_o32
PTR_WORD bcemul_sigill # 067 LD (*)
#else
PTR_WORD _C_LABEL(mips_emul_ld) # 067 LD (*)
#endif
PTR_WORD bcemul_sigill # 070 SC
PTR_WORD _C_LABEL(mips_emul_swc1) # 071 SWC1
PTR_WORD bcemul_sigill # 072 SWC2
PTR_WORD bcemul_sigill # 073
PTR_WORD bcemul_sigill # 074 SCD (*)
PTR_WORD _C_LABEL(mips_emul_sdc1) # 075 SDC1
PTR_WORD bcemul_sigill # 076 SDC2
#ifdef __mips_o32
PTR_WORD bcemul_sigill # 077 SD (*)
#else
PTR_WORD _C_LABEL(mips_emul_sd) # 077 SD (*)
#endif
.text
bcemul_immed_prologue:
srl t1, a0, 21-REG_SCALESHIFT # rs (source)
srl t2, a0, 16-REG_SCALESHIFT # rt (dest)
andi t1, REG_REGMASK
andi t2, REG_REGMASK
PTR_ADDU t1, a1
PTR_ADDU t2, a1
sll v1, a0, 16
sra v1, v1, 16 # signed immed
REG_PROLOGUE
REG_L v0, TF_REG_ZERO(t1) # load source
REG_EPILOGUE
jr ra # execute the instruction
bcemul_uimmed_prologue:
srl t1, a0, 21-REG_SCALESHIFT # rs (source)
srl t2, a0, 16-REG_SCALESHIFT # rt (dest)
andi t1, REG_REGMASK
andi t2, REG_REGMASK
PTR_ADDU t1, a1
PTR_ADDU t2, a1
andi v1, a0, 0xffff # unsigned immed
REG_PROLOGUE
REG_L v0, TF_REG_ZERO(t1) # load source
REG_EPILOGUE
jr ra
#ifndef __mips_o32
bcemul_daddi:
bal bcemul_immed_prologue
dadd t0, v0, v1
b bcemul_check_add_overflow
#endif
bcemul_addi:
bal bcemul_immed_prologue
addu t0, v0, v1
bcemul_check_add_overflow:
move ta0, t0 # result
move ta1, v0 # addend 1
move ta2, v1 # addend 2
bcemul_check_overflow:
xor ta2, ta1
bltz ta2, bcemul_store_and_done
xor ta1, ta0
bgez ta1, bcemul_store_and_done
b bcemul_sigill
bcemul_addiu:
bal bcemul_immed_prologue
addu t0, v0, v1
b bcemul_store_and_done
#ifndef __mips_o32
bcemul_daddiu:
bal bcemul_immed_prologue
daddu t0, v0, v1
b bcemul_store_and_done
#endif
bcemul_slti:
bal bcemul_immed_prologue
slt t0, v0, v1
b bcemul_store_and_done
bcemul_sltiu:
bal bcemul_immed_prologue
sltu t0, v0, v1
b bcemul_store_and_done
bcemul_andi:
bal bcemul_uimmed_prologue
and t0, v0, v1
b bcemul_store_and_done
bcemul_ori:
bal bcemul_uimmed_prologue
or t0, v0, v1
b bcemul_store_and_done
bcemul_xori:
bal bcemul_uimmed_prologue
xor t0, v0, v1
b bcemul_store_and_done
bcemul_lui:
srl t2, a0, 16-REG_SCALESHIFT # rt
andi t2, REG_REGMASK
PTR_ADDU t2, a1
sll t0, a0, 16
b bcemul_store_and_done
.rdata
bcemul_specialtbl:
PTR_WORD bcemul_special_genshift # 000 SLL
PTR_WORD bcemul_sigill # 001 MOVC1
PTR_WORD bcemul_special_genshift # 002 SRL
PTR_WORD bcemul_special_genshift # 003 SRA
PTR_WORD bcemul_special_genshiftv # 004 SLLV
PTR_WORD bcemul_sigill # 005
PTR_WORD bcemul_special_genshiftv # 006 SRLV
PTR_WORD bcemul_special_genshiftv # 007 SRAV
PTR_WORD bcemul_sigill # 010 JR
PTR_WORD bcemul_sigill # 011 JALR
PTR_WORD bcemul_sigill # 012 MOVZ
PTR_WORD bcemul_sigill # 013 MOVN
PTR_WORD bcemul_sigill # 014 SYSCALL
PTR_WORD bcemul_sigill # 015 BREAK
PTR_WORD bcemul_sigill # 016
PTR_WORD bcemul_special_sync # 017 SYNC
PTR_WORD bcemul_special_mfhilo # 020 MFHI
PTR_WORD bcemul_special_mthilo # 021 MTHI
PTR_WORD bcemul_special_mfhilo # 022 MFLO
PTR_WORD bcemul_special_mthilo # 023 MTLO
#ifdef __mips_o32
PTR_WORD bcemul_sigill # 024 DSLLV (*)
PTR_WORD bcemul_sigill # 025
PTR_WORD bcemul_sigill # 026 DSRLV (*)
PTR_WORD bcemul_sigill # 027 DSRAV (*)
#else
PTR_WORD bcemul_special_genshiftv # 024 DSLLV (*)
PTR_WORD bcemul_sigill # 025
PTR_WORD bcemul_special_genshiftv # 026 DSRLV (*)
PTR_WORD bcemul_special_genshiftv # 027 DSRAV (*)
#endif
PTR_WORD bcemul_special_genmultdiv # 030 MULT
PTR_WORD bcemul_special_genmultdiv # 031 MULTU
PTR_WORD bcemul_special_genmultdiv # 032 DIV
PTR_WORD bcemul_special_genmultdiv # 033 DIVU
#ifdef __mips_o32
PTR_WORD bcemul_sigill # 034 DMULT (*)
PTR_WORD bcemul_sigill # 035 DMULTU (*)
PTR_WORD bcemul_sigill # 036 DDIV (*)
PTR_WORD bcemul_sigill # 037 DDIVU (*)
#else
PTR_WORD bcemul_special_genmultdiv # 034 DMULT (*)
PTR_WORD bcemul_special_genmultdiv # 035 DMULTU (*)
PTR_WORD bcemul_special_genmultdiv # 036 DDIV (*)
PTR_WORD bcemul_special_genmultdiv # 037 DDIVU (*)
#endif
PTR_WORD bcemul_special_genadd # 040 ADD
PTR_WORD bcemul_special_gen3op # 041 ADDU
PTR_WORD bcemul_special_gensub # 042 SUB
PTR_WORD bcemul_special_gen3op # 043 SUBU
PTR_WORD bcemul_special_gen3op # 044 AND
PTR_WORD bcemul_special_gen3op # 045 OR
PTR_WORD bcemul_special_gen3op # 046 XOR
PTR_WORD bcemul_special_gen3op # 047 NOR
PTR_WORD bcemul_sigill # 050
PTR_WORD bcemul_sigill # 051
PTR_WORD bcemul_special_gen3op # 052 SLT
PTR_WORD bcemul_special_gen3op # 053 SLTU
#ifdef __mips_o32
PTR_WORD bcemul_sigill # 054 DADD (*)
PTR_WORD bcemul_sigill # 055 DADDU (*)
PTR_WORD bcemul_sigill # 056 DSUB (*)
PTR_WORD bcemul_sigill # 057 DSUBU (*)
#else
PTR_WORD bcemul_special_genadd # 054 DADD (*)
PTR_WORD bcemul_special_gen3op # 055 DADDU (*)
PTR_WORD bcemul_special_gensub # 056 DSUB (*)
PTR_WORD bcemul_special_gen3op # 057 DSUBU (*)
#endif
PTR_WORD bcemul_sigill # 060 TGE
PTR_WORD bcemul_sigill # 061 TGEU
PTR_WORD bcemul_sigill # 062 TLT
PTR_WORD bcemul_sigill # 063 TLTU
PTR_WORD bcemul_sigill # 064 TEQ
PTR_WORD bcemul_sigill # 065
PTR_WORD bcemul_sigill # 066 TNE
PTR_WORD bcemul_sigill # 067
#ifdef __mips_o32
PTR_WORD bcemul_sigill # 070 DSLL (*)
PTR_WORD bcemul_sigill # 071
PTR_WORD bcemul_sigill # 072 DSRL (*)
PTR_WORD bcemul_sigill # 073 DSRA (*)
PTR_WORD bcemul_sigill # 074 DSLL32 (*)
PTR_WORD bcemul_sigill # 075
PTR_WORD bcemul_sigill # 076 DSRL32 (*)
PTR_WORD bcemul_sigill # 077 DSRA32 (*)
#else
PTR_WORD bcemul_special_genshift # 070 DSLL (*)
PTR_WORD bcemul_sigill # 071
PTR_WORD bcemul_special_genshift # 072 DSRL (*)
PTR_WORD bcemul_special_genshift # 073 DSRA (*)
PTR_WORD bcemul_special_genshift # 074 DSLL32 (*)
PTR_WORD bcemul_sigill # 075
PTR_WORD bcemul_special_genshift # 076 DSRL32 (*)
PTR_WORD bcemul_special_genshift # 077 DSRA32 (*)
#endif
.text
.set push
.set noreorder
.set nomacro
.set mips64
bcemul_special_op:
jr ra; sllv t0, v0, v1 # 000 SLL
jr ra; nop # 001 MOVC1
jr ra; srlv t0, v0, v1 # 002 SRL
jr ra; srav t0, v0, v1 # 003 SRA
jr ra; sllv t0, v0, v1 # 004 SLLV
jr ra; nop # 005 *
jr ra; srlv t0, v0, v1 # 006 SRLV
jr ra; srav t0, v0, v1 # 007 SRAV
jr ra; nop # 010 JR
jr ra; nop # 011 JALR
jr ra; movz t0, v0, v1 # 012 MOVZ
jr ra; movn t0, v0, v1 # 013 MOVN
jr ra; nop # 014 SYSCALL
jr ra; nop # 015 BREAK
jr ra; nop # 016 *
jr ra; nop # 017 SYNC
jr ra; mfhi t0 # 020 MFHI
jr ra; mthi v0 # 021 MTHI
jr ra; mflo t0 # 022 MFLO
jr ra; mtlo v0 # 023 MTLO
jr ra; dsllv t0, v0, v1 # 024 DSLLV
jr ra; nop # 025 *
jr ra; dsrlv t0, v0, v1 # 026 DSRLV
jr ra; dsrav t0, v0, v1 # 027 DSRAV
jr ra; mult v0, v1 # 030 MULT
jr ra; multu v0, v1 # 031 MULTU
jr ra; div $0, v0, v1 # 032 DIV
jr ra; divu $0, v0, v1 # 033 DIVU
jr ra; dmult v0, v1 # 034 DMULT
jr ra; dmultu v0, v1 # 035 DMULTU
jr ra; ddiv $0, v0, v1 # 036 DDIV
jr ra; ddivu $0, v0, v1 # 037 DDIVU
jr ra; add t0, v0, v1 # 040 ADD
jr ra; addu t0, v0, v1 # 041 ADDU
jr ra; sub t0, v0, v1 # 042 SUB
jr ra; subu t0, v0, v1 # 043 SUBU
jr ra; and t0, v0, v1 # 044 AND
jr ra; or t0, v0, v1 # 045 OR
jr ra; xor t0, v0, v1 # 046 XOR
jr ra; nor t0, v0, v1 # 047 NOR
jr ra; nop # 050 *
jr ra; nop # 051 *
jr ra; slt t0, v0, v1 # 052 SLT
jr ra; sltu t0, v0, v1 # 053 SLTU
jr ra; dadd t0, v0, v1 # 054 DADD
jr ra; daddu t0, v0, v1 # 055 DADDU
jr ra; dsub t0, v0, v1 # 056 DSUB
jr ra; dsubu t0, v0, v1 # 057 DSUBU
jr ra; tge v0, v1 # 060 TGE
jr ra; tgeu v0, v1 # 061 TGEU
jr ra; tlt v0, v1 # 062 TLT
jr ra; tltu v0, v1 # 063 TLTU
jr ra; teq v0, v1 # 064 TEQ
jr ra; nop # 065 *
jr ra; tne v0, v1 # 066 TNE
jr ra; nop # 067 *
jr ra; dsllv t0, v0, v1 # 070 DSLL
jr ra; nop # 071 *
jr ra; dsrlv t0, v0, v1 # 072 DSRL
jr ra; dsrav t0, v0, v1 # 073 DSRA
jr ra; dsllv t0, v0, v1 # 074 DSLL32
jr ra; nop # 075 *
jr ra; dsrlv t0, v0, v1 # 076 DSRL32
jr ra; dsrav t0, v0, v1 # 077 DSRA32
.set pop
bcemul_special:
andi t0, a0, 0x3f # get special code
sll t1, t0, 3 # calculate index in specialop
sll t0, PTR_SCALESHIFT
PTR_L t9, bcemul_specialtbl(t0)
PTR_LA t0, bcemul_special_op(t1)
jr t9
bcemul_special_3op_prologue:
move t9, t0
srl t0, a0, 21-REG_SCALESHIFT # rs (source1)
srl t1, a0, 16-REG_SCALESHIFT # rt (source2)
srl t2, a0, 11-REG_SCALESHIFT # rd (dest)
andi t0, REG_REGMASK
andi t1, REG_REGMASK
andi t2, REG_REGMASK
PTR_ADDU t0, a1
PTR_ADDU t1, a1
PTR_ADDU t2, a1
REG_PROLOGUE
REG_L v0, TF_REG_ZERO(t0) # load source1
REG_L v1, TF_REG_ZERO(t1) # load source2
REG_EPILOGUE
jr t9
bcemul_special_2src_prologue:
move t9, t0
srl t0, a0, 21-REG_SCALESHIFT # rs (source1)
srl t1, a0, 16-REG_SCALESHIFT # rt (source2)
andi t0, REG_REGMASK
andi t1, REG_REGMASK
PTR_ADDU t0, a1
PTR_ADDU t1, a1
REG_PROLOGUE
REG_L v0, TF_REG_ZERO(t0) # load source1
REG_L v1, TF_REG_ZERO(t1) # load source2
REG_EPILOGUE
jr t9
bcemul_special_genshift:
move t9, t0
srl t1, a0, 16-REG_SCALESHIFT # rt (source)
srl t2, a0, 11-REG_SCALESHIFT # rd (dest)
srl v1, a0, 6 # sa
andi t1, REG_REGMASK
andi t2, REG_REGMASK
beqz t2, bcemul_done # fast escape for nop variants
andi v1, 0x001F
#ifndef __mips_o32
andi v0, a0, 077 # focus on special op
sltiu v0, v0, 074 # less than DSLL32?
xori v0, 1 # invert result
sll v0, 5 # shift by 5 (now 0 or 32)
addu v1, v0 # add to shift count
#endif
PTR_ADDU t1, a1
PTR_ADDU t2, a1
REG_PROLOGUE
REG_L v0, TF_REG_ZERO(t1) # load source
REG_EPILOGUE
jal t9
j bcemul_store_and_done
bcemul_special_sync:
b bcemul_done
bcemul_special_mfhilo:
srl t2, a0, 11-REG_SCALESHIFT # rd (dest)
andi t2, REG_REGMASK
PTR_ADDU t1, a1, TF_REG_MULHI
PTR_ADDU t2, a1
and v0, a0, 2 # bit 1: 0=HI 1=LO
sll v0, REG_SCALESHIFT - 1
#if TF_REG_MULLO < TF_REG_MULHI
PTR_SUBU t1, v0
#else
PTR_ADDU t1, v0
#endif
REG_PROLOGUE
REG_L t0, TF_REG_ZERO(t1) # load source (mullo or mulhi)
REG_EPILOGUE
b bcemul_store_and_done
bcemul_special_mthilo:
srl t1, a0, 21-REG_SCALESHIFT # rs (source)
andi t1, REG_REGMASK
PTR_ADDU t1, a1
PTR_ADDU t2, a1, TF_REG_MULHI
and v0, a0, 2 # bit 1: 0=HI l=LO
sll v0, REG_SCALESHIFT - 1
#if TF_REG_MULLO < TF_REG_MULHI
PTR_SUBU t2, v0
#else
PTR_ADDU t2, v0
#endif
REG_PROLOGUE
REG_L t0, TF_REG_ZERO(t1)
REG_EPILOGUE
b bcemul_store_and_done
bcemul_special_genmultdiv:
bal bcemul_special_2src_prologue # grab operands and do it.
mflo v0
mfhi v1
REG_PROLOGUE
REG_S v0, TF_REG_MULLO(a1)
REG_S v1, TF_REG_MULHI(a1)
REG_EPILOGUE
b bcemul_done
bcemul_special_genadd:
bal bcemul_special_3op_prologue
b bcemul_check_add_overflow
bcemul_special_gensub:
bal bcemul_special_3op_prologue
move ta0, v0
move ta1, t0
move ta2, v1
b bcemul_check_overflow
bcemul_special_genshiftv:
bcemul_special_gen3op:
bal bcemul_special_3op_prologue
bcemul_store_and_done:
beq a1, t2, bcemul_done # don't store to zero
REG_PROLOGUE
REG_S t0, TF_REG_ZERO(t2)
REG_EPILOGUE
bcemul_done:
PTR_SUBU sp, CALLFRAME_SIZ
REG_S t3, CALLFRAME_RA(sp)
REG_S s0, CALLFRAME_S0(sp)
move s0, a1 # save trapframe
REG_PROLOGUE
REG_L a0, TF_REG_EPC(s0)
REG_EPILOGUE
jal _C_LABEL(mips_ufetch32)
sll t0, v0, 16
sra t0, t0, 16-2
REG_PROLOGUE
REG_L t1, TF_REG_EPC(s0)
PTR_ADDU t0, 4
PTR_ADDU t1, t0
REG_S t1, TF_REG_EPC(s0)
REG_EPILOGUE
REG_L ra, CALLFRAME_RA(sp)
REG_L s0, CALLFRAME_S0(sp)
PTR_ADDU sp, CALLFRAME_SIZ
jr ra
bcemul_sigill:
li t0, 0xFFFFFF00
and a2, a2, t0
ori a2, a2, T_RES_INST << MIPS_CR_EXC_CODE_SHIFT
REG_PROLOGUE
REG_S a2, TF_REG_CAUSE(a1)
REG_EPILOGUE
move ra, t3 # restore ra
move a1, a0 # code = instruction
move a0, MIPS_CURLWP # get current process
j _C_LABEL(mips_fpuillinst)
END(mips_emul_branchdelayslot)