~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP2M68000 Hi-Performance Microprocessor Division3M68060 Software Package4Production Release P1.00 -- October 10, 199456M68060 Software Package Copyright © 1993, 1994 Motorola Inc. All rights reserved.78THE SOFTWARE is provided on an "AS IS" basis and without warranty.9To the maximum extent permitted by applicable law,10MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED,11INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE12and any warranty against infringement with regard to the SOFTWARE13(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials.1415To the maximum extent permitted by applicable law,16IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER17(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,18BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS)19ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.20Motorola assumes no responsibility for the maintenance and support of the SOFTWARE.2122You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE23so long as this entire notice is retained without alteration in any modified and/or24redistributed versions, and that such modified versions are clearly identified as such.25No licenses are granted by implication, estoppel or otherwise under any patents26or trademarks of Motorola, Inc.27~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~28# ireal.s:29# This file is appended to the top of the 060ISP package30# and contains the entry points into the package. The user, in31# effect, branches to one of the branch table entries located32# after _060ISP_TABLE.33# Also, subroutine stubs exist in this file (_isp_done for34# example) that are referenced by the ISP package itself in order35# to call a given routine. The stub routine actually performs the36# callout. The ISP code does a "bsr" to the stub routine. This37# extra layer of hierarchy adds a slight performance penalty but38# it makes the ISP code easier to read and more mainatinable.39#4041set _off_chk, 0x0042set _off_divbyzero, 0x0443set _off_trace, 0x0844set _off_access, 0x0c45set _off_done, 0x104647set _off_cas, 0x1448set _off_cas2, 0x1849set _off_lock, 0x1c50set _off_unlock, 0x205152set _off_imr, 0x4053set _off_dmr, 0x4454set _off_dmw, 0x4855set _off_irw, 0x4c56set _off_irl, 0x5057set _off_drb, 0x5458set _off_drw, 0x5859set _off_drl, 0x5c60set _off_dwb, 0x6061set _off_dww, 0x6462set _off_dwl, 0x686364_060ISP_TABLE:6566# Here's the table of ENTRY POINTS for those linking the package.67bra.l _isp_unimp68short 0x00006970bra.l _isp_cas71short 0x00007273bra.l _isp_cas274short 0x00007576bra.l _isp_cas_finish77short 0x00007879bra.l _isp_cas2_finish80short 0x00008182bra.l _isp_cas_inrange83short 0x00008485bra.l _isp_cas_terminate86short 0x00008788bra.l _isp_cas_restart89short 0x00009091space 649293#############################################################9495global _real_chk96_real_chk:97mov.l %d0,-(%sp)98mov.l (_060ISP_TABLE-0x80+_off_chk,%pc),%d099pea.l (_060ISP_TABLE-0x80,%pc,%d0)100mov.l 0x4(%sp),%d0101rtd &0x4102103global _real_divbyzero104_real_divbyzero:105mov.l %d0,-(%sp)106mov.l (_060ISP_TABLE-0x80+_off_divbyzero,%pc),%d0107pea.l (_060ISP_TABLE-0x80,%pc,%d0)108mov.l 0x4(%sp),%d0109rtd &0x4110111global _real_trace112_real_trace:113mov.l %d0,-(%sp)114mov.l (_060ISP_TABLE-0x80+_off_trace,%pc),%d0115pea.l (_060ISP_TABLE-0x80,%pc,%d0)116mov.l 0x4(%sp),%d0117rtd &0x4118119global _real_access120_real_access:121mov.l %d0,-(%sp)122mov.l (_060ISP_TABLE-0x80+_off_access,%pc),%d0123pea.l (_060ISP_TABLE-0x80,%pc,%d0)124mov.l 0x4(%sp),%d0125rtd &0x4126127global _isp_done128_isp_done:129mov.l %d0,-(%sp)130mov.l (_060ISP_TABLE-0x80+_off_done,%pc),%d0131pea.l (_060ISP_TABLE-0x80,%pc,%d0)132mov.l 0x4(%sp),%d0133rtd &0x4134135#######################################136137global _real_cas138_real_cas:139mov.l %d0,-(%sp)140mov.l (_060ISP_TABLE-0x80+_off_cas,%pc),%d0141pea.l (_060ISP_TABLE-0x80,%pc,%d0)142mov.l 0x4(%sp),%d0143rtd &0x4144145global _real_cas2146_real_cas2:147mov.l %d0,-(%sp)148mov.l (_060ISP_TABLE-0x80+_off_cas2,%pc),%d0149pea.l (_060ISP_TABLE-0x80,%pc,%d0)150mov.l 0x4(%sp),%d0151rtd &0x4152153global _real_lock_page154_real_lock_page:155mov.l %d0,-(%sp)156mov.l (_060ISP_TABLE-0x80+_off_lock,%pc),%d0157pea.l (_060ISP_TABLE-0x80,%pc,%d0)158mov.l 0x4(%sp),%d0159rtd &0x4160161global _real_unlock_page162_real_unlock_page:163mov.l %d0,-(%sp)164mov.l (_060ISP_TABLE-0x80+_off_unlock,%pc),%d0165pea.l (_060ISP_TABLE-0x80,%pc,%d0)166mov.l 0x4(%sp),%d0167rtd &0x4168169#######################################170171global _imem_read172_imem_read:173mov.l %d0,-(%sp)174mov.l (_060ISP_TABLE-0x80+_off_imr,%pc),%d0175pea.l (_060ISP_TABLE-0x80,%pc,%d0)176mov.l 0x4(%sp),%d0177rtd &0x4178179global _dmem_read180_dmem_read:181mov.l %d0,-(%sp)182mov.l (_060ISP_TABLE-0x80+_off_dmr,%pc),%d0183pea.l (_060ISP_TABLE-0x80,%pc,%d0)184mov.l 0x4(%sp),%d0185rtd &0x4186187global _dmem_write188_dmem_write:189mov.l %d0,-(%sp)190mov.l (_060ISP_TABLE-0x80+_off_dmw,%pc),%d0191pea.l (_060ISP_TABLE-0x80,%pc,%d0)192mov.l 0x4(%sp),%d0193rtd &0x4194195global _imem_read_word196_imem_read_word:197mov.l %d0,-(%sp)198mov.l (_060ISP_TABLE-0x80+_off_irw,%pc),%d0199pea.l (_060ISP_TABLE-0x80,%pc,%d0)200mov.l 0x4(%sp),%d0201rtd &0x4202203global _imem_read_long204_imem_read_long:205mov.l %d0,-(%sp)206mov.l (_060ISP_TABLE-0x80+_off_irl,%pc),%d0207pea.l (_060ISP_TABLE-0x80,%pc,%d0)208mov.l 0x4(%sp),%d0209rtd &0x4210211global _dmem_read_byte212_dmem_read_byte:213mov.l %d0,-(%sp)214mov.l (_060ISP_TABLE-0x80+_off_drb,%pc),%d0215pea.l (_060ISP_TABLE-0x80,%pc,%d0)216mov.l 0x4(%sp),%d0217rtd &0x4218219global _dmem_read_word220_dmem_read_word:221mov.l %d0,-(%sp)222mov.l (_060ISP_TABLE-0x80+_off_drw,%pc),%d0223pea.l (_060ISP_TABLE-0x80,%pc,%d0)224mov.l 0x4(%sp),%d0225rtd &0x4226227global _dmem_read_long228_dmem_read_long:229mov.l %d0,-(%sp)230mov.l (_060ISP_TABLE-0x80+_off_drl,%pc),%d0231pea.l (_060ISP_TABLE-0x80,%pc,%d0)232mov.l 0x4(%sp),%d0233rtd &0x4234235global _dmem_write_byte236_dmem_write_byte:237mov.l %d0,-(%sp)238mov.l (_060ISP_TABLE-0x80+_off_dwb,%pc),%d0239pea.l (_060ISP_TABLE-0x80,%pc,%d0)240mov.l 0x4(%sp),%d0241rtd &0x4242243global _dmem_write_word244_dmem_write_word:245mov.l %d0,-(%sp)246mov.l (_060ISP_TABLE-0x80+_off_dww,%pc),%d0247pea.l (_060ISP_TABLE-0x80,%pc,%d0)248mov.l 0x4(%sp),%d0249rtd &0x4250251global _dmem_write_long252_dmem_write_long:253mov.l %d0,-(%sp)254mov.l (_060ISP_TABLE-0x80+_off_dwl,%pc),%d0255pea.l (_060ISP_TABLE-0x80,%pc,%d0)256mov.l 0x4(%sp),%d0257rtd &0x4258259#260# This file contains a set of define statements for constants261# in oreder to promote readability within the core code itself.262#263264set LOCAL_SIZE, 96 # stack frame size(bytes)265set LV, -LOCAL_SIZE # stack offset266267set EXC_ISR, 0x4 # stack status register268set EXC_IPC, 0x6 # stack pc269set EXC_IVOFF, 0xa # stacked vector offset270271set EXC_AREGS, LV+64 # offset of all address regs272set EXC_DREGS, LV+32 # offset of all data regs273274set EXC_A7, EXC_AREGS+(7*4) # offset of a7275set EXC_A6, EXC_AREGS+(6*4) # offset of a6276set EXC_A5, EXC_AREGS+(5*4) # offset of a5277set EXC_A4, EXC_AREGS+(4*4) # offset of a4278set EXC_A3, EXC_AREGS+(3*4) # offset of a3279set EXC_A2, EXC_AREGS+(2*4) # offset of a2280set EXC_A1, EXC_AREGS+(1*4) # offset of a1281set EXC_A0, EXC_AREGS+(0*4) # offset of a0282set EXC_D7, EXC_DREGS+(7*4) # offset of d7283set EXC_D6, EXC_DREGS+(6*4) # offset of d6284set EXC_D5, EXC_DREGS+(5*4) # offset of d5285set EXC_D4, EXC_DREGS+(4*4) # offset of d4286set EXC_D3, EXC_DREGS+(3*4) # offset of d3287set EXC_D2, EXC_DREGS+(2*4) # offset of d2288set EXC_D1, EXC_DREGS+(1*4) # offset of d1289set EXC_D0, EXC_DREGS+(0*4) # offset of d0290291set EXC_TEMP, LV+16 # offset of temp stack space292293set EXC_SAVVAL, LV+12 # offset of old areg value294set EXC_SAVREG, LV+11 # offset of old areg index295296set SPCOND_FLG, LV+10 # offset of spc condition flg297298set EXC_CC, LV+8 # offset of cc register299set EXC_EXTWPTR, LV+4 # offset of current PC300set EXC_EXTWORD, LV+2 # offset of current ext opword301set EXC_OPWORD, LV+0 # offset of current opword302303###########################304# SPecial CONDition FLaGs #305###########################306set mia7_flg, 0x04 # (a7)+ flag307set mda7_flg, 0x08 # -(a7) flag308set ichk_flg, 0x10 # chk exception flag309set idbyz_flg, 0x20 # divbyzero flag310set restore_flg, 0x40 # restore -(an)+ flag311set immed_flg, 0x80 # immediate data flag312313set mia7_bit, 0x2 # (a7)+ bit314set mda7_bit, 0x3 # -(a7) bit315set ichk_bit, 0x4 # chk exception bit316set idbyz_bit, 0x5 # divbyzero bit317set restore_bit, 0x6 # restore -(a7)+ bit318set immed_bit, 0x7 # immediate data bit319320#########321# Misc. #322#########323set BYTE, 1 # len(byte) == 1 byte324set WORD, 2 # len(word) == 2 bytes325set LONG, 4 # len(longword) == 4 bytes326327#########################################################################328# XDEF **************************************************************** #329# _isp_unimp(): 060ISP entry point for Unimplemented Instruction #330# #331# This handler should be the first code executed upon taking the #332# "Unimplemented Integer Instruction" exception in an operating #333# system. #334# #335# XREF **************************************************************** #336# _imem_read_{word,long}() - read instruction word/longword #337# _mul64() - emulate 64-bit multiply #338# _div64() - emulate 64-bit divide #339# _moveperipheral() - emulate "movep" #340# _compandset() - emulate misaligned "cas" #341# _compandset2() - emulate "cas2" #342# _chk2_cmp2() - emulate "cmp2" and "chk2" #343# _isp_done() - "callout" for normal final exit #344# _real_trace() - "callout" for Trace exception #345# _real_chk() - "callout" for Chk exception #346# _real_divbyzero() - "callout" for DZ exception #347# _real_access() - "callout" for access error exception #348# #349# INPUT *************************************************************** #350# - The system stack contains the Unimp Int Instr stack frame #351# #352# OUTPUT ************************************************************** #353# If Trace exception: #354# - The system stack changed to contain Trace exc stack frame #355# If Chk exception: #356# - The system stack changed to contain Chk exc stack frame #357# If DZ exception: #358# - The system stack changed to contain DZ exc stack frame #359# If access error exception: #360# - The system stack changed to contain access err exc stk frame #361# Else: #362# - Results saved as appropriate #363# #364# ALGORITHM *********************************************************** #365# This handler fetches the first instruction longword from #366# memory and decodes it to determine which of the unimplemented #367# integer instructions caused this exception. This handler then calls #368# one of _mul64(), _div64(), _moveperipheral(), _compandset(), #369# _compandset2(), or _chk2_cmp2() as appropriate. #370# Some of these instructions, by their nature, may produce other #371# types of exceptions. "div" can produce a divide-by-zero exception, #372# and "chk2" can cause a "Chk" exception. In both cases, the current #373# exception stack frame must be converted to an exception stack frame #374# of the correct exception type and an exit must be made through #375# _real_divbyzero() or _real_chk() as appropriate. In addition, all #376# instructions may be executing while Trace is enabled. If so, then #377# a Trace exception stack frame must be created and an exit made #378# through _real_trace(). #379# Meanwhile, if any read or write to memory using the #380# _mem_{read,write}() "callout"s returns a failing value, then an #381# access error frame must be created and an exit made through #382# _real_access(). #383# If none of these occur, then a normal exit is made through #384# _isp_done(). #385# #386# This handler, upon entry, saves almost all user-visible #387# address and data registers to the stack. Although this may seem to #388# cause excess memory traffic, it was found that due to having to #389# access these register files for things like data retrieval and <ea> #390# calculations, it was more efficient to have them on the stack where #391# they could be accessed by indexing rather than to make subroutine #392# calls to retrieve a register of a particular index. #393# #394#########################################################################395396global _isp_unimp397_isp_unimp:398link.w %a6,&-LOCAL_SIZE # create room for stack frame399400movm.l &0x3fff,EXC_DREGS(%a6) # store d0-d7/a0-a5401mov.l (%a6),EXC_A6(%a6) # store a6402403btst &0x5,EXC_ISR(%a6) # from s or u mode?404bne.b uieh_s # supervisor mode405uieh_u:406mov.l %usp,%a0 # fetch user stack pointer407mov.l %a0,EXC_A7(%a6) # store a7408bra.b uieh_cont409uieh_s:410lea 0xc(%a6),%a0411mov.l %a0,EXC_A7(%a6) # store corrected sp412413###############################################################################414415uieh_cont:416clr.b SPCOND_FLG(%a6) # clear "special case" flag417418mov.w EXC_ISR(%a6),EXC_CC(%a6) # store cc copy on stack419mov.l EXC_IPC(%a6),EXC_EXTWPTR(%a6) # store extwptr on stack420421#422# fetch the opword and first extension word pointed to by the stacked pc423# and store them to the stack for now424#425mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr426addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr427bsr.l _imem_read_long # fetch opword & extword428mov.l %d0,EXC_OPWORD(%a6) # store extword on stack429430431#########################################################################432# muls.l 0100 1100 00 |<ea>| 0*** 1100 0000 0*** #433# mulu.l 0100 1100 00 |<ea>| 0*** 0100 0000 0*** #434# #435# divs.l 0100 1100 01 |<ea>| 0*** 1100 0000 0*** #436# divu.l 0100 1100 01 |<ea>| 0*** 0100 0000 0*** #437# #438# movep.w m2r 0000 ***1 00 001*** | <displacement> | #439# movep.l m2r 0000 ***1 01 001*** | <displacement> | #440# movep.w r2m 0000 ***1 10 001*** | <displacement> | #441# movep.l r2m 0000 ***1 11 001*** | <displacement> | #442# #443# cas.w 0000 1100 11 |<ea>| 0000 000* **00 0*** #444# cas.l 0000 1110 11 |<ea>| 0000 000* **00 0*** #445# #446# cas2.w 0000 1100 11 111100 **** 000* **00 0*** #447# **** 000* **00 0*** #448# cas2.l 0000 1110 11 111100 **** 000* **00 0*** #449# **** 000* **00 0*** #450# #451# chk2.b 0000 0000 11 |<ea>| **** 1000 0000 0000 #452# chk2.w 0000 0010 11 |<ea>| **** 1000 0000 0000 #453# chk2.l 0000 0100 11 |<ea>| **** 1000 0000 0000 #454# #455# cmp2.b 0000 0000 11 |<ea>| **** 0000 0000 0000 #456# cmp2.w 0000 0010 11 |<ea>| **** 0000 0000 0000 #457# cmp2.l 0000 0100 11 |<ea>| **** 0000 0000 0000 #458#########################################################################459460#461# using bit 14 of the operation word, separate into 2 groups:462# (group1) mul64, div64463# (group2) movep, chk2, cmp2, cas2, cas464#465btst &0x1e,%d0 # group1 or group2466beq.b uieh_group2 # go handle group2467468#469# now, w/ group1, make mul64's decode the fastest since it will470# most likely be used the most.471#472uieh_group1:473btst &0x16,%d0 # test for div64474bne.b uieh_div64 # go handle div64475476uieh_mul64:477# mul64() may use ()+ addressing and may, therefore, alter a7478479bsr.l _mul64 # _mul64()480481btst &0x5,EXC_ISR(%a6) # supervisor mode?482beq.w uieh_done483btst &mia7_bit,SPCOND_FLG(%a6) # was a7 changed?484beq.w uieh_done # no485btst &0x7,EXC_ISR(%a6) # is trace enabled?486bne.w uieh_trace_a7 # yes487bra.w uieh_a7 # no488489uieh_div64:490# div64() may use ()+ addressing and may, therefore, alter a7.491# div64() may take a divide by zero exception.492493bsr.l _div64 # _div64()494495# here, we sort out all of the special cases that may have happened.496btst &mia7_bit,SPCOND_FLG(%a6) # was a7 changed?497bne.b uieh_div64_a7 # yes498uieh_div64_dbyz:499btst &idbyz_bit,SPCOND_FLG(%a6) # did divide-by-zero occur?500bne.w uieh_divbyzero # yes501bra.w uieh_done # no502uieh_div64_a7:503btst &0x5,EXC_ISR(%a6) # supervisor mode?504beq.b uieh_div64_dbyz # no505# here, a7 has been incremented by 4 bytes in supervisor mode. we still506# may have the following 3 cases:507# (i) (a7)+508# (ii) (a7)+; trace509# (iii) (a7)+; divide-by-zero510#511btst &idbyz_bit,SPCOND_FLG(%a6) # did divide-by-zero occur?512bne.w uieh_divbyzero_a7 # yes513tst.b EXC_ISR(%a6) # no; is trace enabled?514bmi.w uieh_trace_a7 # yes515bra.w uieh_a7 # no516517#518# now, w/ group2, make movep's decode the fastest since it will519# most likely be used the most.520#521uieh_group2:522btst &0x18,%d0 # test for not movep523beq.b uieh_not_movep524525526bsr.l _moveperipheral # _movep()527bra.w uieh_done528529uieh_not_movep:530btst &0x1b,%d0 # test for chk2,cmp2531beq.b uieh_chk2cmp2 # go handle chk2,cmp2532533swap %d0 # put opword in lo word534cmpi.b %d0,&0xfc # test for cas2535beq.b uieh_cas2 # go handle cas2536537uieh_cas:538539bsr.l _compandset # _cas()540541# the cases of "cas Dc,Du,(a7)+" and "cas Dc,Du,-(a7)" used from supervisor542# mode are simply not considered valid and therefore are not handled.543544bra.w uieh_done545546uieh_cas2:547548mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr549addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr550bsr.l _imem_read_word # read extension word551552tst.l %d1 # ifetch error?553bne.w isp_iacc # yes554555bsr.l _compandset2 # _cas2()556bra.w uieh_done557558uieh_chk2cmp2:559# chk2 may take a chk exception560561bsr.l _chk2_cmp2 # _chk2_cmp2()562563# here we check to see if a chk trap should be taken564cmpi.b SPCOND_FLG(%a6),&ichk_flg565bne.w uieh_done566bra.b uieh_chk_trap567568###########################################################################569570#571# the required emulation has been completed. now, clean up the necessary stack572# info and prepare for rte573#574uieh_done:575mov.b EXC_CC+1(%a6),EXC_ISR+1(%a6) # insert new ccodes576577# if exception occurred in user mode, then we have to restore a7 in case it578# changed. we don't have to update a7 for supervisor mose because that case579# doesn't flow through here580btst &0x5,EXC_ISR(%a6) # user or supervisor?581bne.b uieh_finish # supervisor582583mov.l EXC_A7(%a6),%a0 # fetch user stack pointer584mov.l %a0,%usp # restore it585586uieh_finish:587movm.l EXC_DREGS(%a6),&0x3fff # restore d0-d7/a0-a5588589btst &0x7,EXC_ISR(%a6) # is trace mode on?590bne.b uieh_trace # yes;go handle trace mode591592mov.l EXC_EXTWPTR(%a6),EXC_IPC(%a6) # new pc on stack frame593mov.l EXC_A6(%a6),(%a6) # prepare new a6 for unlink594unlk %a6 # unlink stack frame595bra.l _isp_done596597#598# The instruction that was just emulated was also being traced. The trace599# trap for this instruction will be lost unless we jump to the trace handler.600# So, here we create a Trace Exception format number two exception stack601# frame from the Unimplemented Integer Intruction Exception stack frame602# format number zero and jump to the user supplied hook "_real_trace()".603#604# UIEH FRAME TRACE FRAME605# ***************** *****************606# * 0x0 * 0x0f4 * * Current *607# ***************** * PC *608# * Current * *****************609# * PC * * 0x2 * 0x024 *610# ***************** *****************611# * SR * * Next *612# ***************** * PC *613# ->* Old * *****************614# from link -->* A6 * * SR *615# ***************** *****************616# /* A7 * * New * <-- for final unlink617# / * * * A6 *618# link frame < ***************** *****************619# \ ~ ~ ~ ~620# \***************** *****************621#622uieh_trace:623mov.l EXC_A6(%a6),-0x4(%a6)624mov.w EXC_ISR(%a6),0x0(%a6)625mov.l EXC_IPC(%a6),0x8(%a6)626mov.l EXC_EXTWPTR(%a6),0x2(%a6)627mov.w &0x2024,0x6(%a6)628sub.l &0x4,%a6629unlk %a6630bra.l _real_trace631632#633# UIEH FRAME CHK FRAME634# ***************** *****************635# * 0x0 * 0x0f4 * * Current *636# ***************** * PC *637# * Current * *****************638# * PC * * 0x2 * 0x018 *639# ***************** *****************640# * SR * * Next *641# ***************** * PC *642# (4 words) *****************643# * SR *644# *****************645# (6 words)646#647# the chk2 instruction should take a chk trap. so, here we must create a648# chk stack frame from an unimplemented integer instruction exception frame649# and jump to the user supplied entry point "_real_chk()".650#651uieh_chk_trap:652mov.b EXC_CC+1(%a6),EXC_ISR+1(%a6) # insert new ccodes653movm.l EXC_DREGS(%a6),&0x3fff # restore d0-d7/a0-a5654655mov.w EXC_ISR(%a6),(%a6) # put new SR on stack656mov.l EXC_IPC(%a6),0x8(%a6) # put "Current PC" on stack657mov.l EXC_EXTWPTR(%a6),0x2(%a6) # put "Next PC" on stack658mov.w &0x2018,0x6(%a6) # put Vector Offset on stack659660mov.l EXC_A6(%a6),%a6 # restore a6661add.l &LOCAL_SIZE,%sp # clear stack frame662663bra.l _real_chk664665#666# UIEH FRAME DIVBYZERO FRAME667# ***************** *****************668# * 0x0 * 0x0f4 * * Current *669# ***************** * PC *670# * Current * *****************671# * PC * * 0x2 * 0x014 *672# ***************** *****************673# * SR * * Next *674# ***************** * PC *675# (4 words) *****************676# * SR *677# *****************678# (6 words)679#680# the divide instruction should take an integer divide by zero trap. so, here681# we must create a divbyzero stack frame from an unimplemented integer682# instruction exception frame and jump to the user supplied entry point683# "_real_divbyzero()".684#685uieh_divbyzero:686mov.b EXC_CC+1(%a6),EXC_ISR+1(%a6) # insert new ccodes687movm.l EXC_DREGS(%a6),&0x3fff # restore d0-d7/a0-a5688689mov.w EXC_ISR(%a6),(%a6) # put new SR on stack690mov.l EXC_IPC(%a6),0x8(%a6) # put "Current PC" on stack691mov.l EXC_EXTWPTR(%a6),0x2(%a6) # put "Next PC" on stack692mov.w &0x2014,0x6(%a6) # put Vector Offset on stack693694mov.l EXC_A6(%a6),%a6 # restore a6695add.l &LOCAL_SIZE,%sp # clear stack frame696697bra.l _real_divbyzero698699#700# DIVBYZERO FRAME701# *****************702# * Current *703# UIEH FRAME * PC *704# ***************** *****************705# * 0x0 * 0x0f4 * * 0x2 * 0x014 *706# ***************** *****************707# * Current * * Next *708# * PC * * PC *709# ***************** *****************710# * SR * * SR *711# ***************** *****************712# (4 words) (6 words)713#714# the divide instruction should take an integer divide by zero trap. so, here715# we must create a divbyzero stack frame from an unimplemented integer716# instruction exception frame and jump to the user supplied entry point717# "_real_divbyzero()".718#719# However, we must also deal with the fact that (a7)+ was used from supervisor720# mode, thereby shifting the stack frame up 4 bytes.721#722uieh_divbyzero_a7:723mov.b EXC_CC+1(%a6),EXC_ISR+1(%a6) # insert new ccodes724movm.l EXC_DREGS(%a6),&0x3fff # restore d0-d7/a0-a5725726mov.l EXC_IPC(%a6),0xc(%a6) # put "Current PC" on stack727mov.w &0x2014,0xa(%a6) # put Vector Offset on stack728mov.l EXC_EXTWPTR(%a6),0x6(%a6) # put "Next PC" on stack729730mov.l EXC_A6(%a6),%a6 # restore a6731add.l &4+LOCAL_SIZE,%sp # clear stack frame732733bra.l _real_divbyzero734735#736# TRACE FRAME737# *****************738# * Current *739# UIEH FRAME * PC *740# ***************** *****************741# * 0x0 * 0x0f4 * * 0x2 * 0x024 *742# ***************** *****************743# * Current * * Next *744# * PC * * PC *745# ***************** *****************746# * SR * * SR *747# ***************** *****************748# (4 words) (6 words)749#750#751# The instruction that was just emulated was also being traced. The trace752# trap for this instruction will be lost unless we jump to the trace handler.753# So, here we create a Trace Exception format number two exception stack754# frame from the Unimplemented Integer Intruction Exception stack frame755# format number zero and jump to the user supplied hook "_real_trace()".756#757# However, we must also deal with the fact that (a7)+ was used from supervisor758# mode, thereby shifting the stack frame up 4 bytes.759#760uieh_trace_a7:761mov.b EXC_CC+1(%a6),EXC_ISR+1(%a6) # insert new ccodes762movm.l EXC_DREGS(%a6),&0x3fff # restore d0-d7/a0-a5763764mov.l EXC_IPC(%a6),0xc(%a6) # put "Current PC" on stack765mov.w &0x2024,0xa(%a6) # put Vector Offset on stack766mov.l EXC_EXTWPTR(%a6),0x6(%a6) # put "Next PC" on stack767768mov.l EXC_A6(%a6),%a6 # restore a6769add.l &4+LOCAL_SIZE,%sp # clear stack frame770771bra.l _real_trace772773#774# UIEH FRAME775# *****************776# * 0x0 * 0x0f4 *777# UIEH FRAME *****************778# ***************** * Next *779# * 0x0 * 0x0f4 * * PC *780# ***************** *****************781# * Current * * SR *782# * PC * *****************783# ***************** (4 words)784# * SR *785# *****************786# (4 words)787uieh_a7:788mov.b EXC_CC+1(%a6),EXC_ISR+1(%a6) # insert new ccodes789movm.l EXC_DREGS(%a6),&0x3fff # restore d0-d7/a0-a5790791mov.w &0x00f4,0xe(%a6) # put Vector Offset on stack792mov.l EXC_EXTWPTR(%a6),0xa(%a6) # put "Next PC" on stack793mov.w EXC_ISR(%a6),0x8(%a6) # put SR on stack794795mov.l EXC_A6(%a6),%a6 # restore a6796add.l &8+LOCAL_SIZE,%sp # clear stack frame797bra.l _isp_done798799##########800801# this is the exit point if a data read or write fails.802# a0 = failing address803# d0 = fslw804isp_dacc:805mov.l %a0,(%a6) # save address806mov.l %d0,-0x4(%a6) # save partial fslw807808lea -64(%a6),%sp809movm.l (%sp)+,&0x7fff # restore d0-d7/a0-a6810811mov.l 0xc(%sp),-(%sp) # move voff,hi(pc)812mov.l 0x4(%sp),0x10(%sp) # store fslw813mov.l 0xc(%sp),0x4(%sp) # store sr,lo(pc)814mov.l 0x8(%sp),0xc(%sp) # store address815mov.l (%sp)+,0x4(%sp) # store voff,hi(pc)816mov.w &0x4008,0x6(%sp) # store new voff817818bra.b isp_acc_exit819820# this is the exit point if an instruction word read fails.821# FSLW:822# misaligned = true823# read = true824# size = word825# instruction = true826# software emulation error = true827isp_iacc:828movm.l EXC_DREGS(%a6),&0x3fff # restore d0-d7/a0-a5829unlk %a6 # unlink frame830sub.w &0x8,%sp # make room for acc frame831mov.l 0x8(%sp),(%sp) # store sr,lo(pc)832mov.w 0xc(%sp),0x4(%sp) # store hi(pc)833mov.w &0x4008,0x6(%sp) # store new voff834mov.l 0x2(%sp),0x8(%sp) # store address (=pc)835mov.l &0x09428001,0xc(%sp) # store fslw836837isp_acc_exit:838btst &0x5,(%sp) # user or supervisor?839beq.b isp_acc_exit2 # user840bset &0x2,0xd(%sp) # set supervisor TM bit841isp_acc_exit2:842bra.l _real_access843844# if the addressing mode was (an)+ or -(an), the address register must845# be restored to its pre-exception value before entering _real_access.846isp_restore:847cmpi.b SPCOND_FLG(%a6),&restore_flg # do we need a restore?848bne.b isp_restore_done # no849clr.l %d0850mov.b EXC_SAVREG(%a6),%d0 # regno to restore851mov.l EXC_SAVVAL(%a6),(EXC_AREGS,%a6,%d0.l*4) # restore value852isp_restore_done:853rts854855#########################################################################856# XDEF **************************************************************** #857# _calc_ea(): routine to calculate effective address #858# #859# XREF **************************************************************** #860# _imem_read_word() - read instruction word #861# _imem_read_long() - read instruction longword #862# _dmem_read_long() - read data longword (for memory indirect) #863# isp_iacc() - handle instruction access error exception #864# isp_dacc() - handle data access error exception #865# #866# INPUT *************************************************************** #867# d0 = number of bytes related to effective address (w,l) #868# #869# OUTPUT ************************************************************** #870# If exiting through isp_dacc... #871# a0 = failing address #872# d0 = FSLW #873# elsif exiting though isp_iacc... #874# none #875# else #876# a0 = effective address #877# #878# ALGORITHM *********************************************************** #879# The effective address type is decoded from the opword residing #880# on the stack. A jump table is used to vector to a routine for the #881# appropriate mode. Since none of the emulated integer instructions #882# uses byte-sized operands, only handle word and long operations. #883# #884# Dn,An - shouldn't enter here #885# (An) - fetch An value from stack #886# -(An) - fetch An value from stack; return decr value; #887# place decr value on stack; store old value in case of #888# future access error; if -(a7), set mda7_flg in #889# SPCOND_FLG #890# (An)+ - fetch An value from stack; return value; #891# place incr value on stack; store old value in case of #892# future access error; if (a7)+, set mia7_flg in #893# SPCOND_FLG #894# (d16,An) - fetch An value from stack; read d16 using #895# _imem_read_word(); fetch may fail -> branch to #896# isp_iacc() #897# (xxx).w,(xxx).l - use _imem_read_{word,long}() to fetch #898# address; fetch may fail #899# #<data> - return address of immediate value; set immed_flg #900# in SPCOND_FLG #901# (d16,PC) - fetch stacked PC value; read d16 using #902# _imem_read_word(); fetch may fail -> branch to #903# isp_iacc() #904# everything else - read needed displacements as appropriate w/ #905# _imem_read_{word,long}(); read may fail; if memory #906# indirect, read indirect address using #907# _dmem_read_long() which may also fail #908# #909#########################################################################910911global _calc_ea912_calc_ea:913mov.l %d0,%a0 # move # bytes to a0914915# MODE and REG are taken from the EXC_OPWORD.916mov.w EXC_OPWORD(%a6),%d0 # fetch opcode word917mov.w %d0,%d1 # make a copy918919andi.w &0x3f,%d0 # extract mode field920andi.l &0x7,%d1 # extract reg field921922# jump to the corresponding function for each {MODE,REG} pair.923mov.w (tbl_ea_mode.b,%pc,%d0.w*2), %d0 # fetch jmp distance924jmp (tbl_ea_mode.b,%pc,%d0.w*1) # jmp to correct ea mode925926swbeg &64927tbl_ea_mode:928short tbl_ea_mode - tbl_ea_mode929short tbl_ea_mode - tbl_ea_mode930short tbl_ea_mode - tbl_ea_mode931short tbl_ea_mode - tbl_ea_mode932short tbl_ea_mode - tbl_ea_mode933short tbl_ea_mode - tbl_ea_mode934short tbl_ea_mode - tbl_ea_mode935short tbl_ea_mode - tbl_ea_mode936937short tbl_ea_mode - tbl_ea_mode938short tbl_ea_mode - tbl_ea_mode939short tbl_ea_mode - tbl_ea_mode940short tbl_ea_mode - tbl_ea_mode941short tbl_ea_mode - tbl_ea_mode942short tbl_ea_mode - tbl_ea_mode943short tbl_ea_mode - tbl_ea_mode944short tbl_ea_mode - tbl_ea_mode945946short addr_ind_a0 - tbl_ea_mode947short addr_ind_a1 - tbl_ea_mode948short addr_ind_a2 - tbl_ea_mode949short addr_ind_a3 - tbl_ea_mode950short addr_ind_a4 - tbl_ea_mode951short addr_ind_a5 - tbl_ea_mode952short addr_ind_a6 - tbl_ea_mode953short addr_ind_a7 - tbl_ea_mode954955short addr_ind_p_a0 - tbl_ea_mode956short addr_ind_p_a1 - tbl_ea_mode957short addr_ind_p_a2 - tbl_ea_mode958short addr_ind_p_a3 - tbl_ea_mode959short addr_ind_p_a4 - tbl_ea_mode960short addr_ind_p_a5 - tbl_ea_mode961short addr_ind_p_a6 - tbl_ea_mode962short addr_ind_p_a7 - tbl_ea_mode963964short addr_ind_m_a0 - tbl_ea_mode965short addr_ind_m_a1 - tbl_ea_mode966short addr_ind_m_a2 - tbl_ea_mode967short addr_ind_m_a3 - tbl_ea_mode968short addr_ind_m_a4 - tbl_ea_mode969short addr_ind_m_a5 - tbl_ea_mode970short addr_ind_m_a6 - tbl_ea_mode971short addr_ind_m_a7 - tbl_ea_mode972973short addr_ind_disp_a0 - tbl_ea_mode974short addr_ind_disp_a1 - tbl_ea_mode975short addr_ind_disp_a2 - tbl_ea_mode976short addr_ind_disp_a3 - tbl_ea_mode977short addr_ind_disp_a4 - tbl_ea_mode978short addr_ind_disp_a5 - tbl_ea_mode979short addr_ind_disp_a6 - tbl_ea_mode980short addr_ind_disp_a7 - tbl_ea_mode981982short _addr_ind_ext - tbl_ea_mode983short _addr_ind_ext - tbl_ea_mode984short _addr_ind_ext - tbl_ea_mode985short _addr_ind_ext - tbl_ea_mode986short _addr_ind_ext - tbl_ea_mode987short _addr_ind_ext - tbl_ea_mode988short _addr_ind_ext - tbl_ea_mode989short _addr_ind_ext - tbl_ea_mode990991short abs_short - tbl_ea_mode992short abs_long - tbl_ea_mode993short pc_ind - tbl_ea_mode994short pc_ind_ext - tbl_ea_mode995short immediate - tbl_ea_mode996short tbl_ea_mode - tbl_ea_mode997short tbl_ea_mode - tbl_ea_mode998short tbl_ea_mode - tbl_ea_mode9991000###################################1001# Address register indirect: (An) #1002###################################1003addr_ind_a0:1004mov.l EXC_A0(%a6),%a0 # Get current a01005rts10061007addr_ind_a1:1008mov.l EXC_A1(%a6),%a0 # Get current a11009rts10101011addr_ind_a2:1012mov.l EXC_A2(%a6),%a0 # Get current a21013rts10141015addr_ind_a3:1016mov.l EXC_A3(%a6),%a0 # Get current a31017rts10181019addr_ind_a4:1020mov.l EXC_A4(%a6),%a0 # Get current a41021rts10221023addr_ind_a5:1024mov.l EXC_A5(%a6),%a0 # Get current a51025rts10261027addr_ind_a6:1028mov.l EXC_A6(%a6),%a0 # Get current a61029rts10301031addr_ind_a7:1032mov.l EXC_A7(%a6),%a0 # Get current a71033rts10341035#####################################################1036# Address register indirect w/ postincrement: (An)+ #1037#####################################################1038addr_ind_p_a0:1039mov.l %a0,%d0 # copy no. bytes1040mov.l EXC_A0(%a6),%a0 # load current value1041add.l %a0,%d0 # increment1042mov.l %d0,EXC_A0(%a6) # save incremented value10431044mov.l %a0,EXC_SAVVAL(%a6) # save in case of access error1045mov.b &0x0,EXC_SAVREG(%a6) # save regno, too1046mov.b &restore_flg,SPCOND_FLG(%a6) # set flag1047rts10481049addr_ind_p_a1:1050mov.l %a0,%d0 # copy no. bytes1051mov.l EXC_A1(%a6),%a0 # load current value1052add.l %a0,%d0 # increment1053mov.l %d0,EXC_A1(%a6) # save incremented value10541055mov.l %a0,EXC_SAVVAL(%a6) # save in case of access error1056mov.b &0x1,EXC_SAVREG(%a6) # save regno, too1057mov.b &restore_flg,SPCOND_FLG(%a6) # set flag1058rts10591060addr_ind_p_a2:1061mov.l %a0,%d0 # copy no. bytes1062mov.l EXC_A2(%a6),%a0 # load current value1063add.l %a0,%d0 # increment1064mov.l %d0,EXC_A2(%a6) # save incremented value10651066mov.l %a0,EXC_SAVVAL(%a6) # save in case of access error1067mov.b &0x2,EXC_SAVREG(%a6) # save regno, too1068mov.b &restore_flg,SPCOND_FLG(%a6) # set flag1069rts10701071addr_ind_p_a3:1072mov.l %a0,%d0 # copy no. bytes1073mov.l EXC_A3(%a6),%a0 # load current value1074add.l %a0,%d0 # increment1075mov.l %d0,EXC_A3(%a6) # save incremented value10761077mov.l %a0,EXC_SAVVAL(%a6) # save in case of access error1078mov.b &0x3,EXC_SAVREG(%a6) # save regno, too1079mov.b &restore_flg,SPCOND_FLG(%a6) # set flag1080rts10811082addr_ind_p_a4:1083mov.l %a0,%d0 # copy no. bytes1084mov.l EXC_A4(%a6),%a0 # load current value1085add.l %a0,%d0 # increment1086mov.l %d0,EXC_A4(%a6) # save incremented value10871088mov.l %a0,EXC_SAVVAL(%a6) # save in case of access error1089mov.b &0x4,EXC_SAVREG(%a6) # save regno, too1090mov.b &restore_flg,SPCOND_FLG(%a6) # set flag1091rts10921093addr_ind_p_a5:1094mov.l %a0,%d0 # copy no. bytes1095mov.l EXC_A5(%a6),%a0 # load current value1096add.l %a0,%d0 # increment1097mov.l %d0,EXC_A5(%a6) # save incremented value10981099mov.l %a0,EXC_SAVVAL(%a6) # save in case of access error1100mov.b &0x5,EXC_SAVREG(%a6) # save regno, too1101mov.b &restore_flg,SPCOND_FLG(%a6) # set flag1102rts11031104addr_ind_p_a6:1105mov.l %a0,%d0 # copy no. bytes1106mov.l EXC_A6(%a6),%a0 # load current value1107add.l %a0,%d0 # increment1108mov.l %d0,EXC_A6(%a6) # save incremented value11091110mov.l %a0,EXC_SAVVAL(%a6) # save in case of access error1111mov.b &0x6,EXC_SAVREG(%a6) # save regno, too1112mov.b &restore_flg,SPCOND_FLG(%a6) # set flag1113rts11141115addr_ind_p_a7:1116mov.b &mia7_flg,SPCOND_FLG(%a6) # set "special case" flag11171118mov.l %a0,%d0 # copy no. bytes1119mov.l EXC_A7(%a6),%a0 # load current value1120add.l %a0,%d0 # increment1121mov.l %d0,EXC_A7(%a6) # save incremented value1122rts11231124####################################################1125# Address register indirect w/ predecrement: -(An) #1126####################################################1127addr_ind_m_a0:1128mov.l EXC_A0(%a6),%d0 # Get current a01129mov.l %d0,EXC_SAVVAL(%a6) # save in case of access error1130sub.l %a0,%d0 # Decrement1131mov.l %d0,EXC_A0(%a6) # Save decr value1132mov.l %d0,%a011331134mov.b &0x0,EXC_SAVREG(%a6) # save regno, too1135mov.b &restore_flg,SPCOND_FLG(%a6) # set flag1136rts11371138addr_ind_m_a1:1139mov.l EXC_A1(%a6),%d0 # Get current a11140mov.l %d0,EXC_SAVVAL(%a6) # save in case of access error1141sub.l %a0,%d0 # Decrement1142mov.l %d0,EXC_A1(%a6) # Save decr value1143mov.l %d0,%a011441145mov.b &0x1,EXC_SAVREG(%a6) # save regno, too1146mov.b &restore_flg,SPCOND_FLG(%a6) # set flag1147rts11481149addr_ind_m_a2:1150mov.l EXC_A2(%a6),%d0 # Get current a21151mov.l %d0,EXC_SAVVAL(%a6) # save in case of access error1152sub.l %a0,%d0 # Decrement1153mov.l %d0,EXC_A2(%a6) # Save decr value1154mov.l %d0,%a011551156mov.b &0x2,EXC_SAVREG(%a6) # save regno, too1157mov.b &restore_flg,SPCOND_FLG(%a6) # set flag1158rts11591160addr_ind_m_a3:1161mov.l EXC_A3(%a6),%d0 # Get current a31162mov.l %d0,EXC_SAVVAL(%a6) # save in case of access error1163sub.l %a0,%d0 # Decrement1164mov.l %d0,EXC_A3(%a6) # Save decr value1165mov.l %d0,%a011661167mov.b &0x3,EXC_SAVREG(%a6) # save regno, too1168mov.b &restore_flg,SPCOND_FLG(%a6) # set flag1169rts11701171addr_ind_m_a4:1172mov.l EXC_A4(%a6),%d0 # Get current a41173mov.l %d0,EXC_SAVVAL(%a6) # save in case of access error1174sub.l %a0,%d0 # Decrement1175mov.l %d0,EXC_A4(%a6) # Save decr value1176mov.l %d0,%a011771178mov.b &0x4,EXC_SAVREG(%a6) # save regno, too1179mov.b &restore_flg,SPCOND_FLG(%a6) # set flag1180rts11811182addr_ind_m_a5:1183mov.l EXC_A5(%a6),%d0 # Get current a51184mov.l %d0,EXC_SAVVAL(%a6) # save in case of access error1185sub.l %a0,%d0 # Decrement1186mov.l %d0,EXC_A5(%a6) # Save decr value1187mov.l %d0,%a011881189mov.b &0x5,EXC_SAVREG(%a6) # save regno, too1190mov.b &restore_flg,SPCOND_FLG(%a6) # set flag1191rts11921193addr_ind_m_a6:1194mov.l EXC_A6(%a6),%d0 # Get current a61195mov.l %d0,EXC_SAVVAL(%a6) # save in case of access error1196sub.l %a0,%d0 # Decrement1197mov.l %d0,EXC_A6(%a6) # Save decr value1198mov.l %d0,%a011991200mov.b &0x6,EXC_SAVREG(%a6) # save regno, too1201mov.b &restore_flg,SPCOND_FLG(%a6) # set flag1202rts12031204addr_ind_m_a7:1205mov.b &mda7_flg,SPCOND_FLG(%a6) # set "special case" flag12061207mov.l EXC_A7(%a6),%d0 # Get current a71208sub.l %a0,%d0 # Decrement1209mov.l %d0,EXC_A7(%a6) # Save decr value1210mov.l %d0,%a01211rts12121213########################################################1214# Address register indirect w/ displacement: (d16, An) #1215########################################################1216addr_ind_disp_a0:1217mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr1218addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr1219bsr.l _imem_read_word12201221tst.l %d1 # ifetch error?1222bne.l isp_iacc # yes12231224mov.w %d0,%a0 # sign extend displacement1225add.l EXC_A0(%a6),%a0 # a0 + d161226rts12271228addr_ind_disp_a1:1229mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr1230addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr1231bsr.l _imem_read_word12321233tst.l %d1 # ifetch error?1234bne.l isp_iacc # yes12351236mov.w %d0,%a0 # sign extend displacement1237add.l EXC_A1(%a6),%a0 # a1 + d161238rts12391240addr_ind_disp_a2:1241mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr1242addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr1243bsr.l _imem_read_word12441245tst.l %d1 # ifetch error?1246bne.l isp_iacc # yes12471248mov.w %d0,%a0 # sign extend displacement1249add.l EXC_A2(%a6),%a0 # a2 + d161250rts12511252addr_ind_disp_a3:1253mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr1254addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr1255bsr.l _imem_read_word12561257tst.l %d1 # ifetch error?1258bne.l isp_iacc # yes12591260mov.w %d0,%a0 # sign extend displacement1261add.l EXC_A3(%a6),%a0 # a3 + d161262rts12631264addr_ind_disp_a4:1265mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr1266addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr1267bsr.l _imem_read_word12681269tst.l %d1 # ifetch error?1270bne.l isp_iacc # yes12711272mov.w %d0,%a0 # sign extend displacement1273add.l EXC_A4(%a6),%a0 # a4 + d161274rts12751276addr_ind_disp_a5:1277mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr1278addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr1279bsr.l _imem_read_word12801281tst.l %d1 # ifetch error?1282bne.l isp_iacc # yes12831284mov.w %d0,%a0 # sign extend displacement1285add.l EXC_A5(%a6),%a0 # a5 + d161286rts12871288addr_ind_disp_a6:1289mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr1290addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr1291bsr.l _imem_read_word12921293tst.l %d1 # ifetch error?1294bne.l isp_iacc # yes12951296mov.w %d0,%a0 # sign extend displacement1297add.l EXC_A6(%a6),%a0 # a6 + d161298rts12991300addr_ind_disp_a7:1301mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr1302addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr1303bsr.l _imem_read_word13041305tst.l %d1 # ifetch error?1306bne.l isp_iacc # yes13071308mov.w %d0,%a0 # sign extend displacement1309add.l EXC_A7(%a6),%a0 # a7 + d161310rts13111312########################################################################1313# Address register indirect w/ index(8-bit displacement): (dn, An, Xn) #1314# " " " w/ " (base displacement): (bd, An, Xn) #1315# Memory indirect postindexed: ([bd, An], Xn, od) #1316# Memory indirect preindexed: ([bd, An, Xn], od) #1317########################################################################1318_addr_ind_ext:1319mov.l %d1,-(%sp)13201321mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr1322addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr1323bsr.l _imem_read_word # fetch extword in d013241325tst.l %d1 # ifetch error?1326bne.l isp_iacc # yes13271328mov.l (%sp)+,%d113291330mov.l (EXC_AREGS,%a6,%d1.w*4),%a0 # put base in a013311332btst &0x8,%d01333beq.b addr_ind_index_8bit # for ext word or not?13341335movm.l &0x3c00,-(%sp) # save d2-d513361337mov.l %d0,%d5 # put extword in d51338mov.l %a0,%d3 # put base in d313391340bra.l calc_mem_ind # calc memory indirect13411342addr_ind_index_8bit:1343mov.l %d2,-(%sp) # save old d213441345mov.l %d0,%d11346rol.w &0x4,%d11347andi.w &0xf,%d1 # extract index regno13481349mov.l (EXC_DREGS,%a6,%d1.w*4),%d1 # fetch index reg value13501351btst &0xb,%d0 # is it word or long?1352bne.b aii8_long1353ext.l %d1 # sign extend word index1354aii8_long:1355mov.l %d0,%d21356rol.w &0x7,%d21357andi.l &0x3,%d2 # extract scale value13581359lsl.l %d2,%d1 # shift index by scale13601361extb.l %d0 # sign extend displacement1362add.l %d1,%d0 # index + disp1363add.l %d0,%a0 # An + (index + disp)13641365mov.l (%sp)+,%d2 # restore old d21366rts13671368######################1369# Immediate: #<data> #1370#########################################################################1371# word, long: <ea> of the data is the current extension word #1372# pointer value. new extension word pointer is simply the old #1373# plus the number of bytes in the data type(2 or 4). #1374#########################################################################1375immediate:1376mov.b &immed_flg,SPCOND_FLG(%a6) # set immediate flag13771378mov.l EXC_EXTWPTR(%a6),%a0 # fetch extension word ptr1379rts13801381###########################1382# Absolute short: (XXX).W #1383###########################1384abs_short:1385mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr1386addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr1387bsr.l _imem_read_word # fetch short address13881389tst.l %d1 # ifetch error?1390bne.l isp_iacc # yes13911392mov.w %d0,%a0 # return <ea> in a01393rts13941395##########################1396# Absolute long: (XXX).L #1397##########################1398abs_long:1399mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr1400addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr1401bsr.l _imem_read_long # fetch long address14021403tst.l %d1 # ifetch error?1404bne.l isp_iacc # yes14051406mov.l %d0,%a0 # return <ea> in a01407rts14081409#######################################################1410# Program counter indirect w/ displacement: (d16, PC) #1411#######################################################1412pc_ind:1413mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr1414addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr1415bsr.l _imem_read_word # fetch word displacement14161417tst.l %d1 # ifetch error?1418bne.l isp_iacc # yes14191420mov.w %d0,%a0 # sign extend displacement14211422add.l EXC_EXTWPTR(%a6),%a0 # pc + d1614231424# _imem_read_word() increased the extwptr by 2. need to adjust here.1425subq.l &0x2,%a0 # adjust <ea>14261427rts14281429##########################################################1430# PC indirect w/ index(8-bit displacement): (d8, PC, An) #1431# " " w/ " (base displacement): (bd, PC, An) #1432# PC memory indirect postindexed: ([bd, PC], Xn, od) #1433# PC memory indirect preindexed: ([bd, PC, Xn], od) #1434##########################################################1435pc_ind_ext:1436mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr1437addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr1438bsr.l _imem_read_word # fetch ext word14391440tst.l %d1 # ifetch error?1441bne.l isp_iacc # yes14421443mov.l EXC_EXTWPTR(%a6),%a0 # put base in a01444subq.l &0x2,%a0 # adjust base14451446btst &0x8,%d0 # is disp only 8 bits?1447beq.b pc_ind_index_8bit # yes14481449# the indexed addressing mode uses a base displacement of size1450# word or long1451movm.l &0x3c00,-(%sp) # save d2-d514521453mov.l %d0,%d5 # put extword in d51454mov.l %a0,%d3 # put base in d314551456bra.l calc_mem_ind # calc memory indirect14571458pc_ind_index_8bit:1459mov.l %d2,-(%sp) # create a temp register14601461mov.l %d0,%d1 # make extword copy1462rol.w &0x4,%d1 # rotate reg num into place1463andi.w &0xf,%d1 # extract register number14641465mov.l (EXC_DREGS,%a6,%d1.w*4),%d1 # fetch index reg value14661467btst &0xb,%d0 # is index word or long?1468bne.b pii8_long # long1469ext.l %d1 # sign extend word index1470pii8_long:1471mov.l %d0,%d2 # make extword copy1472rol.w &0x7,%d2 # rotate scale value into place1473andi.l &0x3,%d2 # extract scale value14741475lsl.l %d2,%d1 # shift index by scale14761477extb.l %d0 # sign extend displacement1478add.l %d1,%d0 # index + disp1479add.l %d0,%a0 # An + (index + disp)14801481mov.l (%sp)+,%d2 # restore temp register14821483rts14841485# a5 = exc_extwptr (global to uaeh)1486# a4 = exc_opword (global to uaeh)1487# a3 = exc_dregs (global to uaeh)14881489# d2 = index (internal " " )1490# d3 = base (internal " " )1491# d4 = od (internal " " )1492# d5 = extword (internal " " )1493calc_mem_ind:1494btst &0x6,%d5 # is the index suppressed?1495beq.b calc_index1496clr.l %d2 # yes, so index = 01497bra.b base_supp_ck1498calc_index:1499bfextu %d5{&16:&4},%d21500mov.l (EXC_DREGS,%a6,%d2.w*4),%d21501btst &0xb,%d5 # is index word or long?1502bne.b no_ext1503ext.l %d21504no_ext:1505bfextu %d5{&21:&2},%d01506lsl.l %d0,%d21507base_supp_ck:1508btst &0x7,%d5 # is the bd suppressed?1509beq.b no_base_sup1510clr.l %d31511no_base_sup:1512bfextu %d5{&26:&2},%d0 # get bd size1513# beq.l _error # if (size == 0) it's reserved1514cmpi.b %d0,&21515blt.b no_bd1516beq.b get_word_bd15171518mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr1519addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr1520bsr.l _imem_read_long15211522tst.l %d1 # ifetch error?1523bne.l isp_iacc # yes15241525bra.b chk_ind1526get_word_bd:1527mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr1528addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr1529bsr.l _imem_read_word15301531tst.l %d1 # ifetch error?1532bne.l isp_iacc # yes15331534ext.l %d0 # sign extend bd15351536chk_ind:1537add.l %d0,%d3 # base += bd1538no_bd:1539bfextu %d5{&30:&2},%d0 # is od suppressed?1540beq.w aii_bd1541cmpi.b %d0,&0x21542blt.b null_od1543beq.b word_od15441545mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr1546addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr1547bsr.l _imem_read_long15481549tst.l %d1 # ifetch error?1550bne.l isp_iacc # yes15511552bra.b add_them15531554word_od:1555mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr1556addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr1557bsr.l _imem_read_word15581559tst.l %d1 # ifetch error?1560bne.l isp_iacc # yes15611562ext.l %d0 # sign extend od1563bra.b add_them15641565null_od:1566clr.l %d01567add_them:1568mov.l %d0,%d41569btst &0x2,%d5 # pre or post indexing?1570beq.b pre_indexed15711572mov.l %d3,%a01573bsr.l _dmem_read_long15741575tst.l %d1 # dfetch error?1576bne.b calc_ea_err # yes15771578add.l %d2,%d0 # <ea> += index1579add.l %d4,%d0 # <ea> += od1580bra.b done_ea15811582pre_indexed:1583add.l %d2,%d3 # preindexing1584mov.l %d3,%a01585bsr.l _dmem_read_long15861587tst.l %d1 # ifetch error?1588bne.b calc_ea_err # yes15891590add.l %d4,%d0 # ea += od1591bra.b done_ea15921593aii_bd:1594add.l %d2,%d3 # ea = (base + bd) + index1595mov.l %d3,%d01596done_ea:1597mov.l %d0,%a015981599movm.l (%sp)+,&0x003c # restore d2-d51600rts16011602# if dmem_read_long() returns a fail message in d1, the package1603# must create an access error frame. here, we pass a skeleton fslw1604# and the failing address to the routine that creates the new frame.1605# FSLW:1606# read = true1607# size = longword1608# TM = data1609# software emulation error = true1610calc_ea_err:1611mov.l %d3,%a0 # pass failing address1612mov.l &0x01010001,%d0 # pass fslw1613bra.l isp_dacc16141615#########################################################################1616# XDEF **************************************************************** #1617# _moveperipheral(): routine to emulate movep instruction #1618# #1619# XREF **************************************************************** #1620# _dmem_read_byte() - read byte from memory #1621# _dmem_write_byte() - write byte to memory #1622# isp_dacc() - handle data access error exception #1623# #1624# INPUT *************************************************************** #1625# none #1626# #1627# OUTPUT ************************************************************** #1628# If exiting through isp_dacc... #1629# a0 = failing address #1630# d0 = FSLW #1631# else #1632# none #1633# #1634# ALGORITHM *********************************************************** #1635# Decode the movep instruction words stored at EXC_OPWORD and #1636# either read or write the required bytes from/to memory. Use the #1637# _dmem_{read,write}_byte() routines. If one of the memory routines #1638# returns a failing value, we must pass the failing address and a FSLW #1639# to the _isp_dacc() routine. #1640# Since this instruction is used to access peripherals, make sure #1641# to only access the required bytes. #1642# #1643#########################################################################16441645###########################1646# movep.(w,l) Dx,(d,Ay) #1647# movep.(w,l) (d,Ay),Dx #1648###########################1649global _moveperipheral1650_moveperipheral:1651mov.w EXC_OPWORD(%a6),%d1 # fetch the opcode word16521653mov.b %d1,%d01654and.w &0x7,%d0 # extract Ay from opcode word16551656mov.l (EXC_AREGS,%a6,%d0.w*4),%a0 # fetch ay16571658add.w EXC_EXTWORD(%a6),%a0 # add: an + sgn_ext(disp)16591660btst &0x7,%d1 # (reg 2 mem) or (mem 2 reg)1661beq.w mem2reg16621663# reg2mem: fetch dx, then write it to memory1664reg2mem:1665mov.w %d1,%d01666rol.w &0x7,%d01667and.w &0x7,%d0 # extract Dx from opcode word16681669mov.l (EXC_DREGS,%a6,%d0.w*4), %d0 # fetch dx16701671btst &0x6,%d1 # word or long operation?1672beq.b r2mwtrans16731674# a0 = dst addr1675# d0 = Dx1676r2mltrans:1677mov.l %d0,%d2 # store data1678mov.l %a0,%a2 # store addr1679rol.l &0x8,%d21680mov.l %d2,%d016811682bsr.l _dmem_write_byte # os : write hi16831684tst.l %d1 # dfetch error?1685bne.w movp_write_err # yes16861687add.w &0x2,%a2 # incr addr1688mov.l %a2,%a01689rol.l &0x8,%d21690mov.l %d2,%d016911692bsr.l _dmem_write_byte # os : write lo16931694tst.l %d1 # dfetch error?1695bne.w movp_write_err # yes16961697add.w &0x2,%a2 # incr addr1698mov.l %a2,%a01699rol.l &0x8,%d21700mov.l %d2,%d017011702bsr.l _dmem_write_byte # os : write lo17031704tst.l %d1 # dfetch error?1705bne.w movp_write_err # yes17061707add.w &0x2,%a2 # incr addr1708mov.l %a2,%a01709rol.l &0x8,%d21710mov.l %d2,%d017111712bsr.l _dmem_write_byte # os : write lo17131714tst.l %d1 # dfetch error?1715bne.w movp_write_err # yes17161717rts17181719# a0 = dst addr1720# d0 = Dx1721r2mwtrans:1722mov.l %d0,%d2 # store data1723mov.l %a0,%a2 # store addr1724lsr.w &0x8,%d017251726bsr.l _dmem_write_byte # os : write hi17271728tst.l %d1 # dfetch error?1729bne.w movp_write_err # yes17301731add.w &0x2,%a21732mov.l %a2,%a01733mov.l %d2,%d017341735bsr.l _dmem_write_byte # os : write lo17361737tst.l %d1 # dfetch error?1738bne.w movp_write_err # yes17391740rts17411742# mem2reg: read bytes from memory.1743# determines the dest register, and then writes the bytes into it.1744mem2reg:1745btst &0x6,%d1 # word or long operation?1746beq.b m2rwtrans17471748# a0 = dst addr1749m2rltrans:1750mov.l %a0,%a2 # store addr17511752bsr.l _dmem_read_byte # read first byte17531754tst.l %d1 # dfetch error?1755bne.w movp_read_err # yes17561757mov.l %d0,%d217581759add.w &0x2,%a2 # incr addr by 2 bytes1760mov.l %a2,%a017611762bsr.l _dmem_read_byte # read second byte17631764tst.l %d1 # dfetch error?1765bne.w movp_read_err # yes17661767lsl.w &0x8,%d21768mov.b %d0,%d2 # append bytes17691770add.w &0x2,%a2 # incr addr by 2 bytes1771mov.l %a2,%a017721773bsr.l _dmem_read_byte # read second byte17741775tst.l %d1 # dfetch error?1776bne.w movp_read_err # yes17771778lsl.l &0x8,%d21779mov.b %d0,%d2 # append bytes17801781add.w &0x2,%a2 # incr addr by 2 bytes1782mov.l %a2,%a017831784bsr.l _dmem_read_byte # read second byte17851786tst.l %d1 # dfetch error?1787bne.w movp_read_err # yes17881789lsl.l &0x8,%d21790mov.b %d0,%d2 # append bytes17911792mov.b EXC_OPWORD(%a6),%d11793lsr.b &0x1,%d11794and.w &0x7,%d1 # extract Dx from opcode word17951796mov.l %d2,(EXC_DREGS,%a6,%d1.w*4) # store dx17971798rts17991800# a0 = dst addr1801m2rwtrans:1802mov.l %a0,%a2 # store addr18031804bsr.l _dmem_read_byte # read first byte18051806tst.l %d1 # dfetch error?1807bne.w movp_read_err # yes18081809mov.l %d0,%d218101811add.w &0x2,%a2 # incr addr by 2 bytes1812mov.l %a2,%a018131814bsr.l _dmem_read_byte # read second byte18151816tst.l %d1 # dfetch error?1817bne.w movp_read_err # yes18181819lsl.w &0x8,%d21820mov.b %d0,%d2 # append bytes18211822mov.b EXC_OPWORD(%a6),%d11823lsr.b &0x1,%d11824and.w &0x7,%d1 # extract Dx from opcode word18251826mov.w %d2,(EXC_DREGS+2,%a6,%d1.w*4) # store dx18271828rts18291830# if dmem_{read,write}_byte() returns a fail message in d1, the package1831# must create an access error frame. here, we pass a skeleton fslw1832# and the failing address to the routine that creates the new frame.1833# FSLW:1834# write = true1835# size = byte1836# TM = data1837# software emulation error = true1838movp_write_err:1839mov.l %a2,%a0 # pass failing address1840mov.l &0x00a10001,%d0 # pass fslw1841bra.l isp_dacc18421843# FSLW:1844# read = true1845# size = byte1846# TM = data1847# software emulation error = true1848movp_read_err:1849mov.l %a2,%a0 # pass failing address1850mov.l &0x01210001,%d0 # pass fslw1851bra.l isp_dacc18521853#########################################################################1854# XDEF **************************************************************** #1855# _chk2_cmp2(): routine to emulate chk2/cmp2 instructions #1856# #1857# XREF **************************************************************** #1858# _calc_ea(): calculate effective address #1859# _dmem_read_long(): read operands #1860# _dmem_read_word(): read operands #1861# isp_dacc(): handle data access error exception #1862# #1863# INPUT *************************************************************** #1864# none #1865# #1866# OUTPUT ************************************************************** #1867# If exiting through isp_dacc... #1868# a0 = failing address #1869# d0 = FSLW #1870# else #1871# none #1872# #1873# ALGORITHM *********************************************************** #1874# First, calculate the effective address, then fetch the byte, #1875# word, or longword sized operands. Then, in the interest of #1876# simplicity, all operands are converted to longword size whether the #1877# operation is byte, word, or long. The bounds are sign extended #1878# accordingly. If Rn is a data regsiter, Rn is also sign extended. If #1879# Rn is an address register, it need not be sign extended since the #1880# full register is always used. #1881# The comparisons are made and the condition codes calculated. #1882# If the instruction is chk2 and the Rn value is out-of-bounds, set #1883# the ichk_flg in SPCOND_FLG. #1884# If the memory fetch returns a failing value, pass the failing #1885# address and FSLW to the isp_dacc() routine. #1886# #1887#########################################################################18881889global _chk2_cmp21890_chk2_cmp2:18911892# passing size parameter doesn't matter since chk2 & cmp2 can't do1893# either predecrement, postincrement, or immediate.1894bsr.l _calc_ea # calculate <ea>18951896mov.b EXC_EXTWORD(%a6), %d0 # fetch hi extension word1897rol.b &0x4, %d0 # rotate reg bits into lo1898and.w &0xf, %d0 # extract reg bits18991900mov.l (EXC_DREGS,%a6,%d0.w*4), %d2 # get regval19011902cmpi.b EXC_OPWORD(%a6), &0x2 # what size is operation?1903blt.b chk2_cmp2_byte # size == byte1904beq.b chk2_cmp2_word # size == word19051906# the bounds are longword size. call routine to read the lower1907# bound into d0 and the higher bound into d1.1908chk2_cmp2_long:1909mov.l %a0,%a2 # save copy of <ea>1910bsr.l _dmem_read_long # fetch long lower bound19111912tst.l %d1 # dfetch error?1913bne.w chk2_cmp2_err_l # yes19141915mov.l %d0,%d3 # save long lower bound1916addq.l &0x4,%a21917mov.l %a2,%a0 # pass <ea> of long upper bound1918bsr.l _dmem_read_long # fetch long upper bound19191920tst.l %d1 # dfetch error?1921bne.w chk2_cmp2_err_l # yes19221923mov.l %d0,%d1 # long upper bound in d11924mov.l %d3,%d0 # long lower bound in d01925bra.w chk2_cmp2_compare # go do the compare emulation19261927# the bounds are word size. fetch them in one subroutine call by1928# reading a longword. sign extend both. if it's a data operation,1929# sign extend Rn to long, also.1930chk2_cmp2_word:1931mov.l %a0,%a21932bsr.l _dmem_read_long # fetch 2 word bounds19331934tst.l %d1 # dfetch error?1935bne.w chk2_cmp2_err_l # yes19361937mov.w %d0, %d1 # place hi in %d11938swap %d0 # place lo in %d019391940ext.l %d0 # sign extend lo bnd1941ext.l %d1 # sign extend hi bnd19421943btst &0x7, EXC_EXTWORD(%a6) # address compare?1944bne.w chk2_cmp2_compare # yes; don't sign extend19451946# operation is a data register compare.1947# sign extend word to long so we can do simple longword compares.1948ext.l %d2 # sign extend data word1949bra.w chk2_cmp2_compare # go emulate compare19501951# the bounds are byte size. fetch them in one subroutine call by1952# reading a word. sign extend both. if it's a data operation,1953# sign extend Rn to long, also.1954chk2_cmp2_byte:1955mov.l %a0,%a21956bsr.l _dmem_read_word # fetch 2 byte bounds19571958tst.l %d1 # dfetch error?1959bne.w chk2_cmp2_err_w # yes19601961mov.b %d0, %d1 # place hi in %d11962lsr.w &0x8, %d0 # place lo in %d019631964extb.l %d0 # sign extend lo bnd1965extb.l %d1 # sign extend hi bnd19661967btst &0x7, EXC_EXTWORD(%a6) # address compare?1968bne.b chk2_cmp2_compare # yes; don't sign extend19691970# operation is a data register compare.1971# sign extend byte to long so we can do simple longword compares.1972extb.l %d2 # sign extend data byte19731974#1975# To set the ccodes correctly:1976# (1) save 'Z' bit from (Rn - lo)1977# (2) save 'Z' and 'N' bits from ((hi - lo) - (Rn - hi))1978# (3) keep 'X', 'N', and 'V' from before instruction1979# (4) combine ccodes1980#1981chk2_cmp2_compare:1982sub.l %d0, %d2 # (Rn - lo)1983mov.w %cc, %d3 # fetch resulting ccodes1984andi.b &0x4, %d3 # keep 'Z' bit1985sub.l %d0, %d1 # (hi - lo)1986cmp.l %d1,%d2 # ((hi - lo) - (Rn - hi))19871988mov.w %cc, %d4 # fetch resulting ccodes1989or.b %d4, %d3 # combine w/ earlier ccodes1990andi.b &0x5, %d3 # keep 'Z' and 'N'19911992mov.w EXC_CC(%a6), %d4 # fetch old ccodes1993andi.b &0x1a, %d4 # keep 'X','N','V' bits1994or.b %d3, %d4 # insert new ccodes1995mov.w %d4, EXC_CC(%a6) # save new ccodes19961997btst &0x3, EXC_EXTWORD(%a6) # separate chk2,cmp21998bne.b chk2_finish # it's a chk219992000rts20012002# this code handles the only difference between chk2 and cmp2. chk2 would2003# have trapped out if the value was out of bounds. we check this by seeing2004# if the 'N' bit was set by the operation.2005chk2_finish:2006btst &0x0, %d4 # is 'N' bit set?2007bne.b chk2_trap # yes;chk2 should trap2008rts2009chk2_trap:2010mov.b &ichk_flg,SPCOND_FLG(%a6) # set "special case" flag2011rts20122013# if dmem_read_{long,word}() returns a fail message in d1, the package2014# must create an access error frame. here, we pass a skeleton fslw2015# and the failing address to the routine that creates the new frame.2016# FSLW:2017# read = true2018# size = longword2019# TM = data2020# software emulation error = true2021chk2_cmp2_err_l:2022mov.l %a2,%a0 # pass failing address2023mov.l &0x01010001,%d0 # pass fslw2024bra.l isp_dacc20252026# FSLW:2027# read = true2028# size = word2029# TM = data2030# software emulation error = true2031chk2_cmp2_err_w:2032mov.l %a2,%a0 # pass failing address2033mov.l &0x01410001,%d0 # pass fslw2034bra.l isp_dacc20352036#########################################################################2037# XDEF **************************************************************** #2038# _div64(): routine to emulate div{u,s}.l <ea>,Dr:Dq #2039# 64/32->32r:32q #2040# #2041# XREF **************************************************************** #2042# _calc_ea() - calculate effective address #2043# isp_iacc() - handle instruction access error exception #2044# isp_dacc() - handle data access error exception #2045# isp_restore() - restore An on access error w/ -() or ()+ #2046# #2047# INPUT *************************************************************** #2048# none #2049# #2050# OUTPUT ************************************************************** #2051# If exiting through isp_dacc... #2052# a0 = failing address #2053# d0 = FSLW #2054# else #2055# none #2056# #2057# ALGORITHM *********************************************************** #2058# First, decode the operand location. If it's in Dn, fetch from #2059# the stack. If it's in memory, use _calc_ea() to calculate the #2060# effective address. Use _dmem_read_long() to fetch at that address. #2061# Unless the operand is immediate data. Then use _imem_read_long(). #2062# Send failures to isp_dacc() or isp_iacc() as appropriate. #2063# If the operands are signed, make them unsigned and save the #2064# sign info for later. Separate out special cases like divide-by-zero #2065# or 32-bit divides if possible. Else, use a special math algorithm #2066# to calculate the result. #2067# Restore sign info if signed instruction. Set the condition #2068# codes. Set idbyz_flg in SPCOND_FLG if divisor was zero. Store the #2069# quotient and remainder in the appropriate data registers on the stack.#2070# #2071#########################################################################20722073set NDIVISOR, EXC_TEMP+0x02074set NDIVIDEND, EXC_TEMP+0x12075set NDRSAVE, EXC_TEMP+0x22076set NDQSAVE, EXC_TEMP+0x42077set DDSECOND, EXC_TEMP+0x62078set DDQUOTIENT, EXC_TEMP+0x82079set DDNORMAL, EXC_TEMP+0xc20802081global _div642082#############2083# div(u,s)l #2084#############2085_div64:2086mov.b EXC_OPWORD+1(%a6), %d02087andi.b &0x38, %d0 # extract src mode20882089bne.w dcontrolmodel_s # %dn dest or control mode?20902091mov.b EXC_OPWORD+1(%a6), %d0 # extract Dn from opcode2092andi.w &0x7, %d02093mov.l (EXC_DREGS,%a6,%d0.w*4), %d7 # fetch divisor from register20942095dgotsrcl:2096beq.w div64eq0 # divisor is = 0!!!20972098mov.b EXC_EXTWORD+1(%a6), %d0 # extract Dr from extword2099mov.b EXC_EXTWORD(%a6), %d1 # extract Dq from extword2100and.w &0x7, %d02101lsr.b &0x4, %d12102and.w &0x7, %d12103mov.w %d0, NDRSAVE(%a6) # save Dr for later2104mov.w %d1, NDQSAVE(%a6) # save Dq for later21052106# fetch %dr and %dq directly off stack since all regs are saved there2107mov.l (EXC_DREGS,%a6,%d0.w*4), %d5 # get dividend hi2108mov.l (EXC_DREGS,%a6,%d1.w*4), %d6 # get dividend lo21092110# separate signed and unsigned divide2111btst &0x3, EXC_EXTWORD(%a6) # signed or unsigned?2112beq.b dspecialcases # use positive divide21132114# save the sign of the divisor2115# make divisor unsigned if it's negative2116tst.l %d7 # chk sign of divisor2117slt NDIVISOR(%a6) # save sign of divisor2118bpl.b dsgndividend2119neg.l %d7 # complement negative divisor21202121# save the sign of the dividend2122# make dividend unsigned if it's negative2123dsgndividend:2124tst.l %d5 # chk sign of hi(dividend)2125slt NDIVIDEND(%a6) # save sign of dividend2126bpl.b dspecialcases21272128mov.w &0x0, %cc # clear 'X' cc bit2129negx.l %d6 # complement signed dividend2130negx.l %d521312132# extract some special cases:2133# - is (dividend == 0) ?2134# - is (hi(dividend) == 0 && (divisor <= lo(dividend))) ? (32-bit div)2135dspecialcases:2136tst.l %d5 # is (hi(dividend) == 0)2137bne.b dnormaldivide # no, so try it the long way21382139tst.l %d6 # is (lo(dividend) == 0), too2140beq.w ddone # yes, so (dividend == 0)21412142cmp.l %d7,%d6 # is (divisor <= lo(dividend))2143bls.b d32bitdivide # yes, so use 32 bit divide21442145exg %d5,%d6 # q = 0, r = dividend2146bra.w divfinish # can't divide, we're done.21472148d32bitdivide:2149tdivu.l %d7, %d5:%d6 # it's only a 32/32 bit div!21502151bra.b divfinish21522153dnormaldivide:2154# last special case:2155# - is hi(dividend) >= divisor ? if yes, then overflow2156cmp.l %d7,%d52157bls.b ddovf # answer won't fit in 32 bits21582159# perform the divide algorithm:2160bsr.l dclassical # do int divide21612162# separate into signed and unsigned finishes.2163divfinish:2164btst &0x3, EXC_EXTWORD(%a6) # do divs, divu separately2165beq.b ddone # divu has no processing!!!21662167# it was a divs.l, so ccode setting is a little more complicated...2168tst.b NDIVIDEND(%a6) # remainder has same sign2169beq.b dcc # as dividend.2170neg.l %d5 # sgn(rem) = sgn(dividend)2171dcc:2172mov.b NDIVISOR(%a6), %d02173eor.b %d0, NDIVIDEND(%a6) # chk if quotient is negative2174beq.b dqpos # branch to quot positive21752176# 0x80000000 is the largest number representable as a 32-bit negative2177# number. the negative of 0x80000000 is 0x80000000.2178cmpi.l %d6, &0x80000000 # will (-quot) fit in 32 bits?2179bhi.b ddovf21802181neg.l %d6 # make (-quot) 2's comp21822183bra.b ddone21842185dqpos:2186btst &0x1f, %d6 # will (+quot) fit in 32 bits?2187bne.b ddovf21882189ddone:2190# at this point, result is normal so ccodes are set based on result.2191mov.w EXC_CC(%a6), %cc2192tst.l %d6 # set %ccode bits2193mov.w %cc, EXC_CC(%a6)21942195mov.w NDRSAVE(%a6), %d0 # get Dr off stack2196mov.w NDQSAVE(%a6), %d1 # get Dq off stack21972198# if the register numbers are the same, only the quotient gets saved.2199# so, if we always save the quotient second, we save ourselves a cmp&beq2200mov.l %d5, (EXC_DREGS,%a6,%d0.w*4) # save remainder2201mov.l %d6, (EXC_DREGS,%a6,%d1.w*4) # save quotient22022203rts22042205ddovf:2206bset &0x1, EXC_CC+1(%a6) # 'V' set on overflow2207bclr &0x0, EXC_CC+1(%a6) # 'C' cleared on overflow22082209rts22102211div64eq0:2212andi.b &0x1e, EXC_CC+1(%a6) # clear 'C' bit on divbyzero2213ori.b &idbyz_flg,SPCOND_FLG(%a6) # set "special case" flag2214rts22152216###########################################################################2217#########################################################################2218# This routine uses the 'classical' Algorithm D from Donald Knuth's #2219# Art of Computer Programming, vol II, Seminumerical Algorithms. #2220# For this implementation b=2**16, and the target is U1U2U3U4/V1V2, #2221# where U,V are words of the quadword dividend and longword divisor, #2222# and U1, V1 are the most significant words. #2223# #2224# The most sig. longword of the 64 bit dividend must be in %d5, least #2225# in %d6. The divisor must be in the variable ddivisor, and the #2226# signed/unsigned flag ddusign must be set (0=unsigned,1=signed). #2227# The quotient is returned in %d6, remainder in %d5, unless the #2228# v (overflow) bit is set in the saved %ccr. If overflow, the dividend #2229# is unchanged. #2230#########################################################################2231dclassical:2232# if the divisor msw is 0, use simpler algorithm then the full blown2233# one at ddknuth:22342235cmpi.l %d7, &0xffff2236bhi.b ddknuth # go use D. Knuth algorithm22372238# Since the divisor is only a word (and larger than the mslw of the dividend),2239# a simpler algorithm may be used :2240# In the general case, four quotient words would be created by2241# dividing the divisor word into each dividend word. In this case,2242# the first two quotient words must be zero, or overflow would occur.2243# Since we already checked this case above, we can treat the most significant2244# longword of the dividend as (0) remainder (see Knuth) and merely complete2245# the last two divisions to get a quotient longword and word remainder:22462247clr.l %d12248swap %d5 # same as r*b if previous step rqd2249swap %d6 # get u3 to lsw position2250mov.w %d6, %d5 # rb + u322512252divu.w %d7, %d522532254mov.w %d5, %d1 # first quotient word2255swap %d6 # get u42256mov.w %d6, %d5 # rb + u422572258divu.w %d7, %d522592260swap %d12261mov.w %d5, %d1 # 2nd quotient 'digit'2262clr.w %d52263swap %d5 # now remainder2264mov.l %d1, %d6 # and quotient22652266rts22672268ddknuth:2269# In this algorithm, the divisor is treated as a 2 digit (word) number2270# which is divided into a 3 digit (word) dividend to get one quotient2271# digit (word). After subtraction, the dividend is shifted and the2272# process repeated. Before beginning, the divisor and quotient are2273# 'normalized' so that the process of estimating the quotient digit2274# will yield verifiably correct results..22752276clr.l DDNORMAL(%a6) # count of shifts for normalization2277clr.b DDSECOND(%a6) # clear flag for quotient digits2278clr.l %d1 # %d1 will hold trial quotient2279ddnchk:2280btst &31, %d7 # must we normalize? first word of2281bne.b ddnormalized # divisor (V1) must be >= 65536/22282addq.l &0x1, DDNORMAL(%a6) # count normalization shifts2283lsl.l &0x1, %d7 # shift the divisor2284lsl.l &0x1, %d6 # shift u4,u3 with overflow to u22285roxl.l &0x1, %d5 # shift u1,u22286bra.w ddnchk2287ddnormalized:22882289# Now calculate an estimate of the quotient words (msw first, then lsw).2290# The comments use subscripts for the first quotient digit determination.2291mov.l %d7, %d3 # divisor2292mov.l %d5, %d2 # dividend mslw2293swap %d22294swap %d32295cmp.w %d2, %d3 # V1 = U1 ?2296bne.b ddqcalc12297mov.w &0xffff, %d1 # use max trial quotient word2298bra.b ddadj02299ddqcalc1:2300mov.l %d5, %d123012302divu.w %d3, %d1 # use quotient of mslw/msw23032304andi.l &0x0000ffff, %d1 # zero any remainder2305ddadj0:23062307# now test the trial quotient and adjust. This step plus the2308# normalization assures (according to Knuth) that the trial2309# quotient will be at worst 1 too large.2310mov.l %d6, -(%sp)2311clr.w %d6 # word u3 left2312swap %d6 # in lsw position2313ddadj1: mov.l %d7, %d32314mov.l %d1, %d22315mulu.w %d7, %d2 # V2q2316swap %d32317mulu.w %d1, %d3 # V1q2318mov.l %d5, %d4 # U1U22319sub.l %d3, %d4 # U1U2 - V1q23202321swap %d423222323mov.w %d4,%d02324mov.w %d6,%d4 # insert lower word (U3)23252326tst.w %d0 # is upper word set?2327bne.w ddadjd123282329# add.l %d6, %d4 # (U1U2 - V1q) + U323302331cmp.l %d2, %d42332bls.b ddadjd1 # is V2q > (U1U2-V1q) + U3 ?2333subq.l &0x1, %d1 # yes, decrement and recheck2334bra.b ddadj12335ddadjd1:2336# now test the word by multiplying it by the divisor (V1V2) and comparing2337# the 3 digit (word) result with the current dividend words2338mov.l %d5, -(%sp) # save %d5 (%d6 already saved)2339mov.l %d1, %d62340swap %d6 # shift answer to ms 3 words2341mov.l %d7, %d52342bsr.l dmm22343mov.l %d5, %d2 # now %d2,%d3 are trial*divisor2344mov.l %d6, %d32345mov.l (%sp)+, %d5 # restore dividend2346mov.l (%sp)+, %d62347sub.l %d3, %d62348subx.l %d2, %d5 # subtract double precision2349bcc dd2nd # no carry, do next quotient digit2350subq.l &0x1, %d1 # q is one too large2351# need to add back divisor longword to current ms 3 digits of dividend2352# - according to Knuth, this is done only 2 out of 65536 times for random2353# divisor, dividend selection.2354clr.l %d22355mov.l %d7, %d32356swap %d32357clr.w %d3 # %d3 now ls word of divisor2358add.l %d3, %d6 # aligned with 3rd word of dividend2359addx.l %d2, %d52360mov.l %d7, %d32361clr.w %d3 # %d3 now ms word of divisor2362swap %d3 # aligned with 2nd word of dividend2363add.l %d3, %d52364dd2nd:2365tst.b DDSECOND(%a6) # both q words done?2366bne.b ddremain2367# first quotient digit now correct. store digit and shift the2368# (subtracted) dividend2369mov.w %d1, DDQUOTIENT(%a6)2370clr.l %d12371swap %d52372swap %d62373mov.w %d6, %d52374clr.w %d62375st DDSECOND(%a6) # second digit2376bra.w ddnormalized2377ddremain:2378# add 2nd word to quotient, get the remainder.2379mov.w %d1, DDQUOTIENT+2(%a6)2380# shift down one word/digit to renormalize remainder.2381mov.w %d5, %d62382swap %d62383swap %d52384mov.l DDNORMAL(%a6), %d7 # get norm shift count2385beq.b ddrn2386subq.l &0x1, %d7 # set for loop count2387ddnlp:2388lsr.l &0x1, %d5 # shift into %d62389roxr.l &0x1, %d62390dbf %d7, ddnlp2391ddrn:2392mov.l %d6, %d5 # remainder2393mov.l DDQUOTIENT(%a6), %d6 # quotient23942395rts2396dmm2:2397# factors for the 32X32->64 multiplication are in %d5 and %d6.2398# returns 64 bit result in %d5 (hi) %d6(lo).2399# destroys %d2,%d3,%d4.24002401# multiply hi,lo words of each factor to get 4 intermediate products2402mov.l %d6, %d22403mov.l %d6, %d32404mov.l %d5, %d42405swap %d32406swap %d42407mulu.w %d5, %d6 # %d6 <- lsw*lsw2408mulu.w %d3, %d5 # %d5 <- msw-dest*lsw-source2409mulu.w %d4, %d2 # %d2 <- msw-source*lsw-dest2410mulu.w %d4, %d3 # %d3 <- msw*msw2411# now use swap and addx to consolidate to two longwords2412clr.l %d42413swap %d62414add.w %d5, %d6 # add msw of l*l to lsw of m*l product2415addx.w %d4, %d3 # add any carry to m*m product2416add.w %d2, %d6 # add in lsw of other m*l product2417addx.w %d4, %d3 # add any carry to m*m product2418swap %d6 # %d6 is low 32 bits of final product2419clr.w %d52420clr.w %d2 # lsw of two mixed products used,2421swap %d5 # now use msws of longwords2422swap %d22423add.l %d2, %d52424add.l %d3, %d5 # %d5 now ms 32 bits of final product2425rts24262427##########2428dcontrolmodel_s:2429movq.l &LONG,%d02430bsr.l _calc_ea # calc <ea>24312432cmpi.b SPCOND_FLG(%a6),&immed_flg # immediate addressing mode?2433beq.b dimmed # yes24342435mov.l %a0,%a22436bsr.l _dmem_read_long # fetch divisor from <ea>24372438tst.l %d1 # dfetch error?2439bne.b div64_err # yes24402441mov.l %d0, %d72442bra.w dgotsrcl24432444# we have to split out immediate data here because it must be read using2445# imem_read() instead of dmem_read(). this becomes especially important2446# if the fetch runs into some deadly fault.2447dimmed:2448addq.l &0x4,EXC_EXTWPTR(%a6)2449bsr.l _imem_read_long # read immediate value24502451tst.l %d1 # ifetch error?2452bne.l isp_iacc # yes24532454mov.l %d0,%d72455bra.w dgotsrcl24562457##########24582459# if dmem_read_long() returns a fail message in d1, the package2460# must create an access error frame. here, we pass a skeleton fslw2461# and the failing address to the routine that creates the new frame.2462# also, we call isp_restore in case the effective addressing mode was2463# (an)+ or -(an) in which case the previous "an" value must be restored.2464# FSLW:2465# read = true2466# size = longword2467# TM = data2468# software emulation error = true2469div64_err:2470bsr.l isp_restore # restore addr reg2471mov.l %a2,%a0 # pass failing address2472mov.l &0x01010001,%d0 # pass fslw2473bra.l isp_dacc24742475#########################################################################2476# XDEF **************************************************************** #2477# _mul64(): routine to emulate mul{u,s}.l <ea>,Dh:Dl 32x32->64 #2478# #2479# XREF **************************************************************** #2480# _calc_ea() - calculate effective address #2481# isp_iacc() - handle instruction access error exception #2482# isp_dacc() - handle data access error exception #2483# isp_restore() - restore An on access error w/ -() or ()+ #2484# #2485# INPUT *************************************************************** #2486# none #2487# #2488# OUTPUT ************************************************************** #2489# If exiting through isp_dacc... #2490# a0 = failing address #2491# d0 = FSLW #2492# else #2493# none #2494# #2495# ALGORITHM *********************************************************** #2496# First, decode the operand location. If it's in Dn, fetch from #2497# the stack. If it's in memory, use _calc_ea() to calculate the #2498# effective address. Use _dmem_read_long() to fetch at that address. #2499# Unless the operand is immediate data. Then use _imem_read_long(). #2500# Send failures to isp_dacc() or isp_iacc() as appropriate. #2501# If the operands are signed, make them unsigned and save the #2502# sign info for later. Perform the multiplication using 16x16->32 #2503# unsigned multiplies and "add" instructions. Store the high and low #2504# portions of the result in the appropriate data registers on the #2505# stack. Calculate the condition codes, also. #2506# #2507#########################################################################25082509#############2510# mul(u,s)l #2511#############2512global _mul642513_mul64:2514mov.b EXC_OPWORD+1(%a6), %d0 # extract src {mode,reg}2515cmpi.b %d0, &0x7 # is src mode Dn or other?2516bgt.w mul64_memop # src is in memory25172518# multiplier operand in the data register file.2519# must extract the register number and fetch the operand from the stack.2520mul64_regop:2521andi.w &0x7, %d0 # extract Dn2522mov.l (EXC_DREGS,%a6,%d0.w*4), %d3 # fetch multiplier25232524# multiplier is in %d3. now, extract Dl and Dh fields and fetch the2525# multiplicand from the data register specified by Dl.2526mul64_multiplicand:2527mov.w EXC_EXTWORD(%a6), %d2 # fetch ext word2528clr.w %d1 # clear Dh reg2529mov.b %d2, %d1 # grab Dh2530rol.w &0x4, %d2 # align Dl byte2531andi.w &0x7, %d2 # extract Dl25322533mov.l (EXC_DREGS,%a6,%d2.w*4), %d4 # get multiplicand25342535# check for the case of "zero" result early2536tst.l %d4 # test multiplicand2537beq.w mul64_zero # handle zero separately2538tst.l %d3 # test multiplier2539beq.w mul64_zero # handle zero separately25402541# multiplier is in %d3 and multiplicand is in %d4.2542# if the operation is to be signed, then the operands are converted2543# to unsigned and the result sign is saved for the end.2544clr.b EXC_TEMP(%a6) # clear temp space2545btst &0x3, EXC_EXTWORD(%a6) # signed or unsigned?2546beq.b mul64_alg # unsigned; skip sgn calc25472548tst.l %d3 # is multiplier negative?2549bge.b mul64_chk_md_sgn # no2550neg.l %d3 # make multiplier positive2551ori.b &0x1, EXC_TEMP(%a6) # save multiplier sgn25522553# the result sign is the exclusive or of the operand sign bits.2554mul64_chk_md_sgn:2555tst.l %d4 # is multiplicand negative?2556bge.b mul64_alg # no2557neg.l %d4 # make multiplicand positive2558eori.b &0x1, EXC_TEMP(%a6) # calculate correct sign25592560#########################################################################2561# 63 32 0 #2562# ---------------------------- #2563# | hi(mplier) * hi(mplicand)| #2564# ---------------------------- #2565# ----------------------------- #2566# | hi(mplier) * lo(mplicand) | #2567# ----------------------------- #2568# ----------------------------- #2569# | lo(mplier) * hi(mplicand) | #2570# ----------------------------- #2571# | ----------------------------- #2572# --|-- | lo(mplier) * lo(mplicand) | #2573# | ----------------------------- #2574# ======================================================== #2575# -------------------------------------------------------- #2576# | hi(result) | lo(result) | #2577# -------------------------------------------------------- #2578#########################################################################2579mul64_alg:2580# load temp registers with operands2581mov.l %d3, %d5 # mr in %d52582mov.l %d3, %d6 # mr in %d62583mov.l %d4, %d7 # md in %d72584swap %d6 # hi(mr) in lo %d62585swap %d7 # hi(md) in lo %d725862587# complete necessary multiplies:2588mulu.w %d4, %d3 # [1] lo(mr) * lo(md)2589mulu.w %d6, %d4 # [2] hi(mr) * lo(md)2590mulu.w %d7, %d5 # [3] lo(mr) * hi(md)2591mulu.w %d7, %d6 # [4] hi(mr) * hi(md)25922593# add lo portions of [2],[3] to hi portion of [1].2594# add carries produced from these adds to [4].2595# lo([1]) is the final lo 16 bits of the result.2596clr.l %d7 # load %d7 w/ zero value2597swap %d3 # hi([1]) <==> lo([1])2598add.w %d4, %d3 # hi([1]) + lo([2])2599addx.l %d7, %d6 # [4] + carry2600add.w %d5, %d3 # hi([1]) + lo([3])2601addx.l %d7, %d6 # [4] + carry2602swap %d3 # lo([1]) <==> hi([1])26032604# lo portions of [2],[3] have been added in to final result.2605# now, clear lo, put hi in lo reg, and add to [4]2606clr.w %d4 # clear lo([2])2607clr.w %d5 # clear hi([3])2608swap %d4 # hi([2]) in lo %d42609swap %d5 # hi([3]) in lo %d52610add.l %d5, %d4 # [4] + hi([2])2611add.l %d6, %d4 # [4] + hi([3])26122613# unsigned result is now in {%d4,%d3}2614tst.b EXC_TEMP(%a6) # should result be signed?2615beq.b mul64_done # no26162617# result should be a signed negative number.2618# compute 2's complement of the unsigned number:2619# -negate all bits and add 12620mul64_neg:2621not.l %d3 # negate lo(result) bits2622not.l %d4 # negate hi(result) bits2623addq.l &1, %d3 # add 1 to lo(result)2624addx.l %d7, %d4 # add carry to hi(result)26252626# the result is saved to the register file.2627# for '040 compatibility, if Dl == Dh then only the hi(result) is2628# saved. so, saving hi after lo accomplishes this without need to2629# check Dl,Dh equality.2630mul64_done:2631mov.l %d3, (EXC_DREGS,%a6,%d2.w*4) # save lo(result)2632mov.w &0x0, %cc2633mov.l %d4, (EXC_DREGS,%a6,%d1.w*4) # save hi(result)26342635# now, grab the condition codes. only one that can be set is 'N'.2636# 'N' CAN be set if the operation is unsigned if bit 63 is set.2637mov.w %cc, %d7 # fetch %ccr to see if 'N' set2638andi.b &0x8, %d7 # extract 'N' bit26392640mul64_ccode_set:2641mov.b EXC_CC+1(%a6), %d6 # fetch previous %ccr2642andi.b &0x10, %d6 # all but 'X' bit changes26432644or.b %d7, %d6 # group 'X' and 'N'2645mov.b %d6, EXC_CC+1(%a6) # save new %ccr26462647rts26482649# one or both of the operands is zero so the result is also zero.2650# save the zero result to the register file and set the 'Z' ccode bit.2651mul64_zero:2652clr.l (EXC_DREGS,%a6,%d2.w*4) # save lo(result)2653clr.l (EXC_DREGS,%a6,%d1.w*4) # save hi(result)26542655movq.l &0x4, %d7 # set 'Z' ccode bit2656bra.b mul64_ccode_set # finish ccode set26572658##########26592660# multiplier operand is in memory at the effective address.2661# must calculate the <ea> and go fetch the 32-bit operand.2662mul64_memop:2663movq.l &LONG, %d0 # pass # of bytes2664bsr.l _calc_ea # calculate <ea>26652666cmpi.b SPCOND_FLG(%a6),&immed_flg # immediate addressing mode?2667beq.b mul64_immed # yes26682669mov.l %a0,%a22670bsr.l _dmem_read_long # fetch src from addr (%a0)26712672tst.l %d1 # dfetch error?2673bne.w mul64_err # yes26742675mov.l %d0, %d3 # store multiplier in %d326762677bra.w mul64_multiplicand26782679# we have to split out immediate data here because it must be read using2680# imem_read() instead of dmem_read(). this becomes especially important2681# if the fetch runs into some deadly fault.2682mul64_immed:2683addq.l &0x4,EXC_EXTWPTR(%a6)2684bsr.l _imem_read_long # read immediate value26852686tst.l %d1 # ifetch error?2687bne.l isp_iacc # yes26882689mov.l %d0,%d32690bra.w mul64_multiplicand26912692##########26932694# if dmem_read_long() returns a fail message in d1, the package2695# must create an access error frame. here, we pass a skeleton fslw2696# and the failing address to the routine that creates the new frame.2697# also, we call isp_restore in case the effective addressing mode was2698# (an)+ or -(an) in which case the previous "an" value must be restored.2699# FSLW:2700# read = true2701# size = longword2702# TM = data2703# software emulation error = true2704mul64_err:2705bsr.l isp_restore # restore addr reg2706mov.l %a2,%a0 # pass failing address2707mov.l &0x01010001,%d0 # pass fslw2708bra.l isp_dacc27092710#########################################################################2711# XDEF **************************************************************** #2712# _compandset2(): routine to emulate cas2() #2713# (internal to package) #2714# #2715# _isp_cas2_finish(): store ccodes, store compare regs #2716# (external to package) #2717# #2718# XREF **************************************************************** #2719# _real_lock_page() - "callout" to lock op's page from page-outs #2720# _cas_terminate2() - access error exit #2721# _real_cas2() - "callout" to core cas2 emulation code #2722# _real_unlock_page() - "callout" to unlock page #2723# #2724# INPUT *************************************************************** #2725# _compandset2(): #2726# d0 = instruction extension word #2727# #2728# _isp_cas2_finish(): #2729# see cas2 core emulation code #2730# #2731# OUTPUT ************************************************************** #2732# _compandset2(): #2733# see cas2 core emulation code #2734# #2735# _isp_cas_finish(): #2736# None (register file or memroy changed as appropriate) #2737# #2738# ALGORITHM *********************************************************** #2739# compandset2(): #2740# Decode the instruction and fetch the appropriate Update and #2741# Compare operands. Then call the "callout" _real_lock_page() for each #2742# memory operand address so that the operating system can keep these #2743# pages from being paged out. If either _real_lock_page() fails, exit #2744# through _cas_terminate2(). Don't forget to unlock the 1st locked page #2745# using _real_unlock_paged() if the 2nd lock-page fails. #2746# Finally, branch to the core cas2 emulation code by calling the #2747# "callout" _real_cas2(). #2748# #2749# _isp_cas2_finish(): #2750# Re-perform the comparison so we can determine the condition #2751# codes which were too much trouble to keep around during the locked #2752# emulation. Then unlock each operands page by calling the "callout" #2753# _real_unlock_page(). #2754# #2755#########################################################################27562757set ADDR1, EXC_TEMP+0xc2758set ADDR2, EXC_TEMP+0x02759set DC2, EXC_TEMP+0xa2760set DC1, EXC_TEMP+0x827612762global _compandset22763_compandset2:2764mov.l %d0,EXC_TEMP+0x4(%a6) # store for possible restart2765mov.l %d0,%d1 # extension word in d027662767rol.w &0x4,%d02768andi.w &0xf,%d0 # extract Rn22769mov.l (EXC_DREGS,%a6,%d0.w*4),%a1 # fetch ADDR22770mov.l %a1,ADDR2(%a6)27712772mov.l %d1,%d027732774lsr.w &0x6,%d12775andi.w &0x7,%d1 # extract Du22776mov.l (EXC_DREGS,%a6,%d1.w*4),%d5 # fetch Update2 Op27772778andi.w &0x7,%d0 # extract Dc22779mov.l (EXC_DREGS,%a6,%d0.w*4),%d3 # fetch Compare2 Op2780mov.w %d0,DC2(%a6)27812782mov.w EXC_EXTWORD(%a6),%d02783mov.l %d0,%d127842785rol.w &0x4,%d02786andi.w &0xf,%d0 # extract Rn12787mov.l (EXC_DREGS,%a6,%d0.w*4),%a0 # fetch ADDR12788mov.l %a0,ADDR1(%a6)27892790mov.l %d1,%d027912792lsr.w &0x6,%d12793andi.w &0x7,%d1 # extract Du12794mov.l (EXC_DREGS,%a6,%d1.w*4),%d4 # fetch Update1 Op27952796andi.w &0x7,%d0 # extract Dc12797mov.l (EXC_DREGS,%a6,%d0.w*4),%d2 # fetch Compare1 Op2798mov.w %d0,DC1(%a6)27992800btst &0x1,EXC_OPWORD(%a6) # word or long?2801sne %d728022803btst &0x5,EXC_ISR(%a6) # user or supervisor?2804sne %d628052806mov.l %a0,%a22807mov.l %a1,%a328082809mov.l %d7,%d1 # pass size2810mov.l %d6,%d0 # pass mode2811bsr.l _real_lock_page # lock page2812mov.l %a2,%a02813tst.l %d0 # error?2814bne.l _cas_terminate2 # yes28152816mov.l %d7,%d1 # pass size2817mov.l %d6,%d0 # pass mode2818mov.l %a3,%a0 # pass addr2819bsr.l _real_lock_page # lock page2820mov.l %a3,%a02821tst.l %d0 # error?2822bne.b cas_preterm # yes28232824mov.l %a2,%a02825mov.l %a3,%a128262827bra.l _real_cas228282829# if the 2nd lock attempt fails, then we must still unlock the2830# first page(s).2831cas_preterm:2832mov.l %d0,-(%sp) # save FSLW2833mov.l %d7,%d1 # pass size2834mov.l %d6,%d0 # pass mode2835mov.l %a2,%a0 # pass ADDR12836bsr.l _real_unlock_page # unlock first page(s)2837mov.l (%sp)+,%d0 # restore FSLW2838mov.l %a3,%a0 # pass failing addr2839bra.l _cas_terminate228402841#############################################################28422843global _isp_cas2_finish2844_isp_cas2_finish:2845btst &0x1,EXC_OPWORD(%a6)2846bne.b cas2_finish_l28472848mov.w EXC_CC(%a6),%cc # load old ccodes2849cmp.w %d0,%d22850bne.b cas2_finish_w_save2851cmp.w %d1,%d32852cas2_finish_w_save:2853mov.w %cc,EXC_CC(%a6) # save new ccodes28542855tst.b %d4 # update compare reg?2856bne.b cas2_finish_w_done # no28572858mov.w DC2(%a6),%d3 # fetch Dc22859mov.w %d1,(2+EXC_DREGS,%a6,%d3.w*4) # store new Compare2 Op28602861mov.w DC1(%a6),%d2 # fetch Dc12862mov.w %d0,(2+EXC_DREGS,%a6,%d2.w*4) # store new Compare1 Op28632864cas2_finish_w_done:2865btst &0x5,EXC_ISR(%a6)2866sne %d22867mov.l %d2,%d0 # pass mode2868sf %d1 # pass size2869mov.l ADDR1(%a6),%a0 # pass ADDR12870bsr.l _real_unlock_page # unlock page28712872mov.l %d2,%d0 # pass mode2873sf %d1 # pass size2874mov.l ADDR2(%a6),%a0 # pass ADDR22875bsr.l _real_unlock_page # unlock page2876rts28772878cas2_finish_l:2879mov.w EXC_CC(%a6),%cc # load old ccodes2880cmp.l %d0,%d22881bne.b cas2_finish_l_save2882cmp.l %d1,%d32883cas2_finish_l_save:2884mov.w %cc,EXC_CC(%a6) # save new ccodes28852886tst.b %d4 # update compare reg?2887bne.b cas2_finish_l_done # no28882889mov.w DC2(%a6),%d3 # fetch Dc22890mov.l %d1,(EXC_DREGS,%a6,%d3.w*4) # store new Compare2 Op28912892mov.w DC1(%a6),%d2 # fetch Dc12893mov.l %d0,(EXC_DREGS,%a6,%d2.w*4) # store new Compare1 Op28942895cas2_finish_l_done:2896btst &0x5,EXC_ISR(%a6)2897sne %d22898mov.l %d2,%d0 # pass mode2899st %d1 # pass size2900mov.l ADDR1(%a6),%a0 # pass ADDR12901bsr.l _real_unlock_page # unlock page29022903mov.l %d2,%d0 # pass mode2904st %d1 # pass size2905mov.l ADDR2(%a6),%a0 # pass ADDR22906bsr.l _real_unlock_page # unlock page2907rts29082909########2910global cr_cas22911cr_cas2:2912mov.l EXC_TEMP+0x4(%a6),%d02913bra.w _compandset229142915#########################################################################2916# XDEF **************************************************************** #2917# _compandset(): routine to emulate cas w/ misaligned <ea> #2918# (internal to package) #2919# _isp_cas_finish(): routine called when cas emulation completes #2920# (external and internal to package) #2921# _isp_cas_restart(): restart cas emulation after a fault #2922# (external to package) #2923# _isp_cas_terminate(): create access error stack frame on fault #2924# (external and internal to package) #2925# _isp_cas_inrange(): checks whether instr addess is within range #2926# of core cas/cas2emulation code #2927# (external to package) #2928# #2929# XREF **************************************************************** #2930# _calc_ea(): calculate effective address #2931# #2932# INPUT *************************************************************** #2933# compandset(): #2934# none #2935# _isp_cas_restart(): #2936# d6 = previous sfc/dfc #2937# _isp_cas_finish(): #2938# _isp_cas_terminate(): #2939# a0 = failing address #2940# d0 = FSLW #2941# d6 = previous sfc/dfc #2942# _isp_cas_inrange(): #2943# a0 = instruction address to be checked #2944# #2945# OUTPUT ************************************************************** #2946# compandset(): #2947# none #2948# _isp_cas_restart(): #2949# a0 = effective address #2950# d7 = word or longword flag #2951# _isp_cas_finish(): #2952# a0 = effective address #2953# _isp_cas_terminate(): #2954# initial register set before emulation exception #2955# _isp_cas_inrange(): #2956# d0 = 0 => in range; -1 => out of range #2957# #2958# ALGORITHM *********************************************************** #2959# #2960# compandset(): #2961# First, calculate the effective address. Then, decode the #2962# instruction word and fetch the "compare" (DC) and "update" (Du) #2963# operands. #2964# Next, call the external routine _real_lock_page() so that the #2965# operating system can keep this page from being paged out while we're #2966# in this routine. If this call fails, jump to _cas_terminate2(). #2967# The routine then branches to _real_cas(). This external routine #2968# that actually emulates cas can be supplied by the external os or #2969# made to point directly back into the 060ISP which has a routine for #2970# this purpose. #2971# #2972# _isp_cas_finish(): #2973# Either way, after emulation, the package is re-entered at #2974# _isp_cas_finish(). This routine re-compares the operands in order to #2975# set the condition codes. Finally, these routines will call #2976# _real_unlock_page() in order to unlock the pages that were previously #2977# locked. #2978# #2979# _isp_cas_restart(): #2980# This routine can be entered from an access error handler where #2981# the emulation sequence should be re-started from the beginning. #2982# #2983# _isp_cas_terminate(): #2984# This routine can be entered from an access error handler where #2985# an emulation operand access failed and the operating system would #2986# like an access error stack frame created instead of the current #2987# unimplemented integer instruction frame. #2988# Also, the package enters here if a call to _real_lock_page() #2989# fails. #2990# #2991# _isp_cas_inrange(): #2992# Checks to see whether the instruction address passed to it in #2993# a0 is within the software package cas/cas2 emulation routines. This #2994# can be helpful for an operating system to determine whether an access #2995# error during emulation was due to a cas/cas2 emulation access. #2996# #2997#########################################################################29982999set DC, EXC_TEMP+0x83000set ADDR, EXC_TEMP+0x430013002global _compandset3003_compandset:3004btst &0x1,EXC_OPWORD(%a6) # word or long operation?3005bne.b compandsetl # long30063007compandsetw:3008movq.l &0x2,%d0 # size = 2 bytes3009bsr.l _calc_ea # a0 = calculated <ea>3010mov.l %a0,ADDR(%a6) # save <ea> for possible restart3011sf %d7 # clear d7 for word size3012bra.b compandsetfetch30133014compandsetl:3015movq.l &0x4,%d0 # size = 4 bytes3016bsr.l _calc_ea # a0 = calculated <ea>3017mov.l %a0,ADDR(%a6) # save <ea> for possible restart3018st %d7 # set d7 for longword size30193020compandsetfetch:3021mov.w EXC_EXTWORD(%a6),%d0 # fetch cas extension word3022mov.l %d0,%d1 # make a copy30233024lsr.w &0x6,%d03025andi.w &0x7,%d0 # extract Du3026mov.l (EXC_DREGS,%a6,%d0.w*4),%d2 # get update operand30273028andi.w &0x7,%d1 # extract Dc3029mov.l (EXC_DREGS,%a6,%d1.w*4),%d4 # get compare operand3030mov.w %d1,DC(%a6) # save Dc30313032btst &0x5,EXC_ISR(%a6) # which mode for exception?3033sne %d6 # set on supervisor mode30343035mov.l %a0,%a2 # save temporarily3036mov.l %d7,%d1 # pass size3037mov.l %d6,%d0 # pass mode3038bsr.l _real_lock_page # lock page3039tst.l %d0 # did error occur?3040bne.w _cas_terminate2 # yes, clean up the mess3041mov.l %a2,%a0 # pass addr in a030423043bra.l _real_cas30443045########3046global _isp_cas_finish3047_isp_cas_finish:3048btst &0x1,EXC_OPWORD(%a6)3049bne.b cas_finish_l30503051# just do the compare again since it's faster than saving the ccodes3052# from the locked routine...3053cas_finish_w:3054mov.w EXC_CC(%a6),%cc # restore cc3055cmp.w %d0,%d4 # do word compare3056mov.w %cc,EXC_CC(%a6) # save cc30573058tst.b %d1 # update compare reg?3059bne.b cas_finish_w_done # no30603061mov.w DC(%a6),%d33062mov.w %d0,(EXC_DREGS+2,%a6,%d3.w*4) # Dc = destination30633064cas_finish_w_done:3065mov.l ADDR(%a6),%a0 # pass addr3066sf %d1 # pass size3067btst &0x5,EXC_ISR(%a6)3068sne %d0 # pass mode3069bsr.l _real_unlock_page # unlock page3070rts30713072# just do the compare again since it's faster than saving the ccodes3073# from the locked routine...3074cas_finish_l:3075mov.w EXC_CC(%a6),%cc # restore cc3076cmp.l %d0,%d4 # do longword compare3077mov.w %cc,EXC_CC(%a6) # save cc30783079tst.b %d1 # update compare reg?3080bne.b cas_finish_l_done # no30813082mov.w DC(%a6),%d33083mov.l %d0,(EXC_DREGS,%a6,%d3.w*4) # Dc = destination30843085cas_finish_l_done:3086mov.l ADDR(%a6),%a0 # pass addr3087st %d1 # pass size3088btst &0x5,EXC_ISR(%a6)3089sne %d0 # pass mode3090bsr.l _real_unlock_page # unlock page3091rts30923093########30943095global _isp_cas_restart3096_isp_cas_restart:3097mov.l %d6,%sfc # restore previous sfc3098mov.l %d6,%dfc # restore previous dfc30993100cmpi.b EXC_OPWORD+1(%a6),&0xfc # cas or cas2?3101beq.l cr_cas2 # cas23102cr_cas:3103mov.l ADDR(%a6),%a0 # load <ea>3104btst &0x1,EXC_OPWORD(%a6) # word or long operation?3105sne %d7 # set d7 accordingly3106bra.w compandsetfetch31073108########31093110# At this stage, it would be nice if d0 held the FSLW.3111global _isp_cas_terminate3112_isp_cas_terminate:3113mov.l %d6,%sfc # restore previous sfc3114mov.l %d6,%dfc # restore previous dfc31153116global _cas_terminate23117_cas_terminate2:3118mov.l %a0,%a2 # copy failing addr to a231193120mov.l %d0,-(%sp)3121bsr.l isp_restore # restore An (if ()+ or -())3122mov.l (%sp)+,%d031233124addq.l &0x4,%sp # remove sub return addr3125subq.l &0x8,%sp # make room for bigger stack3126subq.l &0x8,%a6 # shift frame ptr down, too3127mov.l &26,%d1 # want to move 51 longwords3128lea 0x8(%sp),%a0 # get address of old stack3129lea 0x0(%sp),%a1 # get address of new stack3130cas_term_cont:3131mov.l (%a0)+,(%a1)+ # move a longword3132dbra.w %d1,cas_term_cont # keep going31333134mov.w &0x4008,EXC_IVOFF(%a6) # put new stk fmt, voff3135mov.l %a2,EXC_IVOFF+0x2(%a6) # put faulting addr on stack3136mov.l %d0,EXC_IVOFF+0x6(%a6) # put FSLW on stack3137movm.l EXC_DREGS(%a6),&0x3fff # restore user regs3138unlk %a6 # unlink stack frame3139bra.l _real_access31403141########31423143global _isp_cas_inrange3144_isp_cas_inrange:3145clr.l %d0 # clear return result3146lea _CASHI(%pc),%a1 # load end of CAS core code3147cmp.l %a1,%a0 # is PC in range?3148blt.b cin_no # no3149lea _CASLO(%pc),%a1 # load begin of CAS core code3150cmp.l %a0,%a1 # is PC in range?3151blt.b cin_no # no3152rts # yes; return d0 = 03153cin_no:3154mov.l &-0x1,%d0 # out of range; return d0 = -13155rts31563157#################################################################3158#################################################################3159#################################################################3160# This is the start of the cas and cas2 "core" emulation code. #3161# This is the section that may need to be replaced by the host #3162# OS if it is too operating system-specific. #3163# Please refer to the package documentation to see how to #3164# "replace" this section, if necessary. #3165#################################################################3166#################################################################3167#################################################################31683169# ###### ## ###### ####3170# # # # # # #3171# # ###### ###### #3172# # # # # #3173# ###### # # ###### ######31743175#########################################################################3176# XDEF **************************************************************** #3177# _isp_cas2(): "core" emulation code for the cas2 instruction #3178# #3179# XREF **************************************************************** #3180# _isp_cas2_finish() - only exit point for this emulation code; #3181# do clean-up; calculate ccodes; store #3182# Compare Ops if appropriate. #3183# #3184# INPUT *************************************************************** #3185# *see chart below* #3186# #3187# OUTPUT ************************************************************** #3188# *see chart below* #3189# #3190# ALGORITHM *********************************************************** #3191# (1) Make several copies of the effective address. #3192# (2) Save current SR; Then mask off all maskable interrupts. #3193# (3) Save current SFC/DFC (ASSUMED TO BE EQUAL!!!); Then set #3194# according to whether exception occurred in user or #3195# supervisor mode. #3196# (4) Use "plpaw" instruction to pre-load ATC with effective #3197# address pages(s). THIS SHOULD NOT FAULT!!! The relevant #3198# page(s) should have already been made resident prior to #3199# entering this routine. #3200# (5) Push the operand lines from the cache w/ "cpushl". #3201# In the 68040, this was done within the locked region. In #3202# the 68060, it is done outside of the locked region. #3203# (6) Use "plpar" instruction to do a re-load of ATC entries for #3204# ADDR1 since ADDR2 entries may have pushed ADDR1 out of the #3205# ATC. #3206# (7) Pre-fetch the core emulation instructions by executing #3207# one branch within each physical line (16 bytes) of the code #3208# before actually executing the code. #3209# (8) Load the BUSCR w/ the bus lock value. #3210# (9) Fetch the source operands using "moves". #3211# (10)Do the compares. If both equal, go to step (13). #3212# (11)Unequal. No update occurs. But, we do write the DST1 op #3213# back to itself (as w/ the '040) so we can gracefully unlock #3214# the bus (and assert LOCKE*) using BUSCR and the final move. #3215# (12)Exit. #3216# (13)Write update operand to the DST locations. Use BUSCR to #3217# assert LOCKE* for the final write operation. #3218# (14)Exit. #3219# #3220# The algorithm is actually implemented slightly differently #3221# depending on the size of the operation and the misalignment of the #3222# operands. A misaligned operand must be written in aligned chunks or #3223# else the BUSCR register control gets confused. #3224# #3225#########################################################################32263227#################################################################3228# THIS IS THE STATE OF THE INTEGER REGISTER FILE UPON #3229# ENTERING _isp_cas2(). #3230# #3231# D0 = xxxxxxxx #3232# D1 = xxxxxxxx #3233# D2 = cmp operand 1 #3234# D3 = cmp operand 2 #3235# D4 = update oper 1 #3236# D5 = update oper 2 #3237# D6 = 'xxxxxxff if supervisor mode; 'xxxxxx00 if user mode #3238# D7 = 'xxxxxxff if longword operation; 'xxxxxx00 if word #3239# A0 = ADDR1 #3240# A1 = ADDR2 #3241# A2 = xxxxxxxx #3242# A3 = xxxxxxxx #3243# A4 = xxxxxxxx #3244# A5 = xxxxxxxx #3245# A6 = frame pointer #3246# A7 = stack pointer #3247#################################################################32483249# align 0x10003250# beginning label used by _isp_cas_inrange()3251global _CASLO3252_CASLO:32533254global _isp_cas23255_isp_cas2:3256tst.b %d6 # user or supervisor mode?3257bne.b cas2_supervisor # supervisor3258cas2_user:3259movq.l &0x1,%d0 # load user data fc3260bra.b cas2_cont3261cas2_supervisor:3262movq.l &0x5,%d0 # load supervisor data fc3263cas2_cont:3264tst.b %d7 # word or longword?3265beq.w cas2w # word32663267####3268cas2l:3269mov.l %a0,%a2 # copy ADDR13270mov.l %a1,%a3 # copy ADDR23271mov.l %a0,%a4 # copy ADDR13272mov.l %a1,%a5 # copy ADDR232733274addq.l &0x3,%a4 # ADDR1+33275addq.l &0x3,%a5 # ADDR2+33276mov.l %a2,%d1 # ADDR132773278# mask interrupts levels 0-6. save old mask value.3279mov.w %sr,%d7 # save current SR3280ori.w &0x0700,%sr # inhibit interrupts32813282# load the SFC and DFC with the appropriate mode.3283movc %sfc,%d6 # save old SFC/DFC3284movc %d0,%sfc # store new SFC3285movc %d0,%dfc # store new DFC32863287# pre-load the operand ATC. no page faults should occur here because3288# _real_lock_page() should have taken care of this.3289plpaw (%a2) # load atc for ADDR13290plpaw (%a4) # load atc for ADDR1+33291plpaw (%a3) # load atc for ADDR23292plpaw (%a5) # load atc for ADDR2+332933294# push the operand lines from the cache if they exist.3295cpushl %dc,(%a2) # push line for ADDR13296cpushl %dc,(%a4) # push line for ADDR1+33297cpushl %dc,(%a3) # push line for ADDR23298cpushl %dc,(%a5) # push line for ADDR2+232993300mov.l %d1,%a2 # ADDR13301addq.l &0x3,%d13302mov.l %d1,%a4 # ADDR1+33303# if ADDR1 was ATC resident before the above "plpaw" and was executed3304# and it was the next entry scheduled for replacement and ADDR23305# shares the same set, then the "plpaw" for ADDR2 can push the ADDR13306# entries from the ATC. so, we do a second set of "plpa"s.3307plpar (%a2) # load atc for ADDR13308plpar (%a4) # load atc for ADDR1+333093310# load the BUSCR values.3311mov.l &0x80000000,%a2 # assert LOCK* buscr value3312mov.l &0xa0000000,%a3 # assert LOCKE* buscr value3313mov.l &0x00000000,%a4 # buscr unlock value33143315# there are three possible mis-aligned cases for longword cas. they3316# are separated because the final write which asserts LOCKE* must3317# be aligned.3318mov.l %a0,%d0 # is ADDR1 misaligned?3319andi.b &0x3,%d03320beq.b CAS2L_ENTER # no3321cmpi.b %d0,&0x23322beq.w CAS2L2_ENTER # yes; word misaligned3323bra.w CAS2L3_ENTER # yes; byte misaligned33243325#3326# D0 = dst operand 1 <-3327# D1 = dst operand 2 <-3328# D2 = cmp operand 13329# D3 = cmp operand 23330# D4 = update oper 13331# D5 = update oper 23332# D6 = old SFC/DFC3333# D7 = old SR3334# A0 = ADDR13335# A1 = ADDR23336# A2 = bus LOCK* value3337# A3 = bus LOCKE* value3338# A4 = bus unlock value3339# A5 = xxxxxxxx3340#3341align 0x103342CAS2L_START:3343movc %a2,%buscr # assert LOCK*3344movs.l (%a1),%d1 # fetch Dest2[31:0]3345movs.l (%a0),%d0 # fetch Dest1[31:0]3346bra.b CAS2L_CONT3347CAS2L_ENTER:3348bra.b ~+1633493350CAS2L_CONT:3351cmp.l %d0,%d2 # Dest1 - Compare13352bne.b CAS2L_NOUPDATE3353cmp.l %d1,%d3 # Dest2 - Compare23354bne.b CAS2L_NOUPDATE3355movs.l %d5,(%a1) # Update2[31:0] -> DEST23356bra.b CAS2L_UPDATE3357bra.b ~+1633583359CAS2L_UPDATE:3360movc %a3,%buscr # assert LOCKE*3361movs.l %d4,(%a0) # Update1[31:0] -> DEST13362movc %a4,%buscr # unlock the bus3363bra.b cas2l_update_done3364bra.b ~+1633653366CAS2L_NOUPDATE:3367movc %a3,%buscr # assert LOCKE*3368movs.l %d0,(%a0) # Dest1[31:0] -> DEST13369movc %a4,%buscr # unlock the bus3370bra.b cas2l_noupdate_done3371bra.b ~+1633723373CAS2L_FILLER:3374nop3375nop3376nop3377nop3378nop3379nop3380nop3381bra.b CAS2L_START33823383####33843385#################################################################3386# THIS MUST BE THE STATE OF THE INTEGER REGISTER FILE UPON #3387# ENTERING _isp_cas2(). #3388# #3389# D0 = destination[31:0] operand 1 #3390# D1 = destination[31:0] operand 2 #3391# D2 = cmp[31:0] operand 1 #3392# D3 = cmp[31:0] operand 2 #3393# D4 = 'xxxxxx11 -> no reg update; 'xxxxxx00 -> update required #3394# D5 = xxxxxxxx #3395# D6 = xxxxxxxx #3396# D7 = xxxxxxxx #3397# A0 = xxxxxxxx #3398# A1 = xxxxxxxx #3399# A2 = xxxxxxxx #3400# A3 = xxxxxxxx #3401# A4 = xxxxxxxx #3402# A5 = xxxxxxxx #3403# A6 = frame pointer #3404# A7 = stack pointer #3405#################################################################34063407cas2l_noupdate_done:34083409# restore previous SFC/DFC value.3410movc %d6,%sfc # restore old SFC3411movc %d6,%dfc # restore old DFC34123413# restore previous interrupt mask level.3414mov.w %d7,%sr # restore old SR34153416sf %d4 # indicate no update was done3417bra.l _isp_cas2_finish34183419cas2l_update_done:34203421# restore previous SFC/DFC value.3422movc %d6,%sfc # restore old SFC3423movc %d6,%dfc # restore old DFC34243425# restore previous interrupt mask level.3426mov.w %d7,%sr # restore old SR34273428st %d4 # indicate update was done3429bra.l _isp_cas2_finish3430####34313432align 0x103433CAS2L2_START:3434movc %a2,%buscr # assert LOCK*3435movs.l (%a1),%d1 # fetch Dest2[31:0]3436movs.l (%a0),%d0 # fetch Dest1[31:0]3437bra.b CAS2L2_CONT3438CAS2L2_ENTER:3439bra.b ~+1634403441CAS2L2_CONT:3442cmp.l %d0,%d2 # Dest1 - Compare13443bne.b CAS2L2_NOUPDATE3444cmp.l %d1,%d3 # Dest2 - Compare23445bne.b CAS2L2_NOUPDATE3446movs.l %d5,(%a1) # Update2[31:0] -> Dest23447bra.b CAS2L2_UPDATE3448bra.b ~+1634493450CAS2L2_UPDATE:3451swap %d4 # get Update1[31:16]3452movs.w %d4,(%a0)+ # Update1[31:16] -> DEST13453movc %a3,%buscr # assert LOCKE*3454swap %d4 # get Update1[15:0]3455bra.b CAS2L2_UPDATE23456bra.b ~+1634573458CAS2L2_UPDATE2:3459movs.w %d4,(%a0) # Update1[15:0] -> DEST1+0x23460movc %a4,%buscr # unlock the bus3461bra.w cas2l_update_done3462nop3463bra.b ~+1634643465CAS2L2_NOUPDATE:3466swap %d0 # get Dest1[31:16]3467movs.w %d0,(%a0)+ # Dest1[31:16] -> DEST13468movc %a3,%buscr # assert LOCKE*3469swap %d0 # get Dest1[15:0]3470bra.b CAS2L2_NOUPDATE23471bra.b ~+1634723473CAS2L2_NOUPDATE2:3474movs.w %d0,(%a0) # Dest1[15:0] -> DEST1+0x23475movc %a4,%buscr # unlock the bus3476bra.w cas2l_noupdate_done3477nop3478bra.b ~+1634793480CAS2L2_FILLER:3481nop3482nop3483nop3484nop3485nop3486nop3487nop3488bra.b CAS2L2_START34893490#################################34913492align 0x103493CAS2L3_START:3494movc %a2,%buscr # assert LOCK*3495movs.l (%a1),%d1 # fetch Dest2[31:0]3496movs.l (%a0),%d0 # fetch Dest1[31:0]3497bra.b CAS2L3_CONT3498CAS2L3_ENTER:3499bra.b ~+1635003501CAS2L3_CONT:3502cmp.l %d0,%d2 # Dest1 - Compare13503bne.b CAS2L3_NOUPDATE3504cmp.l %d1,%d3 # Dest2 - Compare23505bne.b CAS2L3_NOUPDATE3506movs.l %d5,(%a1) # Update2[31:0] -> DEST23507bra.b CAS2L3_UPDATE3508bra.b ~+1635093510CAS2L3_UPDATE:3511rol.l &0x8,%d4 # get Update1[31:24]3512movs.b %d4,(%a0)+ # Update1[31:24] -> DEST13513swap %d4 # get Update1[23:8]3514movs.w %d4,(%a0)+ # Update1[23:8] -> DEST1+0x13515bra.b CAS2L3_UPDATE23516bra.b ~+1635173518CAS2L3_UPDATE2:3519rol.l &0x8,%d4 # get Update1[7:0]3520movc %a3,%buscr # assert LOCKE*3521movs.b %d4,(%a0) # Update1[7:0] -> DEST1+0x33522bra.b CAS2L3_UPDATE33523nop3524bra.b ~+1635253526CAS2L3_UPDATE3:3527movc %a4,%buscr # unlock the bus3528bra.w cas2l_update_done3529nop3530nop3531nop3532bra.b ~+1635333534CAS2L3_NOUPDATE:3535rol.l &0x8,%d0 # get Dest1[31:24]3536movs.b %d0,(%a0)+ # Dest1[31:24] -> DEST13537swap %d0 # get Dest1[23:8]3538movs.w %d0,(%a0)+ # Dest1[23:8] -> DEST1+0x13539bra.b CAS2L3_NOUPDATE23540bra.b ~+1635413542CAS2L3_NOUPDATE2:3543rol.l &0x8,%d0 # get Dest1[7:0]3544movc %a3,%buscr # assert LOCKE*3545movs.b %d0,(%a0) # Update1[7:0] -> DEST1+0x33546bra.b CAS2L3_NOUPDATE33547nop3548bra.b ~+1635493550CAS2L3_NOUPDATE3:3551movc %a4,%buscr # unlock the bus3552bra.w cas2l_noupdate_done3553nop3554nop3555nop3556bra.b ~+1435573558CAS2L3_FILLER:3559nop3560nop3561nop3562nop3563nop3564nop3565bra.w CAS2L3_START35663567#############################################################3568#############################################################35693570cas2w:3571mov.l %a0,%a2 # copy ADDR13572mov.l %a1,%a3 # copy ADDR23573mov.l %a0,%a4 # copy ADDR13574mov.l %a1,%a5 # copy ADDR235753576addq.l &0x1,%a4 # ADDR1+13577addq.l &0x1,%a5 # ADDR2+13578mov.l %a2,%d1 # ADDR135793580# mask interrupt levels 0-6. save old mask value.3581mov.w %sr,%d7 # save current SR3582ori.w &0x0700,%sr # inhibit interrupts35833584# load the SFC and DFC with the appropriate mode.3585movc %sfc,%d6 # save old SFC/DFC3586movc %d0,%sfc # store new SFC3587movc %d0,%dfc # store new DFC35883589# pre-load the operand ATC. no page faults should occur because3590# _real_lock_page() should have taken care of this.3591plpaw (%a2) # load atc for ADDR13592plpaw (%a4) # load atc for ADDR1+13593plpaw (%a3) # load atc for ADDR23594plpaw (%a5) # load atc for ADDR2+135953596# push the operand cache lines from the cache if they exist.3597cpushl %dc,(%a2) # push line for ADDR13598cpushl %dc,(%a4) # push line for ADDR1+13599cpushl %dc,(%a3) # push line for ADDR23600cpushl %dc,(%a5) # push line for ADDR2+136013602mov.l %d1,%a2 # ADDR13603addq.l &0x3,%d13604mov.l %d1,%a4 # ADDR1+33605# if ADDR1 was ATC resident before the above "plpaw" and was executed3606# and it was the next entry scheduled for replacement and ADDR23607# shares the same set, then the "plpaw" for ADDR2 can push the ADDR13608# entries from the ATC. so, we do a second set of "plpa"s.3609plpar (%a2) # load atc for ADDR13610plpar (%a4) # load atc for ADDR1+336113612# load the BUSCR values.3613mov.l &0x80000000,%a2 # assert LOCK* buscr value3614mov.l &0xa0000000,%a3 # assert LOCKE* buscr value3615mov.l &0x00000000,%a4 # buscr unlock value36163617# there are two possible mis-aligned cases for word cas. they3618# are separated because the final write which asserts LOCKE* must3619# be aligned.3620mov.l %a0,%d0 # is ADDR1 misaligned?3621btst &0x0,%d03622bne.w CAS2W2_ENTER # yes3623bra.b CAS2W_ENTER # no36243625#3626# D0 = dst operand 1 <-3627# D1 = dst operand 2 <-3628# D2 = cmp operand 13629# D3 = cmp operand 23630# D4 = update oper 13631# D5 = update oper 23632# D6 = old SFC/DFC3633# D7 = old SR3634# A0 = ADDR13635# A1 = ADDR23636# A2 = bus LOCK* value3637# A3 = bus LOCKE* value3638# A4 = bus unlock value3639# A5 = xxxxxxxx3640#3641align 0x103642CAS2W_START:3643movc %a2,%buscr # assert LOCK*3644movs.w (%a1),%d1 # fetch Dest2[15:0]3645movs.w (%a0),%d0 # fetch Dest1[15:0]3646bra.b CAS2W_CONT23647CAS2W_ENTER:3648bra.b ~+1636493650CAS2W_CONT2:3651cmp.w %d0,%d2 # Dest1 - Compare13652bne.b CAS2W_NOUPDATE3653cmp.w %d1,%d3 # Dest2 - Compare23654bne.b CAS2W_NOUPDATE3655movs.w %d5,(%a1) # Update2[15:0] -> DEST23656bra.b CAS2W_UPDATE3657bra.b ~+1636583659CAS2W_UPDATE:3660movc %a3,%buscr # assert LOCKE*3661movs.w %d4,(%a0) # Update1[15:0] -> DEST13662movc %a4,%buscr # unlock the bus3663bra.b cas2w_update_done3664bra.b ~+1636653666CAS2W_NOUPDATE:3667movc %a3,%buscr # assert LOCKE*3668movs.w %d0,(%a0) # Dest1[15:0] -> DEST13669movc %a4,%buscr # unlock the bus3670bra.b cas2w_noupdate_done3671bra.b ~+1636723673CAS2W_FILLER:3674nop3675nop3676nop3677nop3678nop3679nop3680nop3681bra.b CAS2W_START36823683####36843685#################################################################3686# THIS MUST BE THE STATE OF THE INTEGER REGISTER FILE UPON #3687# ENTERING _isp_cas2(). #3688# #3689# D0 = destination[15:0] operand 1 #3690# D1 = destination[15:0] operand 2 #3691# D2 = cmp[15:0] operand 1 #3692# D3 = cmp[15:0] operand 2 #3693# D4 = 'xxxxxx11 -> no reg update; 'xxxxxx00 -> update required #3694# D5 = xxxxxxxx #3695# D6 = xxxxxxxx #3696# D7 = xxxxxxxx #3697# A0 = xxxxxxxx #3698# A1 = xxxxxxxx #3699# A2 = xxxxxxxx #3700# A3 = xxxxxxxx #3701# A4 = xxxxxxxx #3702# A5 = xxxxxxxx #3703# A6 = frame pointer #3704# A7 = stack pointer #3705#################################################################37063707cas2w_noupdate_done:37083709# restore previous SFC/DFC value.3710movc %d6,%sfc # restore old SFC3711movc %d6,%dfc # restore old DFC37123713# restore previous interrupt mask level.3714mov.w %d7,%sr # restore old SR37153716sf %d4 # indicate no update was done3717bra.l _isp_cas2_finish37183719cas2w_update_done:37203721# restore previous SFC/DFC value.3722movc %d6,%sfc # restore old SFC3723movc %d6,%dfc # restore old DFC37243725# restore previous interrupt mask level.3726mov.w %d7,%sr # restore old SR37273728st %d4 # indicate update was done3729bra.l _isp_cas2_finish3730####37313732align 0x103733CAS2W2_START:3734movc %a2,%buscr # assert LOCK*3735movs.w (%a1),%d1 # fetch Dest2[15:0]3736movs.w (%a0),%d0 # fetch Dest1[15:0]3737bra.b CAS2W2_CONT23738CAS2W2_ENTER:3739bra.b ~+1637403741CAS2W2_CONT2:3742cmp.w %d0,%d2 # Dest1 - Compare13743bne.b CAS2W2_NOUPDATE3744cmp.w %d1,%d3 # Dest2 - Compare23745bne.b CAS2W2_NOUPDATE3746movs.w %d5,(%a1) # Update2[15:0] -> DEST23747bra.b CAS2W2_UPDATE3748bra.b ~+1637493750CAS2W2_UPDATE:3751ror.l &0x8,%d4 # get Update1[15:8]3752movs.b %d4,(%a0)+ # Update1[15:8] -> DEST13753movc %a3,%buscr # assert LOCKE*3754rol.l &0x8,%d4 # get Update1[7:0]3755bra.b CAS2W2_UPDATE23756bra.b ~+1637573758CAS2W2_UPDATE2:3759movs.b %d4,(%a0) # Update1[7:0] -> DEST1+0x13760movc %a4,%buscr # unlock the bus3761bra.w cas2w_update_done3762nop3763bra.b ~+1637643765CAS2W2_NOUPDATE:3766ror.l &0x8,%d0 # get Dest1[15:8]3767movs.b %d0,(%a0)+ # Dest1[15:8] -> DEST13768movc %a3,%buscr # assert LOCKE*3769rol.l &0x8,%d0 # get Dest1[7:0]3770bra.b CAS2W2_NOUPDATE23771bra.b ~+1637723773CAS2W2_NOUPDATE2:3774movs.b %d0,(%a0) # Dest1[7:0] -> DEST1+0x13775movc %a4,%buscr # unlock the bus3776bra.w cas2w_noupdate_done3777nop3778bra.b ~+1637793780CAS2W2_FILLER:3781nop3782nop3783nop3784nop3785nop3786nop3787nop3788bra.b CAS2W2_START37893790# ###### ## ######3791# # # # #3792# # ###### ######3793# # # # #3794# ###### # # ######37953796#########################################################################3797# XDEF **************************************************************** #3798# _isp_cas(): "core" emulation code for the cas instruction #3799# #3800# XREF **************************************************************** #3801# _isp_cas_finish() - only exit point for this emulation code; #3802# do clean-up #3803# #3804# INPUT *************************************************************** #3805# *see entry chart below* #3806# #3807# OUTPUT ************************************************************** #3808# *see exit chart below* #3809# #3810# ALGORITHM *********************************************************** #3811# (1) Make several copies of the effective address. #3812# (2) Save current SR; Then mask off all maskable interrupts. #3813# (3) Save current DFC/SFC (ASSUMED TO BE EQUAL!!!); Then set #3814# SFC/DFC according to whether exception occurred in user or #3815# supervisor mode. #3816# (4) Use "plpaw" instruction to pre-load ATC with efective #3817# address page(s). THIS SHOULD NOT FAULT!!! The relevant #3818# page(s) should have been made resident prior to entering #3819# this routine. #3820# (5) Push the operand lines from the cache w/ "cpushl". #3821# In the 68040, this was done within the locked region. In #3822# the 68060, it is done outside of the locked region. #3823# (6) Pre-fetch the core emulation instructions by executing one #3824# branch within each physical line (16 bytes) of the code #3825# before actually executing the code. #3826# (7) Load the BUSCR with the bus lock value. #3827# (8) Fetch the source operand. #3828# (9) Do the compare. If equal, go to step (12). #3829# (10)Unequal. No update occurs. But, we do write the DST op back #3830# to itself (as w/ the '040) so we can gracefully unlock #3831# the bus (and assert LOCKE*) using BUSCR and the final move. #3832# (11)Exit. #3833# (12)Write update operand to the DST location. Use BUSCR to #3834# assert LOCKE* for the final write operation. #3835# (13)Exit. #3836# #3837# The algorithm is actually implemented slightly differently #3838# depending on the size of the operation and the misalignment of the #3839# operand. A misaligned operand must be written in aligned chunks or #3840# else the BUSCR register control gets confused. #3841# #3842#########################################################################38433844#########################################################3845# THIS IS THE STATE OF THE INTEGER REGISTER FILE UPON #3846# ENTERING _isp_cas(). #3847# #3848# D0 = xxxxxxxx #3849# D1 = xxxxxxxx #3850# D2 = update operand #3851# D3 = xxxxxxxx #3852# D4 = compare operand #3853# D5 = xxxxxxxx #3854# D6 = supervisor ('xxxxxxff) or user mode ('xxxxxx00) #3855# D7 = longword ('xxxxxxff) or word size ('xxxxxx00) #3856# A0 = ADDR #3857# A1 = xxxxxxxx #3858# A2 = xxxxxxxx #3859# A3 = xxxxxxxx #3860# A4 = xxxxxxxx #3861# A5 = xxxxxxxx #3862# A6 = frame pointer #3863# A7 = stack pointer #3864#########################################################38653866global _isp_cas3867_isp_cas:3868tst.b %d6 # user or supervisor mode?3869bne.b cas_super # supervisor3870cas_user:3871movq.l &0x1,%d0 # load user data fc3872bra.b cas_cont3873cas_super:3874movq.l &0x5,%d0 # load supervisor data fc38753876cas_cont:3877tst.b %d7 # word or longword?3878bne.w casl # longword38793880####3881casw:3882mov.l %a0,%a1 # make copy for plpaw13883mov.l %a0,%a2 # make copy for plpaw23884addq.l &0x1,%a2 # plpaw2 points to end of word38853886mov.l %d2,%d3 # d3 = update[7:0]3887lsr.w &0x8,%d2 # d2 = update[15:8]38883889# mask interrupt levels 0-6. save old mask value.3890mov.w %sr,%d7 # save current SR3891ori.w &0x0700,%sr # inhibit interrupts38923893# load the SFC and DFC with the appropriate mode.3894movc %sfc,%d6 # save old SFC/DFC3895movc %d0,%sfc # load new sfc3896movc %d0,%dfc # load new dfc38973898# pre-load the operand ATC. no page faults should occur here because3899# _real_lock_page() should have taken care of this.3900plpaw (%a1) # load atc for ADDR3901plpaw (%a2) # load atc for ADDR+139023903# push the operand lines from the cache if they exist.3904cpushl %dc,(%a1) # push dirty data3905cpushl %dc,(%a2) # push dirty data39063907# load the BUSCR values.3908mov.l &0x80000000,%a1 # assert LOCK* buscr value3909mov.l &0xa0000000,%a2 # assert LOCKE* buscr value3910mov.l &0x00000000,%a3 # buscr unlock value39113912# pre-load the instruction cache for the following algorithm.3913# this will minimize the number of cycles that LOCK* will be asserted.3914bra.b CASW_ENTER # start pre-loading icache39153916#3917# D0 = dst operand <-3918# D1 = update[15:8] operand3919# D2 = update[7:0] operand3920# D3 = xxxxxxxx3921# D4 = compare[15:0] operand3922# D5 = xxxxxxxx3923# D6 = old SFC/DFC3924# D7 = old SR3925# A0 = ADDR3926# A1 = bus LOCK* value3927# A2 = bus LOCKE* value3928# A3 = bus unlock value3929# A4 = xxxxxxxx3930# A5 = xxxxxxxx3931#3932align 0x103933CASW_START:3934movc %a1,%buscr # assert LOCK*3935movs.w (%a0),%d0 # fetch Dest[15:0]3936cmp.w %d0,%d4 # Dest - Compare3937bne.b CASW_NOUPDATE3938bra.b CASW_UPDATE3939CASW_ENTER:3940bra.b ~+1639413942CASW_UPDATE:3943movs.b %d2,(%a0)+ # Update[15:8] -> DEST3944movc %a2,%buscr # assert LOCKE*3945movs.b %d3,(%a0) # Update[7:0] -> DEST+0x13946bra.b CASW_UPDATE23947bra.b ~+1639483949CASW_UPDATE2:3950movc %a3,%buscr # unlock the bus3951bra.b casw_update_done3952nop3953nop3954nop3955nop3956bra.b ~+1639573958CASW_NOUPDATE:3959ror.l &0x8,%d0 # get Dest[15:8]3960movs.b %d0,(%a0)+ # Dest[15:8] -> DEST3961movc %a2,%buscr # assert LOCKE*3962rol.l &0x8,%d0 # get Dest[7:0]3963bra.b CASW_NOUPDATE23964bra.b ~+1639653966CASW_NOUPDATE2:3967movs.b %d0,(%a0) # Dest[7:0] -> DEST+0x13968movc %a3,%buscr # unlock the bus3969bra.b casw_noupdate_done3970nop3971nop3972bra.b ~+1639733974CASW_FILLER:3975nop3976nop3977nop3978nop3979nop3980nop3981nop3982bra.b CASW_START39833984#################################################################3985# THIS MUST BE THE STATE OF THE INTEGER REGISTER FILE UPON #3986# CALLING _isp_cas_finish(). #3987# #3988# D0 = destination[15:0] operand #3989# D1 = 'xxxxxx11 -> no reg update; 'xxxxxx00 -> update required #3990# D2 = xxxxxxxx #3991# D3 = xxxxxxxx #3992# D4 = compare[15:0] operand #3993# D5 = xxxxxxxx #3994# D6 = xxxxxxxx #3995# D7 = xxxxxxxx #3996# A0 = xxxxxxxx #3997# A1 = xxxxxxxx #3998# A2 = xxxxxxxx #3999# A3 = xxxxxxxx #4000# A4 = xxxxxxxx #4001# A5 = xxxxxxxx #4002# A6 = frame pointer #4003# A7 = stack pointer #4004#################################################################40054006casw_noupdate_done:40074008# restore previous SFC/DFC value.4009movc %d6,%sfc # restore old SFC4010movc %d6,%dfc # restore old DFC40114012# restore previous interrupt mask level.4013mov.w %d7,%sr # restore old SR40144015sf %d1 # indicate no update was done4016bra.l _isp_cas_finish40174018casw_update_done:40194020# restore previous SFC/DFC value.4021movc %d6,%sfc # restore old SFC4022movc %d6,%dfc # restore old DFC40234024# restore previous interrupt mask level.4025mov.w %d7,%sr # restore old SR40264027st %d1 # indicate update was done4028bra.l _isp_cas_finish40294030################40314032# there are two possible mis-aligned cases for longword cas. they4033# are separated because the final write which asserts LOCKE* must4034# be an aligned write.4035casl:4036mov.l %a0,%a1 # make copy for plpaw14037mov.l %a0,%a2 # make copy for plpaw24038addq.l &0x3,%a2 # plpaw2 points to end of longword40394040mov.l %a0,%d1 # byte or word misaligned?4041btst &0x0,%d14042bne.w casl2 # byte misaligned40434044mov.l %d2,%d3 # d3 = update[15:0]4045swap %d2 # d2 = update[31:16]40464047# mask interrupts levels 0-6. save old mask value.4048mov.w %sr,%d7 # save current SR4049ori.w &0x0700,%sr # inhibit interrupts40504051# load the SFC and DFC with the appropriate mode.4052movc %sfc,%d6 # save old SFC/DFC4053movc %d0,%sfc # load new sfc4054movc %d0,%dfc # load new dfc40554056# pre-load the operand ATC. no page faults should occur here because4057# _real_lock_page() should have taken care of this.4058plpaw (%a1) # load atc for ADDR4059plpaw (%a2) # load atc for ADDR+340604061# push the operand lines from the cache if they exist.4062cpushl %dc,(%a1) # push dirty data4063cpushl %dc,(%a2) # push dirty data40644065# load the BUSCR values.4066mov.l &0x80000000,%a1 # assert LOCK* buscr value4067mov.l &0xa0000000,%a2 # assert LOCKE* buscr value4068mov.l &0x00000000,%a3 # buscr unlock value40694070bra.b CASL_ENTER # start pre-loading icache40714072#4073# D0 = dst operand <-4074# D1 = xxxxxxxx4075# D2 = update[31:16] operand4076# D3 = update[15:0] operand4077# D4 = compare[31:0] operand4078# D5 = xxxxxxxx4079# D6 = old SFC/DFC4080# D7 = old SR4081# A0 = ADDR4082# A1 = bus LOCK* value4083# A2 = bus LOCKE* value4084# A3 = bus unlock value4085# A4 = xxxxxxxx4086# A5 = xxxxxxxx4087#4088align 0x104089CASL_START:4090movc %a1,%buscr # assert LOCK*4091movs.l (%a0),%d0 # fetch Dest[31:0]4092cmp.l %d0,%d4 # Dest - Compare4093bne.b CASL_NOUPDATE4094bra.b CASL_UPDATE4095CASL_ENTER:4096bra.b ~+1640974098CASL_UPDATE:4099movs.w %d2,(%a0)+ # Update[31:16] -> DEST4100movc %a2,%buscr # assert LOCKE*4101movs.w %d3,(%a0) # Update[15:0] -> DEST+0x24102bra.b CASL_UPDATE24103bra.b ~+1641044105CASL_UPDATE2:4106movc %a3,%buscr # unlock the bus4107bra.b casl_update_done4108nop4109nop4110nop4111nop4112bra.b ~+1641134114CASL_NOUPDATE:4115swap %d0 # get Dest[31:16]4116movs.w %d0,(%a0)+ # Dest[31:16] -> DEST4117swap %d0 # get Dest[15:0]4118movc %a2,%buscr # assert LOCKE*4119bra.b CASL_NOUPDATE24120bra.b ~+1641214122CASL_NOUPDATE2:4123movs.w %d0,(%a0) # Dest[15:0] -> DEST+0x24124movc %a3,%buscr # unlock the bus4125bra.b casl_noupdate_done4126nop4127nop4128bra.b ~+1641294130CASL_FILLER:4131nop4132nop4133nop4134nop4135nop4136nop4137nop4138bra.b CASL_START41394140#################################################################4141# THIS MUST BE THE STATE OF THE INTEGER REGISTER FILE UPON #4142# CALLING _isp_cas_finish(). #4143# #4144# D0 = destination[31:0] operand #4145# D1 = 'xxxxxx11 -> no reg update; 'xxxxxx00 -> update required #4146# D2 = xxxxxxxx #4147# D3 = xxxxxxxx #4148# D4 = compare[31:0] operand #4149# D5 = xxxxxxxx #4150# D6 = xxxxxxxx #4151# D7 = xxxxxxxx #4152# A0 = xxxxxxxx #4153# A1 = xxxxxxxx #4154# A2 = xxxxxxxx #4155# A3 = xxxxxxxx #4156# A4 = xxxxxxxx #4157# A5 = xxxxxxxx #4158# A6 = frame pointer #4159# A7 = stack pointer #4160#################################################################41614162casl_noupdate_done:41634164# restore previous SFC/DFC value.4165movc %d6,%sfc # restore old SFC4166movc %d6,%dfc # restore old DFC41674168# restore previous interrupt mask level.4169mov.w %d7,%sr # restore old SR41704171sf %d1 # indicate no update was done4172bra.l _isp_cas_finish41734174casl_update_done:41754176# restore previous SFC/DFC value.4177movc %d6,%sfc # restore old SFC4178movc %d6,%dfc # restore old DFC41794180# restore previous interrupts mask level.4181mov.w %d7,%sr # restore old SR41824183st %d1 # indicate update was done4184bra.l _isp_cas_finish41854186#######################################4187casl2:4188mov.l %d2,%d5 # d5 = Update[7:0]4189lsr.l &0x8,%d24190mov.l %d2,%d3 # d3 = Update[23:8]4191swap %d2 # d2 = Update[31:24]41924193# mask interrupts levels 0-6. save old mask value.4194mov.w %sr,%d7 # save current SR4195ori.w &0x0700,%sr # inhibit interrupts41964197# load the SFC and DFC with the appropriate mode.4198movc %sfc,%d6 # save old SFC/DFC4199movc %d0,%sfc # load new sfc4200movc %d0,%dfc # load new dfc42014202# pre-load the operand ATC. no page faults should occur here because4203# _real_lock_page() should have taken care of this already.4204plpaw (%a1) # load atc for ADDR4205plpaw (%a2) # load atc for ADDR+342064207# puch the operand lines from the cache if they exist.4208cpushl %dc,(%a1) # push dirty data4209cpushl %dc,(%a2) # push dirty data42104211# load the BUSCR values.4212mov.l &0x80000000,%a1 # assert LOCK* buscr value4213mov.l &0xa0000000,%a2 # assert LOCKE* buscr value4214mov.l &0x00000000,%a3 # buscr unlock value42154216# pre-load the instruction cache for the following algorithm.4217# this will minimize the number of cycles that LOCK* will be asserted.4218bra.b CASL2_ENTER # start pre-loading icache42194220#4221# D0 = dst operand <-4222# D1 = xxxxxxxx4223# D2 = update[31:24] operand4224# D3 = update[23:8] operand4225# D4 = compare[31:0] operand4226# D5 = update[7:0] operand4227# D6 = old SFC/DFC4228# D7 = old SR4229# A0 = ADDR4230# A1 = bus LOCK* value4231# A2 = bus LOCKE* value4232# A3 = bus unlock value4233# A4 = xxxxxxxx4234# A5 = xxxxxxxx4235#4236align 0x104237CASL2_START:4238movc %a1,%buscr # assert LOCK*4239movs.l (%a0),%d0 # fetch Dest[31:0]4240cmp.l %d0,%d4 # Dest - Compare4241bne.b CASL2_NOUPDATE4242bra.b CASL2_UPDATE4243CASL2_ENTER:4244bra.b ~+1642454246CASL2_UPDATE:4247movs.b %d2,(%a0)+ # Update[31:24] -> DEST4248movs.w %d3,(%a0)+ # Update[23:8] -> DEST+0x14249movc %a2,%buscr # assert LOCKE*4250bra.b CASL2_UPDATE24251bra.b ~+1642524253CASL2_UPDATE2:4254movs.b %d5,(%a0) # Update[7:0] -> DEST+0x34255movc %a3,%buscr # unlock the bus4256bra.w casl_update_done4257nop4258bra.b ~+1642594260CASL2_NOUPDATE:4261rol.l &0x8,%d0 # get Dest[31:24]4262movs.b %d0,(%a0)+ # Dest[31:24] -> DEST4263swap %d0 # get Dest[23:8]4264movs.w %d0,(%a0)+ # Dest[23:8] -> DEST+0x14265bra.b CASL2_NOUPDATE24266bra.b ~+1642674268CASL2_NOUPDATE2:4269rol.l &0x8,%d0 # get Dest[7:0]4270movc %a2,%buscr # assert LOCKE*4271movs.b %d0,(%a0) # Dest[7:0] -> DEST+0x34272bra.b CASL2_NOUPDATE34273nop4274bra.b ~+1642754276CASL2_NOUPDATE3:4277movc %a3,%buscr # unlock the bus4278bra.w casl_noupdate_done4279nop4280nop4281nop4282bra.b ~+1642834284CASL2_FILLER:4285nop4286nop4287nop4288nop4289nop4290nop4291nop4292bra.b CASL2_START42934294####4295####4296# end label used by _isp_cas_inrange()4297global _CASHI4298_CASHI:429943004301