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.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ireal.s:
# This file is appended to the top of the 060ISP package
# and contains the entry points into the package. The user, in
# effect, branches to one of the branch table entries located
# after _060ISP_TABLE.
# Also, subroutine stubs exist in this file (_isp_done for
# example) that are referenced by the ISP package itself in order
# to call a given routine. The stub routine actually performs the
# callout. The ISP code does a "bsr" to the stub routine. This
# extra layer of hierarchy adds a slight performance penalty but
# it makes the ISP code easier to read and more mainatinable.
#
set _off_chk, 0x00 set _off_divbyzero, 0x04 set _off_trace, 0x08 set _off_access, 0x0c set _off_done, 0x10
set _off_cas, 0x14 set _off_cas2, 0x18 set _off_lock, 0x1c set _off_unlock, 0x20
set _off_imr, 0x40 set _off_dmr, 0x44 set _off_dmw, 0x48 set _off_irw, 0x4c set _off_irl, 0x50 set _off_drb, 0x54 set _off_drw, 0x58 set _off_drl, 0x5c set _off_dwb, 0x60 set _off_dww, 0x64 set _off_dwl, 0x68
_060ISP_TABLE:
# Here's the table of ENTRY POINTS for those linking the package.
bra.l _isp_unimp
short 0x0000
#
# This file contains a set of define statements for constants
# in oreder to promote readability within the core code itself.
#
set LOCAL_SIZE, 96 # stack frame size(bytes) set LV, -LOCAL_SIZE # stack offset
set EXC_ISR, 0x4 # stack status register set EXC_IPC, 0x6 # stack pc set EXC_IVOFF, 0xa # stacked vector offset
set EXC_AREGS, LV+64 # offset of all address regs set EXC_DREGS, LV+32 # offset of all data regs
set EXC_A7, EXC_AREGS+(7*4) # offset of a7 set EXC_A6, EXC_AREGS+(6*4) # offset of a6 set EXC_A5, EXC_AREGS+(5*4) # offset of a5 set EXC_A4, EXC_AREGS+(4*4) # offset of a4 set EXC_A3, EXC_AREGS+(3*4) # offset of a3 set EXC_A2, EXC_AREGS+(2*4) # offset of a2 set EXC_A1, EXC_AREGS+(1*4) # offset of a1 set EXC_A0, EXC_AREGS+(0*4) # offset of a0 set EXC_D7, EXC_DREGS+(7*4) # offset of d7 set EXC_D6, EXC_DREGS+(6*4) # offset of d6 set EXC_D5, EXC_DREGS+(5*4) # offset of d5 set EXC_D4, EXC_DREGS+(4*4) # offset of d4 set EXC_D3, EXC_DREGS+(3*4) # offset of d3 set EXC_D2, EXC_DREGS+(2*4) # offset of d2 set EXC_D1, EXC_DREGS+(1*4) # offset of d1 set EXC_D0, EXC_DREGS+(0*4) # offset of d0
set EXC_TEMP, LV+16 # offset of temp stack space
set EXC_SAVVAL, LV+12 # offset of old areg value set EXC_SAVREG, LV+11 # offset of old areg index
set SPCOND_FLG, LV+10 # offset of spc condition flg
set EXC_CC, LV+8 # offset of cc register set EXC_EXTWPTR, LV+4 # offset of current PC set EXC_EXTWORD, LV+2 # offset of current ext opword set EXC_OPWORD, LV+0 # offset of current opword
###########################
# SPecial CONDition FLaGs #
########################### set mia7_flg, 0x04 # (a7)+ flag set mda7_flg, 0x08 # -(a7) flag set ichk_flg, 0x10 # chk exception flag set idbyz_flg, 0x20 # divbyzero flag set restore_flg, 0x40 # restore -(an)+ flag set immed_flg, 0x80 # immediate data flag
set mia7_bit, 0x2 # (a7)+ bit set mda7_bit, 0x3 # -(a7) bit set ichk_bit, 0x4 # chk exception bit set idbyz_bit, 0x5 # divbyzero bit set restore_bit, 0x6 # restore -(a7)+ bit set immed_bit, 0x7 # immediate data bit
#########################################################################
# XDEF **************************************************************** #
# _isp_unimp(): 060ISP entry point for Unimplemented Instruction #
# #
# This handler should be the first code executed upon taking the #
# "Unimplemented Integer Instruction" exception in an operating #
# system. #
# #
# XREF **************************************************************** #
# _imem_read_{word,long}() - read instruction word/longword #
# _mul64() - emulate 64-bit multiply #
# _div64() - emulate 64-bit divide #
# _moveperipheral() - emulate "movep" #
# _compandset() - emulate misaligned "cas" #
# _compandset2() - emulate "cas2" #
# _chk2_cmp2() - emulate "cmp2" and "chk2" #
# _isp_done() - "callout" for normal final exit #
# _real_trace() - "callout" for Trace exception #
# _real_chk() - "callout" for Chk exception #
# _real_divbyzero() - "callout" for DZ exception #
# _real_access() - "callout" for access error exception #
# #
# INPUT *************************************************************** #
# - The system stack contains the Unimp Int Instr stack frame #
# #
# OUTPUT ************************************************************** #
# If Trace exception: #
# - The system stack changed to contain Trace exc stack frame #
# If Chk exception: #
# - The system stack changed to contain Chk exc stack frame #
# If DZ exception: #
# - The system stack changed to contain DZ exc stack frame #
# If access error exception: #
# - The system stack changed to contain access err exc stk frame #
# Else: #
# - Results saved as appropriate #
# #
# ALGORITHM *********************************************************** #
# This handler fetches the first instruction longword from #
# memory and decodes it to determine which of the unimplemented #
# integer instructions caused this exception. This handler then calls #
# one of _mul64(), _div64(), _moveperipheral(), _compandset(), #
# _compandset2(), or _chk2_cmp2() as appropriate. #
# Some of these instructions, by their nature, may produce other #
# types of exceptions. "div" can produce a divide-by-zero exception, #
# and "chk2" can cause a "Chk" exception. In both cases, the current #
# exception stack frame must be converted to an exception stack frame #
# of the correct exception type and an exit must be made through #
# _real_divbyzero() or _real_chk() as appropriate. In addition, all #
# instructions may be executing while Trace is enabled. If so, then #
# a Trace exception stack frame must be created and an exit made #
# through _real_trace(). #
# Meanwhile, if any read or write to memory using the #
# _mem_{read,write}() "callout"s returns a failing value, then an #
# access error frame must be created and an exit made through #
# _real_access(). #
# If none of these occur, then a normal exit is made through #
# _isp_done(). #
# #
# This handler, upon entry, saves almost all user-visible #
# address and data registers to the stack. Although this may seem to #
# cause excess memory traffic, it was found that due to having to #
# access these register files for things like data retrieval and <ea> #
# calculations, it was more efficient to have them on the stack where #
# they could be accessed by indexing rather than to make subroutine #
# calls to retrieve a register of a particular index. #
# #
#########################################################################
global _isp_unimp
_isp_unimp:
link.w %a6,&-LOCAL_SIZE # create room for stack frame
movm.l &0x3fff,EXC_DREGS(%a6) # store d0-d7/a0-a5
mov.l (%a6),EXC_A6(%a6) # store a6
btst &0x5,EXC_ISR(%a6) # from s or u mode?
bne.b uieh_s # supervisor mode
uieh_u:
mov.l %usp,%a0 # fetch user stack pointer
mov.l %a0,EXC_A7(%a6) # store a7
bra.b uieh_cont
uieh_s:
lea 0xc(%a6),%a0
mov.l %a0,EXC_A7(%a6) # store corrected sp
uieh_cont: clr.b SPCOND_FLG(%a6) # clear "special case" flag
mov.w EXC_ISR(%a6),EXC_CC(%a6) # store cc copy on stack
mov.l EXC_IPC(%a6),EXC_EXTWPTR(%a6) # store extwptr on stack
#
# fetch the opword and first extension word pointed to by the stacked pc
# and store them to the stack for now
#
mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
bsr.l _imem_read_long # fetch opword & extword
mov.l %d0,EXC_OPWORD(%a6) # store extword on stack
#
# using bit 14 of the operation word, separate into 2 groups:
# (group1) mul64, div64
# (group2) movep, chk2, cmp2, cas2, cas
#
btst &0x1e,%d0 # group1 or group2
beq.b uieh_group2 # go handle group2
#
# now, w/ group1, make mul64's decode the fastest since it will
# most likely be used the most.
#
uieh_group1:
btst &0x16,%d0 # test for div64
bne.b uieh_div64 # go handle div64
uieh_mul64:
# mul64() may use ()+ addressing and may, therefore, alter a7
bsr.l _mul64 # _mul64()
btst &0x5,EXC_ISR(%a6) # supervisor mode?
beq.w uieh_done
btst &mia7_bit,SPCOND_FLG(%a6) # was a7 changed?
beq.w uieh_done # no
btst &0x7,EXC_ISR(%a6) # is trace enabled?
bne.w uieh_trace_a7 # yes
bra.w uieh_a7 # no
uieh_div64:
# div64() may use ()+ addressing and may, therefore, alter a7.
# div64() may take a divide by zero exception.
bsr.l _div64 # _div64()
# here, we sort out all of the special cases that may have happened.
btst &mia7_bit,SPCOND_FLG(%a6) # was a7 changed?
bne.b uieh_div64_a7 # yes
uieh_div64_dbyz:
btst &idbyz_bit,SPCOND_FLG(%a6) # did divide-by-zero occur?
bne.w uieh_divbyzero # yes
bra.w uieh_done # no
uieh_div64_a7:
btst &0x5,EXC_ISR(%a6) # supervisor mode?
beq.b uieh_div64_dbyz # no
# here, a7 has been incremented by 4 bytes in supervisor mode. we still
# may have the following 3 cases:
# (i) (a7)+
# (ii) (a7)+; trace
# (iii) (a7)+; divide-by-zero
#
btst &idbyz_bit,SPCOND_FLG(%a6) # did divide-by-zero occur?
bne.w uieh_divbyzero_a7 # yes
tst.b EXC_ISR(%a6) # no; is trace enabled?
bmi.w uieh_trace_a7 # yes
bra.w uieh_a7 # no
#
# now, w/ group2, make movep's decode the fastest since it will
# most likely be used the most.
#
uieh_group2:
btst &0x18,%d0 # test for not movep
beq.b uieh_not_movep
bsr.l _moveperipheral # _movep()
bra.w uieh_done
uieh_not_movep:
btst &0x1b,%d0 # test for chk2,cmp2
beq.b uieh_chk2cmp2 # go handle chk2,cmp2
swap %d0 # put opword in loword
cmpi.b %d0,&0xfc # test for cas2
beq.b uieh_cas2 # go handle cas2
uieh_cas:
bsr.l _compandset # _cas()
# the cases of "cas Dc,Du,(a7)+" and "cas Dc,Du,-(a7)" used from supervisor
# mode are simply not considered valid and therefore are not handled.
#
# the required emulation has been completed. now, clean up the necessary stack
# info and prepare for rte
#
uieh_done:
mov.b EXC_CC+1(%a6),EXC_ISR+1(%a6) # insert new ccodes
# if exception occurred in user mode, then we have to restore a7 in case it
# changed. we don't have to update a7 for supervisor mose because that case
# doesn't flow through here
btst &0x5,EXC_ISR(%a6) # user or supervisor?
bne.b uieh_finish # supervisor
mov.l EXC_A7(%a6),%a0 # fetch user stack pointer
mov.l %a0,%usp # restore it
mov.l EXC_EXTWPTR(%a6),EXC_IPC(%a6) # new pc on stack frame
mov.l EXC_A6(%a6),(%a6) # prepare new a6 for unlink
unlk %a6 # unlink stack frame
bra.l _isp_done
#
# The instruction that was just emulated was also being traced. The trace
# trap for this instruction will be lost unless we jump to the trace handler.
# So, here we create a Trace Exception format number two exception stack
# frame from the Unimplemented Integer Intruction Exception stack frame
# format number zero and jump to the user supplied hook "_real_trace()".
#
# UIEH FRAME TRACE FRAME
# ***************** *****************
# * 0x0 * 0x0f4 * * Current *
# ***************** * PC *
# * Current * *****************
# * PC * * 0x2 * 0x024 *
# ***************** *****************
# * SR * * Next *
# ***************** * PC *
# ->* Old * *****************
# from link -->* A6 * * SR *
# ***************** *****************
# /* A7 * * New * <-- for final unlink # / * * * A6 * # link frame < ***************** ***************** # \ ~ ~ ~ ~ # \***************** ***************** # uieh_trace: mov.l EXC_A6(%a6),-0x4(%a6) mov.w EXC_ISR(%a6),0x0(%a6) mov.l EXC_IPC(%a6),0x8(%a6) mov.l EXC_EXTWPTR(%a6),0x2(%a6) mov.w &0x2024,0x6(%a6) sub.l &0x4,%a6 unlk %a6 bra.l _real_trace
# # UIEH FRAME CHK FRAME # ***************** ***************** # * 0x0 * 0x0f4 * * Current * # ***************** * PC * # * Current * ***************** # * PC * * 0x2 * 0x018 * # ***************** ***************** # * SR * * Next * # ***************** * PC * # (4 words) ***************** # * SR * # ***************** # (6 words) # # the chk2 instruction should take a chk trap. so, here we must create a # chk stack frame from an unimplemented integer instruction exception frame # and jump to the user supplied entry point "_real_chk()". # uieh_chk_trap: mov.b EXC_CC+1(%a6),EXC_ISR+1(%a6) # insert new ccodes movm.l EXC_DREGS(%a6),&0x3fff # restore d0-d7/a0-a5
mov.w EXC_ISR(%a6),(%a6) # put new SR on stack mov.l EXC_IPC(%a6),0x8(%a6) # put "Current PC" on stack mov.l EXC_EXTWPTR(%a6),0x2(%a6) # put "Next PC" on stack mov.w &0x2018,0x6(%a6) # put Vector Offset on stack
# # UIEH FRAME DIVBYZERO FRAME # ***************** ***************** # * 0x0 * 0x0f4 * * Current * # ***************** * PC * # * Current * ***************** # * PC * * 0x2 * 0x014 * # ***************** ***************** # * SR * * Next * # ***************** * PC * # (4 words) ***************** # * SR * # ***************** # (6 words) # # the divide instruction should take an integer divide by zero trap. so, here # we must create a divbyzero stack frame from an unimplemented integer # instruction exception frame and jump to the user supplied entry point # "_real_divbyzero()". # uieh_divbyzero: mov.b EXC_CC+1(%a6),EXC_ISR+1(%a6) # insert new ccodes movm.l EXC_DREGS(%a6),&0x3fff # restore d0-d7/a0-a5
mov.w EXC_ISR(%a6),(%a6) # put new SR on stack mov.l EXC_IPC(%a6),0x8(%a6) # put "Current PC" on stack mov.l EXC_EXTWPTR(%a6),0x2(%a6) # put "Next PC" on stack mov.w &0x2014,0x6(%a6) # put Vector Offset on stack
# # DIVBYZERO FRAME # ***************** # * Current * # UIEH FRAME * PC * # ***************** ***************** # * 0x0 * 0x0f4 * * 0x2 * 0x014 * # ***************** ***************** # * Current * * Next * # * PC * * PC * # ***************** ***************** # * SR * * SR * # ***************** ***************** # (4 words) (6 words) # # the divide instruction should take an integer divide by zero trap. so, here # we must create a divbyzero stack frame from an unimplemented integer # instruction exception frame and jump to the user supplied entry point # "_real_divbyzero()". # # However, we must also deal with the fact that (a7)+ was used from supervisor # mode, thereby shifting the stack frame up 4 bytes. # uieh_divbyzero_a7: mov.b EXC_CC+1(%a6),EXC_ISR+1(%a6) # insert new ccodes movm.l EXC_DREGS(%a6),&0x3fff # restore d0-d7/a0-a5
mov.l EXC_IPC(%a6),0xc(%a6) # put "Current PC" on stack mov.w &0x2014,0xa(%a6) # put Vector Offset on stack mov.l EXC_EXTWPTR(%a6),0x6(%a6) # put "Next PC" on stack
# # TRACE FRAME # ***************** # * Current * # UIEH FRAME * PC * # ***************** ***************** # * 0x0 * 0x0f4 * * 0x2 * 0x024 * # ***************** ***************** # * Current * * Next * # * PC * * PC * # ***************** ***************** # * SR * * SR * # ***************** ***************** # (4 words) (6 words) # # # The instruction that was just emulated was also being traced. The trace # trap for this instruction will be lost unless we jump to the trace handler. # So, here we create a Trace Exception format number two exception stack # frame from the Unimplemented Integer Intruction Exception stack frame # format number zero and jump to the user supplied hook "_real_trace()". # # However, we must also deal with the fact that (a7)+ was used from supervisor # mode, thereby shifting the stack frame up 4 bytes. # uieh_trace_a7: mov.b EXC_CC+1(%a6),EXC_ISR+1(%a6) # insert new ccodes movm.l EXC_DREGS(%a6),&0x3fff # restore d0-d7/a0-a5
mov.l EXC_IPC(%a6),0xc(%a6) # put "Current PC" on stack mov.w &0x2024,0xa(%a6) # put Vector Offset on stack mov.l EXC_EXTWPTR(%a6),0x6(%a6) # put "Next PC" on stack
# # UIEH FRAME # ***************** # * 0x0 * 0x0f4 * # UIEH FRAME ***************** # ***************** * Next * # * 0x0 * 0x0f4 * * PC * # ***************** ***************** # * Current * * SR * # * PC * ***************** # ***************** (4 words) # * SR * # ***************** # (4 words) uieh_a7: mov.b EXC_CC+1(%a6),EXC_ISR+1(%a6) # insert new ccodes movm.l EXC_DREGS(%a6),&0x3fff # restore d0-d7/a0-a5
mov.w &0x00f4,0xe(%a6) # put Vector Offset on stack mov.l EXC_EXTWPTR(%a6),0xa(%a6) # put "Next PC" on stack mov.w EXC_ISR(%a6),0x8(%a6) # put SR on stack
# this is the exit point if a data read or write fails. # a0 = failing address # d0 = fslw isp_dacc: mov.l %a0,(%a6) # save address mov.l %d0,-0x4(%a6) # save partial fslw
mov.l 0xc(%sp),-(%sp) # move voff,hi(pc) mov.l 0x4(%sp),0x10(%sp) # store fslw mov.l 0xc(%sp),0x4(%sp) # store sr,lo(pc) mov.l 0x8(%sp),0xc(%sp) # store address mov.l (%sp)+,0x4(%sp) # store voff,hi(pc) mov.w &0x4008,0x6(%sp) # store new voff
bra.b isp_acc_exit
# this is the exit point if an instruction word read fails. # FSLW: # misaligned = true # read = true # size = word # instruction = true # software emulation error = true isp_iacc: movm.l EXC_DREGS(%a6),&0x3fff # restore d0-d7/a0-a5 unlk %a6 # unlink frame sub.w &0x8,%sp # make room for acc frame mov.l 0x8(%sp),(%sp) # store sr,lo(pc) mov.w 0xc(%sp),0x4(%sp) # store hi(pc) mov.w &0x4008,0x6(%sp) # store new voff mov.l 0x2(%sp),0x8(%sp) # store address (=pc) mov.l &0x09428001,0xc(%sp) # store fslw
isp_acc_exit: btst &0x5,(%sp) # user or supervisor? beq.b isp_acc_exit2 # user bset &0x2,0xd(%sp) # set supervisor TM bit isp_acc_exit2: bra.l _real_access
# if the addressing mode was (an)+ or -(an), the address register must # be restored to its pre-exception value before entering _real_access. isp_restore: cmpi.b SPCOND_FLG(%a6),&restore_flg # do we need a restore? bne.b isp_restore_done # no clr.l %d0 mov.b EXC_SAVREG(%a6),%d0 # regno to restore mov.l EXC_SAVVAL(%a6),(EXC_AREGS,%a6,%d0.l*4) # restore value isp_restore_done: rts
######################################################################### # XDEF **************************************************************** # # _calc_ea(): routine to calculate effective address # # # # XREF **************************************************************** # # _imem_read_word() - read instruction word # # _imem_read_long() - read instruction longword # # _dmem_read_long() - read data longword (for memory indirect) # # isp_iacc() - handle instruction access error exception # # isp_dacc() - handle data access error exception # # # # INPUT *************************************************************** # # d0 = number of bytes related to effective address (w,l) # # # # OUTPUT ************************************************************** # # If exiting through isp_dacc... # # a0 = failing address # # d0 = FSLW # # elsif exiting though isp_iacc... # # none # # else # # a0 = effective address # # # # ALGORITHM *********************************************************** # # The effective address type is decoded from the opword residing # # on the stack. A jump table is used to vector to a routine for the # # appropriate mode. Since none of the emulated integer instructions # # uses byte-sized operands, only handle word and long operations. # # # # Dn,An - shouldn't enter here # # (An) - fetch An value from stack # # -(An) - fetch An value from stack; return decr value; # # place decr value on stack; store old value in case of # # future access error; if -(a7), set mda7_flg in # # SPCOND_FLG # # (An)+ - fetch An value from stack; return value; # # place incr value on stack; store old value in case of # # future access error; if (a7)+, set mia7_flg in # # SPCOND_FLG # # (d16,An) - fetch An value from stack; read d16 using # # _imem_read_word(); fetch may fail -> branch to # # isp_iacc() # # (xxx).w,(xxx).l - use _imem_read_{word,long}() to fetch # # address; fetch may fail # # #<data> - return address of immediate value; set immed_flg # # in SPCOND_FLG # # (d16,PC) - fetch stacked PC value; read d16 using # # _imem_read_word(); fetch may fail -> branch to # # isp_iacc() # # everything else - read needed displacements as appropriate w/ # # _imem_read_{word,long}(); read may fail; if memory # # indirect, read indirect address using # # _dmem_read_long() which may also fail # # # #########################################################################
global _calc_ea _calc_ea: mov.l %d0,%a0 # move # bytes to a0
# MODE and REG are taken from the EXC_OPWORD. mov.w EXC_OPWORD(%a6),%d0 # fetch opcode word mov.w %d0,%d1 # make a copy
andi.w &0x3f,%d0 # extract mode field andi.l &0x7,%d1 # extract reg field
# jump to the corresponding function for each {MODE,REG} pair. mov.w (tbl_ea_mode.b,%pc,%d0.w*2), %d0 # fetch jmp distance jmp (tbl_ea_mode.b,%pc,%d0.w*1) # jmp to correct ea mode
swbeg &64 tbl_ea_mode: short tbl_ea_mode - tbl_ea_mode short tbl_ea_mode - tbl_ea_mode short tbl_ea_mode - tbl_ea_mode short tbl_ea_mode - tbl_ea_mode short tbl_ea_mode - tbl_ea_mode short tbl_ea_mode - tbl_ea_mode short tbl_ea_mode - tbl_ea_mode short tbl_ea_mode - tbl_ea_mode
short tbl_ea_mode - tbl_ea_mode short tbl_ea_mode - tbl_ea_mode short tbl_ea_mode - tbl_ea_mode short tbl_ea_mode - tbl_ea_mode short tbl_ea_mode - tbl_ea_mode short tbl_ea_mode - tbl_ea_mode short tbl_ea_mode - tbl_ea_mode short tbl_ea_mode - tbl_ea_mode
short addr_ind_a0 - tbl_ea_mode short addr_ind_a1 - tbl_ea_mode short addr_ind_a2 - tbl_ea_mode short addr_ind_a3 - tbl_ea_mode short addr_ind_a4 - tbl_ea_mode short addr_ind_a5 - tbl_ea_mode short addr_ind_a6 - tbl_ea_mode short addr_ind_a7 - tbl_ea_mode
short addr_ind_p_a0 - tbl_ea_mode short addr_ind_p_a1 - tbl_ea_mode short addr_ind_p_a2 - tbl_ea_mode short addr_ind_p_a3 - tbl_ea_mode short addr_ind_p_a4 - tbl_ea_mode short addr_ind_p_a5 - tbl_ea_mode short addr_ind_p_a6 - tbl_ea_mode short addr_ind_p_a7 - tbl_ea_mode
short addr_ind_m_a0 - tbl_ea_mode short addr_ind_m_a1 - tbl_ea_mode short addr_ind_m_a2 - tbl_ea_mode short addr_ind_m_a3 - tbl_ea_mode short addr_ind_m_a4 - tbl_ea_mode short addr_ind_m_a5 - tbl_ea_mode short addr_ind_m_a6 - tbl_ea_mode short addr_ind_m_a7 - tbl_ea_mode
short addr_ind_disp_a0 - tbl_ea_mode short addr_ind_disp_a1 - tbl_ea_mode short addr_ind_disp_a2 - tbl_ea_mode short addr_ind_disp_a3 - tbl_ea_mode short addr_ind_disp_a4 - tbl_ea_mode short addr_ind_disp_a5 - tbl_ea_mode short addr_ind_disp_a6 - tbl_ea_mode short addr_ind_disp_a7 - tbl_ea_mode
short _addr_ind_ext - tbl_ea_mode short _addr_ind_ext - tbl_ea_mode short _addr_ind_ext - tbl_ea_mode short _addr_ind_ext - tbl_ea_mode short _addr_ind_ext - tbl_ea_mode short _addr_ind_ext - tbl_ea_mode short _addr_ind_ext - tbl_ea_mode short _addr_ind_ext - tbl_ea_mode
short abs_short - tbl_ea_mode short abs_long - tbl_ea_mode short pc_ind - tbl_ea_mode short pc_ind_ext - tbl_ea_mode short immediate - tbl_ea_mode short tbl_ea_mode - tbl_ea_mode short tbl_ea_mode - tbl_ea_mode short tbl_ea_mode - tbl_ea_mode
################################### # Address register indirect: (An) # ################################### addr_ind_a0: mov.l EXC_A0(%a6),%a0 # Get current a0 rts
addr_ind_a1: mov.l EXC_A1(%a6),%a0 # Get current a1 rts
addr_ind_a2: mov.l EXC_A2(%a6),%a0 # Get current a2 rts
addr_ind_a3: mov.l EXC_A3(%a6),%a0 # Get current a3 rts
addr_ind_a4: mov.l EXC_A4(%a6),%a0 # Get current a4 rts
addr_ind_a5: mov.l EXC_A5(%a6),%a0 # Get current a5 rts
addr_ind_a6: mov.l EXC_A6(%a6),%a0 # Get current a6 rts
addr_ind_a7: mov.l EXC_A7(%a6),%a0 # Get current a7 rts
##################################################### # Address register indirect w/ postincrement: (An)+ # ##################################################### addr_ind_p_a0: mov.l %a0,%d0 # copy no. bytes mov.l EXC_A0(%a6),%a0 # load current value add.l %a0,%d0 # increment mov.l %d0,EXC_A0(%a6) # save incremented value
mov.l %a0,EXC_SAVVAL(%a6) # save in case of access error mov.b &0x0,EXC_SAVREG(%a6) # save regno, too mov.b &restore_flg,SPCOND_FLG(%a6) # set flag rts
addr_ind_p_a1: mov.l %a0,%d0 # copy no. bytes mov.l EXC_A1(%a6),%a0 # load current value add.l %a0,%d0 # increment mov.l %d0,EXC_A1(%a6) # save incremented value
mov.l %a0,EXC_SAVVAL(%a6) # save in case of access error mov.b &0x1,EXC_SAVREG(%a6) # save regno, too mov.b &restore_flg,SPCOND_FLG(%a6) # set flag rts
addr_ind_p_a2: mov.l %a0,%d0 # copy no. bytes mov.l EXC_A2(%a6),%a0 # load current value add.l %a0,%d0 # increment mov.l %d0,EXC_A2(%a6) # save incremented value
mov.l %a0,EXC_SAVVAL(%a6) # save in case of access error mov.b &0x2,EXC_SAVREG(%a6) # save regno, too mov.b &restore_flg,SPCOND_FLG(%a6) # set flag rts
addr_ind_p_a3: mov.l %a0,%d0 # copy no. bytes mov.l EXC_A3(%a6),%a0 # load current value add.l %a0,%d0 # increment mov.l %d0,EXC_A3(%a6) # save incremented value
mov.l %a0,EXC_SAVVAL(%a6) # save in case of access error mov.b &0x3,EXC_SAVREG(%a6) # save regno, too mov.b &restore_flg,SPCOND_FLG(%a6) # set flag rts
addr_ind_p_a4: mov.l %a0,%d0 # copy no. bytes mov.l EXC_A4(%a6),%a0 # load current value add.l %a0,%d0 # increment mov.l %d0,EXC_A4(%a6) # save incremented value
mov.l %a0,EXC_SAVVAL(%a6) # save in case of access error mov.b &0x4,EXC_SAVREG(%a6) # save regno, too mov.b &restore_flg,SPCOND_FLG(%a6) # set flag rts
addr_ind_p_a5: mov.l %a0,%d0 # copy no. bytes mov.l EXC_A5(%a6),%a0 # load current value add.l %a0,%d0 # increment mov.l %d0,EXC_A5(%a6) # save incremented value
mov.l %a0,EXC_SAVVAL(%a6) # save in case of access error mov.b &0x5,EXC_SAVREG(%a6) # save regno, too mov.b &restore_flg,SPCOND_FLG(%a6) # set flag rts
addr_ind_p_a6: mov.l %a0,%d0 # copy no. bytes mov.l EXC_A6(%a6),%a0 # load current value add.l %a0,%d0 # increment mov.l %d0,EXC_A6(%a6) # save incremented value
mov.l %a0,EXC_SAVVAL(%a6) # save in case of access error mov.b &0x6,EXC_SAVREG(%a6) # save regno, too mov.b &restore_flg,SPCOND_FLG(%a6) # set flag rts
addr_ind_p_a7: mov.b &mia7_flg,SPCOND_FLG(%a6) # set "special case" flag
mov.l %a0,%d0 # copy no. bytes mov.l EXC_A7(%a6),%a0 # load current value add.l %a0,%d0 # increment mov.l %d0,EXC_A7(%a6) # save incremented value rts
#################################################### # Address register indirect w/ predecrement: -(An) # #################################################### addr_ind_m_a0: mov.l EXC_A0(%a6),%d0 # Get current a0 mov.l %d0,EXC_SAVVAL(%a6) # save in case of access error sub.l %a0,%d0 # Decrement mov.l %d0,EXC_A0(%a6) # Save decr value mov.l %d0,%a0
mov.b &0x0,EXC_SAVREG(%a6) # save regno, too mov.b &restore_flg,SPCOND_FLG(%a6) # set flag rts
addr_ind_m_a1: mov.l EXC_A1(%a6),%d0 # Get current a1 mov.l %d0,EXC_SAVVAL(%a6) # save in case of access error sub.l %a0,%d0 # Decrement mov.l %d0,EXC_A1(%a6) # Save decr value mov.l %d0,%a0
mov.b &0x1,EXC_SAVREG(%a6) # save regno, too mov.b &restore_flg,SPCOND_FLG(%a6) # set flag rts
addr_ind_m_a2: mov.l EXC_A2(%a6),%d0 # Get current a2 mov.l %d0,EXC_SAVVAL(%a6) # save in case of access error sub.l %a0,%d0 # Decrement mov.l %d0,EXC_A2(%a6) # Save decr value mov.l %d0,%a0
mov.b &0x2,EXC_SAVREG(%a6) # save regno, too mov.b &restore_flg,SPCOND_FLG(%a6) # set flag rts
addr_ind_m_a3: mov.l EXC_A3(%a6),%d0 # Get current a3 mov.l %d0,EXC_SAVVAL(%a6) # save in case of access error sub.l %a0,%d0 # Decrement mov.l %d0,EXC_A3(%a6) # Save decr value mov.l %d0,%a0
mov.b &0x3,EXC_SAVREG(%a6) # save regno, too mov.b &restore_flg,SPCOND_FLG(%a6) # set flag rts
addr_ind_m_a4: mov.l EXC_A4(%a6),%d0 # Get current a4 mov.l %d0,EXC_SAVVAL(%a6) # save in case of access error sub.l %a0,%d0 # Decrement mov.l %d0,EXC_A4(%a6) # Save decr value mov.l %d0,%a0
mov.b &0x4,EXC_SAVREG(%a6) # save regno, too mov.b &restore_flg,SPCOND_FLG(%a6) # set flag rts
addr_ind_m_a5: mov.l EXC_A5(%a6),%d0 # Get current a5 mov.l %d0,EXC_SAVVAL(%a6) # save in case of access error sub.l %a0,%d0 # Decrement mov.l %d0,EXC_A5(%a6) # Save decr value mov.l %d0,%a0
mov.b &0x5,EXC_SAVREG(%a6) # save regno, too mov.b &restore_flg,SPCOND_FLG(%a6) # set flag rts
addr_ind_m_a6: mov.l EXC_A6(%a6),%d0 # Get current a6 mov.l %d0,EXC_SAVVAL(%a6) # save in case of access error sub.l %a0,%d0 # Decrement mov.l %d0,EXC_A6(%a6) # Save decr value mov.l %d0,%a0
mov.b &0x6,EXC_SAVREG(%a6) # save regno, too mov.b &restore_flg,SPCOND_FLG(%a6) # set flag rts
addr_ind_m_a7: mov.b &mda7_flg,SPCOND_FLG(%a6) # set "special case" flag
mov.l EXC_A7(%a6),%d0 # Get current a7 sub.l %a0,%d0 # Decrement mov.l %d0,EXC_A7(%a6) # Save decr value mov.l %d0,%a0 rts
mov.l (EXC_AREGS,%a6,%d1.w*4),%a0 # put base in a0
btst &0x8,%d0 beq.b addr_ind_index_8bit # for ext word or not?
movm.l &0x3c00,-(%sp) # save d2-d5
mov.l %d0,%d5 # put extword in d5 mov.l %a0,%d3 # put base in d3
bra.l calc_mem_ind # calc memory indirect
addr_ind_index_8bit: mov.l %d2,-(%sp) # save old d2
mov.l %d0,%d1 rol.w &0x4,%d1 andi.w &0xf,%d1 # extract index regno
mov.l (EXC_DREGS,%a6,%d1.w*4),%d1 # fetch index reg value
btst &0xb,%d0 # is it word or long? bne.b aii8_long ext.l %d1 # sign extend word index aii8_long: mov.l %d0,%d2 rol.w &0x7,%d2 andi.l &0x3,%d2 # extract scale value
lsl.l %d2,%d1 # shift index by scale
extb.l %d0 # sign extend displacement add.l %d1,%d0 # index + disp add.l %d0,%a0 # An + (index + disp)
mov.l (%sp)+,%d2 # restore old d2 rts
###################### # Immediate: #<data> # ######################################################################### # word, long: <ea> of the data is the current extension word # # pointer value. new extension word pointer is simply the old # # plus the number of bytes in the data type(2 or 4). # ######################################################################### immediate: mov.b &immed_flg,SPCOND_FLG(%a6) # set immediate flag
mov.l EXC_EXTWPTR(%a6),%a0 # fetch extension word ptr rts
mov.l EXC_EXTWPTR(%a6),%a0 # put base in a0 subq.l &0x2,%a0 # adjust base
btst &0x8,%d0 # is disp only 8 bits? beq.b pc_ind_index_8bit # yes
# the indexed addressing mode uses a base displacement of size # word or long movm.l &0x3c00,-(%sp) # save d2-d5
mov.l %d0,%d5 # put extword in d5 mov.l %a0,%d3 # put base in d3
bra.l calc_mem_ind # calc memory indirect
pc_ind_index_8bit: mov.l %d2,-(%sp) # create a temp register
mov.l %d0,%d1 # make extword copy rol.w &0x4,%d1 # rotate reg num into place andi.w &0xf,%d1 # extract register number
mov.l (EXC_DREGS,%a6,%d1.w*4),%d1 # fetch index reg value
btst &0xb,%d0 # is index word or long? bne.b pii8_long # long ext.l %d1 # sign extend word index pii8_long: mov.l %d0,%d2 # make extword copy rol.w &0x7,%d2 # rotate scale value into place andi.l &0x3,%d2 # extract scale value
lsl.l %d2,%d1 # shift index by scale
extb.l %d0 # sign extend displacement add.l %d1,%d0 # index + disp add.l %d0,%a0 # An + (index + disp)
mov.l (%sp)+,%d2 # restore temp register
rts
# a5 = exc_extwptr (global to uaeh) # a4 = exc_opword (global to uaeh) # a3 = exc_dregs (global to uaeh)
# d2 = index (internal " " ) # d3 = base (internal " " ) # d4 = od (internal " " ) # d5 = extword (internal " " ) calc_mem_ind: btst &0x6,%d5 # is the index suppressed? beq.b calc_index clr.l %d2 # yes, so index = 0 bra.b base_supp_ck calc_index: bfextu %d5{&16:&4},%d2 mov.l (EXC_DREGS,%a6,%d2.w*4),%d2 btst &0xb,%d5 # is index word or long? bne.b no_ext ext.l %d2 no_ext: bfextu %d5{&21:&2},%d0 lsl.l %d0,%d2 base_supp_ck: btst &0x7,%d5 # is the bd suppressed? beq.b no_base_sup clr.l %d3 no_base_sup: bfextu %d5{&26:&2},%d0 # get bd size # beq.l _error # if (size == 0) it's reserved cmpi.b %d0,&2 blt.b no_bd beq.b get_word_bd
aii_bd: add.l %d2,%d3 # ea = (base + bd) + index mov.l %d3,%d0 done_ea: mov.l %d0,%a0
movm.l (%sp)+,&0x003c # restore d2-d5 rts
# if dmem_read_long() 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 = true calc_ea_err: mov.l %d3,%a0 # pass failing address mov.l &0x01010001,%d0 # pass fslw bra.l isp_dacc
######################################################################### # XDEF **************************************************************** # # _moveperipheral(): routine to emulate movep instruction # # # # XREF **************************************************************** # # _dmem_read_byte() - read byte from memory # # _dmem_write_byte() - write byte to memory # # isp_dacc() - handle data access error exception # # # # INPUT *************************************************************** # # none # # # # OUTPUT ************************************************************** # # If exiting through isp_dacc... # # a0 = failing address # # d0 = FSLW # # else # # none # # # # ALGORITHM *********************************************************** # # Decode the movep instruction words stored at EXC_OPWORD and # # either read or write the required bytes from/to memory. Use the # # _dmem_{read,write}_byte() routines. If one of the memory routines # # returns a failing value, we must pass the failing address and a FSLW # # to the _isp_dacc() routine. # # Since this instruction is used to access peripherals, make sure # # to only access the required bytes. # # # #########################################################################
########################### # movep.(w,l) Dx,(d,Ay) # # movep.(w,l) (d,Ay),Dx # ########################### global _moveperipheral _moveperipheral: mov.w EXC_OPWORD(%a6),%d1 # fetch the opcode word
mov.b %d1,%d0 and.w &0x7,%d0 # extract Ay from opcode word
mov.l (EXC_AREGS,%a6,%d0.w*4),%a0 # fetch ay
add.w EXC_EXTWORD(%a6),%a0 # add: an + sgn_ext(disp)
# mem2reg: read bytes from memory. # determines the dest register, and then writes the bytes into it. mem2reg: btst &0x6,%d1 # word or long operation? beq.b m2rwtrans
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 = true movp_write_err: mov.l %a2,%a0 # pass failing address mov.l &0x00a10001,%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 register, 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
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
# 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
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 rts chk2_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 = true chk2_cmp2_err_l: mov.l %a2,%a0 # pass failing address mov.l &0x01010001,%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+0x0 set NDIVIDEND, EXC_TEMP+0x1 set NDRSAVE, EXC_TEMP+0x2 set NDQSAVE, EXC_TEMP+0x4 set DDSECOND, EXC_TEMP+0x6 set DDQUOTIENT, EXC_TEMP+0x8 set DDNORMAL, EXC_TEMP+0xc
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 register
dgotsrcl: 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 negative dsgndividend: 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
d32bitdivide: tdivu.l %d7, %d5:%d6 # it's only a 32/32 bit div!
bra.b divfinish
dnormaldivide: # 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 ddone
dqpos: btst &0x1f, %d6 # will (+quot) fit in 32 bits? bne.b ddovf
ddone: # 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
rts
ddovf: bset &0x1, EXC_CC+1(%a6) # 'V' set on overflow bclr &0x0, EXC_CC+1(%a6) # 'C' cleared on overflow
rts
div64eq0:
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.25 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.