123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932 |
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
- M68000 Hi-Performance Microprocessor Division
- M68060 Software Package
- Production Release P1.00 -- October 10, 1994
- M68060 Software Package Copyright © 1993, 1994 Motorola Inc. All rights reserved.
- THE SOFTWARE is provided on an "AS IS" basis and without warranty.
- To the maximum extent permitted by applicable law,
- MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED,
- INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
- and any warranty against infringement with regard to the SOFTWARE
- (INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials.
- To the maximum extent permitted by applicable law,
- IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
- (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
- BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS)
- ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
- Motorola assumes no responsibility for the maintenance and support of the SOFTWARE.
- You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE
- so long as this entire notice is retained without alteration in any modified and/or
- redistributed versions, and that such modified versions are clearly identified as such.
- No licenses are granted by implication, estoppel or otherwise under any patents
- or trademarks of Motorola, Inc.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- # litop.s:
- # This file is appended to the top of the 060FPLSP package
- # and contains the entry points into the package. The user, in
- # effect, branches to one of the branch table entries located here.
- #
- bra.l _060LSP__idivs64_
- short 0x0000
- bra.l _060LSP__idivu64_
- short 0x0000
- bra.l _060LSP__imuls64_
- short 0x0000
- bra.l _060LSP__imulu64_
- short 0x0000
- bra.l _060LSP__cmp2_Ab_
- short 0x0000
- bra.l _060LSP__cmp2_Aw_
- short 0x0000
- bra.l _060LSP__cmp2_Al_
- short 0x0000
- bra.l _060LSP__cmp2_Db_
- short 0x0000
- bra.l _060LSP__cmp2_Dw_
- short 0x0000
- bra.l _060LSP__cmp2_Dl_
- short 0x0000
- # leave room for future possible aditions.
- align 0x200
- #########################################################################
- # XDEF **************************************************************** #
- # _060LSP__idivu64_(): Emulate 64-bit unsigned div instruction. #
- # _060LSP__idivs64_(): Emulate 64-bit signed div instruction. #
- # #
- # This is the library version which is accessed as a subroutine #
- # and therefore does not work exactly like the 680X0 div{s,u}.l #
- # 64-bit divide instruction. #
- # #
- # XREF **************************************************************** #
- # None. #
- # #
- # INPUT *************************************************************** #
- # 0x4(sp) = divisor #
- # 0x8(sp) = hi(dividend) #
- # 0xc(sp) = lo(dividend) #
- # 0x10(sp) = pointer to location to place quotient/remainder #
- # #
- # OUTPUT ************************************************************** #
- # 0x10(sp) = points to location of remainder/quotient. #
- # remainder is in first longword, quotient is in 2nd. #
- # #
- # ALGORITHM *********************************************************** #
- # 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 before performing the final "rts". If the divisor was equal to #
- # zero, then perform a divide-by-zero using a 16-bit implemented #
- # divide instruction. This way, the operating system can record that #
- # the event occurred even though it may not point to the correct place. #
- # #
- #########################################################################
- set POSNEG, -1
- set NDIVISOR, -2
- set NDIVIDEND, -3
- set DDSECOND, -4
- set DDNORMAL, -8
- set DDQUOTIENT, -12
- set DIV64_CC, -16
- ##########
- # divs.l #
- ##########
- global _060LSP__idivs64_
- _060LSP__idivs64_:
- # PROLOGUE BEGIN ########################################################
- link.w %a6,&-16
- movm.l &0x3f00,-(%sp) # save d2-d7
- # fmovm.l &0x0,-(%sp) # save no fpregs
- # PROLOGUE END ##########################################################
- mov.w %cc,DIV64_CC(%a6)
- st POSNEG(%a6) # signed operation
- bra.b ldiv64_cont
- ##########
- # divu.l #
- ##########
- global _060LSP__idivu64_
- _060LSP__idivu64_:
- # PROLOGUE BEGIN ########################################################
- link.w %a6,&-16
- movm.l &0x3f00,-(%sp) # save d2-d7
- # fmovm.l &0x0,-(%sp) # save no fpregs
- # PROLOGUE END ##########################################################
- mov.w %cc,DIV64_CC(%a6)
- sf POSNEG(%a6) # unsigned operation
- ldiv64_cont:
- mov.l 0x8(%a6),%d7 # fetch divisor
- beq.w ldiv64eq0 # divisor is = 0!!!
- mov.l 0xc(%a6), %d5 # get dividend hi
- mov.l 0x10(%a6), %d6 # get dividend lo
- # separate signed and unsigned divide
- tst.b POSNEG(%a6) # signed or unsigned?
- beq.b ldspecialcases # 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 ldsgndividend
- neg.l %d7 # complement negative divisor
- # save the sign of the dividend
- # make dividend unsigned if it's negative
- ldsgndividend:
- tst.l %d5 # chk sign of hi(dividend)
- slt NDIVIDEND(%a6) # save sign of dividend
- bpl.b ldspecialcases
- 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)
- ldspecialcases:
- tst.l %d5 # is (hi(dividend) == 0)
- bne.b ldnormaldivide # no, so try it the long way
- tst.l %d6 # is (lo(dividend) == 0), too
- beq.w lddone # yes, so (dividend == 0)
- cmp.l %d7,%d6 # is (divisor <= lo(dividend))
- bls.b ld32bitdivide # yes, so use 32 bit divide
- exg %d5,%d6 # q = 0, r = dividend
- bra.w ldivfinish # can't divide, we're done.
- ld32bitdivide:
- tdivu.l %d7, %d5:%d6 # it's only a 32/32 bit div!
- bra.b ldivfinish
- ldnormaldivide:
- # last special case:
- # - is hi(dividend) >= divisor ? if yes, then overflow
- cmp.l %d7,%d5
- bls.b lddovf # answer won't fit in 32 bits
- # perform the divide algorithm:
- bsr.l ldclassical # do int divide
- # separate into signed and unsigned finishes.
- ldivfinish:
- tst.b POSNEG(%a6) # do divs, divu separately
- beq.b lddone # 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 ldcc # as dividend.
- neg.l %d5 # sgn(rem) = sgn(dividend)
- ldcc:
- mov.b NDIVISOR(%a6), %d0
- eor.b %d0, NDIVIDEND(%a6) # chk if quotient is negative
- beq.b ldqpos # 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 lddovf
- neg.l %d6 # make (-quot) 2's comp
- bra.b lddone
- ldqpos:
- btst &0x1f, %d6 # will (+quot) fit in 32 bits?
- bne.b lddovf
- lddone:
- # 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
- andi.w &0x10,DIV64_CC(%a6)
- mov.w DIV64_CC(%a6),%cc
- tst.l %d6 # may set 'N' ccode bit
- # here, the result is in d1 and d0. the current strategy is to save
- # the values at the location pointed to by a0.
- # use movm here to not disturb the condition codes.
- ldexit:
- movm.l &0x0060,([0x14,%a6]) # save result
- # EPILOGUE BEGIN ########################################################
- # fmovm.l (%sp)+,&0x0 # restore no fpregs
- movm.l (%sp)+,&0x00fc # restore d2-d7
- unlk %a6
- # EPILOGUE END ##########################################################
- rts
- # the result should be the unchanged dividend
- lddovf:
- mov.l 0xc(%a6), %d5 # get dividend hi
- mov.l 0x10(%a6), %d6 # get dividend lo
- andi.w &0x1c,DIV64_CC(%a6)
- ori.w &0x02,DIV64_CC(%a6) # set 'V' ccode bit
- mov.w DIV64_CC(%a6),%cc
- bra.b ldexit
- ldiv64eq0:
- mov.l 0xc(%a6),([0x14,%a6])
- mov.l 0x10(%a6),([0x14,%a6],0x4)
- mov.w DIV64_CC(%a6),%cc
- # EPILOGUE BEGIN ########################################################
- # fmovm.l (%sp)+,&0x0 # restore no fpregs
- movm.l (%sp)+,&0x00fc # restore d2-d7
- unlk %a6
- # EPILOGUE END ##########################################################
- divu.w &0x0,%d0 # force a divbyzero exception
- rts
- ###########################################################################
- #########################################################################
- # This routine uses the 'classical' Algorithm D from Donald Knuth's #
- # Art of Computer Programming, vol II, Seminumerical Algorithms. #
- # For this implementation b=2**16, and the target is U1U2U3U4/V1V2, #
- # where U,V are words of the quadword dividend and longword divisor, #
- # and U1, V1 are the most significant words. #
- # #
- # The most sig. longword of the 64 bit dividend must be in %d5, least #
- # in %d6. The divisor must be in the variable ddivisor, and the #
- # signed/unsigned flag ddusign must be set (0=unsigned,1=signed). #
- # The quotient is returned in %d6, remainder in %d5, unless the #
- # v (overflow) bit is set in the saved %ccr. If overflow, the dividend #
- # is unchanged. #
- #########################################################################
- ldclassical:
- # if the divisor msw is 0, use simpler algorithm then the full blown
- # one at ddknuth:
- cmpi.l %d7, &0xffff
- bhi.b lddknuth # go use D. Knuth algorithm
- # Since the divisor is only a word (and larger than the mslw of the dividend),
- # a simpler algorithm may be used :
- # In the general case, four quotient words would be created by
- # dividing the divisor word into each dividend word. In this case,
- # the first two quotient words must be zero, or overflow would occur.
- # Since we already checked this case above, we can treat the most significant
- # longword of the dividend as (0) remainder (see Knuth) and merely complete
- # the last two divisions to get a quotient longword and word remainder:
- clr.l %d1
- swap %d5 # same as r*b if previous step rqd
- swap %d6 # get u3 to lsw position
- mov.w %d6, %d5 # rb + u3
- divu.w %d7, %d5
- mov.w %d5, %d1 # first quotient word
- swap %d6 # get u4
- mov.w %d6, %d5 # rb + u4
- divu.w %d7, %d5
- swap %d1
- mov.w %d5, %d1 # 2nd quotient 'digit'
- clr.w %d5
- swap %d5 # now remainder
- mov.l %d1, %d6 # and quotient
- rts
- lddknuth:
- # In this algorithm, the divisor is treated as a 2 digit (word) number
- # which is divided into a 3 digit (word) dividend to get one quotient
- # digit (word). After subtraction, the dividend is shifted and the
- # process repeated. Before beginning, the divisor and quotient are
- # 'normalized' so that the process of estimating the quotient digit
- # will yield verifiably correct results..
- clr.l DDNORMAL(%a6) # count of shifts for normalization
- clr.b DDSECOND(%a6) # clear flag for quotient digits
- clr.l %d1 # %d1 will hold trial quotient
- lddnchk:
- btst &31, %d7 # must we normalize? first word of
- bne.b lddnormalized # divisor (V1) must be >= 65536/2
- addq.l &0x1, DDNORMAL(%a6) # count normalization shifts
- lsl.l &0x1, %d7 # shift the divisor
- lsl.l &0x1, %d6 # shift u4,u3 with overflow to u2
- roxl.l &0x1, %d5 # shift u1,u2
- bra.w lddnchk
- lddnormalized:
- # Now calculate an estimate of the quotient words (msw first, then lsw).
- # The comments use subscripts for the first quotient digit determination.
- mov.l %d7, %d3 # divisor
- mov.l %d5, %d2 # dividend mslw
- swap %d2
- swap %d3
- cmp.w %d2, %d3 # V1 = U1 ?
- bne.b lddqcalc1
- mov.w &0xffff, %d1 # use max trial quotient word
- bra.b lddadj0
- lddqcalc1:
- mov.l %d5, %d1
- divu.w %d3, %d1 # use quotient of mslw/msw
- andi.l &0x0000ffff, %d1 # zero any remainder
- lddadj0:
- # now test the trial quotient and adjust. This step plus the
- # normalization assures (according to Knuth) that the trial
- # quotient will be at worst 1 too large.
- mov.l %d6, -(%sp)
- clr.w %d6 # word u3 left
- swap %d6 # in lsw position
- lddadj1: mov.l %d7, %d3
- mov.l %d1, %d2
- mulu.w %d7, %d2 # V2q
- swap %d3
- mulu.w %d1, %d3 # V1q
- mov.l %d5, %d4 # U1U2
- sub.l %d3, %d4 # U1U2 - V1q
- swap %d4
- mov.w %d4,%d0
- mov.w %d6,%d4 # insert lower word (U3)
- tst.w %d0 # is upper word set?
- bne.w lddadjd1
- # add.l %d6, %d4 # (U1U2 - V1q) + U3
- cmp.l %d2, %d4
- bls.b lddadjd1 # is V2q > (U1U2-V1q) + U3 ?
- subq.l &0x1, %d1 # yes, decrement and recheck
- bra.b lddadj1
- lddadjd1:
- # now test the word by multiplying it by the divisor (V1V2) and comparing
- # the 3 digit (word) result with the current dividend words
- mov.l %d5, -(%sp) # save %d5 (%d6 already saved)
- mov.l %d1, %d6
- swap %d6 # shift answer to ms 3 words
- mov.l %d7, %d5
- bsr.l ldmm2
- mov.l %d5, %d2 # now %d2,%d3 are trial*divisor
- mov.l %d6, %d3
- mov.l (%sp)+, %d5 # restore dividend
- mov.l (%sp)+, %d6
- sub.l %d3, %d6
- subx.l %d2, %d5 # subtract double precision
- bcc ldd2nd # no carry, do next quotient digit
- subq.l &0x1, %d1 # q is one too large
- # need to add back divisor longword to current ms 3 digits of dividend
- # - according to Knuth, this is done only 2 out of 65536 times for random
- # divisor, dividend selection.
- clr.l %d2
- mov.l %d7, %d3
- swap %d3
- clr.w %d3 # %d3 now ls word of divisor
- add.l %d3, %d6 # aligned with 3rd word of dividend
- addx.l %d2, %d5
- mov.l %d7, %d3
- clr.w %d3 # %d3 now ms word of divisor
- swap %d3 # aligned with 2nd word of dividend
- add.l %d3, %d5
- ldd2nd:
- tst.b DDSECOND(%a6) # both q words done?
- bne.b lddremain
- # first quotient digit now correct. store digit and shift the
- # (subtracted) dividend
- mov.w %d1, DDQUOTIENT(%a6)
- clr.l %d1
- swap %d5
- swap %d6
- mov.w %d6, %d5
- clr.w %d6
- st DDSECOND(%a6) # second digit
- bra.w lddnormalized
- lddremain:
- # add 2nd word to quotient, get the remainder.
- mov.w %d1, DDQUOTIENT+2(%a6)
- # shift down one word/digit to renormalize remainder.
- mov.w %d5, %d6
- swap %d6
- swap %d5
- mov.l DDNORMAL(%a6), %d7 # get norm shift count
- beq.b lddrn
- subq.l &0x1, %d7 # set for loop count
- lddnlp:
- lsr.l &0x1, %d5 # shift into %d6
- roxr.l &0x1, %d6
- dbf %d7, lddnlp
- lddrn:
- mov.l %d6, %d5 # remainder
- mov.l DDQUOTIENT(%a6), %d6 # quotient
- rts
- ldmm2:
- # factors for the 32X32->64 multiplication are in %d5 and %d6.
- # returns 64 bit result in %d5 (hi) %d6(lo).
- # destroys %d2,%d3,%d4.
- # multiply hi,lo words of each factor to get 4 intermediate products
- mov.l %d6, %d2
- mov.l %d6, %d3
- mov.l %d5, %d4
- swap %d3
- swap %d4
- mulu.w %d5, %d6 # %d6 <- lsw*lsw
- mulu.w %d3, %d5 # %d5 <- msw-dest*lsw-source
- mulu.w %d4, %d2 # %d2 <- msw-source*lsw-dest
- mulu.w %d4, %d3 # %d3 <- msw*msw
- # now use swap and addx to consolidate to two longwords
- clr.l %d4
- swap %d6
- add.w %d5, %d6 # add msw of l*l to lsw of m*l product
- addx.w %d4, %d3 # add any carry to m*m product
- add.w %d2, %d6 # add in lsw of other m*l product
- addx.w %d4, %d3 # add any carry to m*m product
- swap %d6 # %d6 is low 32 bits of final product
- clr.w %d5
- clr.w %d2 # lsw of two mixed products used,
- swap %d5 # now use msws of longwords
- swap %d2
- add.l %d2, %d5
- add.l %d3, %d5 # %d5 now ms 32 bits of final product
- rts
- #########################################################################
- # XDEF **************************************************************** #
- # _060LSP__imulu64_(): Emulate 64-bit unsigned mul instruction #
- # _060LSP__imuls64_(): Emulate 64-bit signed mul instruction. #
- # #
- # This is the library version which is accessed as a subroutine #
- # and therefore does not work exactly like the 680X0 mul{s,u}.l #
- # 64-bit multiply instruction. #
- # #
- # XREF **************************************************************** #
- # None #
- # #
- # INPUT *************************************************************** #
- # 0x4(sp) = multiplier #
- # 0x8(sp) = multiplicand #
- # 0xc(sp) = pointer to location to place 64-bit result #
- # #
- # OUTPUT ************************************************************** #
- # 0xc(sp) = points to location of 64-bit result #
- # #
- # ALGORITHM *********************************************************** #
- # Perform the multiply in pieces using 16x16->32 unsigned #
- # multiplies and "add" instructions. #
- # Set the condition codes as appropriate before performing an #
- # "rts". #
- # #
- #########################################################################
- set MUL64_CC, -4
- global _060LSP__imulu64_
- _060LSP__imulu64_:
- # PROLOGUE BEGIN ########################################################
- link.w %a6,&-4
- movm.l &0x3800,-(%sp) # save d2-d4
- # fmovm.l &0x0,-(%sp) # save no fpregs
- # PROLOGUE END ##########################################################
- mov.w %cc,MUL64_CC(%a6) # save incoming ccodes
- mov.l 0x8(%a6),%d0 # store multiplier in d0
- beq.w mulu64_zero # handle zero separately
- mov.l 0xc(%a6),%d1 # get multiplicand in d1
- beq.w mulu64_zero # handle zero separately
- #########################################################################
- # 63 32 0 #
- # ---------------------------- #
- # | hi(mplier) * hi(mplicand)| #
- # ---------------------------- #
- # ----------------------------- #
- # | hi(mplier) * lo(mplicand) | #
- # ----------------------------- #
- # ----------------------------- #
- # | lo(mplier) * hi(mplicand) | #
- # ----------------------------- #
- # | ----------------------------- #
- # --|-- | lo(mplier) * lo(mplicand) | #
- # | ----------------------------- #
- # ======================================================== #
- # -------------------------------------------------------- #
- # | hi(result) | lo(result) | #
- # -------------------------------------------------------- #
- #########################################################################
- mulu64_alg:
- # load temp registers with operands
- mov.l %d0,%d2 # mr in d2
- mov.l %d0,%d3 # mr in d3
- mov.l %d1,%d4 # md in d4
- swap %d3 # hi(mr) in lo d3
- swap %d4 # hi(md) in lo d4
- # complete necessary multiplies:
- mulu.w %d1,%d0 # [1] lo(mr) * lo(md)
- mulu.w %d3,%d1 # [2] hi(mr) * lo(md)
- mulu.w %d4,%d2 # [3] lo(mr) * hi(md)
- mulu.w %d4,%d3 # [4] hi(mr) * hi(md)
- # add lo portions of [2],[3] to hi portion of [1].
- # add carries produced from these adds to [4].
- # lo([1]) is the final lo 16 bits of the result.
- clr.l %d4 # load d4 w/ zero value
- swap %d0 # hi([1]) <==> lo([1])
- add.w %d1,%d0 # hi([1]) + lo([2])
- addx.l %d4,%d3 # [4] + carry
- add.w %d2,%d0 # hi([1]) + lo([3])
- addx.l %d4,%d3 # [4] + carry
- swap %d0 # lo([1]) <==> hi([1])
- # lo portions of [2],[3] have been added in to final result.
- # now, clear lo, put hi in lo reg, and add to [4]
- clr.w %d1 # clear lo([2])
- clr.w %d2 # clear hi([3])
- swap %d1 # hi([2]) in lo d1
- swap %d2 # hi([3]) in lo d2
- add.l %d2,%d1 # [4] + hi([2])
- add.l %d3,%d1 # [4] + hi([3])
- # now, grab the condition codes. only one that can be set is 'N'.
- # 'N' CAN be set if the operation is unsigned if bit 63 is set.
- mov.w MUL64_CC(%a6),%d4
- andi.b &0x10,%d4 # keep old 'X' bit
- tst.l %d1 # may set 'N' bit
- bpl.b mulu64_ddone
- ori.b &0x8,%d4 # set 'N' bit
- mulu64_ddone:
- mov.w %d4,%cc
- # here, the result is in d1 and d0. the current strategy is to save
- # the values at the location pointed to by a0.
- # use movm here to not disturb the condition codes.
- mulu64_end:
- exg %d1,%d0
- movm.l &0x0003,([0x10,%a6]) # save result
- # EPILOGUE BEGIN ########################################################
- # fmovm.l (%sp)+,&0x0 # restore no fpregs
- movm.l (%sp)+,&0x001c # restore d2-d4
- unlk %a6
- # EPILOGUE END ##########################################################
- rts
- # one or both of the operands is zero so the result is also zero.
- # save the zero result to the register file and set the 'Z' ccode bit.
- mulu64_zero:
- clr.l %d0
- clr.l %d1
- mov.w MUL64_CC(%a6),%d4
- andi.b &0x10,%d4
- ori.b &0x4,%d4
- mov.w %d4,%cc # set 'Z' ccode bit
- bra.b mulu64_end
- ##########
- # muls.l #
- ##########
- global _060LSP__imuls64_
- _060LSP__imuls64_:
- # PROLOGUE BEGIN ########################################################
- link.w %a6,&-4
- movm.l &0x3c00,-(%sp) # save d2-d5
- # fmovm.l &0x0,-(%sp) # save no fpregs
- # PROLOGUE END ##########################################################
- mov.w %cc,MUL64_CC(%a6) # save incoming ccodes
- mov.l 0x8(%a6),%d0 # store multiplier in d0
- beq.b mulu64_zero # handle zero separately
- mov.l 0xc(%a6),%d1 # get multiplicand in d1
- beq.b mulu64_zero # handle zero separately
- clr.b %d5 # clear sign tag
- tst.l %d0 # is multiplier negative?
- bge.b muls64_chk_md_sgn # no
- neg.l %d0 # make multiplier positive
- ori.b &0x1,%d5 # save multiplier sgn
- # the result sign is the exclusive or of the operand sign bits.
- muls64_chk_md_sgn:
- tst.l %d1 # is multiplicand negative?
- bge.b muls64_alg # no
- neg.l %d1 # make multiplicand positive
- eori.b &0x1,%d5 # calculate correct sign
- #########################################################################
- # 63 32 0 #
- # ---------------------------- #
- # | hi(mplier) * hi(mplicand)| #
- # ---------------------------- #
- # ----------------------------- #
- # | hi(mplier) * lo(mplicand) | #
- # ----------------------------- #
- # ----------------------------- #
- # | lo(mplier) * hi(mplicand) | #
- # ----------------------------- #
- # | ----------------------------- #
- # --|-- | lo(mplier) * lo(mplicand) | #
- # | ----------------------------- #
- # ======================================================== #
- # -------------------------------------------------------- #
- # | hi(result) | lo(result) | #
- # -------------------------------------------------------- #
- #########################################################################
- muls64_alg:
- # load temp registers with operands
- mov.l %d0,%d2 # mr in d2
- mov.l %d0,%d3 # mr in d3
- mov.l %d1,%d4 # md in d4
- swap %d3 # hi(mr) in lo d3
- swap %d4 # hi(md) in lo d4
- # complete necessary multiplies:
- mulu.w %d1,%d0 # [1] lo(mr) * lo(md)
- mulu.w %d3,%d1 # [2] hi(mr) * lo(md)
- mulu.w %d4,%d2 # [3] lo(mr) * hi(md)
- mulu.w %d4,%d3 # [4] hi(mr) * hi(md)
- # add lo portions of [2],[3] to hi portion of [1].
- # add carries produced from these adds to [4].
- # lo([1]) is the final lo 16 bits of the result.
- clr.l %d4 # load d4 w/ zero value
- swap %d0 # hi([1]) <==> lo([1])
- add.w %d1,%d0 # hi([1]) + lo([2])
- addx.l %d4,%d3 # [4] + carry
- add.w %d2,%d0 # hi([1]) + lo([3])
- addx.l %d4,%d3 # [4] + carry
- swap %d0 # lo([1]) <==> hi([1])
- # lo portions of [2],[3] have been added in to final result.
- # now, clear lo, put hi in lo reg, and add to [4]
- clr.w %d1 # clear lo([2])
- clr.w %d2 # clear hi([3])
- swap %d1 # hi([2]) in lo d1
- swap %d2 # hi([3]) in lo d2
- add.l %d2,%d1 # [4] + hi([2])
- add.l %d3,%d1 # [4] + hi([3])
- tst.b %d5 # should result be signed?
- beq.b muls64_done # no
- # result should be a signed negative number.
- # compute 2's complement of the unsigned number:
- # -negate all bits and add 1
- muls64_neg:
- not.l %d0 # negate lo(result) bits
- not.l %d1 # negate hi(result) bits
- addq.l &1,%d0 # add 1 to lo(result)
- addx.l %d4,%d1 # add carry to hi(result)
- muls64_done:
- mov.w MUL64_CC(%a6),%d4
- andi.b &0x10,%d4 # keep old 'X' bit
- tst.l %d1 # may set 'N' bit
- bpl.b muls64_ddone
- ori.b &0x8,%d4 # set 'N' bit
- muls64_ddone:
- mov.w %d4,%cc
- # here, the result is in d1 and d0. the current strategy is to save
- # the values at the location pointed to by a0.
- # use movm here to not disturb the condition codes.
- muls64_end:
- exg %d1,%d0
- movm.l &0x0003,([0x10,%a6]) # save result at (a0)
- # EPILOGUE BEGIN ########################################################
- # fmovm.l (%sp)+,&0x0 # restore no fpregs
- movm.l (%sp)+,&0x003c # restore d2-d5
- unlk %a6
- # EPILOGUE END ##########################################################
- rts
- # one or both of the operands is zero so the result is also zero.
- # save the zero result to the register file and set the 'Z' ccode bit.
- muls64_zero:
- clr.l %d0
- clr.l %d1
- mov.w MUL64_CC(%a6),%d4
- andi.b &0x10,%d4
- ori.b &0x4,%d4
- mov.w %d4,%cc # set 'Z' ccode bit
- bra.b muls64_end
- #########################################################################
- # XDEF **************************************************************** #
- # _060LSP__cmp2_Ab_(): Emulate "cmp2.b An,<ea>". #
- # _060LSP__cmp2_Aw_(): Emulate "cmp2.w An,<ea>". #
- # _060LSP__cmp2_Al_(): Emulate "cmp2.l An,<ea>". #
- # _060LSP__cmp2_Db_(): Emulate "cmp2.b Dn,<ea>". #
- # _060LSP__cmp2_Dw_(): Emulate "cmp2.w Dn,<ea>". #
- # _060LSP__cmp2_Dl_(): Emulate "cmp2.l Dn,<ea>". #
- # #
- # This is the library version which is accessed as a subroutine #
- # and therefore does not work exactly like the 680X0 "cmp2" #
- # instruction. #
- # #
- # XREF **************************************************************** #
- # None #
- # #
- # INPUT *************************************************************** #
- # 0x4(sp) = Rn #
- # 0x8(sp) = pointer to boundary pair #
- # #
- # OUTPUT ************************************************************** #
- # cc = condition codes are set correctly #
- # #
- # ALGORITHM *********************************************************** #
- # 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 condition codes are set correctly before the final "rts". #
- # #
- #########################################################################
- set CMP2_CC, -4
- global _060LSP__cmp2_Ab_
- _060LSP__cmp2_Ab_:
- # PROLOGUE BEGIN ########################################################
- link.w %a6,&-4
- movm.l &0x3800,-(%sp) # save d2-d4
- # fmovm.l &0x0,-(%sp) # save no fpregs
- # PROLOGUE END ##########################################################
- mov.w %cc,CMP2_CC(%a6)
- mov.l 0x8(%a6), %d2 # get regval
- mov.b ([0xc,%a6],0x0),%d0
- mov.b ([0xc,%a6],0x1),%d1
- extb.l %d0 # sign extend lo bnd
- extb.l %d1 # sign extend hi bnd
- bra.w l_cmp2_cmp # go do the compare emulation
- global _060LSP__cmp2_Aw_
- _060LSP__cmp2_Aw_:
- # PROLOGUE BEGIN ########################################################
- link.w %a6,&-4
- movm.l &0x3800,-(%sp) # save d2-d4
- # fmovm.l &0x0,-(%sp) # save no fpregs
- # PROLOGUE END ##########################################################
- mov.w %cc,CMP2_CC(%a6)
- mov.l 0x8(%a6), %d2 # get regval
- mov.w ([0xc,%a6],0x0),%d0
- mov.w ([0xc,%a6],0x2),%d1
- ext.l %d0 # sign extend lo bnd
- ext.l %d1 # sign extend hi bnd
- bra.w l_cmp2_cmp # go do the compare emulation
- global _060LSP__cmp2_Al_
- _060LSP__cmp2_Al_:
- # PROLOGUE BEGIN ########################################################
- link.w %a6,&-4
- movm.l &0x3800,-(%sp) # save d2-d4
- # fmovm.l &0x0,-(%sp) # save no fpregs
- # PROLOGUE END ##########################################################
- mov.w %cc,CMP2_CC(%a6)
- mov.l 0x8(%a6), %d2 # get regval
- mov.l ([0xc,%a6],0x0),%d0
- mov.l ([0xc,%a6],0x4),%d1
- bra.w l_cmp2_cmp # go do the compare emulation
- global _060LSP__cmp2_Db_
- _060LSP__cmp2_Db_:
- # PROLOGUE BEGIN ########################################################
- link.w %a6,&-4
- movm.l &0x3800,-(%sp) # save d2-d4
- # fmovm.l &0x0,-(%sp) # save no fpregs
- # PROLOGUE END ##########################################################
- mov.w %cc,CMP2_CC(%a6)
- mov.l 0x8(%a6), %d2 # get regval
- mov.b ([0xc,%a6],0x0),%d0
- mov.b ([0xc,%a6],0x1),%d1
- extb.l %d0 # sign extend lo bnd
- extb.l %d1 # sign extend hi bnd
- # 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
- bra.w l_cmp2_cmp # go do the compare emulation
- global _060LSP__cmp2_Dw_
- _060LSP__cmp2_Dw_:
- # PROLOGUE BEGIN ########################################################
- link.w %a6,&-4
- movm.l &0x3800,-(%sp) # save d2-d4
- # fmovm.l &0x0,-(%sp) # save no fpregs
- # PROLOGUE END ##########################################################
- mov.w %cc,CMP2_CC(%a6)
- mov.l 0x8(%a6), %d2 # get regval
- mov.w ([0xc,%a6],0x0),%d0
- mov.w ([0xc,%a6],0x2),%d1
- ext.l %d0 # sign extend lo bnd
- ext.l %d1 # sign extend hi bnd
- # 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 l_cmp2_cmp # go emulate compare
- global _060LSP__cmp2_Dl_
- _060LSP__cmp2_Dl_:
- # PROLOGUE BEGIN ########################################################
- link.w %a6,&-4
- movm.l &0x3800,-(%sp) # save d2-d4
- # fmovm.l &0x0,-(%sp) # save no fpregs
- # PROLOGUE END ##########################################################
- mov.w %cc,CMP2_CC(%a6)
- mov.l 0x8(%a6), %d2 # get regval
- mov.l ([0xc,%a6],0x0),%d0
- mov.l ([0xc,%a6],0x4),%d1
- #
- # 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
- #
- l_cmp2_cmp:
- 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 CMP2_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,%cc # save new ccodes
- # EPILOGUE BEGIN ########################################################
- # fmovm.l (%sp)+,&0x0 # restore no fpregs
- movm.l (%sp)+,&0x001c # restore d2-d4
- unlk %a6
- # EPILOGUE END ##########################################################
- rts
|