📄 isp.s
字号:
bsr.l _dmem_read_byte # read second byte tst.l %d1 # dfetch error? bne.w movp_read_err # yes lsl.l &0x8,%d2 mov.b %d0,%d2 # append bytes add.w &0x2,%a2 # incr addr by 2 bytes mov.l %a2,%a0 bsr.l _dmem_read_byte # read second byte tst.l %d1 # dfetch error? bne.w movp_read_err # yes lsl.l &0x8,%d2 mov.b %d0,%d2 # append bytes mov.b EXC_OPWORD(%a6),%d1 lsr.b &0x1,%d1 and.w &0x7,%d1 # extract Dx from opcode word mov.l %d2,(EXC_DREGS,%a6,%d1.w*4) # store dx rts# a0 = dst addrm2rwtrans: mov.l %a0,%a2 # store addr bsr.l _dmem_read_byte # read first byte tst.l %d1 # dfetch error? bne.w movp_read_err # yes mov.l %d0,%d2 add.w &0x2,%a2 # incr addr by 2 bytes mov.l %a2,%a0 bsr.l _dmem_read_byte # read second byte tst.l %d1 # dfetch error? bne.w movp_read_err # yes lsl.w &0x8,%d2 mov.b %d0,%d2 # append bytes mov.b EXC_OPWORD(%a6),%d1 lsr.b &0x1,%d1 and.w &0x7,%d1 # extract Dx from opcode word mov.w %d2,(EXC_DREGS+2,%a6,%d1.w*4) # store dx rts# if dmem_{read,write}_byte() returns a fail message in d1, the package# must create an access error frame. here, we pass a skeleton fslw# and the failing address to the routine that creates the new frame.# FSLW:# write = true# size = byte# TM = data# software emulation error = truemovp_write_err: mov.l %a2,%a0 # pass failing address mov.l &0x00a10001,%d0 # pass fslw bra.l isp_dacc# FSLW:# read = true# size = byte# TM = data# software emulation error = truemovp_read_err: mov.l %a2,%a0 # pass failing address mov.l &0x01210001,%d0 # pass fslw bra.l isp_dacc########################################################################## XDEF **************************************************************** ## _chk2_cmp2(): routine to emulate chk2/cmp2 instructions ## ## XREF **************************************************************** ## _calc_ea(): calculate effective address ## _dmem_read_long(): read operands ## _dmem_read_word(): read operands ## isp_dacc(): handle data access error exception ## ## INPUT *************************************************************** ## none ## ## OUTPUT ************************************************************** ## If exiting through isp_dacc... ## a0 = failing address ## d0 = FSLW ## else ## none ## ## ALGORITHM *********************************************************** ## First, calculate the effective address, then fetch the byte, ## word, or longword sized operands. Then, in the interest of ## simplicity, all operands are converted to longword size whether the ## operation is byte, word, or long. The bounds are sign extended ## accordingly. If Rn is a data regsiter, Rn is also sign extended. If ## Rn is an address register, it need not be sign extended since the ## full register is always used. ## The comparisons are made and the condition codes calculated. ## If the instruction is chk2 and the Rn value is out-of-bounds, set ## the ichk_flg in SPCOND_FLG. ## If the memory fetch returns a failing value, pass the failing ## address and FSLW to the isp_dacc() routine. ## ########################################################################## global _chk2_cmp2_chk2_cmp2:# passing size parameter doesn't matter since chk2 & cmp2 can't do# either predecrement, postincrement, or immediate. bsr.l _calc_ea # calculate <ea> mov.b EXC_EXTWORD(%a6), %d0 # fetch hi extension word rol.b &0x4, %d0 # rotate reg bits into lo and.w &0xf, %d0 # extract reg bits mov.l (EXC_DREGS,%a6,%d0.w*4), %d2 # get regval cmpi.b EXC_OPWORD(%a6), &0x2 # what size is operation? blt.b chk2_cmp2_byte # size == byte beq.b chk2_cmp2_word # size == word# the bounds are longword size. call routine to read the lower# bound into d0 and the higher bound into d1.chk2_cmp2_long: mov.l %a0,%a2 # save copy of <ea> bsr.l _dmem_read_long # fetch long lower bound tst.l %d1 # dfetch error? bne.w chk2_cmp2_err_l # yes mov.l %d0,%d3 # save long lower bound addq.l &0x4,%a2 mov.l %a2,%a0 # pass <ea> of long upper bound bsr.l _dmem_read_long # fetch long upper bound tst.l %d1 # dfetch error? bne.w chk2_cmp2_err_l # yes mov.l %d0,%d1 # long upper bound in d1 mov.l %d3,%d0 # long lower bound in d0 bra.w chk2_cmp2_compare # go do the compare emulation# the bounds are word size. fetch them in one subroutine call by# reading a longword. sign extend both. if it's a data operation,# sign extend Rn to long, also.chk2_cmp2_word: mov.l %a0,%a2 bsr.l _dmem_read_long # fetch 2 word bounds tst.l %d1 # dfetch error? bne.w chk2_cmp2_err_l # yes mov.w %d0, %d1 # place hi in %d1 swap %d0 # place lo in %d0 ext.l %d0 # sign extend lo bnd ext.l %d1 # sign extend hi bnd btst &0x7, EXC_EXTWORD(%a6) # address compare? bne.w chk2_cmp2_compare # yes; don't sign extend# operation is a data register compare.# sign extend word to long so we can do simple longword compares. ext.l %d2 # sign extend data word bra.w chk2_cmp2_compare # go emulate compare# the bounds are byte size. fetch them in one subroutine call by# reading a word. sign extend both. if it's a data operation,# sign extend Rn to long, also.chk2_cmp2_byte: mov.l %a0,%a2 bsr.l _dmem_read_word # fetch 2 byte bounds tst.l %d1 # dfetch error? bne.w chk2_cmp2_err_w # yes mov.b %d0, %d1 # place hi in %d1 lsr.w &0x8, %d0 # place lo in %d0 extb.l %d0 # sign extend lo bnd extb.l %d1 # sign extend hi bnd btst &0x7, EXC_EXTWORD(%a6) # address compare? bne.b chk2_cmp2_compare # yes; don't sign extend# operation is a data register compare.# sign extend byte to long so we can do simple longword compares. extb.l %d2 # sign extend data byte## To set the ccodes correctly:# (1) save 'Z' bit from (Rn - lo)# (2) save 'Z' and 'N' bits from ((hi - lo) - (Rn - hi))# (3) keep 'X', 'N', and 'V' from before instruction# (4) combine ccodes#chk2_cmp2_compare: sub.l %d0, %d2 # (Rn - lo) mov.w %cc, %d3 # fetch resulting ccodes andi.b &0x4, %d3 # keep 'Z' bit sub.l %d0, %d1 # (hi - lo) cmp.l %d1,%d2 # ((hi - lo) - (Rn - hi)) mov.w %cc, %d4 # fetch resulting ccodes or.b %d4, %d3 # combine w/ earlier ccodes andi.b &0x5, %d3 # keep 'Z' and 'N' mov.w EXC_CC(%a6), %d4 # fetch old ccodes andi.b &0x1a, %d4 # keep 'X','N','V' bits or.b %d3, %d4 # insert new ccodes mov.w %d4, EXC_CC(%a6) # save new ccodes btst &0x3, EXC_EXTWORD(%a6) # separate chk2,cmp2 bne.b chk2_finish # it's a chk2 rts# this code handles the only difference between chk2 and cmp2. chk2 would# have trapped out if the value was out of bounds. we check this by seeing# if the 'N' bit was set by the operation.chk2_finish: btst &0x0, %d4 # is 'N' bit set? bne.b chk2_trap # yes;chk2 should trap rtschk2_trap: mov.b &ichk_flg,SPCOND_FLG(%a6) # set "special case" flag rts# if dmem_read_{long,word}() returns a fail message in d1, the package# must create an access error frame. here, we pass a skeleton fslw# and the failing address to the routine that creates the new frame.# FSLW:# read = true# size = longword# TM = data# software emulation error = truechk2_cmp2_err_l: mov.l %a2,%a0 # pass failing address mov.l &0x01010001,%d0 # pass fslw bra.l isp_dacc# FSLW:# read = true# size = word# TM = data# software emulation error = truechk2_cmp2_err_w: mov.l %a2,%a0 # pass failing address mov.l &0x01410001,%d0 # pass fslw bra.l isp_dacc########################################################################## XDEF **************************************************************** ## _div64(): routine to emulate div{u,s}.l <ea>,Dr:Dq ## 64/32->32r:32q ## ## XREF **************************************************************** ## _calc_ea() - calculate effective address ## isp_iacc() - handle instruction access error exception ## isp_dacc() - handle data access error exception ## isp_restore() - restore An on access error w/ -() or ()+ ## ## INPUT *************************************************************** ## none ## ## OUTPUT ************************************************************** ## If exiting through isp_dacc... ## a0 = failing address ## d0 = FSLW ## else ## none ## ## ALGORITHM *********************************************************** ## First, decode the operand location. If it's in Dn, fetch from ## the stack. If it's in memory, use _calc_ea() to calculate the ## effective address. Use _dmem_read_long() to fetch at that address. ## Unless the operand is immediate data. Then use _imem_read_long(). ## Send failures to isp_dacc() or isp_iacc() as appropriate. ## If the operands are signed, make them unsigned and save the ## sign info for later. Separate out special cases like divide-by-zero ## or 32-bit divides if possible. Else, use a special math algorithm ## to calculate the result. ## Restore sign info if signed instruction. Set the condition ## codes. Set idbyz_flg in SPCOND_FLG if divisor was zero. Store the ## quotient and remainder in the appropriate data registers on the stack.## ##########################################################################set NDIVISOR, EXC_TEMP+0x0set NDIVIDEND, EXC_TEMP+0x1set NDRSAVE, EXC_TEMP+0x2set NDQSAVE, EXC_TEMP+0x4set DDSECOND, EXC_TEMP+0x6set DDQUOTIENT, EXC_TEMP+0x8set DDNORMAL, EXC_TEMP+0xc global _div64############## div(u,s)l ##############_div64: mov.b EXC_OPWORD+1(%a6), %d0 andi.b &0x38, %d0 # extract src mode bne.w dcontrolmodel_s # %dn dest or control mode? mov.b EXC_OPWORD+1(%a6), %d0 # extract Dn from opcode andi.w &0x7, %d0 mov.l (EXC_DREGS,%a6,%d0.w*4), %d7 # fetch divisor from registerdgotsrcl: beq.w div64eq0 # divisor is = 0!!! mov.b EXC_EXTWORD+1(%a6), %d0 # extract Dr from extword mov.b EXC_EXTWORD(%a6), %d1 # extract Dq from extword and.w &0x7, %d0 lsr.b &0x4, %d1 and.w &0x7, %d1 mov.w %d0, NDRSAVE(%a6) # save Dr for later mov.w %d1, NDQSAVE(%a6) # save Dq for later# fetch %dr and %dq directly off stack since all regs are saved there mov.l (EXC_DREGS,%a6,%d0.w*4), %d5 # get dividend hi mov.l (EXC_DREGS,%a6,%d1.w*4), %d6 # get dividend lo# separate signed and unsigned divide btst &0x3, EXC_EXTWORD(%a6) # signed or unsigned? beq.b dspecialcases # use positive divide# save the sign of the divisor# make divisor unsigned if it's negative tst.l %d7 # chk sign of divisor slt NDIVISOR(%a6) # save sign of divisor bpl.b dsgndividend neg.l %d7 # complement negative divisor# save the sign of the dividend# make dividend unsigned if it's negativedsgndividend: tst.l %d5 # chk sign of hi(dividend) slt NDIVIDEND(%a6) # save sign of dividend bpl.b dspecialcases mov.w &0x0, %cc # clear 'X' cc bit negx.l %d6 # complement signed dividend negx.l %d5# extract some special cases:# - is (dividend == 0) ?# - is (hi(dividend) == 0 && (divisor <= lo(dividend))) ? (32-bit div)dspecialcases: tst.l %d5 # is (hi(dividend) == 0) bne.b dnormaldivide # no, so try it the long way tst.l %d6 # is (lo(dividend) == 0), too beq.w ddone # yes, so (dividend == 0) cmp.l %d7,%d6 # is (divisor <= lo(dividend)) bls.b d32bitdivide # yes, so use 32 bit divide exg %d5,%d6 # q = 0, r = dividend bra.w divfinish # can't divide, we're done.d32bitdivide: tdivu.l %d7, %d5:%d6 # it's only a 32/32 bit div! bra.b divfinishdnormaldivide:# last special case:# - is hi(dividend) >= divisor ? if yes, then overflow cmp.l %d7,%d5 bls.b ddovf # answer won't fit in 32 bits# perform the divide algorithm: bsr.l dclassical # do int divide# separate into signed and unsigned finishes.divfinish: btst &0x3, EXC_EXTWORD(%a6) # do divs, divu separately beq.b ddone # divu has no processing!!!# it was a divs.l, so ccode setting is a little more complicated... tst.b NDIVIDEND(%a6) # remainder has same sign beq.b dcc # as dividend. neg.l %d5 # sgn(rem) = sgn(dividend)dcc: mov.b NDIVISOR(%a6), %d0 eor.b %d0, NDIVIDEND(%a6) # chk if quotient is negative beq.b dqpos # branch to quot positive# 0x80000000 is the largest number representable as a 32-bit negative# number. the negative of 0x80000000 is 0x80000000. cmpi.l %d6, &0x80000000 # will (-quot) fit in 32 bits? bhi.b ddovf neg.l %d6 # make (-quot) 2's comp bra.b ddonedqpos: btst &0x1f, %d6 # will (+quot) fit in 32 bits? bne.b ddovfddone:# at this point, result is normal so ccodes are set based on result. mov.w EXC_CC(%a6), %cc tst.l %d6 # set %ccode bits mov.w %cc, EXC_CC(%a6) mov.w NDRSAVE(%a6), %d0 # get Dr off stack mov.w NDQSAVE(%a6), %d1 # get Dq off stack# if the register numbers are the same, only the quotient gets saved.# so, if we always save the quotient second, we save ourselves a cmp&beq mov.l %d5, (EXC_DREGS,%a6,%d0.w*4) # save remainder mov.l %d6, (EXC_DREGS,%a6,%d1.w*4) # save quotient rtsddovf: bset &0x1, EXC_CC+1(%a6) # 'V' set on overflow bclr &0x0, EXC_CC+1(%a6) # 'C' cleared on overflow rtsdiv64eq0:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -