diff options
Diffstat (limited to 'arch/m68k/ifpsp060/src/isp.S')
-rw-r--r-- | arch/m68k/ifpsp060/src/isp.S | 4299 |
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 |