aboutsummaryrefslogtreecommitdiff
path: root/arch/m68k/ifpsp060/src/isp.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/m68k/ifpsp060/src/isp.S')
-rw-r--r--arch/m68k/ifpsp060/src/isp.S4299
1 files changed, 4299 insertions, 0 deletions
diff --git a/arch/m68k/ifpsp060/src/isp.S b/arch/m68k/ifpsp060/src/isp.S
new file mode 100644
index 00000000000..b269091d9df
--- /dev/null
+++ b/arch/m68k/ifpsp060/src/isp.S
@@ -0,0 +1,4299 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+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 increm