Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/arch/m68k/ifpsp060/src/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 123 kB image not shown  

Quelle  isp.S   Sprache: Sparc

 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# 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

 bra.l  _isp_cas
 short  0x0000

 bra.l  _isp_cas2
 short  0x0000

 bra.l  _isp_cas_finish
 short  0x0000

 bra.l  _isp_cas2_finish
 short  0x0000

 bra.l  _isp_cas_inrange
 short  0x0000

 bra.l  _isp_cas_terminate
 short  0x0000

 bra.l  _isp_cas_restart
 short  0x0000

 space  64

#############################################################

 global  _real_chk
_real_chk:
 mov.l  %d0,-(%sp)
 mov.l  (_060ISP_TABLE-0x80+_off_chk,%pc),%d0
 pea.l  (_060ISP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _real_divbyzero
_real_divbyzero:
 mov.l  %d0,-(%sp)
 mov.l  (_060ISP_TABLE-0x80+_off_divbyzero,%pc),%d0
 pea.l  (_060ISP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _real_trace
_real_trace:
 mov.l  %d0,-(%sp)
 mov.l  (_060ISP_TABLE-0x80+_off_trace,%pc),%d0
 pea.l  (_060ISP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _real_access
_real_access:
 mov.l  %d0,-(%sp)
 mov.l  (_060ISP_TABLE-0x80+_off_access,%pc),%d0
 pea.l  (_060ISP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _isp_done
_isp_done:
 mov.l  %d0,-(%sp)
 mov.l  (_060ISP_TABLE-0x80+_off_done,%pc),%d0
 pea.l  (_060ISP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

#######################################

 global  _real_cas
_real_cas:
 mov.l  %d0,-(%sp)
 mov.l  (_060ISP_TABLE-0x80+_off_cas,%pc),%d0
 pea.l  (_060ISP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _real_cas2
_real_cas2:
 mov.l  %d0,-(%sp)
 mov.l  (_060ISP_TABLE-0x80+_off_cas2,%pc),%d0
 pea.l  (_060ISP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _real_lock_page
_real_lock_page:
 mov.l  %d0,-(%sp)
 mov.l  (_060ISP_TABLE-0x80+_off_lock,%pc),%d0
 pea.l  (_060ISP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _real_unlock_page
_real_unlock_page:
 mov.l  %d0,-(%sp)
 mov.l  (_060ISP_TABLE-0x80+_off_unlock,%pc),%d0
 pea.l  (_060ISP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

#######################################

 global  _imem_read
_imem_read:
 mov.l  %d0,-(%sp)
 mov.l  (_060ISP_TABLE-0x80+_off_imr,%pc),%d0
 pea.l  (_060ISP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _dmem_read
_dmem_read:
 mov.l  %d0,-(%sp)
 mov.l  (_060ISP_TABLE-0x80+_off_dmr,%pc),%d0
 pea.l  (_060ISP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _dmem_write
_dmem_write:
 mov.l  %d0,-(%sp)
 mov.l  (_060ISP_TABLE-0x80+_off_dmw,%pc),%d0
 pea.l  (_060ISP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _imem_read_word
_imem_read_word:
 mov.l  %d0,-(%sp)
 mov.l  (_060ISP_TABLE-0x80+_off_irw,%pc),%d0
 pea.l  (_060ISP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _imem_read_long
_imem_read_long:
 mov.l  %d0,-(%sp)
 mov.l  (_060ISP_TABLE-0x80+_off_irl,%pc),%d0
 pea.l  (_060ISP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _dmem_read_byte
_dmem_read_byte:
 mov.l  %d0,-(%sp)
 mov.l  (_060ISP_TABLE-0x80+_off_drb,%pc),%d0
 pea.l  (_060ISP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _dmem_read_word
_dmem_read_word:
 mov.l  %d0,-(%sp)
 mov.l  (_060ISP_TABLE-0x80+_off_drw,%pc),%d0
 pea.l  (_060ISP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _dmem_read_long
_dmem_read_long:
 mov.l  %d0,-(%sp)
 mov.l  (_060ISP_TABLE-0x80+_off_drl,%pc),%d0
 pea.l  (_060ISP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _dmem_write_byte
_dmem_write_byte:
 mov.l  %d0,-(%sp)
 mov.l  (_060ISP_TABLE-0x80+_off_dwb,%pc),%d0
 pea.l  (_060ISP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _dmem_write_word
_dmem_write_word:
 mov.l  %d0,-(%sp)
 mov.l  (_060ISP_TABLE-0x80+_off_dww,%pc),%d0
 pea.l  (_060ISP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

 global  _dmem_write_long
_dmem_write_long:
 mov.l  %d0,-(%sp)
 mov.l  (_060ISP_TABLE-0x80+_off_dwl,%pc),%d0
 pea.l  (_060ISP_TABLE-0x80,%pc,%d0)
 mov.l  0x4(%sp),%d0
 rtd  &0x4

#
# 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

#########
# Misc. #
#########
set BYTE,  1   # len(byte) == 1 byte
set WORD,  2   # len(word) == 2 bytes
set LONG,  4   # len(longword) == 4 bytes

#########################################################################
# 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


#########################################################################
# muls.l 0100 1100 00 |<ea>| 0*** 1100 0000 0***  #
# mulu.l 0100 1100 00 |<ea>| 0*** 0100 0000 0***  #
#         #
# divs.l 0100 1100 01 |<ea>| 0*** 1100 0000 0***  #
# divu.l 0100 1100 01 |<ea>| 0*** 0100 0000 0***  #
#         #
# movep.w m2r 0000 ***1 00 001*** | <displacement>  |  #
# movep.l m2r 0000 ***1 01 001*** | <displacement>  |  #
# movep.w r2m 0000 ***1 10 001*** | <displacement>  |  #
# movep.l r2m 0000 ***1 11 001*** | <displacement>  |  #
#         #
cas.w  0000 1100 11 |<ea>| 0000 000* **00 0***  #
cas.l  0000 1110 11 |<ea>| 0000 000* **00 0***  #
#         #
# cas2.w 0000 1100 11 111100 **** 000* **00 0***  #
#     **** 000* **00 0***  #
# cas2.l 0000 1110 11 111100 **** 000* **00 0***  #
#     **** 000* **00 0***  #
#         #
# chk2.b 0000 0000 11 |<ea>| **** 1000 0000 0000  #
# chk2.w 0000 0010 11 |<ea>| **** 1000 0000 0000  #
# chk2.l 0000 0100 11 |<ea>| **** 1000 0000 0000  #
#         #
# cmp2.b 0000 0000 11 |<ea>| **** 0000 0000 0000  #
# cmp2.w 0000 0010 11 |<ea>| **** 0000 0000 0000  #
# cmp2.l 0000 0100 11 |<ea>| **** 0000 0000 0000  #
#########################################################################

#
# 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 lo word
 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.

 bra.w  uieh_done

uieh_cas2:

 mov.l  EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
 addq.l  &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
 bsr.l  _imem_read_word  # read extension word

 tst.l  %d1   # ifetch error?
 bne.w  isp_iacc  # yes

 bsr.l  _compandset2  # _cas2()
 bra.w  uieh_done

uieh_chk2cmp2:
# chk2 may take a chk exception

 bsr.l  _chk2_cmp2  # _chk2_cmp2()

# here we check to see if a chk trap should be taken
 cmpi.b  SPCOND_FLG(%a6),&ichk_flg
 bne.w  uieh_done
 bra.b  uieh_chk_trap

###########################################################################

#
# 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

uieh_finish:
 movm.l  EXC_DREGS(%a6),&0x3fff # restore d0-d7/a0-a5

 btst  &0x7,EXC_ISR(%a6) # is trace mode on?
 bne.b  uieh_trace  # yes;go handle trace mode

 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

mov.l EXC_A6(%a6),%a6 # restore a6
add.l &LOCAL_SIZE,%sp # clear stack frame

bra.l _real_chk

#
#    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

mov.l EXC_A6(%a6),%a6 # restore a6
add.l &LOCAL_SIZE,%sp # clear stack frame

bra.l _real_divbyzero

#
#  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

mov.l EXC_A6(%a6),%a6 # restore a6
add.l &4+LOCAL_SIZE,%sp # clear stack frame

bra.l _real_divbyzero

#
#    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

mov.l EXC_A6(%a6),%a6 # restore a6
add.l &4+LOCAL_SIZE,%sp # clear stack frame

bra.l _real_trace

#
#    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

mov.l EXC_A6(%a6),%a6 # restore a6
add.l &8+LOCAL_SIZE,%sp # clear stack frame
bra.l _isp_done

##########

# 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

lea -64(%a6),%sp
movm.l (%sp)+,&0x7fff # restore d0-d7/a0-a6

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

########################################################
# Address register indirect w/ displacement: (d16, An) #
########################################################
addr_ind_disp_a0:
mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
bsr.l _imem_read_word

tst.l %d1 # ifetch error?
bne.l isp_iacc # yes

mov.w %d0,%a0 # sign extend displacement
add.l EXC_A0(%a6),%a0 # a0 + d16
rts

addr_ind_disp_a1:
mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
bsr.l _imem_read_word

tst.l %d1 # ifetch error?
bne.l isp_iacc # yes

mov.w %d0,%a0 # sign extend displacement
add.l EXC_A1(%a6),%a0 # a1 + d16
rts

addr_ind_disp_a2:
mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
bsr.l _imem_read_word

tst.l %d1 # ifetch error?
bne.l isp_iacc # yes

mov.w %d0,%a0 # sign extend displacement
add.l EXC_A2(%a6),%a0 # a2 + d16
rts

addr_ind_disp_a3:
mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
bsr.l _imem_read_word

tst.l %d1 # ifetch error?
bne.l isp_iacc # yes

mov.w %d0,%a0 # sign extend displacement
add.l EXC_A3(%a6),%a0 # a3 + d16
rts

addr_ind_disp_a4:
mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
bsr.l _imem_read_word

tst.l %d1 # ifetch error?
bne.l isp_iacc # yes

mov.w %d0,%a0 # sign extend displacement
add.l EXC_A4(%a6),%a0 # a4 + d16
rts

addr_ind_disp_a5:
mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
bsr.l _imem_read_word

tst.l %d1 # ifetch error?
bne.l isp_iacc # yes

mov.w %d0,%a0 # sign extend displacement
add.l EXC_A5(%a6),%a0 # a5 + d16
rts

addr_ind_disp_a6:
mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
bsr.l _imem_read_word

tst.l %d1 # ifetch error?
bne.l isp_iacc # yes

mov.w %d0,%a0 # sign extend displacement
add.l EXC_A6(%a6),%a0 # a6 + d16
rts

addr_ind_disp_a7:
mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
bsr.l _imem_read_word

tst.l %d1 # ifetch error?
bne.l isp_iacc # yes

mov.w %d0,%a0 # sign extend displacement
add.l EXC_A7(%a6),%a0 # a7 + d16
rts

########################################################################
# Address register indirect w/ index(8-bit displacement): (dn, An, Xn) #
#    "       "         "    w/   "  (base displacement): (bd, An, Xn)  #
# Memory indirect postindexed: ([bd, An], Xn, od)        #
# Memory indirect preindexed: ([bd, An, Xn], od)        #
########################################################################
_addr_ind_ext:
mov.l %d1,-(%sp)

mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
bsr.l _imem_read_word # fetch extword in d0

tst.l %d1 # ifetch error?
bne.l isp_iacc # yes

mov.l (%sp)+,%d1

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

###########################
# Absolute short: (XXX).W #
###########################
abs_short:
mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
bsr.l _imem_read_word # fetch short address

tst.l %d1 # ifetch error?
bne.l isp_iacc # yes

mov.w %d0,%a0 # return <ea> in a0
rts

##########################
# Absolute long: (XXX).L #
##########################
abs_long:
mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
bsr.l _imem_read_long # fetch long address

tst.l %d1 # ifetch error?
bne.l isp_iacc # yes

mov.l %d0,%a0 # return <ea> in a0
rts

#######################################################
# Program counter indirect w/ displacement: (d16, PC) #
#######################################################
pc_ind:
mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
bsr.l _imem_read_word # fetch word displacement

tst.l %d1 # ifetch error?
bne.l isp_iacc # yes

mov.w %d0,%a0 # sign extend displacement

add.l EXC_EXTWPTR(%a6),%a0 # pc + d16

# _imem_read_word() increased the extwptr by 2. need to adjust here.
subq.l &0x2,%a0 # adjust <ea>

rts

##########################################################
# PC indirect w/ index(8-bit displacement): (d8, PC, An) #
# "     "     w/   "  (base displacement): (bd, PC, An)  #
# PC memory indirect postindexed: ([bd, PC], Xn, od)     #
# PC memory indirect preindexed: ([bd, PC, Xn], od)      #
##########################################################
pc_ind_ext:
mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
bsr.l _imem_read_word # fetch ext word

tst.l %d1 # ifetch error?
bne.l isp_iacc # yes

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

mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
bsr.l _imem_read_long

tst.l %d1 # ifetch error?
bne.l isp_iacc # yes

bra.b chk_ind
get_word_bd:
mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
bsr.l _imem_read_word

tst.l %d1 # ifetch error?
bne.l isp_iacc # yes

ext.l %d0 # sign extend bd

chk_ind:
add.l %d0,%d3 # base += bd
no_bd:
bfextu %d5{&30:&2},%d0 # is od suppressed?
beq.w aii_bd
cmpi.b %d0,&0x2
blt.b null_od
beq.b word_od

mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
bsr.l _imem_read_long

tst.l %d1 # ifetch error?
bne.l isp_iacc # yes

bra.b add_them

word_od:
mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
bsr.l _imem_read_word

tst.l %d1 # ifetch error?
bne.l isp_iacc # yes

ext.l %d0 # sign extend od
bra.b add_them

null_od:
clr.l %d0
add_them:
mov.l %d0,%d4
btst &0x2,%d5 # pre or post indexing?
beq.b pre_indexed

mov.l %d3,%a0
bsr.l _dmem_read_long

tst.l %d1 # dfetch error?
bne.b calc_ea_err # yes

add.l %d2,%d0 # <ea> += index
add.l %d4,%d0 # <ea> += od
bra.b done_ea

pre_indexed:
add.l %d2,%d3 # preindexing
mov.l %d3,%a0
bsr.l _dmem_read_long

tst.l %d1 # ifetch error?
bne.b calc_ea_err # yes

add.l %d4,%d0 # ea += od
bra.b done_ea

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)

btst &0x7,%d1 # (reg 2 mem) or (mem 2 reg)
beq.w mem2reg

# reg2mem: fetch dx, then write it to memory
reg2mem:
mov.w %d1,%d0
rol.w &0x7,%d0
and.w &0x7,%d0 # extract Dx from opcode word

mov.l (EXC_DREGS,%a6,%d0.w*4), %d0 # fetch dx

btst &0x6,%d1 # word or long operation?
beq.b r2mwtrans

# a0 = dst addr
# d0 = Dx
r2mltrans:
mov.l %d0,%d2 # store data
mov.l %a0,%a2 # store addr
rol.l &0x8,%d2
mov.l %d2,%d0

bsr.l _dmem_write_byte # os  : write hi

tst.l %d1 # dfetch error?
bne.w movp_write_err # yes

add.w &0x2,%a2 # incr addr
mov.l %a2,%a0
rol.l &0x8,%d2
mov.l %d2,%d0

bsr.l _dmem_write_byte # os  : write lo

tst.l %d1 # dfetch error?
bne.w movp_write_err # yes

add.w &0x2,%a2 # incr addr
mov.l %a2,%a0
rol.l &0x8,%d2
mov.l %d2,%d0

bsr.l _dmem_write_byte # os  : write lo

tst.l %d1 # dfetch error?
bne.w movp_write_err # yes

add.w &0x2,%a2 # incr addr
mov.l %a2,%a0
rol.l &0x8,%d2
mov.l %d2,%d0

bsr.l _dmem_write_byte # os  : write lo

tst.l %d1 # dfetch error?
bne.w movp_write_err # yes

rts

# a0 = dst addr
# d0 = Dx
r2mwtrans:
mov.l %d0,%d2 # store data
mov.l %a0,%a2 # store addr
lsr.w &0x8,%d0

bsr.l _dmem_write_byte # os  : write hi

tst.l %d1 # dfetch error?
bne.w movp_write_err # yes

add.w &0x2,%a2
mov.l %a2,%a0
mov.l %d2,%d0

bsr.l _dmem_write_byte # os  : write lo

tst.l %d1 # dfetch error?
bne.w movp_write_err # yes

rts

# 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

# a0 = dst addr
m2rltrans:
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

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

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 addr
m2rwtrans:
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 = true
movp_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 = true
movp_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 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

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
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

# FSLW:
# read = true
# size = word
# TM = data
# software emulation error = true
chk2_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+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

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 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

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 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
C=100 H=100 G=100

¤ Dauer der Verarbeitung: 0.34 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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.