cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

isp.S (126515B)


      1~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      2MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
      3M68000 Hi-Performance Microprocessor Division
      4M68060 Software Package
      5Production Release P1.00 -- October 10, 1994
      6
      7M68060 Software Package Copyright © 1993, 1994 Motorola Inc.  All rights reserved.
      8
      9THE SOFTWARE is provided on an "AS IS" basis and without warranty.
     10To the maximum extent permitted by applicable law,
     11MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED,
     12INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
     13and any warranty against infringement with regard to the SOFTWARE
     14(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials.
     15
     16To the maximum extent permitted by applicable law,
     17IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
     18(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
     19BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS)
     20ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
     21Motorola assumes no responsibility for the maintenance and support of the SOFTWARE.
     22
     23You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE
     24so long as this entire notice is retained without alteration in any modified and/or
     25redistributed versions, and that such modified versions are clearly identified as such.
     26No licenses are granted by implication, estoppel or otherwise under any patents
     27or trademarks of Motorola, Inc.
     28~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     29# ireal.s:
     30#	This file is appended to the top of the 060ISP package
     31# and contains the entry points into the package. The user, in
     32# effect, branches to one of the branch table entries located
     33# after _060ISP_TABLE.
     34#	Also, subroutine stubs exist in this file (_isp_done for
     35# example) that are referenced by the ISP package itself in order
     36# to call a given routine. The stub routine actually performs the
     37# callout. The ISP code does a "bsr" to the stub routine. This
     38# extra layer of hierarchy adds a slight performance penalty but
     39# it makes the ISP code easier to read and more mainatinable.
     40#
     41
     42set	_off_chk,	0x00
     43set	_off_divbyzero,	0x04
     44set	_off_trace,	0x08
     45set	_off_access,	0x0c
     46set	_off_done,	0x10
     47
     48set	_off_cas,	0x14
     49set	_off_cas2,	0x18
     50set	_off_lock,	0x1c
     51set	_off_unlock,	0x20
     52
     53set	_off_imr,	0x40
     54set	_off_dmr,	0x44
     55set	_off_dmw,	0x48
     56set	_off_irw,	0x4c
     57set	_off_irl,	0x50
     58set	_off_drb,	0x54
     59set	_off_drw,	0x58
     60set	_off_drl,	0x5c
     61set	_off_dwb,	0x60
     62set	_off_dww,	0x64
     63set	_off_dwl,	0x68
     64
     65_060ISP_TABLE:
     66
     67# Here's the table of ENTRY POINTS for those linking the package.
     68	bra.l		_isp_unimp
     69	short		0x0000
     70
     71	bra.l		_isp_cas
     72	short		0x0000
     73
     74	bra.l		_isp_cas2
     75	short		0x0000
     76
     77	bra.l		_isp_cas_finish
     78	short		0x0000
     79
     80	bra.l		_isp_cas2_finish
     81	short		0x0000
     82
     83	bra.l		_isp_cas_inrange
     84	short		0x0000
     85
     86	bra.l		_isp_cas_terminate
     87	short		0x0000
     88
     89	bra.l		_isp_cas_restart
     90	short		0x0000
     91
     92	space		64
     93
     94#############################################################
     95
     96	global		_real_chk
     97_real_chk:
     98	mov.l		%d0,-(%sp)
     99	mov.l		(_060ISP_TABLE-0x80+_off_chk,%pc),%d0
    100	pea.l		(_060ISP_TABLE-0x80,%pc,%d0)
    101	mov.l		0x4(%sp),%d0
    102	rtd		&0x4
    103
    104	global		_real_divbyzero
    105_real_divbyzero:
    106	mov.l		%d0,-(%sp)
    107	mov.l		(_060ISP_TABLE-0x80+_off_divbyzero,%pc),%d0
    108	pea.l		(_060ISP_TABLE-0x80,%pc,%d0)
    109	mov.l		0x4(%sp),%d0
    110	rtd		&0x4
    111
    112	global		_real_trace
    113_real_trace:
    114	mov.l		%d0,-(%sp)
    115	mov.l		(_060ISP_TABLE-0x80+_off_trace,%pc),%d0
    116	pea.l		(_060ISP_TABLE-0x80,%pc,%d0)
    117	mov.l		0x4(%sp),%d0
    118	rtd		&0x4
    119
    120	global		_real_access
    121_real_access:
    122	mov.l		%d0,-(%sp)
    123	mov.l		(_060ISP_TABLE-0x80+_off_access,%pc),%d0
    124	pea.l		(_060ISP_TABLE-0x80,%pc,%d0)
    125	mov.l		0x4(%sp),%d0
    126	rtd		&0x4
    127
    128	global		_isp_done
    129_isp_done:
    130	mov.l		%d0,-(%sp)
    131	mov.l		(_060ISP_TABLE-0x80+_off_done,%pc),%d0
    132	pea.l		(_060ISP_TABLE-0x80,%pc,%d0)
    133	mov.l		0x4(%sp),%d0
    134	rtd		&0x4
    135
    136#######################################
    137
    138	global		_real_cas
    139_real_cas:
    140	mov.l		%d0,-(%sp)
    141	mov.l		(_060ISP_TABLE-0x80+_off_cas,%pc),%d0
    142	pea.l		(_060ISP_TABLE-0x80,%pc,%d0)
    143	mov.l		0x4(%sp),%d0
    144	rtd		&0x4
    145
    146	global		_real_cas2
    147_real_cas2:
    148	mov.l		%d0,-(%sp)
    149	mov.l		(_060ISP_TABLE-0x80+_off_cas2,%pc),%d0
    150	pea.l		(_060ISP_TABLE-0x80,%pc,%d0)
    151	mov.l		0x4(%sp),%d0
    152	rtd		&0x4
    153
    154	global		_real_lock_page
    155_real_lock_page:
    156	mov.l		%d0,-(%sp)
    157	mov.l		(_060ISP_TABLE-0x80+_off_lock,%pc),%d0
    158	pea.l		(_060ISP_TABLE-0x80,%pc,%d0)
    159	mov.l		0x4(%sp),%d0
    160	rtd		&0x4
    161
    162	global		_real_unlock_page
    163_real_unlock_page:
    164	mov.l		%d0,-(%sp)
    165	mov.l		(_060ISP_TABLE-0x80+_off_unlock,%pc),%d0
    166	pea.l		(_060ISP_TABLE-0x80,%pc,%d0)
    167	mov.l		0x4(%sp),%d0
    168	rtd		&0x4
    169
    170#######################################
    171
    172	global		_imem_read
    173_imem_read:
    174	mov.l		%d0,-(%sp)
    175	mov.l		(_060ISP_TABLE-0x80+_off_imr,%pc),%d0
    176	pea.l		(_060ISP_TABLE-0x80,%pc,%d0)
    177	mov.l		0x4(%sp),%d0
    178	rtd		&0x4
    179
    180	global		_dmem_read
    181_dmem_read:
    182	mov.l		%d0,-(%sp)
    183	mov.l		(_060ISP_TABLE-0x80+_off_dmr,%pc),%d0
    184	pea.l		(_060ISP_TABLE-0x80,%pc,%d0)
    185	mov.l		0x4(%sp),%d0
    186	rtd		&0x4
    187
    188	global		_dmem_write
    189_dmem_write:
    190	mov.l		%d0,-(%sp)
    191	mov.l		(_060ISP_TABLE-0x80+_off_dmw,%pc),%d0
    192	pea.l		(_060ISP_TABLE-0x80,%pc,%d0)
    193	mov.l		0x4(%sp),%d0
    194	rtd		&0x4
    195
    196	global		_imem_read_word
    197_imem_read_word:
    198	mov.l		%d0,-(%sp)
    199	mov.l		(_060ISP_TABLE-0x80+_off_irw,%pc),%d0
    200	pea.l		(_060ISP_TABLE-0x80,%pc,%d0)
    201	mov.l		0x4(%sp),%d0
    202	rtd		&0x4
    203
    204	global		_imem_read_long
    205_imem_read_long:
    206	mov.l		%d0,-(%sp)
    207	mov.l		(_060ISP_TABLE-0x80+_off_irl,%pc),%d0
    208	pea.l		(_060ISP_TABLE-0x80,%pc,%d0)
    209	mov.l		0x4(%sp),%d0
    210	rtd		&0x4
    211
    212	global		_dmem_read_byte
    213_dmem_read_byte:
    214	mov.l		%d0,-(%sp)
    215	mov.l		(_060ISP_TABLE-0x80+_off_drb,%pc),%d0
    216	pea.l		(_060ISP_TABLE-0x80,%pc,%d0)
    217	mov.l		0x4(%sp),%d0
    218	rtd		&0x4
    219
    220	global		_dmem_read_word
    221_dmem_read_word:
    222	mov.l		%d0,-(%sp)
    223	mov.l		(_060ISP_TABLE-0x80+_off_drw,%pc),%d0
    224	pea.l		(_060ISP_TABLE-0x80,%pc,%d0)
    225	mov.l		0x4(%sp),%d0
    226	rtd		&0x4
    227
    228	global		_dmem_read_long
    229_dmem_read_long:
    230	mov.l		%d0,-(%sp)
    231	mov.l		(_060ISP_TABLE-0x80+_off_drl,%pc),%d0
    232	pea.l		(_060ISP_TABLE-0x80,%pc,%d0)
    233	mov.l		0x4(%sp),%d0
    234	rtd		&0x4
    235
    236	global		_dmem_write_byte
    237_dmem_write_byte:
    238	mov.l		%d0,-(%sp)
    239	mov.l		(_060ISP_TABLE-0x80+_off_dwb,%pc),%d0
    240	pea.l		(_060ISP_TABLE-0x80,%pc,%d0)
    241	mov.l		0x4(%sp),%d0
    242	rtd		&0x4
    243
    244	global		_dmem_write_word
    245_dmem_write_word:
    246	mov.l		%d0,-(%sp)
    247	mov.l		(_060ISP_TABLE-0x80+_off_dww,%pc),%d0
    248	pea.l		(_060ISP_TABLE-0x80,%pc,%d0)
    249	mov.l		0x4(%sp),%d0
    250	rtd		&0x4
    251
    252	global		_dmem_write_long
    253_dmem_write_long:
    254	mov.l		%d0,-(%sp)
    255	mov.l		(_060ISP_TABLE-0x80+_off_dwl,%pc),%d0
    256	pea.l		(_060ISP_TABLE-0x80,%pc,%d0)
    257	mov.l		0x4(%sp),%d0
    258	rtd		&0x4
    259
    260#
    261# This file contains a set of define statements for constants
    262# in oreder to promote readability within the core code itself.
    263#
    264
    265set LOCAL_SIZE,		96			# stack frame size(bytes)
    266set LV,			-LOCAL_SIZE		# stack offset
    267
    268set EXC_ISR,		0x4			# stack status register
    269set EXC_IPC,		0x6			# stack pc
    270set EXC_IVOFF,		0xa			# stacked vector offset
    271
    272set EXC_AREGS,		LV+64			# offset of all address regs
    273set EXC_DREGS,		LV+32			# offset of all data regs
    274
    275set EXC_A7,		EXC_AREGS+(7*4)		# offset of a7
    276set EXC_A6,		EXC_AREGS+(6*4)		# offset of a6
    277set EXC_A5,		EXC_AREGS+(5*4)		# offset of a5
    278set EXC_A4,		EXC_AREGS+(4*4)		# offset of a4
    279set EXC_A3,		EXC_AREGS+(3*4)		# offset of a3
    280set EXC_A2,		EXC_AREGS+(2*4)		# offset of a2
    281set EXC_A1,		EXC_AREGS+(1*4)		# offset of a1
    282set EXC_A0,		EXC_AREGS+(0*4)		# offset of a0
    283set EXC_D7,		EXC_DREGS+(7*4)		# offset of d7
    284set EXC_D6,		EXC_DREGS+(6*4)		# offset of d6
    285set EXC_D5,		EXC_DREGS+(5*4)		# offset of d5
    286set EXC_D4,		EXC_DREGS+(4*4)		# offset of d4
    287set EXC_D3,		EXC_DREGS+(3*4)		# offset of d3
    288set EXC_D2,		EXC_DREGS+(2*4)		# offset of d2
    289set EXC_D1,		EXC_DREGS+(1*4)		# offset of d1
    290set EXC_D0,		EXC_DREGS+(0*4)		# offset of d0
    291
    292set EXC_TEMP,		LV+16			# offset of temp stack space
    293
    294set EXC_SAVVAL,		LV+12			# offset of old areg value
    295set EXC_SAVREG,		LV+11			# offset of old areg index
    296
    297set SPCOND_FLG,		LV+10			# offset of spc condition flg
    298
    299set EXC_CC,		LV+8			# offset of cc register
    300set EXC_EXTWPTR,	LV+4			# offset of current PC
    301set EXC_EXTWORD,	LV+2			# offset of current ext opword
    302set EXC_OPWORD,		LV+0			# offset of current opword
    303
    304###########################
    305# SPecial CONDition FLaGs #
    306###########################
    307set mia7_flg,		0x04			# (a7)+ flag
    308set mda7_flg,		0x08			# -(a7) flag
    309set ichk_flg,		0x10			# chk exception flag
    310set idbyz_flg,		0x20			# divbyzero flag
    311set restore_flg,	0x40			# restore -(an)+ flag
    312set immed_flg,		0x80			# immediate data flag
    313
    314set mia7_bit,		0x2			# (a7)+ bit
    315set mda7_bit,		0x3			# -(a7) bit
    316set ichk_bit,		0x4			# chk exception bit
    317set idbyz_bit,		0x5			# divbyzero bit
    318set restore_bit,	0x6			# restore -(a7)+ bit
    319set immed_bit,		0x7			# immediate data bit
    320
    321#########
    322# Misc. #
    323#########
    324set BYTE,		1			# len(byte) == 1 byte
    325set WORD,		2			# len(word) == 2 bytes
    326set LONG,		4			# len(longword) == 4 bytes
    327
    328#########################################################################
    329# XDEF ****************************************************************	#
    330#	_isp_unimp(): 060ISP entry point for Unimplemented Instruction	#
    331#									#
    332#	This handler should be the first code executed upon taking the	#
    333#	"Unimplemented Integer Instruction" exception in an operating	#
    334#	system.								#
    335#									#
    336# XREF ****************************************************************	#
    337#	_imem_read_{word,long}() - read instruction word/longword	#
    338#	_mul64() - emulate 64-bit multiply				#
    339#	_div64() - emulate 64-bit divide				#
    340#	_moveperipheral() - emulate "movep"				#
    341#	_compandset() - emulate misaligned "cas"			#
    342#	_compandset2() - emulate "cas2"					#
    343#	_chk2_cmp2() - emulate "cmp2" and "chk2"			#
    344#	_isp_done() - "callout" for normal final exit			#
    345#	_real_trace() - "callout" for Trace exception			#
    346#	_real_chk() - "callout" for Chk exception			#
    347#	_real_divbyzero() - "callout" for DZ exception			#
    348#	_real_access() - "callout" for access error exception		#
    349#									#
    350# INPUT ***************************************************************	#
    351#	- The system stack contains the Unimp Int Instr stack frame	#
    352#									#
    353# OUTPUT **************************************************************	#
    354#	If Trace exception:						#
    355#	- The system stack changed to contain Trace exc stack frame	#
    356#	If Chk exception:						#
    357#	- The system stack changed to contain Chk exc stack frame	#
    358#	If DZ exception:						#
    359#	- The system stack changed to contain DZ exc stack frame	#
    360#	If access error exception:					#
    361#	- The system stack changed to contain access err exc stk frame	#
    362#	Else:								#
    363#	- Results saved as appropriate					#
    364#									#
    365# ALGORITHM ***********************************************************	#
    366#	This handler fetches the first instruction longword from	#
    367# memory and decodes it to determine which of the unimplemented		#
    368# integer instructions caused this exception. This handler then calls	#
    369# one of _mul64(), _div64(), _moveperipheral(), _compandset(),		#
    370# _compandset2(), or _chk2_cmp2() as appropriate.			#
    371#	Some of these instructions, by their nature, may produce other	#
    372# types of exceptions. "div" can produce a divide-by-zero exception,	#
    373# and "chk2" can cause a "Chk" exception. In both cases, the current	#
    374# exception stack frame must be converted to an exception stack frame	#
    375# of the correct exception type and an exit must be made through	#
    376# _real_divbyzero() or _real_chk() as appropriate. In addition, all	#
    377# instructions may be executing while Trace is enabled. If so, then	#
    378# a Trace exception stack frame must be created and an exit made	#
    379# through _real_trace().						#
    380#	Meanwhile, if any read or write to memory using the		#
    381# _mem_{read,write}() "callout"s returns a failing value, then an	#
    382# access error frame must be created and an exit made through		#
    383# _real_access().							#
    384#	If none of these occur, then a normal exit is made through	#
    385# _isp_done().								#
    386#									#
    387#	This handler, upon entry, saves almost all user-visible		#
    388# address and data registers to the stack. Although this may seem to	#
    389# cause excess memory traffic, it was found that due to having to	#
    390# access these register files for things like data retrieval and <ea>	#
    391# calculations, it was more efficient to have them on the stack where	#
    392# they could be accessed by indexing rather than to make subroutine	#
    393# calls to retrieve a register of a particular index.			#
    394#									#
    395#########################################################################
    396
    397	global		_isp_unimp
    398_isp_unimp:
    399	link.w		%a6,&-LOCAL_SIZE	# create room for stack frame
    400
    401	movm.l		&0x3fff,EXC_DREGS(%a6)	# store d0-d7/a0-a5
    402	mov.l		(%a6),EXC_A6(%a6)	# store a6
    403
    404	btst		&0x5,EXC_ISR(%a6)	# from s or u mode?
    405	bne.b		uieh_s			# supervisor mode
    406uieh_u:
    407	mov.l		%usp,%a0		# fetch user stack pointer
    408	mov.l		%a0,EXC_A7(%a6)		# store a7
    409	bra.b		uieh_cont
    410uieh_s:
    411	lea		0xc(%a6),%a0
    412	mov.l		%a0,EXC_A7(%a6)		# store corrected sp
    413
    414###############################################################################
    415
    416uieh_cont:
    417	clr.b		SPCOND_FLG(%a6)		# clear "special case" flag
    418
    419	mov.w		EXC_ISR(%a6),EXC_CC(%a6) # store cc copy on stack
    420	mov.l		EXC_IPC(%a6),EXC_EXTWPTR(%a6) # store extwptr on stack
    421
    422#
    423# fetch the opword and first extension word pointed to by the stacked pc
    424# and store them to the stack for now
    425#
    426	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
    427	addq.l		&0x4,EXC_EXTWPTR(%a6)	# incr instruction ptr
    428	bsr.l		_imem_read_long		# fetch opword & extword
    429	mov.l		%d0,EXC_OPWORD(%a6)	# store extword on stack
    430
    431
    432#########################################################################
    433# muls.l	0100 1100 00 |<ea>|	0*** 1100 0000 0***		#
    434# mulu.l	0100 1100 00 |<ea>|	0*** 0100 0000 0***		#
    435#									#
    436# divs.l	0100 1100 01 |<ea>|	0*** 1100 0000 0***		#
    437# divu.l	0100 1100 01 |<ea>|	0*** 0100 0000 0***		#
    438#									#
    439# movep.w m2r	0000 ***1 00 001***	| <displacement>  |		#
    440# movep.l m2r	0000 ***1 01 001***	| <displacement>  |		#
    441# movep.w r2m	0000 ***1 10 001***	| <displacement>  |		#
    442# movep.l r2m	0000 ***1 11 001***	| <displacement>  |		#
    443#									#
    444# cas.w		0000 1100 11 |<ea>|	0000 000* **00 0***		#
    445# cas.l		0000 1110 11 |<ea>|	0000 000* **00 0***		#
    446#									#
    447# cas2.w	0000 1100 11 111100	**** 000* **00 0***		#
    448#					**** 000* **00 0***		#
    449# cas2.l	0000 1110 11 111100	**** 000* **00 0***		#
    450#					**** 000* **00 0***		#
    451#									#
    452# chk2.b	0000 0000 11 |<ea>|	**** 1000 0000 0000		#
    453# chk2.w	0000 0010 11 |<ea>|	**** 1000 0000 0000		#
    454# chk2.l	0000 0100 11 |<ea>|	**** 1000 0000 0000		#
    455#									#
    456# cmp2.b	0000 0000 11 |<ea>|	**** 0000 0000 0000		#
    457# cmp2.w	0000 0010 11 |<ea>|	**** 0000 0000 0000		#
    458# cmp2.l	0000 0100 11 |<ea>|	**** 0000 0000 0000		#
    459#########################################################################
    460
    461#
    462# using bit 14 of the operation word, separate into 2 groups:
    463# (group1) mul64, div64
    464# (group2) movep, chk2, cmp2, cas2, cas
    465#
    466	btst		&0x1e,%d0		# group1 or group2
    467	beq.b		uieh_group2		# go handle group2
    468
    469#
    470# now, w/ group1, make mul64's decode the fastest since it will
    471# most likely be used the most.
    472#
    473uieh_group1:
    474	btst		&0x16,%d0		# test for div64
    475	bne.b		uieh_div64		# go handle div64
    476
    477uieh_mul64:
    478# mul64() may use ()+ addressing and may, therefore, alter a7
    479
    480	bsr.l		_mul64			# _mul64()
    481
    482	btst		&0x5,EXC_ISR(%a6)	# supervisor mode?
    483	beq.w		uieh_done
    484	btst		&mia7_bit,SPCOND_FLG(%a6) # was a7 changed?
    485	beq.w		uieh_done		# no
    486	btst		&0x7,EXC_ISR(%a6)	# is trace enabled?
    487	bne.w		uieh_trace_a7		# yes
    488	bra.w		uieh_a7			# no
    489
    490uieh_div64:
    491# div64() may use ()+ addressing and may, therefore, alter a7.
    492# div64() may take a divide by zero exception.
    493
    494	bsr.l		_div64			# _div64()
    495
    496# here, we sort out all of the special cases that may have happened.
    497	btst		&mia7_bit,SPCOND_FLG(%a6) # was a7 changed?
    498	bne.b		uieh_div64_a7		# yes
    499uieh_div64_dbyz:
    500	btst		&idbyz_bit,SPCOND_FLG(%a6) # did divide-by-zero occur?
    501	bne.w		uieh_divbyzero		# yes
    502	bra.w		uieh_done		# no
    503uieh_div64_a7:
    504	btst		&0x5,EXC_ISR(%a6)	# supervisor mode?
    505	beq.b		uieh_div64_dbyz		# no
    506# here, a7 has been incremented by 4 bytes in supervisor mode. we still
    507# may have the following 3 cases:
    508#	(i)	(a7)+
    509#	(ii)	(a7)+; trace
    510#	(iii)	(a7)+; divide-by-zero
    511#
    512	btst		&idbyz_bit,SPCOND_FLG(%a6) # did divide-by-zero occur?
    513	bne.w		uieh_divbyzero_a7	# yes
    514	tst.b		EXC_ISR(%a6)		# no; is trace enabled?
    515	bmi.w		uieh_trace_a7		# yes
    516	bra.w		uieh_a7			# no
    517
    518#
    519# now, w/ group2, make movep's decode the fastest since it will
    520# most likely be used the most.
    521#
    522uieh_group2:
    523	btst		&0x18,%d0		# test for not movep
    524	beq.b		uieh_not_movep
    525
    526
    527	bsr.l		_moveperipheral		# _movep()
    528	bra.w		uieh_done
    529
    530uieh_not_movep:
    531	btst		&0x1b,%d0		# test for chk2,cmp2
    532	beq.b		uieh_chk2cmp2		# go handle chk2,cmp2
    533
    534	swap		%d0			# put opword in lo word
    535	cmpi.b		%d0,&0xfc		# test for cas2
    536	beq.b		uieh_cas2		# go handle cas2
    537
    538uieh_cas:
    539
    540	bsr.l		_compandset		# _cas()
    541
    542# the cases of "cas Dc,Du,(a7)+" and "cas Dc,Du,-(a7)" used from supervisor
    543# mode are simply not considered valid and therefore are not handled.
    544
    545	bra.w		uieh_done
    546
    547uieh_cas2:
    548
    549	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
    550	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
    551	bsr.l		_imem_read_word		# read extension word
    552
    553	tst.l		%d1			# ifetch error?
    554	bne.w		isp_iacc		# yes
    555
    556	bsr.l		_compandset2		# _cas2()
    557	bra.w		uieh_done
    558
    559uieh_chk2cmp2:
    560# chk2 may take a chk exception
    561
    562	bsr.l		_chk2_cmp2		# _chk2_cmp2()
    563
    564# here we check to see if a chk trap should be taken
    565	cmpi.b		SPCOND_FLG(%a6),&ichk_flg
    566	bne.w		uieh_done
    567	bra.b		uieh_chk_trap
    568
    569###########################################################################
    570
    571#
    572# the required emulation has been completed. now, clean up the necessary stack
    573# info and prepare for rte
    574#
    575uieh_done:
    576	mov.b		EXC_CC+1(%a6),EXC_ISR+1(%a6) # insert new ccodes
    577
    578# if exception occurred in user mode, then we have to restore a7 in case it
    579# changed. we don't have to update a7  for supervisor mose because that case
    580# doesn't flow through here
    581	btst		&0x5,EXC_ISR(%a6)	# user or supervisor?
    582	bne.b		uieh_finish		# supervisor
    583
    584	mov.l		EXC_A7(%a6),%a0		# fetch user stack pointer
    585	mov.l		%a0,%usp		# restore it
    586
    587uieh_finish:
    588	movm.l		EXC_DREGS(%a6),&0x3fff	# restore d0-d7/a0-a5
    589
    590	btst		&0x7,EXC_ISR(%a6)	# is trace mode on?
    591	bne.b		uieh_trace		# yes;go handle trace mode
    592
    593	mov.l		EXC_EXTWPTR(%a6),EXC_IPC(%a6) # new pc on stack frame
    594	mov.l		EXC_A6(%a6),(%a6)	# prepare new a6 for unlink
    595	unlk		%a6			# unlink stack frame
    596	bra.l		_isp_done
    597
    598#
    599# The instruction that was just emulated was also being traced. The trace
    600# trap for this instruction will be lost unless we jump to the trace handler.
    601# So, here we create a Trace Exception format number two exception stack
    602# frame from the Unimplemented Integer Intruction Exception stack frame
    603# format number zero and jump to the user supplied hook "_real_trace()".
    604#
    605#		   UIEH FRAME		   TRACE FRAME
    606#		*****************	*****************
    607#		* 0x0 *  0x0f4	*	*    Current	*
    608#		*****************	*      PC	*
    609#		*    Current	*	*****************
    610#		*      PC	*	* 0x2 *  0x024	*
    611#		*****************	*****************
    612#		*      SR	*	*     Next	*
    613#		*****************	*      PC	*
    614#	      ->*     Old	*	*****************
    615#  from link -->*      A6	*	*      SR	*
    616#	        *****************	*****************
    617#	       /*      A7	*	*      New	* <-- for final unlink
    618#	      / *		*	*      A6	*
    619# link frame <  *****************	*****************
    620#	      \ ~		~	~		~
    621#	       \*****************	*****************
    622#
    623uieh_trace:
    624	mov.l		EXC_A6(%a6),-0x4(%a6)
    625	mov.w		EXC_ISR(%a6),0x0(%a6)
    626	mov.l		EXC_IPC(%a6),0x8(%a6)
    627	mov.l		EXC_EXTWPTR(%a6),0x2(%a6)
    628	mov.w		&0x2024,0x6(%a6)
    629	sub.l		&0x4,%a6
    630	unlk		%a6
    631	bra.l		_real_trace
    632
    633#
    634#	   UIEH FRAME		    CHK FRAME
    635#	*****************	*****************
    636#	* 0x0 *  0x0f4	*	*    Current	*
    637#	*****************	*      PC	*
    638#	*    Current	*	*****************
    639#	*      PC	*	* 0x2 *  0x018	*
    640#	*****************	*****************
    641#	*      SR	*	*     Next	*
    642#	*****************	*      PC	*
    643#	    (4 words)		*****************
    644#				*      SR	*
    645#				*****************
    646#				    (6 words)
    647#
    648# the chk2 instruction should take a chk trap. so, here we must create a
    649# chk stack frame from an unimplemented integer instruction exception frame
    650# and jump to the user supplied entry point "_real_chk()".
    651#
    652uieh_chk_trap:
    653	mov.b		EXC_CC+1(%a6),EXC_ISR+1(%a6) # insert new ccodes
    654	movm.l		EXC_DREGS(%a6),&0x3fff	# restore d0-d7/a0-a5
    655
    656	mov.w		EXC_ISR(%a6),(%a6)	# put new SR on stack
    657	mov.l		EXC_IPC(%a6),0x8(%a6)	# put "Current PC" on stack
    658	mov.l		EXC_EXTWPTR(%a6),0x2(%a6) # put "Next PC" on stack
    659	mov.w		&0x2018,0x6(%a6)	# put Vector Offset on stack
    660
    661	mov.l		EXC_A6(%a6),%a6		# restore a6
    662	add.l		&LOCAL_SIZE,%sp		# clear stack frame
    663
    664	bra.l		_real_chk
    665
    666#
    667#	   UIEH FRAME		 DIVBYZERO FRAME
    668#	*****************	*****************
    669#	* 0x0 *  0x0f4	*	*    Current	*
    670#	*****************	*      PC	*
    671#	*    Current	*	*****************
    672#	*      PC	*	* 0x2 *  0x014	*
    673#	*****************	*****************
    674#	*      SR	*	*     Next	*
    675#	*****************	*      PC	*
    676#	    (4 words)		*****************
    677#				*      SR	*
    678#				*****************
    679#				    (6 words)
    680#
    681# the divide instruction should take an integer divide by zero trap. so, here
    682# we must create a divbyzero stack frame from an unimplemented integer
    683# instruction exception frame and jump to the user supplied entry point
    684# "_real_divbyzero()".
    685#
    686uieh_divbyzero:
    687	mov.b		EXC_CC+1(%a6),EXC_ISR+1(%a6) # insert new ccodes
    688	movm.l		EXC_DREGS(%a6),&0x3fff	# restore d0-d7/a0-a5
    689
    690	mov.w		EXC_ISR(%a6),(%a6)	# put new SR on stack
    691	mov.l		EXC_IPC(%a6),0x8(%a6)	# put "Current PC" on stack
    692	mov.l		EXC_EXTWPTR(%a6),0x2(%a6) # put "Next PC" on stack
    693	mov.w		&0x2014,0x6(%a6)	# put Vector Offset on stack
    694
    695	mov.l		EXC_A6(%a6),%a6		# restore a6
    696	add.l		&LOCAL_SIZE,%sp		# clear stack frame
    697
    698	bra.l		_real_divbyzero
    699
    700#
    701#				 DIVBYZERO FRAME
    702#				*****************
    703#				*    Current	*
    704#	   UIEH FRAME		*      PC	*
    705#	*****************	*****************
    706#	* 0x0 *  0x0f4	*	* 0x2 * 0x014	*
    707#	*****************	*****************
    708#	*    Current	*	*     Next	*
    709#	*      PC	*	*      PC	*
    710#	*****************	*****************
    711#	*      SR	*	*      SR	*
    712#	*****************	*****************
    713#	    (4 words)		    (6 words)
    714#
    715# the divide instruction should take an integer divide by zero trap. so, here
    716# we must create a divbyzero stack frame from an unimplemented integer
    717# instruction exception frame and jump to the user supplied entry point
    718# "_real_divbyzero()".
    719#
    720# However, we must also deal with the fact that (a7)+ was used from supervisor
    721# mode, thereby shifting the stack frame up 4 bytes.
    722#
    723uieh_divbyzero_a7:
    724	mov.b		EXC_CC+1(%a6),EXC_ISR+1(%a6) # insert new ccodes
    725	movm.l		EXC_DREGS(%a6),&0x3fff	# restore d0-d7/a0-a5
    726
    727	mov.l		EXC_IPC(%a6),0xc(%a6)	# put "Current PC" on stack
    728	mov.w		&0x2014,0xa(%a6)	# put Vector Offset on stack
    729	mov.l		EXC_EXTWPTR(%a6),0x6(%a6) # put "Next PC" on stack
    730
    731	mov.l		EXC_A6(%a6),%a6		# restore a6
    732	add.l		&4+LOCAL_SIZE,%sp	# clear stack frame
    733
    734	bra.l		_real_divbyzero
    735
    736#
    737#				   TRACE FRAME
    738#				*****************
    739#				*    Current	*
    740#	   UIEH FRAME		*      PC	*
    741#	*****************	*****************
    742#	* 0x0 *  0x0f4	*	* 0x2 * 0x024	*
    743#	*****************	*****************
    744#	*    Current	*	*     Next	*
    745#	*      PC	*	*      PC	*
    746#	*****************	*****************
    747#	*      SR	*	*      SR	*
    748#	*****************	*****************
    749#	    (4 words)		    (6 words)
    750#
    751#
    752# The instruction that was just emulated was also being traced. The trace
    753# trap for this instruction will be lost unless we jump to the trace handler.
    754# So, here we create a Trace Exception format number two exception stack
    755# frame from the Unimplemented Integer Intruction Exception stack frame
    756# format number zero and jump to the user supplied hook "_real_trace()".
    757#
    758# However, we must also deal with the fact that (a7)+ was used from supervisor
    759# mode, thereby shifting the stack frame up 4 bytes.
    760#
    761uieh_trace_a7:
    762	mov.b		EXC_CC+1(%a6),EXC_ISR+1(%a6) # insert new ccodes
    763	movm.l		EXC_DREGS(%a6),&0x3fff	# restore d0-d7/a0-a5
    764
    765	mov.l		EXC_IPC(%a6),0xc(%a6)	# put "Current PC" on stack
    766	mov.w		&0x2024,0xa(%a6)	# put Vector Offset on stack
    767	mov.l		EXC_EXTWPTR(%a6),0x6(%a6) # put "Next PC" on stack
    768
    769	mov.l		EXC_A6(%a6),%a6		# restore a6
    770	add.l		&4+LOCAL_SIZE,%sp	# clear stack frame
    771
    772	bra.l		_real_trace
    773
    774#
    775#				   UIEH FRAME
    776#				*****************
    777#				* 0x0 * 0x0f4	*
    778#	   UIEH FRAME		*****************
    779#	*****************	*     Next	*
    780#	* 0x0 *  0x0f4	*	*      PC	*
    781#	*****************	*****************
    782#	*    Current	*	*      SR	*
    783#	*      PC	*	*****************
    784#	*****************	    (4 words)
    785#	*      SR	*
    786#	*****************
    787#	    (4 words)
    788uieh_a7:
    789	mov.b		EXC_CC+1(%a6),EXC_ISR+1(%a6) # insert new ccodes
    790	movm.l		EXC_DREGS(%a6),&0x3fff	# restore d0-d7/a0-a5
    791
    792	mov.w		&0x00f4,0xe(%a6)	# put Vector Offset on stack
    793	mov.l		EXC_EXTWPTR(%a6),0xa(%a6) # put "Next PC" on stack
    794	mov.w		EXC_ISR(%a6),0x8(%a6)	# put SR on stack
    795
    796	mov.l		EXC_A6(%a6),%a6		# restore a6
    797	add.l		&8+LOCAL_SIZE,%sp	# clear stack frame
    798	bra.l		_isp_done
    799
    800##########
    801
    802# this is the exit point if a data read or write fails.
    803# a0 = failing address
    804# d0 = fslw
    805isp_dacc:
    806	mov.l		%a0,(%a6)		# save address
    807	mov.l		%d0,-0x4(%a6)		# save partial fslw
    808
    809	lea		-64(%a6),%sp
    810	movm.l		(%sp)+,&0x7fff		# restore d0-d7/a0-a6
    811
    812	mov.l		0xc(%sp),-(%sp)		# move voff,hi(pc)
    813	mov.l		0x4(%sp),0x10(%sp)	# store fslw
    814	mov.l		0xc(%sp),0x4(%sp)	# store sr,lo(pc)
    815	mov.l		0x8(%sp),0xc(%sp)	# store address
    816	mov.l		(%sp)+,0x4(%sp)		# store voff,hi(pc)
    817	mov.w		&0x4008,0x6(%sp)	# store new voff
    818
    819	bra.b		isp_acc_exit
    820
    821# this is the exit point if an instruction word read fails.
    822# FSLW:
    823#	misaligned = true
    824#	read = true
    825#	size = word
    826#	instruction = true
    827#	software emulation error = true
    828isp_iacc:
    829	movm.l		EXC_DREGS(%a6),&0x3fff	# restore d0-d7/a0-a5
    830	unlk		%a6			# unlink frame
    831	sub.w		&0x8,%sp		# make room for acc frame
    832	mov.l		0x8(%sp),(%sp)		# store sr,lo(pc)
    833	mov.w		0xc(%sp),0x4(%sp)	# store hi(pc)
    834	mov.w		&0x4008,0x6(%sp)	# store new voff
    835	mov.l		0x2(%sp),0x8(%sp)	# store address (=pc)
    836	mov.l		&0x09428001,0xc(%sp)	# store fslw
    837
    838isp_acc_exit:
    839	btst		&0x5,(%sp)		# user or supervisor?
    840	beq.b		isp_acc_exit2		# user
    841	bset		&0x2,0xd(%sp)		# set supervisor TM bit
    842isp_acc_exit2:
    843	bra.l		_real_access
    844
    845# if the addressing mode was (an)+ or -(an), the address register must
    846# be restored to its pre-exception value before entering _real_access.
    847isp_restore:
    848	cmpi.b		SPCOND_FLG(%a6),&restore_flg # do we need a restore?
    849	bne.b		isp_restore_done	# no
    850	clr.l		%d0
    851	mov.b		EXC_SAVREG(%a6),%d0	# regno to restore
    852	mov.l		EXC_SAVVAL(%a6),(EXC_AREGS,%a6,%d0.l*4) # restore value
    853isp_restore_done:
    854	rts
    855
    856#########################################################################
    857# XDEF ****************************************************************	#
    858#	_calc_ea(): routine to calculate effective address		#
    859#									#
    860# XREF ****************************************************************	#
    861#	_imem_read_word() - read instruction word			#
    862#	_imem_read_long() - read instruction longword			#
    863#	_dmem_read_long() - read data longword (for memory indirect)	#
    864#	isp_iacc() - handle instruction access error exception		#
    865#	isp_dacc() - handle data access error exception			#
    866#									#
    867# INPUT ***************************************************************	#
    868#	d0 = number of bytes related to effective address (w,l)		#
    869#									#
    870# OUTPUT **************************************************************	#
    871#	If exiting through isp_dacc...					#
    872#		a0 = failing address					#
    873#		d0 = FSLW						#
    874#	elsif exiting though isp_iacc...				#
    875#		none							#
    876#	else								#
    877#		a0 = effective address					#
    878#									#
    879# ALGORITHM ***********************************************************	#
    880#	The effective address type is decoded from the opword residing	#
    881# on the stack. A jump table is used to vector to a routine for the	#
    882# appropriate mode. Since none of the emulated integer instructions	#
    883# uses byte-sized operands, only handle word and long operations.	#
    884#									#
    885#	Dn,An	- shouldn't enter here					#
    886#	(An)	- fetch An value from stack				#
    887#	-(An)	- fetch An value from stack; return decr value;		#
    888#		  place decr value on stack; store old value in case of	#
    889#		  future access error; if -(a7), set mda7_flg in	#
    890#		  SPCOND_FLG						#
    891#	(An)+	- fetch An value from stack; return value;		#
    892#		  place incr value on stack; store old value in case of	#
    893#		  future access error; if (a7)+, set mia7_flg in	#
    894#		  SPCOND_FLG						#
    895#	(d16,An) - fetch An value from stack; read d16 using		#
    896#		  _imem_read_word(); fetch may fail -> branch to	#
    897#		  isp_iacc()						#
    898#	(xxx).w,(xxx).l - use _imem_read_{word,long}() to fetch		#
    899#		  address; fetch may fail				#
    900#	#<data> - return address of immediate value; set immed_flg	#
    901#		  in SPCOND_FLG						#
    902#	(d16,PC) - fetch stacked PC value; read d16 using		#
    903#		  _imem_read_word(); fetch may fail -> branch to	#
    904#		  isp_iacc()						#
    905#	everything else - read needed displacements as appropriate w/	#
    906#		  _imem_read_{word,long}(); read may fail; if memory	#
    907#		  indirect, read indirect address using			#
    908#		  _dmem_read_long() which may also fail			#
    909#									#
    910#########################################################################
    911
    912	global		_calc_ea
    913_calc_ea:
    914	mov.l		%d0,%a0			# move # bytes to a0
    915
    916# MODE and REG are taken from the EXC_OPWORD.
    917	mov.w		EXC_OPWORD(%a6),%d0	# fetch opcode word
    918	mov.w		%d0,%d1			# make a copy
    919
    920	andi.w		&0x3f,%d0		# extract mode field
    921	andi.l		&0x7,%d1		# extract reg  field
    922
    923# jump to the corresponding function for each {MODE,REG} pair.
    924	mov.w		(tbl_ea_mode.b,%pc,%d0.w*2), %d0 # fetch jmp distance
    925	jmp		(tbl_ea_mode.b,%pc,%d0.w*1) # jmp to correct ea mode
    926
    927	swbeg		&64
    928tbl_ea_mode:
    929	short		tbl_ea_mode	-	tbl_ea_mode
    930	short		tbl_ea_mode	-	tbl_ea_mode
    931	short		tbl_ea_mode	-	tbl_ea_mode
    932	short		tbl_ea_mode	-	tbl_ea_mode
    933	short		tbl_ea_mode	-	tbl_ea_mode
    934	short		tbl_ea_mode	-	tbl_ea_mode
    935	short		tbl_ea_mode	-	tbl_ea_mode
    936	short		tbl_ea_mode	-	tbl_ea_mode
    937
    938	short		tbl_ea_mode	-	tbl_ea_mode
    939	short		tbl_ea_mode	-	tbl_ea_mode
    940	short		tbl_ea_mode	-	tbl_ea_mode
    941	short		tbl_ea_mode	-	tbl_ea_mode
    942	short		tbl_ea_mode	-	tbl_ea_mode
    943	short		tbl_ea_mode	-	tbl_ea_mode
    944	short		tbl_ea_mode	-	tbl_ea_mode
    945	short		tbl_ea_mode	-	tbl_ea_mode
    946
    947	short		addr_ind_a0	-	tbl_ea_mode
    948	short		addr_ind_a1	-	tbl_ea_mode
    949	short		addr_ind_a2	-	tbl_ea_mode
    950	short		addr_ind_a3	-	tbl_ea_mode
    951	short		addr_ind_a4	-	tbl_ea_mode
    952	short		addr_ind_a5	-	tbl_ea_mode
    953	short		addr_ind_a6	-	tbl_ea_mode
    954	short		addr_ind_a7	-	tbl_ea_mode
    955
    956	short		addr_ind_p_a0	-	tbl_ea_mode
    957	short		addr_ind_p_a1	-	tbl_ea_mode
    958	short		addr_ind_p_a2	-	tbl_ea_mode
    959	short		addr_ind_p_a3	-	tbl_ea_mode
    960	short		addr_ind_p_a4	-	tbl_ea_mode
    961	short		addr_ind_p_a5	-	tbl_ea_mode
    962	short		addr_ind_p_a6	-	tbl_ea_mode
    963	short		addr_ind_p_a7	-	tbl_ea_mode
    964
    965	short		addr_ind_m_a0		-	tbl_ea_mode
    966	short		addr_ind_m_a1		-	tbl_ea_mode
    967	short		addr_ind_m_a2		-	tbl_ea_mode
    968	short		addr_ind_m_a3		-	tbl_ea_mode
    969	short		addr_ind_m_a4		-	tbl_ea_mode
    970	short		addr_ind_m_a5		-	tbl_ea_mode
    971	short		addr_ind_m_a6		-	tbl_ea_mode
    972	short		addr_ind_m_a7		-	tbl_ea_mode
    973
    974	short		addr_ind_disp_a0	-	tbl_ea_mode
    975	short		addr_ind_disp_a1	-	tbl_ea_mode
    976	short		addr_ind_disp_a2	-	tbl_ea_mode
    977	short		addr_ind_disp_a3	-	tbl_ea_mode
    978	short		addr_ind_disp_a4	-	tbl_ea_mode
    979	short		addr_ind_disp_a5	-	tbl_ea_mode
    980	short		addr_ind_disp_a6	-	tbl_ea_mode
    981	short		addr_ind_disp_a7	-	tbl_ea_mode
    982
    983	short		_addr_ind_ext		-	tbl_ea_mode
    984	short		_addr_ind_ext		-	tbl_ea_mode
    985	short		_addr_ind_ext		-	tbl_ea_mode
    986	short		_addr_ind_ext		-	tbl_ea_mode
    987	short		_addr_ind_ext		-	tbl_ea_mode
    988	short		_addr_ind_ext		-	tbl_ea_mode
    989	short		_addr_ind_ext		-	tbl_ea_mode
    990	short		_addr_ind_ext		-	tbl_ea_mode
    991
    992	short		abs_short		-	tbl_ea_mode
    993	short		abs_long		-	tbl_ea_mode
    994	short		pc_ind			-	tbl_ea_mode
    995	short		pc_ind_ext		-	tbl_ea_mode
    996	short		immediate		-	tbl_ea_mode
    997	short		tbl_ea_mode		-	tbl_ea_mode
    998	short		tbl_ea_mode		-	tbl_ea_mode
    999	short		tbl_ea_mode		-	tbl_ea_mode
   1000
   1001###################################
   1002# Address register indirect: (An) #
   1003###################################
   1004addr_ind_a0:
   1005	mov.l		EXC_A0(%a6),%a0		# Get current a0
   1006	rts
   1007
   1008addr_ind_a1:
   1009	mov.l		EXC_A1(%a6),%a0		# Get current a1
   1010	rts
   1011
   1012addr_ind_a2:
   1013	mov.l		EXC_A2(%a6),%a0		# Get current a2
   1014	rts
   1015
   1016addr_ind_a3:
   1017	mov.l		EXC_A3(%a6),%a0		# Get current a3
   1018	rts
   1019
   1020addr_ind_a4:
   1021	mov.l		EXC_A4(%a6),%a0		# Get current a4
   1022	rts
   1023
   1024addr_ind_a5:
   1025	mov.l		EXC_A5(%a6),%a0		# Get current a5
   1026	rts
   1027
   1028addr_ind_a6:
   1029	mov.l		EXC_A6(%a6),%a0		# Get current a6
   1030	rts
   1031
   1032addr_ind_a7:
   1033	mov.l		EXC_A7(%a6),%a0		# Get current a7
   1034	rts
   1035
   1036#####################################################
   1037# Address register indirect w/ postincrement: (An)+ #
   1038#####################################################
   1039addr_ind_p_a0:
   1040	mov.l		%a0,%d0			# copy no. bytes
   1041	mov.l		EXC_A0(%a6),%a0		# load current value
   1042	add.l		%a0,%d0			# increment
   1043	mov.l		%d0,EXC_A0(%a6)		# save incremented value
   1044
   1045	mov.l		%a0,EXC_SAVVAL(%a6)	# save in case of access error
   1046	mov.b		&0x0,EXC_SAVREG(%a6)	# save regno, too
   1047	mov.b		&restore_flg,SPCOND_FLG(%a6) # set flag
   1048	rts
   1049
   1050addr_ind_p_a1:
   1051	mov.l		%a0,%d0			# copy no. bytes
   1052	mov.l		EXC_A1(%a6),%a0		# load current value
   1053	add.l		%a0,%d0			# increment
   1054	mov.l		%d0,EXC_A1(%a6)		# save incremented value
   1055
   1056	mov.l		%a0,EXC_SAVVAL(%a6)	# save in case of access error
   1057	mov.b		&0x1,EXC_SAVREG(%a6)	# save regno, too
   1058	mov.b		&restore_flg,SPCOND_FLG(%a6) # set flag
   1059	rts
   1060
   1061addr_ind_p_a2:
   1062	mov.l		%a0,%d0			# copy no. bytes
   1063	mov.l		EXC_A2(%a6),%a0		# load current value
   1064	add.l		%a0,%d0			# increment
   1065	mov.l		%d0,EXC_A2(%a6)		# save incremented value
   1066
   1067	mov.l		%a0,EXC_SAVVAL(%a6)	# save in case of access error
   1068	mov.b		&0x2,EXC_SAVREG(%a6)	# save regno, too
   1069	mov.b		&restore_flg,SPCOND_FLG(%a6) # set flag
   1070	rts
   1071
   1072addr_ind_p_a3:
   1073	mov.l		%a0,%d0			# copy no. bytes
   1074	mov.l		EXC_A3(%a6),%a0		# load current value
   1075	add.l		%a0,%d0			# increment
   1076	mov.l		%d0,EXC_A3(%a6)		# save incremented value
   1077
   1078	mov.l		%a0,EXC_SAVVAL(%a6)	# save in case of access error
   1079	mov.b		&0x3,EXC_SAVREG(%a6)	# save regno, too
   1080	mov.b		&restore_flg,SPCOND_FLG(%a6) # set flag
   1081	rts
   1082
   1083addr_ind_p_a4:
   1084	mov.l		%a0,%d0			# copy no. bytes
   1085	mov.l		EXC_A4(%a6),%a0		# load current value
   1086	add.l		%a0,%d0			# increment
   1087	mov.l		%d0,EXC_A4(%a6)		# save incremented value
   1088
   1089	mov.l		%a0,EXC_SAVVAL(%a6)	# save in case of access error
   1090	mov.b		&0x4,EXC_SAVREG(%a6)	# save regno, too
   1091	mov.b		&restore_flg,SPCOND_FLG(%a6) # set flag
   1092	rts
   1093
   1094addr_ind_p_a5:
   1095	mov.l		%a0,%d0			# copy no. bytes
   1096	mov.l		EXC_A5(%a6),%a0		# load current value
   1097	add.l		%a0,%d0			# increment
   1098	mov.l		%d0,EXC_A5(%a6)		# save incremented value
   1099
   1100	mov.l		%a0,EXC_SAVVAL(%a6)	# save in case of access error
   1101	mov.b		&0x5,EXC_SAVREG(%a6)	# save regno, too
   1102	mov.b		&restore_flg,SPCOND_FLG(%a6) # set flag
   1103	rts
   1104
   1105addr_ind_p_a6:
   1106	mov.l		%a0,%d0			# copy no. bytes
   1107	mov.l		EXC_A6(%a6),%a0		# load current value
   1108	add.l		%a0,%d0			# increment
   1109	mov.l		%d0,EXC_A6(%a6)		# save incremented value
   1110
   1111	mov.l		%a0,EXC_SAVVAL(%a6)	# save in case of access error
   1112	mov.b		&0x6,EXC_SAVREG(%a6)	# save regno, too
   1113	mov.b		&restore_flg,SPCOND_FLG(%a6) # set flag
   1114	rts
   1115
   1116addr_ind_p_a7:
   1117	mov.b		&mia7_flg,SPCOND_FLG(%a6) # set "special case" flag
   1118
   1119	mov.l		%a0,%d0			# copy no. bytes
   1120	mov.l		EXC_A7(%a6),%a0		# load current value
   1121	add.l		%a0,%d0			# increment
   1122	mov.l		%d0,EXC_A7(%a6)		# save incremented value
   1123	rts
   1124
   1125####################################################
   1126# Address register indirect w/ predecrement: -(An) #
   1127####################################################
   1128addr_ind_m_a0:
   1129	mov.l		EXC_A0(%a6),%d0		# Get current a0
   1130	mov.l		%d0,EXC_SAVVAL(%a6)	# save in case of access error
   1131	sub.l		%a0,%d0			# Decrement
   1132	mov.l		%d0,EXC_A0(%a6)		# Save decr value
   1133	mov.l		%d0,%a0
   1134
   1135	mov.b		&0x0,EXC_SAVREG(%a6)	# save regno, too
   1136	mov.b		&restore_flg,SPCOND_FLG(%a6) # set flag
   1137	rts
   1138
   1139addr_ind_m_a1:
   1140	mov.l		EXC_A1(%a6),%d0		# Get current a1
   1141	mov.l		%d0,EXC_SAVVAL(%a6)	# save in case of access error
   1142	sub.l		%a0,%d0			# Decrement
   1143	mov.l		%d0,EXC_A1(%a6)		# Save decr value
   1144	mov.l		%d0,%a0
   1145
   1146	mov.b		&0x1,EXC_SAVREG(%a6)	# save regno, too
   1147	mov.b		&restore_flg,SPCOND_FLG(%a6) # set flag
   1148	rts
   1149
   1150addr_ind_m_a2:
   1151	mov.l		EXC_A2(%a6),%d0		# Get current a2
   1152	mov.l		%d0,EXC_SAVVAL(%a6)	# save in case of access error
   1153	sub.l		%a0,%d0			# Decrement
   1154	mov.l		%d0,EXC_A2(%a6)		# Save decr value
   1155	mov.l		%d0,%a0
   1156
   1157	mov.b		&0x2,EXC_SAVREG(%a6)	# save regno, too
   1158	mov.b		&restore_flg,SPCOND_FLG(%a6) # set flag
   1159	rts
   1160
   1161addr_ind_m_a3:
   1162	mov.l		EXC_A3(%a6),%d0		# Get current a3
   1163	mov.l		%d0,EXC_SAVVAL(%a6)	# save in case of access error
   1164	sub.l		%a0,%d0			# Decrement
   1165	mov.l		%d0,EXC_A3(%a6)		# Save decr value
   1166	mov.l		%d0,%a0
   1167
   1168	mov.b		&0x3,EXC_SAVREG(%a6)	# save regno, too
   1169	mov.b		&restore_flg,SPCOND_FLG(%a6) # set flag
   1170	rts
   1171
   1172addr_ind_m_a4:
   1173	mov.l		EXC_A4(%a6),%d0		# Get current a4
   1174	mov.l		%d0,EXC_SAVVAL(%a6)	# save in case of access error
   1175	sub.l		%a0,%d0			# Decrement
   1176	mov.l		%d0,EXC_A4(%a6)		# Save decr value
   1177	mov.l		%d0,%a0
   1178
   1179	mov.b		&0x4,EXC_SAVREG(%a6)	# save regno, too
   1180	mov.b		&restore_flg,SPCOND_FLG(%a6) # set flag
   1181	rts
   1182
   1183addr_ind_m_a5:
   1184	mov.l		EXC_A5(%a6),%d0		# Get current a5
   1185	mov.l		%d0,EXC_SAVVAL(%a6)	# save in case of access error
   1186	sub.l		%a0,%d0			# Decrement
   1187	mov.l		%d0,EXC_A5(%a6)		# Save decr value
   1188	mov.l		%d0,%a0
   1189
   1190	mov.b		&0x5,EXC_SAVREG(%a6)	# save regno, too
   1191	mov.b		&restore_flg,SPCOND_FLG(%a6) # set flag
   1192	rts
   1193
   1194addr_ind_m_a6:
   1195	mov.l		EXC_A6(%a6),%d0		# Get current a6
   1196	mov.l		%d0,EXC_SAVVAL(%a6)	# save in case of access error
   1197	sub.l		%a0,%d0			# Decrement
   1198	mov.l		%d0,EXC_A6(%a6)		# Save decr value
   1199	mov.l		%d0,%a0
   1200
   1201	mov.b		&0x6,EXC_SAVREG(%a6)	# save regno, too
   1202	mov.b		&restore_flg,SPCOND_FLG(%a6) # set flag
   1203	rts
   1204
   1205addr_ind_m_a7:
   1206	mov.b		&mda7_flg,SPCOND_FLG(%a6) # set "special case" flag
   1207
   1208	mov.l		EXC_A7(%a6),%d0		# Get current a7
   1209	sub.l		%a0,%d0			# Decrement
   1210	mov.l		%d0,EXC_A7(%a6)		# Save decr value
   1211	mov.l		%d0,%a0
   1212	rts
   1213
   1214########################################################
   1215# Address register indirect w/ displacement: (d16, An) #
   1216########################################################
   1217addr_ind_disp_a0:
   1218	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
   1219	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
   1220	bsr.l		_imem_read_word
   1221
   1222	tst.l		%d1			# ifetch error?
   1223	bne.l		isp_iacc		# yes
   1224
   1225	mov.w		%d0,%a0			# sign extend displacement
   1226	add.l		EXC_A0(%a6),%a0		# a0 + d16
   1227	rts
   1228
   1229addr_ind_disp_a1:
   1230	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
   1231	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
   1232	bsr.l		_imem_read_word
   1233
   1234	tst.l		%d1			# ifetch error?
   1235	bne.l		isp_iacc		# yes
   1236
   1237	mov.w		%d0,%a0			# sign extend displacement
   1238	add.l		EXC_A1(%a6),%a0		# a1 + d16
   1239	rts
   1240
   1241addr_ind_disp_a2:
   1242	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
   1243	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
   1244	bsr.l		_imem_read_word
   1245
   1246	tst.l		%d1			# ifetch error?
   1247	bne.l		isp_iacc		# yes
   1248
   1249	mov.w		%d0,%a0			# sign extend displacement
   1250	add.l		EXC_A2(%a6),%a0		# a2 + d16
   1251	rts
   1252
   1253addr_ind_disp_a3:
   1254	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
   1255	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
   1256	bsr.l		_imem_read_word
   1257
   1258	tst.l		%d1			# ifetch error?
   1259	bne.l		isp_iacc		# yes
   1260
   1261	mov.w		%d0,%a0			# sign extend displacement
   1262	add.l		EXC_A3(%a6),%a0		# a3 + d16
   1263	rts
   1264
   1265addr_ind_disp_a4:
   1266	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
   1267	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
   1268	bsr.l		_imem_read_word
   1269
   1270	tst.l		%d1			# ifetch error?
   1271	bne.l		isp_iacc		# yes
   1272
   1273	mov.w		%d0,%a0			# sign extend displacement
   1274	add.l		EXC_A4(%a6),%a0		# a4 + d16
   1275	rts
   1276
   1277addr_ind_disp_a5:
   1278	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
   1279	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
   1280	bsr.l		_imem_read_word
   1281
   1282	tst.l		%d1			# ifetch error?
   1283	bne.l		isp_iacc		# yes
   1284
   1285	mov.w		%d0,%a0			# sign extend displacement
   1286	add.l		EXC_A5(%a6),%a0		# a5 + d16
   1287	rts
   1288
   1289addr_ind_disp_a6:
   1290	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
   1291	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
   1292	bsr.l		_imem_read_word
   1293
   1294	tst.l		%d1			# ifetch error?
   1295	bne.l		isp_iacc		# yes
   1296
   1297	mov.w		%d0,%a0			# sign extend displacement
   1298	add.l		EXC_A6(%a6),%a0		# a6 + d16
   1299	rts
   1300
   1301addr_ind_disp_a7:
   1302	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
   1303	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
   1304	bsr.l		_imem_read_word
   1305
   1306	tst.l		%d1			# ifetch error?
   1307	bne.l		isp_iacc		# yes
   1308
   1309	mov.w		%d0,%a0			# sign extend displacement
   1310	add.l		EXC_A7(%a6),%a0		# a7 + d16
   1311	rts
   1312
   1313########################################################################
   1314# Address register indirect w/ index(8-bit displacement): (dn, An, Xn) #
   1315#    "       "         "    w/   "  (base displacement): (bd, An, Xn)  #
   1316# Memory indirect postindexed: ([bd, An], Xn, od)		       #
   1317# Memory indirect preindexed: ([bd, An, Xn], od)		       #
   1318########################################################################
   1319_addr_ind_ext:
   1320	mov.l		%d1,-(%sp)
   1321
   1322	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
   1323	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
   1324	bsr.l		_imem_read_word		# fetch extword in d0
   1325
   1326	tst.l		%d1			# ifetch error?
   1327	bne.l		isp_iacc		# yes
   1328
   1329	mov.l		(%sp)+,%d1
   1330
   1331	mov.l		(EXC_AREGS,%a6,%d1.w*4),%a0 # put base in a0
   1332
   1333	btst		&0x8,%d0
   1334	beq.b		addr_ind_index_8bit	# for ext word or not?
   1335
   1336	movm.l		&0x3c00,-(%sp)		# save d2-d5
   1337
   1338	mov.l		%d0,%d5			# put extword in d5
   1339	mov.l		%a0,%d3			# put base in d3
   1340
   1341	bra.l		calc_mem_ind		# calc memory indirect
   1342
   1343addr_ind_index_8bit:
   1344	mov.l		%d2,-(%sp)		# save old d2
   1345
   1346	mov.l		%d0,%d1
   1347	rol.w		&0x4,%d1
   1348	andi.w		&0xf,%d1		# extract index regno
   1349
   1350	mov.l		(EXC_DREGS,%a6,%d1.w*4),%d1 # fetch index reg value
   1351
   1352	btst		&0xb,%d0		# is it word or long?
   1353	bne.b		aii8_long
   1354	ext.l		%d1			# sign extend word index
   1355aii8_long:
   1356	mov.l		%d0,%d2
   1357	rol.w		&0x7,%d2
   1358	andi.l		&0x3,%d2		# extract scale value
   1359
   1360	lsl.l		%d2,%d1			# shift index by scale
   1361
   1362	extb.l		%d0			# sign extend displacement
   1363	add.l		%d1,%d0			# index + disp
   1364	add.l		%d0,%a0			# An + (index + disp)
   1365
   1366	mov.l		(%sp)+,%d2		# restore old d2
   1367	rts
   1368
   1369######################
   1370# Immediate: #<data> #
   1371#########################################################################
   1372# word, long: <ea> of the data is the current extension word		#
   1373#	pointer value. new extension word pointer is simply the old	#
   1374#	plus the number of bytes in the data type(2 or 4).		#
   1375#########################################################################
   1376immediate:
   1377	mov.b		&immed_flg,SPCOND_FLG(%a6) # set immediate flag
   1378
   1379	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch extension word ptr
   1380	rts
   1381
   1382###########################
   1383# Absolute short: (XXX).W #
   1384###########################
   1385abs_short:
   1386	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
   1387	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
   1388	bsr.l		_imem_read_word		# fetch short address
   1389
   1390	tst.l		%d1			# ifetch error?
   1391	bne.l		isp_iacc		# yes
   1392
   1393	mov.w		%d0,%a0			# return <ea> in a0
   1394	rts
   1395
   1396##########################
   1397# Absolute long: (XXX).L #
   1398##########################
   1399abs_long:
   1400	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
   1401	addq.l		&0x4,EXC_EXTWPTR(%a6)	# incr instruction ptr
   1402	bsr.l		_imem_read_long		# fetch long address
   1403
   1404	tst.l		%d1			# ifetch error?
   1405	bne.l		isp_iacc		# yes
   1406
   1407	mov.l		%d0,%a0			# return <ea> in a0
   1408	rts
   1409
   1410#######################################################
   1411# Program counter indirect w/ displacement: (d16, PC) #
   1412#######################################################
   1413pc_ind:
   1414	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
   1415	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
   1416	bsr.l		_imem_read_word		# fetch word displacement
   1417
   1418	tst.l		%d1			# ifetch error?
   1419	bne.l		isp_iacc		# yes
   1420
   1421	mov.w		%d0,%a0			# sign extend displacement
   1422
   1423	add.l		EXC_EXTWPTR(%a6),%a0	# pc + d16
   1424
   1425# _imem_read_word() increased the extwptr by 2. need to adjust here.
   1426	subq.l		&0x2,%a0		# adjust <ea>
   1427
   1428	rts
   1429
   1430##########################################################
   1431# PC indirect w/ index(8-bit displacement): (d8, PC, An) #
   1432# "     "     w/   "  (base displacement): (bd, PC, An)  #
   1433# PC memory indirect postindexed: ([bd, PC], Xn, od)     #
   1434# PC memory indirect preindexed: ([bd, PC, Xn], od)      #
   1435##########################################################
   1436pc_ind_ext:
   1437	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
   1438	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
   1439	bsr.l		_imem_read_word		# fetch ext word
   1440
   1441	tst.l		%d1			# ifetch error?
   1442	bne.l		isp_iacc		# yes
   1443
   1444	mov.l		EXC_EXTWPTR(%a6),%a0	# put base in a0
   1445	subq.l		&0x2,%a0		# adjust base
   1446
   1447	btst		&0x8,%d0		# is disp only 8 bits?
   1448	beq.b		pc_ind_index_8bit	# yes
   1449
   1450# the indexed addressing mode uses a base displacement of size
   1451# word or long
   1452	movm.l		&0x3c00,-(%sp)		# save d2-d5
   1453
   1454	mov.l		%d0,%d5			# put extword in d5
   1455	mov.l		%a0,%d3			# put base in d3
   1456
   1457	bra.l		calc_mem_ind		# calc memory indirect
   1458
   1459pc_ind_index_8bit:
   1460	mov.l		%d2,-(%sp)		# create a temp register
   1461
   1462	mov.l		%d0,%d1			# make extword copy
   1463	rol.w		&0x4,%d1		# rotate reg num into place
   1464	andi.w		&0xf,%d1		# extract register number
   1465
   1466	mov.l		(EXC_DREGS,%a6,%d1.w*4),%d1 # fetch index reg value
   1467
   1468	btst		&0xb,%d0		# is index word or long?
   1469	bne.b		pii8_long		# long
   1470	ext.l		%d1			# sign extend word index
   1471pii8_long:
   1472	mov.l		%d0,%d2			# make extword copy
   1473	rol.w		&0x7,%d2		# rotate scale value into place
   1474	andi.l		&0x3,%d2		# extract scale value
   1475
   1476	lsl.l		%d2,%d1			# shift index by scale
   1477
   1478	extb.l		%d0			# sign extend displacement
   1479	add.l		%d1,%d0			# index + disp
   1480	add.l		%d0,%a0			# An + (index + disp)
   1481
   1482	mov.l		(%sp)+,%d2		# restore temp register
   1483
   1484	rts
   1485
   1486# a5 = exc_extwptr	(global to uaeh)
   1487# a4 = exc_opword	(global to uaeh)
   1488# a3 = exc_dregs	(global to uaeh)
   1489
   1490# d2 = index		(internal "     "    )
   1491# d3 = base		(internal "     "    )
   1492# d4 = od		(internal "     "    )
   1493# d5 = extword		(internal "     "    )
   1494calc_mem_ind:
   1495	btst		&0x6,%d5		# is the index suppressed?
   1496	beq.b		calc_index
   1497	clr.l		%d2			# yes, so index = 0
   1498	bra.b		base_supp_ck
   1499calc_index:
   1500	bfextu		%d5{&16:&4},%d2
   1501	mov.l		(EXC_DREGS,%a6,%d2.w*4),%d2
   1502	btst		&0xb,%d5		# is index word or long?
   1503	bne.b		no_ext
   1504	ext.l		%d2
   1505no_ext:
   1506	bfextu		%d5{&21:&2},%d0
   1507	lsl.l		%d0,%d2
   1508base_supp_ck:
   1509	btst		&0x7,%d5		# is the bd suppressed?
   1510	beq.b		no_base_sup
   1511	clr.l		%d3
   1512no_base_sup:
   1513	bfextu		%d5{&26:&2},%d0	# get bd size
   1514#	beq.l		_error			# if (size == 0) it's reserved
   1515	cmpi.b		%d0,&2
   1516	blt.b		no_bd
   1517	beq.b		get_word_bd
   1518
   1519	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
   1520	addq.l		&0x4,EXC_EXTWPTR(%a6)	# incr instruction ptr
   1521	bsr.l		_imem_read_long
   1522
   1523	tst.l		%d1			# ifetch error?
   1524	bne.l		isp_iacc		# yes
   1525
   1526	bra.b		chk_ind
   1527get_word_bd:
   1528	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
   1529	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
   1530	bsr.l		_imem_read_word
   1531
   1532	tst.l		%d1			# ifetch error?
   1533	bne.l		isp_iacc		# yes
   1534
   1535	ext.l		%d0			# sign extend bd
   1536
   1537chk_ind:
   1538	add.l		%d0,%d3			# base += bd
   1539no_bd:
   1540	bfextu		%d5{&30:&2},%d0		# is od suppressed?
   1541	beq.w		aii_bd
   1542	cmpi.b		%d0,&0x2
   1543	blt.b		null_od
   1544	beq.b		word_od
   1545
   1546	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
   1547	addq.l		&0x4,EXC_EXTWPTR(%a6)	# incr instruction ptr
   1548	bsr.l		_imem_read_long
   1549
   1550	tst.l		%d1			# ifetch error?
   1551	bne.l		isp_iacc		# yes
   1552
   1553	bra.b		add_them
   1554
   1555word_od:
   1556	mov.l		EXC_EXTWPTR(%a6),%a0	# fetch instruction addr
   1557	addq.l		&0x2,EXC_EXTWPTR(%a6)	# incr instruction ptr
   1558	bsr.l		_imem_read_word
   1559
   1560	tst.l		%d1			# ifetch error?
   1561	bne.l		isp_iacc		# yes
   1562
   1563	ext.l		%d0			# sign extend od
   1564	bra.b		add_them
   1565
   1566null_od:
   1567	clr.l		%d0
   1568add_them:
   1569	mov.l		%d0,%d4
   1570	btst		&0x2,%d5		# pre or post indexing?
   1571	beq.b		pre_indexed
   1572
   1573	mov.l		%d3,%a0
   1574	bsr.l		_dmem_read_long
   1575
   1576	tst.l		%d1			# dfetch error?
   1577	bne.b		calc_ea_err		# yes
   1578
   1579	add.l		%d2,%d0			# <ea> += index
   1580	add.l		%d4,%d0			# <ea> += od
   1581	bra.b		done_ea
   1582
   1583pre_indexed:
   1584	add.l		%d2,%d3			# preindexing
   1585	mov.l		%d3,%a0
   1586	bsr.l		_dmem_read_long
   1587
   1588	tst.l		%d1			# ifetch error?
   1589	bne.b		calc_ea_err		# yes
   1590
   1591	add.l		%d4,%d0			# ea += od
   1592	bra.b		done_ea
   1593
   1594aii_bd:
   1595	add.l		%d2,%d3			# ea = (base + bd) + index
   1596	mov.l		%d3,%d0
   1597done_ea:
   1598	mov.l		%d0,%a0
   1599
   1600	movm.l		(%sp)+,&0x003c		# restore d2-d5
   1601	rts
   1602
   1603# if dmem_read_long() returns a fail message in d1, the package
   1604# must create an access error frame. here, we pass a skeleton fslw
   1605# and the failing address to the routine that creates the new frame.
   1606# FSLW:
   1607#	read = true
   1608#	size = longword
   1609#	TM = data
   1610#	software emulation error = true
   1611calc_ea_err:
   1612	mov.l		%d3,%a0			# pass failing address
   1613	mov.l		&0x01010001,%d0		# pass fslw
   1614	bra.l		isp_dacc
   1615
   1616#########################################################################
   1617# XDEF **************************************************************** #
   1618#	_moveperipheral(): routine to emulate movep instruction		#
   1619#									#
   1620# XREF **************************************************************** #
   1621#	_dmem_read_byte() - read byte from memory			#
   1622#	_dmem_write_byte() - write byte to memory			#
   1623#	isp_dacc() - handle data access error exception			#
   1624#									#
   1625# INPUT *************************************************************** #
   1626#	none								#
   1627#									#
   1628# OUTPUT ************************************************************** #
   1629#	If exiting through isp_dacc...					#
   1630#		a0 = failing address					#
   1631#		d0 = FSLW						#
   1632#	else								#
   1633#		none							#
   1634#									#
   1635# ALGORITHM ***********************************************************	#
   1636#	Decode the movep instruction words stored at EXC_OPWORD and	#
   1637# either read or write the required bytes from/to memory. Use the	#
   1638# _dmem_{read,write}_byte() routines. If one of the memory routines	#
   1639# returns a failing value, we must pass the failing address and	a FSLW	#
   1640# to the _isp_dacc() routine.						#
   1641#	Since this instruction is used to access peripherals, make sure	#
   1642# to only access the required bytes.					#
   1643#									#
   1644#########################################################################
   1645
   1646###########################
   1647# movep.(w,l)	Dx,(d,Ay) #
   1648# movep.(w,l)	(d,Ay),Dx #
   1649###########################
   1650	global		_moveperipheral
   1651_moveperipheral:
   1652	mov.w		EXC_OPWORD(%a6),%d1	# fetch the opcode word
   1653
   1654	mov.b		%d1,%d0
   1655	and.w		&0x7,%d0		# extract Ay from opcode word
   1656
   1657	mov.l		(EXC_AREGS,%a6,%d0.w*4),%a0 # fetch ay
   1658
   1659	add.w		EXC_EXTWORD(%a6),%a0	# add: an + sgn_ext(disp)
   1660
   1661	btst		&0x7,%d1		# (reg 2 mem) or (mem 2 reg)
   1662	beq.w		mem2reg
   1663
   1664# reg2mem: fetch dx, then write it to memory
   1665reg2mem:
   1666	mov.w		%d1,%d0
   1667	rol.w		&0x7,%d0
   1668	and.w		&0x7,%d0		# extract Dx from opcode word
   1669
   1670	mov.l		(EXC_DREGS,%a6,%d0.w*4), %d0 # fetch dx
   1671
   1672	btst		&0x6,%d1		# word or long operation?
   1673	beq.b		r2mwtrans
   1674
   1675# a0 = dst addr
   1676# d0 = Dx
   1677r2mltrans:
   1678	mov.l		%d0,%d2			# store data
   1679	mov.l		%a0,%a2			# store addr
   1680	rol.l		&0x8,%d2
   1681	mov.l		%d2,%d0
   1682
   1683	bsr.l		_dmem_write_byte	# os  : write hi
   1684
   1685	tst.l		%d1			# dfetch error?
   1686	bne.w		movp_write_err		# yes
   1687
   1688	add.w		&0x2,%a2		# incr addr
   1689	mov.l		%a2,%a0
   1690	rol.l		&0x8,%d2
   1691	mov.l		%d2,%d0
   1692
   1693	bsr.l		_dmem_write_byte	# os  : write lo
   1694
   1695	tst.l		%d1			# dfetch error?
   1696	bne.w		movp_write_err		# yes
   1697
   1698	add.w		&0x2,%a2		# incr addr
   1699	mov.l		%a2,%a0
   1700	rol.l		&0x8,%d2
   1701	mov.l		%d2,%d0
   1702
   1703	bsr.l		_dmem_write_byte	# os  : write lo
   1704
   1705	tst.l		%d1			# dfetch error?
   1706	bne.w		movp_write_err		# yes
   1707
   1708	add.w		&0x2,%a2		# incr addr
   1709	mov.l		%a2,%a0
   1710	rol.l		&0x8,%d2
   1711	mov.l		%d2,%d0
   1712
   1713	bsr.l		_dmem_write_byte	# os  : write lo
   1714
   1715	tst.l		%d1			# dfetch error?
   1716	bne.w		movp_write_err		# yes
   1717
   1718	rts
   1719
   1720# a0 = dst addr
   1721# d0 = Dx
   1722r2mwtrans:
   1723	mov.l		%d0,%d2			# store data
   1724	mov.l		%a0,%a2			# store addr
   1725	lsr.w		&0x8,%d0
   1726
   1727	bsr.l		_dmem_write_byte	# os  : write hi
   1728
   1729	tst.l		%d1			# dfetch error?
   1730	bne.w		movp_write_err		# yes
   1731
   1732	add.w		&0x2,%a2
   1733	mov.l		%a2,%a0
   1734	mov.l		%d2,%d0
   1735
   1736	bsr.l		_dmem_write_byte	# os  : write lo
   1737
   1738	tst.l		%d1			# dfetch error?
   1739	bne.w		movp_write_err		# yes
   1740
   1741	rts
   1742
   1743# mem2reg: read bytes from memory.
   1744# determines the dest register, and then writes the bytes into it.
   1745mem2reg:
   1746	btst		&0x6,%d1		# word or long operation?
   1747	beq.b		m2rwtrans
   1748
   1749# a0 = dst addr
   1750m2rltrans:
   1751	mov.l		%a0,%a2			# store addr
   1752
   1753	bsr.l		_dmem_read_byte		# read first byte
   1754
   1755	tst.l		%d1			# dfetch error?
   1756	bne.w		movp_read_err		# yes
   1757
   1758	mov.l		%d0,%d2
   1759
   1760	add.w		&0x2,%a2		# incr addr by 2 bytes
   1761	mov.l		%a2,%a0
   1762
   1763	bsr.l		_dmem_read_byte		# read second byte
   1764
   1765	tst.l		%d1			# dfetch error?
   1766	bne.w		movp_read_err		# yes
   1767
   1768	lsl.w		&0x8,%d2
   1769	mov.b		%d0,%d2			# append bytes
   1770
   1771	add.w		&0x2,%a2		# incr addr by 2 bytes
   1772	mov.l		%a2,%a0
   1773
   1774	bsr.l		_dmem_read_byte		# read second byte
   1775
   1776	tst.l		%d1			# dfetch error?
   1777	bne.w		movp_read_err		# yes
   1778
   1779	lsl.l		&0x8,%d2
   1780	mov.b		%d0,%d2			# append bytes
   1781
   1782	add.w		&0x2,%a2		# incr addr by 2 bytes
   1783	mov.l		%a2,%a0
   1784
   1785	bsr.l		_dmem_read_byte		# read second byte
   1786
   1787	tst.l		%d1			# dfetch error?
   1788	bne.w		movp_read_err		# yes
   1789
   1790	lsl.l		&0x8,%d2
   1791	mov.b		%d0,%d2			# append bytes
   1792
   1793	mov.b		EXC_OPWORD(%a6),%d1
   1794	lsr.b		&0x1,%d1
   1795	and.w		&0x7,%d1		# extract Dx from opcode word
   1796
   1797	mov.l		%d2,(EXC_DREGS,%a6,%d1.w*4) # store dx
   1798
   1799	rts
   1800
   1801# a0 = dst addr
   1802m2rwtrans:
   1803	mov.l		%a0,%a2			# store addr
   1804
   1805	bsr.l		_dmem_read_byte		# read first byte
   1806
   1807	tst.l		%d1			# dfetch error?
   1808	bne.w		movp_read_err		# yes
   1809
   1810	mov.l		%d0,%d2
   1811
   1812	add.w		&0x2,%a2		# incr addr by 2 bytes
   1813	mov.l		%a2,%a0
   1814
   1815	bsr.l		_dmem_read_byte		# read second byte
   1816
   1817	tst.l		%d1			# dfetch error?
   1818	bne.w		movp_read_err		# yes
   1819
   1820	lsl.w		&0x8,%d2
   1821	mov.b		%d0,%d2			# append bytes
   1822
   1823	mov.b		EXC_OPWORD(%a6),%d1
   1824	lsr.b		&0x1,%d1
   1825	and.w		&0x7,%d1		# extract Dx from opcode word
   1826
   1827	mov.w		%d2,(EXC_DREGS+2,%a6,%d1.w*4) # store dx
   1828
   1829	rts
   1830
   1831# if dmem_{read,write}_byte() returns a fail message in d1, the package
   1832# must create an access error frame. here, we pass a skeleton fslw
   1833# and the failing address to the routine that creates the new frame.
   1834# FSLW:
   1835#	write = true
   1836#	size = byte
   1837#	TM = data
   1838#	software emulation error = true
   1839movp_write_err:
   1840	mov.l		%a2,%a0			# pass failing address
   1841	mov.l		&0x00a10001,%d0		# pass fslw
   1842	bra.l		isp_dacc
   1843
   1844# FSLW:
   1845#	read = true
   1846#	size = byte
   1847#	TM = data
   1848#	software emulation error = true
   1849movp_read_err:
   1850	mov.l		%a2,%a0			# pass failing address
   1851	mov.l		&0x01210001,%d0		# pass fslw
   1852	bra.l		isp_dacc
   1853
   1854#########################################################################
   1855# XDEF ****************************************************************	#
   1856#	_chk2_cmp2(): routine to emulate chk2/cmp2 instructions		#
   1857#									#
   1858# XREF ****************************************************************	#
   1859#	_calc_ea(): calculate effective address				#
   1860#	_dmem_read_long(): read operands				#
   1861#	_dmem_read_word(): read operands				#
   1862#	isp_dacc(): handle data access error exception			#
   1863#									#
   1864# INPUT ***************************************************************	#
   1865#	none								#
   1866#									#
   1867# OUTPUT **************************************************************	#
   1868#	If exiting through isp_dacc...					#
   1869#		a0 = failing address					#
   1870#		d0 = FSLW						#
   1871#	else								#
   1872#		none							#
   1873#									#
   1874# ALGORITHM ***********************************************************	#
   1875#	First, calculate the effective address, then fetch the byte,	#
   1876# word, or longword sized operands. Then, in the interest of		#
   1877# simplicity, all operands are converted to longword size whether the	#
   1878# operation is byte, word, or long. The bounds are sign extended	#
   1879# accordingly. If Rn is a data register, Rn is also sign extended. If	#
   1880# Rn is an address register, it need not be sign extended since the	#
   1881# full register is always used.						#
   1882#	The comparisons are made and the condition codes calculated.	#
   1883# If the instruction is chk2 and the Rn value is out-of-bounds, set	#
   1884# the ichk_flg in SPCOND_FLG.						#
   1885#	If the memory fetch returns a failing value, pass the failing	#
   1886# address and FSLW to the isp_dacc() routine.				#
   1887#									#
   1888#########################################################################
   1889
   1890	global		_chk2_cmp2
   1891_chk2_cmp2:
   1892
   1893# passing size parameter doesn't matter since chk2 & cmp2 can't do
   1894# either predecrement, postincrement, or immediate.
   1895	bsr.l		_calc_ea		# calculate <ea>
   1896
   1897	mov.b		EXC_EXTWORD(%a6), %d0	# fetch hi extension word
   1898	rol.b		&0x4, %d0		# rotate reg bits into lo
   1899	and.w		&0xf, %d0		# extract reg bits
   1900
   1901	mov.l		(EXC_DREGS,%a6,%d0.w*4), %d2 # get regval
   1902
   1903	cmpi.b		EXC_OPWORD(%a6), &0x2	# what size is operation?
   1904	blt.b		chk2_cmp2_byte		# size == byte
   1905	beq.b		chk2_cmp2_word		# size == word
   1906
   1907# the bounds are longword size. call routine to read the lower
   1908# bound into d0 and the higher bound into d1.
   1909chk2_cmp2_long:
   1910	mov.l		%a0,%a2			# save copy of <ea>
   1911	bsr.l		_dmem_read_long		# fetch long lower bound
   1912
   1913	tst.l		%d1			# dfetch error?
   1914	bne.w		chk2_cmp2_err_l		# yes
   1915
   1916	mov.l		%d0,%d3			# save long lower bound
   1917	addq.l		&0x4,%a2
   1918	mov.l		%a2,%a0			# pass <ea> of long upper bound
   1919	bsr.l		_dmem_read_long		# fetch long upper bound
   1920
   1921	tst.l		%d1			# dfetch error?
   1922	bne.w		chk2_cmp2_err_l		# yes
   1923
   1924	mov.l		%d0,%d1			# long upper bound in d1
   1925	mov.l		%d3,%d0			# long lower bound in d0
   1926	bra.w		chk2_cmp2_compare	# go do the compare emulation
   1927
   1928# the bounds are word size. fetch them in one subroutine call by
   1929# reading a longword. sign extend both. if it's a data operation,
   1930# sign extend Rn to long, also.
   1931chk2_cmp2_word:
   1932	mov.l		%a0,%a2
   1933	bsr.l		_dmem_read_long		# fetch 2 word bounds
   1934
   1935	tst.l		%d1			# dfetch error?
   1936	bne.w		chk2_cmp2_err_l		# yes
   1937
   1938	mov.w		%d0, %d1		# place hi in %d1
   1939	swap		%d0			# place lo in %d0
   1940
   1941	ext.l		%d0			# sign extend lo bnd
   1942	ext.l		%d1			# sign extend hi bnd
   1943
   1944	btst		&0x7, EXC_EXTWORD(%a6)	# address compare?
   1945	bne.w		chk2_cmp2_compare	# yes; don't sign extend
   1946
   1947# operation is a data register compare.
   1948# sign extend word to long so we can do simple longword compares.
   1949	ext.l		%d2			# sign extend data word
   1950	bra.w		chk2_cmp2_compare	# go emulate compare
   1951
   1952# the bounds are byte size. fetch them in one subroutine call by
   1953# reading a word. sign extend both. if it's a data operation,
   1954# sign extend Rn to long, also.
   1955chk2_cmp2_byte:
   1956	mov.l		%a0,%a2
   1957	bsr.l		_dmem_read_word		# fetch 2 byte bounds
   1958
   1959	tst.l		%d1			# dfetch error?
   1960	bne.w		chk2_cmp2_err_w		# yes
   1961
   1962	mov.b		%d0, %d1		# place hi in %d1
   1963	lsr.w		&0x8, %d0		# place lo in %d0
   1964
   1965	extb.l		%d0			# sign extend lo bnd
   1966	extb.l		%d1			# sign extend hi bnd
   1967
   1968	btst		&0x7, EXC_EXTWORD(%a6)	# address compare?
   1969	bne.b		chk2_cmp2_compare	# yes; don't sign extend
   1970
   1971# operation is a data register compare.
   1972# sign extend byte to long so we can do simple longword compares.
   1973	extb.l		%d2			# sign extend data byte
   1974
   1975#
   1976# To set the ccodes correctly:
   1977#	(1) save 'Z' bit from (Rn - lo)
   1978#	(2) save 'Z' and 'N' bits from ((hi - lo) - (Rn - hi))
   1979#	(3) keep 'X', 'N', and 'V' from before instruction
   1980#	(4) combine ccodes
   1981#
   1982chk2_cmp2_compare:
   1983	sub.l		%d0, %d2		# (Rn - lo)
   1984	mov.w		%cc, %d3		# fetch resulting ccodes
   1985	andi.b		&0x4, %d3		# keep 'Z' bit
   1986	sub.l		%d0, %d1		# (hi - lo)
   1987	cmp.l		%d1,%d2			# ((hi - lo) - (Rn - hi))
   1988
   1989	mov.w		%cc, %d4		# fetch resulting ccodes
   1990	or.b		%d4, %d3		# combine w/ earlier ccodes
   1991	andi.b		&0x5, %d3		# keep 'Z' and 'N'
   1992
   1993	mov.w		EXC_CC(%a6), %d4	# fetch old ccodes
   1994	andi.b		&0x1a, %d4		# keep 'X','N','V' bits
   1995	or.b		%d3, %d4		# insert new ccodes
   1996	mov.w		%d4, EXC_CC(%a6)	# save new ccodes
   1997
   1998	btst		&0x3, EXC_EXTWORD(%a6)	# separate chk2,cmp2
   1999	bne.b		chk2_finish		# it's a chk2
   2000
   2001	rts
   2002
   2003# this code handles the only difference between chk2 and cmp2. chk2 would
   2004# have trapped out if the value was out of bounds. we check this by seeing
   2005# if the 'N' bit was set by the operation.
   2006chk2_finish:
   2007	btst		&0x0, %d4		# is 'N' bit set?
   2008	bne.b		chk2_trap		# yes;chk2 should trap
   2009	rts
   2010chk2_trap:
   2011	mov.b		&ichk_flg,SPCOND_FLG(%a6) # set "special case" flag
   2012	rts
   2013
   2014# if dmem_read_{long,word}() returns a fail message in d1, the package
   2015# must create an access error frame. here, we pass a skeleton fslw
   2016# and the failing address to the routine that creates the new frame.
   2017# FSLW:
   2018#	read = true
   2019#	size = longword
   2020#	TM = data
   2021#	software emulation error = true
   2022chk2_cmp2_err_l:
   2023	mov.l		%a2,%a0			# pass failing address
   2024	mov.l		&0x01010001,%d0		# pass fslw
   2025	bra.l		isp_dacc
   2026
   2027# FSLW:
   2028#	read = true
   2029#	size = word
   2030#	TM = data
   2031#	software emulation error = true
   2032chk2_cmp2_err_w:
   2033	mov.l		%a2,%a0			# pass failing address
   2034	mov.l		&0x01410001,%d0		# pass fslw
   2035	bra.l		isp_dacc
   2036
   2037#########################################################################
   2038# XDEF ****************************************************************	#
   2039#	_div64(): routine to emulate div{u,s}.l <ea>,Dr:Dq		#
   2040#							64/32->32r:32q	#
   2041#									#
   2042# XREF ****************************************************************	#
   2043#	_calc_ea() - calculate effective address			#
   2044#	isp_iacc() - handle instruction access error exception		#
   2045#	isp_dacc() - handle data access error exception			#
   2046#	isp_restore() - restore An on access error w/ -() or ()+	#
   2047#									#
   2048# INPUT ***************************************************************	#
   2049#	none								#
   2050#									#
   2051# OUTPUT **************************************************************	#
   2052#	If exiting through isp_dacc...					#
   2053#		a0 = failing address					#
   2054#		d0 = FSLW						#
   2055#	else								#
   2056#		none							#
   2057#									#
   2058# ALGORITHM ***********************************************************	#
   2059#	First, decode the operand location. If it's in Dn, fetch from	#
   2060# the stack. If it's in memory, use _calc_ea() to calculate the		#
   2061# effective address. Use _dmem_read_long() to fetch at that address.	#
   2062# Unless the operand is immediate data. Then use _imem_read_long().	#
   2063# Send failures to isp_dacc() or isp_iacc() as appropriate.		#
   2064#	If the operands are signed, make them unsigned and save	the	#
   2065# sign info for later. Separate out special cases like divide-by-zero	#
   2066# or 32-bit divides if possible. Else, use a special math algorithm	#
   2067# to calculate the result.						#
   2068#	Restore sign info if signed instruction. Set the condition	#
   2069# codes. Set idbyz_flg in SPCOND_FLG if divisor was zero. Store the	#
   2070# quotient and remainder in the appropriate data registers on the stack.#
   2071#									#
   2072#########################################################################
   2073
   2074set	NDIVISOR,	EXC_TEMP+0x0
   2075set	NDIVIDEND,	EXC_TEMP+0x1
   2076set	NDRSAVE,	EXC_TEMP+0x2
   2077set	NDQSAVE,	EXC_TEMP+0x4
   2078set	DDSECOND,	EXC_TEMP+0x6
   2079set	DDQUOTIENT,	EXC_TEMP+0x8
   2080set	DDNORMAL,	EXC_TEMP+0xc
   2081
   2082	global		_div64
   2083#############
   2084# div(u,s)l #
   2085#############
   2086_div64:
   2087	mov.b		EXC_OPWORD+1(%a6), %d0
   2088	andi.b		&0x38, %d0		# extract src mode
   2089
   2090	bne.w		dcontrolmodel_s		# %dn dest or control mode?
   2091
   2092	mov.b		EXC_OPWORD+1(%a6), %d0	# extract Dn from opcode
   2093	andi.w		&0x7, %d0
   2094	mov.l		(EXC_DREGS,%a6,%d0.w*4), %d7 # fetch divisor from register
   2095
   2096dgotsrcl:
   2097	beq.w		div64eq0		# divisor is = 0!!!
   2098
   2099	mov.b		EXC_EXTWORD+1(%a6), %d0	# extract Dr from extword
   2100	mov.b		EXC_EXTWORD(%a6), %d1	# extract Dq from extword
   2101	and.w		&0x7, %d0
   2102	lsr.b		&0x4, %d1
   2103	and.w		&0x7, %d1
   2104	mov.w		%d0, NDRSAVE(%a6)	# save Dr for later
   2105	mov.w		%d1, NDQSAVE(%a6)	# save Dq for later
   2106
   2107# fetch %dr and %dq directly off stack since all regs are saved there
   2108	mov.l		(EXC_DREGS,%a6,%d0.w*4), %d5 # get dividend hi
   2109	mov.l		(EXC_DREGS,%a6,%d1.w*4), %d6 # get dividend lo
   2110
   2111# separate signed and unsigned divide
   2112	btst		&0x3, EXC_EXTWORD(%a6)	# signed or unsigned?
   2113	beq.b		dspecialcases		# use positive divide
   2114
   2115# save the sign of the divisor
   2116# make divisor unsigned if it's negative
   2117	tst.l		%d7			# chk sign of divisor
   2118	slt		NDIVISOR(%a6)		# save sign of divisor
   2119	bpl.b		dsgndividend
   2120	neg.l		%d7			# complement negative divisor
   2121
   2122# save the sign of the dividend
   2123# make dividend unsigned if it's negative
   2124dsgndividend:
   2125	tst.l		%d5			# chk sign of hi(dividend)
   2126	slt		NDIVIDEND(%a6)		# save sign of dividend
   2127	bpl.b		dspecialcases
   2128
   2129	mov.w		&0x0, %cc		# clear 'X' cc bit
   2130	negx.l		%d6			# complement signed dividend
   2131	negx.l		%d5
   2132
   2133# extract some special cases:
   2134#	- is (dividend == 0) ?
   2135#	- is (hi(dividend) == 0 && (divisor <= lo(dividend))) ? (32-bit div)
   2136dspecialcases:
   2137	tst.l		%d5			# is (hi(dividend) == 0)
   2138	bne.b		dnormaldivide		# no, so try it the long way
   2139
   2140	tst.l		%d6			# is (lo(dividend) == 0), too
   2141	beq.w		ddone			# yes, so (dividend == 0)
   2142
   2143	cmp.l		%d7,%d6			# is (divisor <= lo(dividend))
   2144	bls.b		d32bitdivide		# yes, so use 32 bit divide
   2145
   2146	exg		%d5,%d6			# q = 0, r = dividend
   2147	bra.w		divfinish		# can't divide, we're done.
   2148
   2149d32bitdivide:
   2150	tdivu.l		%d7, %d5:%d6		# it's only a 32/32 bit div!
   2151
   2152	bra.b		divfinish
   2153
   2154dnormaldivide:
   2155# last special case:
   2156#	- is hi(dividend) >= divisor ? if yes, then overflow
   2157	cmp.l		%d7,%d5
   2158	bls.b		ddovf			# answer won't fit in 32 bits
   2159
   2160# perform the divide algorithm:
   2161	bsr.l		dclassical		# do int divide
   2162
   2163# separate into signed and unsigned finishes.
   2164divfinish:
   2165	btst		&0x3, EXC_EXTWORD(%a6)	# do divs, divu separately
   2166	beq.b		ddone			# divu has no processing!!!
   2167
   2168# it was a divs.l, so ccode setting is a little more complicated...
   2169	tst.b		NDIVIDEND(%a6)		# remainder has same sign
   2170	beq.b		dcc			# as dividend.
   2171	neg.l		%d5			# sgn(rem) = sgn(dividend)
   2172dcc:
   2173	mov.b		NDIVISOR(%a6), %d0
   2174	eor.b		%d0, NDIVIDEND(%a6)	# chk if quotient is negative
   2175	beq.b		dqpos			# branch to quot positive
   2176
   2177# 0x80000000 is the largest number representable as a 32-bit negative
   2178# number. the negative of 0x80000000 is 0x80000000.
   2179	cmpi.l		%d6, &0x80000000	# will (-quot) fit in 32 bits?
   2180	bhi.b		ddovf
   2181
   2182	neg.l		%d6			# make (-quot) 2's comp
   2183
   2184	bra.b		ddone
   2185
   2186dqpos:
   2187	btst		&0x1f, %d6		# will (+quot) fit in 32 bits?
   2188	bne.b		ddovf
   2189
   2190ddone:
   2191# at this point, result is normal so ccodes are set based on result.
   2192	mov.w		EXC_CC(%a6), %cc
   2193	tst.l		%d6			# set %ccode bits
   2194	mov.w		%cc, EXC_CC(%a6)
   2195
   2196	mov.w		NDRSAVE(%a6), %d0	# get Dr off stack
   2197	mov.w		NDQSAVE(%a6), %d1	# get Dq off stack
   2198
   2199# if the register numbers are the same, only the quotient gets saved.
   2200# so, if we always save the quotient second, we save ourselves a cmp&beq
   2201	mov.l		%d5, (EXC_DREGS,%a6,%d0.w*4) # save remainder
   2202	mov.l		%d6, (EXC_DREGS,%a6,%d1.w*4) # save quotient
   2203
   2204	rts
   2205
   2206ddovf:
   2207	bset		&0x1, EXC_CC+1(%a6)	# 'V' set on overflow
   2208	bclr		&0x0, EXC_CC+1(%a6)	# 'C' cleared on overflow
   2209
   2210	rts
   2211
   2212div64eq0:
   2213	andi.b		&0x1e, EXC_CC+1(%a6)	# clear 'C' bit on divbyzero
   2214	ori.b		&idbyz_flg,SPCOND_FLG(%a6) # set "special case" flag
   2215	rts
   2216
   2217###########################################################################
   2218#########################################################################
   2219# This routine uses the 'classical' Algorithm D from Donald Knuth's	#
   2220# Art of Computer Programming, vol II, Seminumerical Algorithms.	#
   2221# For this implementation b=2**16, and the target is U1U2U3U4/V1V2,	#
   2222# where U,V are words of the quadword dividend and longword divisor,	#
   2223# and U1, V1 are the most significant words.				#
   2224#									#
   2225# The most sig. longword of the 64 bit dividend must be in %d5, least	#
   2226# in %d6. The divisor must be in the variable ddivisor, and the		#
   2227# signed/unsigned flag ddusign must be set (0=unsigned,1=signed).	#
   2228# The quotient is returned in %d6, remainder in %d5, unless the		#
   2229# v (overflow) bit is set in the saved %ccr. If overflow, the dividend	#
   2230# is unchanged.								#
   2231#########################################################################
   2232dclassical:
   2233# if the divisor msw is 0, use simpler algorithm then the full blown
   2234# one at ddknuth:
   2235
   2236	cmpi.l		%d7, &0xffff
   2237	bhi.b		ddknuth			# go use D. Knuth algorithm
   2238
   2239# Since the divisor is only a word (and larger than the mslw of the dividend),
   2240# a simpler algorithm may be used :
   2241# In the general case, four quotient words would be created by
   2242# dividing the divisor word into each dividend word. In this case,
   2243# the first two quotient words must be zero, or overflow would occur.
   2244# Since we already checked this case above, we can treat the most significant
   2245# longword of the dividend as (0) remainder (see Knuth) and merely complete
   2246# the last two divisions to get a quotient longword and word remainder:
   2247
   2248	clr.l		%d1
   2249	swap		%d5			# same as r*b if previous step rqd
   2250	swap		%d6			# get u3 to lsw position
   2251	mov.w		%d6, %d5		# rb + u3
   2252
   2253	divu.w		%d7, %d5
   2254
   2255	mov.w		%d5, %d1		# first quotient word
   2256	swap		%d6			# get u4
   2257	mov.w		%d6, %d5		# rb + u4
   2258
   2259	divu.w		%d7, %d5
   2260
   2261	swap		%d1
   2262	mov.w		%d5, %d1		# 2nd quotient 'digit'
   2263	clr.w		%d5
   2264	swap		%d5			# now remainder
   2265	mov.l		%d1, %d6		# and quotient
   2266
   2267	rts
   2268
   2269ddknuth:
   2270# In this algorithm, the divisor is treated as a 2 digit (word) number
   2271# which is divided into a 3 digit (word) dividend to get one quotient
   2272# digit (word). After subtraction, the dividend is shifted and the
   2273# process repeated. Before beginning, the divisor and quotient are
   2274# 'normalized' so that the process of estimating the quotient digit
   2275# will yield verifiably correct results..
   2276
   2277	clr.l		DDNORMAL(%a6)		# count of shifts for normalization
   2278	clr.b		DDSECOND(%a6)		# clear flag for quotient digits
   2279	clr.l		%d1			# %d1 will hold trial quotient
   2280ddnchk:
   2281	btst		&31, %d7		# must we normalize? first word of
   2282	bne.b		ddnormalized		# divisor (V1) must be >= 65536/2
   2283	addq.l		&0x1, DDNORMAL(%a6)	# count normalization shifts
   2284	lsl.l		&0x1, %d7		# shift the divisor
   2285	lsl.l		&0x1, %d6		# shift u4,u3 with overflow to u2
   2286	roxl.l		&0x1, %d5		# shift u1,u2
   2287	bra.w		ddnchk
   2288ddnormalized:
   2289
   2290# Now calculate an estimate of the quotient words (msw first, then lsw).
   2291# The comments use subscripts for the first quotient digit determination.
   2292	mov.l		%d7, %d3		# divisor
   2293	mov.l		%d5, %d2		# dividend mslw
   2294	swap		%d2
   2295	swap		%d3
   2296	cmp.w		%d2, %d3		# V1 = U1 ?
   2297	bne.b		ddqcalc1
   2298	mov.w		&0xffff, %d1		# use max trial quotient word
   2299	bra.b		ddadj0
   2300ddqcalc1:
   2301	mov.l		%d5, %d1
   2302
   2303	divu.w		%d3, %d1		# use quotient of mslw/msw
   2304
   2305	andi.l		&0x0000ffff, %d1	# zero any remainder
   2306ddadj0:
   2307
   2308# now test the trial quotient and adjust. This step plus the
   2309# normalization assures (according to Knuth) that the trial
   2310# quotient will be at worst 1 too large.
   2311	mov.l		%d6, -(%sp)
   2312	clr.w		%d6			# word u3 left
   2313	swap		%d6			# in lsw position
   2314ddadj1: mov.l		%d7, %d3
   2315	mov.l		%d1, %d2
   2316	mulu.w		%d7, %d2		# V2q
   2317	swap		%d3
   2318	mulu.w		%d1, %d3		# V1q
   2319	mov.l		%d5, %d4		# U1U2
   2320	sub.l		%d3, %d4		# U1U2 - V1q
   2321
   2322	swap		%d4
   2323
   2324	mov.w		%d4,%d0
   2325	mov.w		%d6,%d4			# insert lower word (U3)
   2326
   2327	tst.w		%d0			# is upper word set?
   2328	bne.w		ddadjd1
   2329
   2330#	add.l		%d6, %d4		# (U1U2 - V1q) + U3
   2331
   2332	cmp.l		%d2, %d4
   2333	bls.b		ddadjd1			# is V2q > (U1U2-V1q) + U3 ?
   2334	subq.l		&0x1, %d1		# yes, decrement and recheck
   2335	bra.b		ddadj1
   2336ddadjd1:
   2337# now test the word by multiplying it by the divisor (V1V2) and comparing
   2338# the 3 digit (word) result with the current dividend words
   2339	mov.l		%d5, -(%sp)		# save %d5 (%d6 already saved)
   2340	mov.l		%d1, %d6
   2341	swap		%d6			# shift answer to ms 3 words
   2342	mov.l		%d7, %d5
   2343	bsr.l		dmm2
   2344	mov.l		%d5, %d2		# now %d2,%d3 are trial*divisor
   2345	mov.l		%d6, %d3
   2346	mov.l		(%sp)+, %d5		# restore dividend
   2347	mov.l		(%sp)+, %d6
   2348	sub.l		%d3, %d6
   2349	subx.l		%d2, %d5		# subtract double precision
   2350	bcc		dd2nd			# no carry, do next quotient digit
   2351	subq.l		&0x1, %d1		# q is one too large
   2352# need to add back divisor longword to current ms 3 digits of dividend
   2353# - according to Knuth, this is done only 2 out of 65536 times for random
   2354# divisor, dividend selection.
   2355	clr.l		%d2
   2356	mov.l		%d7, %d3
   2357	swap		%d3
   2358	clr.w		%d3			# %d3 now ls word of divisor
   2359	add.l		%d3, %d6		# aligned with 3rd word of dividend
   2360	addx.l		%d2, %d5
   2361	mov.l		%d7, %d3
   2362	clr.w		%d3			# %d3 now ms word of divisor
   2363	swap		%d3			# aligned with 2nd word of dividend
   2364	add.l		%d3, %d5
   2365dd2nd:
   2366	tst.b		DDSECOND(%a6)		# both q words done?
   2367	bne.b		ddremain
   2368# first quotient digit now correct. store digit and shift the
   2369# (subtracted) dividend
   2370	mov.w		%d1, DDQUOTIENT(%a6)
   2371	clr.l		%d1
   2372	swap		%d5
   2373	swap		%d6
   2374	mov.w		%d6, %d5
   2375	clr.w		%d6
   2376	st		DDSECOND(%a6)		# second digit
   2377	bra.w		ddnormalized
   2378ddremain:
   2379# add 2nd word to quotient, get the remainder.
   2380	mov.w		%d1, DDQUOTIENT+2(%a6)
   2381# shift down one word/digit to renormalize remainder.
   2382	mov.w		%d5, %d6
   2383	swap		%d6
   2384	swap		%d5
   2385	mov.l		DDNORMAL(%a6), %d7	# get norm shift count
   2386	beq.b		ddrn
   2387	subq.l		&0x1, %d7		# set for loop count
   2388ddnlp:
   2389	lsr.l		&0x1, %d5		# shift into %d6
   2390	roxr.l		&0x1, %d6
   2391	dbf		%d7, ddnlp
   2392ddrn:
   2393	mov.l		%d6, %d5		# remainder
   2394	mov.l		DDQUOTIENT(%a6), %d6	# quotient
   2395
   2396	rts
   2397dmm2:
   2398# factors for the 32X32->64 multiplication are in %d5 and %d6.
   2399# returns 64 bit result in %d5 (hi) %d6(lo).
   2400# destroys %d2,%d3,%d4.
   2401
   2402# multiply hi,lo words of each factor to get 4 intermediate products
   2403	mov.l		%d6, %d2
   2404	mov.l		%d6, %d3
   2405	mov.l		%d5, %d4
   2406	swap		%d3
   2407	swap		%d4
   2408	mulu.w		%d5, %d6		# %d6 <- lsw*lsw
   2409	mulu.w		%d3, %d5		# %d5 <- msw-dest*lsw-source
   2410	mulu.w		%d4, %d2		# %d2 <- msw-source*lsw-dest
   2411	mulu.w		%d4, %d3		# %d3 <- msw*msw
   2412# now use swap and addx to consolidate to two longwords
   2413	clr.l		%d4
   2414	swap		%d6
   2415	add.w		%d5, %d6		# add msw of l*l to lsw of m*l product
   2416	addx.w		%d4, %d3		# add any carry to m*m product
   2417	add.w		%d2, %d6		# add in lsw of other m*l product
   2418	addx.w		%d4, %d3		# add any carry to m*m product
   2419	swap		%d6			# %d6 is low 32 bits of final product
   2420	clr.w		%d5
   2421	clr.w		%d2			# lsw of two mixed products used,
   2422	swap		%d5			# now use msws of longwords
   2423	swap		%d2
   2424	add.l		%d2, %d5
   2425	add.l		%d3, %d5		# %d5 now ms 32 bits of final product
   2426	rts
   2427
   2428##########
   2429dcontrolmodel_s:
   2430	movq.l		&LONG,%d0
   2431	bsr.l		_calc_ea		# calc <ea>
   2432
   2433	cmpi.b		SPCOND_FLG(%a6),&immed_flg # immediate addressing mode?
   2434	beq.b		dimmed			# yes
   2435
   2436	mov.l		%a0,%a2
   2437	bsr.l		_dmem_read_long		# fetch divisor from <ea>
   2438
   2439	tst.l		%d1			# dfetch error?
   2440	bne.b		div64_err		# yes
   2441
   2442	mov.l		%d0, %d7
   2443	bra.w		dgotsrcl
   2444
   2445# we have to split out immediate data here because it must be read using
   2446# imem_read() instead of dmem_read(). this becomes especially important
   2447# if the fetch runs into some deadly fault.
   2448dimmed:
   2449	addq.l		&0x4,EXC_EXTWPTR(%a6)
   2450	bsr.l		_imem_read_long		# read immediate value
   2451
   2452	tst.l		%d1			# ifetch error?
   2453	bne.l		isp_iacc		# yes
   2454
   2455	mov.l		%d0,%d7
   2456	bra.w		dgotsrcl
   2457
   2458##########
   2459
   2460# if dmem_read_long() returns a fail message in d1, the package
   2461# must create an access error frame. here, we pass a skeleton fslw
   2462# and the failing address to the routine that creates the new frame.
   2463# also, we call isp_restore in case the effective addressing mode was
   2464# (an)+ or -(an) in which case the previous "an" value must be restored.
   2465# FSLW:
   2466#	read = true
   2467#	size = longword
   2468#	TM = data
   2469#	software emulation error = true
   2470div64_err:
   2471	bsr.l		isp_restore		# restore addr reg
   2472	mov.l		%a2,%a0			# pass failing address
   2473	mov.l		&0x01010001,%d0		# pass fslw
   2474	bra.l		isp_dacc
   2475
   2476#########################################################################
   2477# XDEF ****************************************************************	#
   2478#	_mul64(): routine to emulate mul{u,s}.l <ea>,Dh:Dl 32x32->64	#
   2479#									#
   2480# XREF ****************************************************************	#
   2481#	_calc_ea() - calculate effective address			#
   2482#	isp_iacc() - handle instruction access error exception		#
   2483#	isp_dacc() - handle data access error exception			#
   2484#	isp_restore() - restore An on access error w/ -() or ()+	#
   2485#									#
   2486# INPUT ***************************************************************	#
   2487#	none								#
   2488#									#
   2489# OUTPUT **************************************************************	#
   2490#	If exiting through isp_dacc...					#
   2491#		a0 = failing address					#
   2492#		d0 = FSLW						#
   2493#	else								#
   2494#		none							#
   2495#									#
   2496# ALGORITHM ***********************************************************	#
   2497#	First, decode the operand location. If it's in Dn, fetch from	#
   2498# the stack. If it's in memory, use _calc_ea() to calculate the		#
   2499# effective address. Use _dmem_read_long() to fetch at that address.	#
   2500# Unless the operand is immediate data. Then use _imem_read_long().	#
   2501# Send failures to isp_dacc() or isp_iacc() as appropriate.		#
   2502#	If the operands are signed, make them unsigned and save the	#
   2503# sign info for later. Perform the multiplication using 16x16->32	#
   2504# unsigned multiplies and "add" instructions. Store the high and low	#
   2505# portions of the result in the appropriate data registers on the	#
   2506# stack. Calculate the condition codes, also.				#
   2507#									#
   2508#########################################################################
   2509
   2510#############
   2511# mul(u,s)l #
   2512#############
   2513	global		_mul64
   2514_mul64:
   2515	mov.b		EXC_OPWORD+1(%a6), %d0	# extract src {mode,reg}
   2516	cmpi.b		%d0, &0x7		# is src mode Dn or other?
   2517	bgt.w		mul64_memop		# src is in memory
   2518
   2519# multiplier operand in the data register file.
   2520# must extract the register number and fetch the operand from the stack.
   2521mul64_regop:
   2522	andi.w		&0x7, %d0		# extract Dn
   2523	mov.l		(EXC_DREGS,%a6,%d0.w*4), %d3 # fetch multiplier
   2524
   2525# multiplier is in %d3. now, extract Dl and Dh fields and fetch the
   2526# multiplicand from the data register specified by Dl.
   2527mul64_multiplicand:
   2528	mov.w		EXC_EXTWORD(%a6), %d2	# fetch ext word
   2529	clr.w		%d1			# clear Dh reg
   2530	mov.b		%d2, %d1		# grab Dh
   2531	rol.w		&0x4, %d2		# align Dl byte
   2532	andi.w		&0x7, %d2		# extract Dl
   2533
   2534	mov.l		(EXC_DREGS,%a6,%d2.w*4), %d4 # get multiplicand
   2535
   2536# check for the case of "zero" result early
   2537	tst.l		%d4			# test multiplicand
   2538	beq.w		mul64_zero		# handle zero separately
   2539	tst.l		%d3			# test multiplier
   2540	beq.w		mul64_zero		# handle zero separately
   2541
   2542# multiplier is in %d3 and multiplicand is in %d4.
   2543# if the operation is to be signed, then the operands are converted
   2544# to unsigned and the result sign is saved for the end.
   2545	clr.b		EXC_TEMP(%a6)		# clear temp space
   2546	btst		&0x3, EXC_EXTWORD(%a6)	# signed or unsigned?
   2547	beq.b		mul64_alg		# unsigned; skip sgn calc
   2548
   2549	tst.l		%d3			# is multiplier negative?
   2550	bge.b		mul64_chk_md_sgn	# no
   2551	neg.l		%d3			# make multiplier positive
   2552	ori.b		&0x1, EXC_TEMP(%a6)	# save multiplier sgn
   2553
   2554# the result sign is the exclusive or of the operand sign bits.
   2555mul64_chk_md_sgn:
   2556	tst.l		%d4			# is multiplicand negative?
   2557	bge.b		mul64_alg		# no
   2558	neg.l		%d4			# make multiplicand positive
   2559	eori.b		&0x1, EXC_TEMP(%a6)	# calculate correct sign
   2560
   2561#########################################################################
   2562#	63			   32				0	#
   2563#	----------------------------					#
   2564#	| hi(mplier) * hi(mplicand)|					#
   2565#	----------------------------					#
   2566#		     -----------------------------			#
   2567#		     | hi(mplier) * lo(mplicand) |			#
   2568#		     -----------------------------			#
   2569#		     -----------------------------			#
   2570#		     | lo(mplier) * hi(mplicand) |			#
   2571#		     -----------------------------			#
   2572#	  |			   -----------------------------	#
   2573#	--|--			   | lo(mplier) * lo(mplicand) |	#
   2574#	  |			   -----------------------------	#
   2575#	========================================================	#
   2576#	--------------------------------------------------------	#
   2577#	|	hi(result)	   |	    lo(result)         |	#
   2578#	--------------------------------------------------------	#
   2579#########################################################################
   2580mul64_alg:
   2581# load temp registers with operands
   2582	mov.l		%d3, %d5		# mr in %d5
   2583	mov.l		%d3, %d6		# mr in %d6
   2584	mov.l		%d4, %d7		# md in %d7
   2585	swap		%d6			# hi(mr) in lo %d6
   2586	swap		%d7			# hi(md) in lo %d7
   2587
   2588# complete necessary multiplies:
   2589	mulu.w		%d4, %d3		# [1] lo(mr) * lo(md)
   2590	mulu.w		%d6, %d4		# [2] hi(mr) * lo(md)
   2591	mulu.w		%d7, %d5		# [3] lo(mr) * hi(md)
   2592	mulu.w		%d7, %d6		# [4] hi(mr) * hi(md)
   2593
   2594# add lo portions of [2],[3] to hi portion of [1].
   2595# add carries produced from these adds to [4].
   2596# lo([1]) is the final lo 16 bits of the result.
   2597	clr.l		%d7			# load %d7 w/ zero value
   2598	swap		%d3			# hi([1]) <==> lo([1])
   2599	add.w		%d4, %d3		# hi([1]) + lo([2])
   2600	addx.l		%d7, %d6		#    [4]  + carry
   2601	add.w		%d5, %d3		# hi([1]) + lo([3])
   2602	addx.l		%d7, %d6		#    [4]  + carry
   2603	swap		%d3			# lo([1]) <==> hi([1])
   2604
   2605# lo portions of [2],[3] have been added in to final result.
   2606# now, clear lo, put hi in lo reg, and add to [4]
   2607	clr.w		%d4			# clear lo([2])
   2608	clr.w		%d5			# clear hi([3])
   2609	swap		%d4			# hi([2]) in lo %d4
   2610	swap		%d5			# hi([3]) in lo %d5
   2611	add.l		%d5, %d4		#    [4]  + hi([2])
   2612	add.l		%d6, %d4		#    [4]  + hi([3])
   2613
   2614# unsigned result is now in {%d4,%d3}
   2615	tst.b		EXC_TEMP(%a6)		# should result be signed?
   2616	beq.b		mul64_done		# no
   2617
   2618# result should be a signed negative number.
   2619# compute 2's complement of the unsigned number:
   2620#   -negate all bits and add 1
   2621mul64_neg:
   2622	not.l		%d3			# negate lo(result) bits
   2623	not.l		%d4			# negate hi(result) bits
   2624	addq.l		&1, %d3			# add 1 to lo(result)
   2625	addx.l		%d7, %d4		# add carry to hi(result)
   2626
   2627# the result is saved to the register file.
   2628# for '040 compatibility, if Dl == Dh then only the hi(result) is
   2629# saved. so, saving hi after lo accomplishes this without need to
   2630# check Dl,Dh equality.
   2631mul64_done:
   2632	mov.l		%d3, (EXC_DREGS,%a6,%d2.w*4) # save lo(result)
   2633	mov.w		&0x0, %cc
   2634	mov.l		%d4, (EXC_DREGS,%a6,%d1.w*4) # save hi(result)
   2635
   2636# now, grab the condition codes. only one that can be set is 'N'.
   2637# 'N' CAN be set if the operation is unsigned if bit 63 is set.
   2638	mov.w		%cc, %d7		# fetch %ccr to see if 'N' set
   2639	andi.b		&0x8, %d7		# extract 'N' bit
   2640
   2641mul64_ccode_set:
   2642	mov.b		EXC_CC+1(%a6), %d6	# fetch previous %ccr
   2643	andi.b		&0x10, %d6		# all but 'X' bit changes
   2644
   2645	or.b		%d7, %d6		# group 'X' and 'N'
   2646	mov.b		%d6, EXC_CC+1(%a6)	# save new %ccr
   2647
   2648	rts
   2649
   2650# one or both of the operands is zero so the result is also zero.
   2651# save the zero result to the register file and set the 'Z' ccode bit.
   2652mul64_zero:
   2653	clr.l		(EXC_DREGS,%a6,%d2.w*4) # save lo(result)
   2654	clr.l		(EXC_DREGS,%a6,%d1.w*4) # save hi(result)
   2655
   2656	movq.l		&0x4, %d7		# set 'Z' ccode bit
   2657	bra.b		mul64_ccode_set		# finish ccode set
   2658
   2659##########
   2660
   2661# multiplier operand is in memory at the effective address.
   2662# must calculate the <ea> and go fetch the 32-bit operand.
   2663mul64_memop:
   2664	movq.l		&LONG, %d0		# pass # of bytes
   2665	bsr.l		_calc_ea		# calculate <ea>
   2666
   2667	cmpi.b		SPCOND_FLG(%a6),&immed_flg # immediate addressing mode?
   2668	beq.b		mul64_immed		# yes
   2669
   2670	mov.l		%a0,%a2
   2671	bsr.l		_dmem_read_long		# fetch src from addr (%a0)
   2672
   2673	tst.l		%d1			# dfetch error?
   2674	bne.w		mul64_err		# yes
   2675
   2676	mov.l		%d0, %d3		# store multiplier in %d3
   2677
   2678	bra.w		mul64_multiplicand
   2679
   2680# we have to split out immediate data here because it must be read using
   2681# imem_read() instead of dmem_read(). this becomes especially important
   2682# if the fetch runs into some deadly fault.
   2683mul64_immed:
   2684	addq.l		&0x4,EXC_EXTWPTR(%a6)
   2685	bsr.l		_imem_read_long		# read immediate value
   2686
   2687	tst.l		%d1			# ifetch error?
   2688	bne.l		isp_iacc		# yes
   2689
   2690	mov.l		%d0,%d3
   2691	bra.w		mul64_multiplicand
   2692
   2693##########
   2694
   2695# if dmem_read_long() returns a fail message in d1, the package
   2696# must create an access error frame. here, we pass a skeleton fslw
   2697# and the failing address to the routine that creates the new frame.
   2698# also, we call isp_restore in case the effective addressing mode was
   2699# (an)+ or -(an) in which case the previous "an" value must be restored.
   2700# FSLW:
   2701#	read = true
   2702#	size = longword
   2703#	TM = data
   2704#	software emulation error = true
   2705mul64_err:
   2706	bsr.l		isp_restore		# restore addr reg
   2707	mov.l		%a2,%a0			# pass failing address
   2708	mov.l		&0x01010001,%d0		# pass fslw
   2709	bra.l		isp_dacc
   2710
   2711#########################################################################
   2712# XDEF ****************************************************************	#
   2713#	_compandset2(): routine to emulate cas2()			#
   2714#			(internal to package)				#
   2715#									#
   2716#	_isp_cas2_finish(): store ccodes, store compare regs		#
   2717#			    (external to package)			#
   2718#									#
   2719# XREF ****************************************************************	#
   2720#	_real_lock_page() - "callout" to lock op's page from page-outs	#
   2721#	_cas_terminate2() - access error exit				#
   2722#	_real_cas2() - "callout" to core cas2 emulation code		#
   2723#	_real_unlock_page() - "callout" to unlock page			#
   2724#									#
   2725# INPUT ***************************************************************	#
   2726# _compandset2():							#
   2727#	d0 = instruction extension word					#
   2728#									#
   2729# _isp_cas2_finish():							#
   2730#	see cas2 core emulation code					#
   2731#									#
   2732# OUTPUT **************************************************************	#
   2733# _compandset2():							#
   2734#	see cas2 core emulation code					#
   2735#									#
   2736# _isp_cas_finish():							#
   2737#	None (register file or memroy changed as appropriate)		#
   2738#									#
   2739# ALGORITHM ***********************************************************	#
   2740# compandset2():							#
   2741#	Decode the instruction and fetch the appropriate Update and	#
   2742# Compare operands. Then call the "callout" _real_lock_page() for each	#
   2743# memory operand address so that the operating system can keep these	#
   2744# pages from being paged out. If either _real_lock_page() fails, exit	#
   2745# through _cas_terminate2(). Don't forget to unlock the 1st locked page	#
   2746# using _real_unlock_paged() if the 2nd lock-page fails.		#
   2747# Finally, branch to the core cas2 emulation code by calling the	#
   2748# "callout" _real_cas2().						#
   2749#									#
   2750# _isp_cas2_finish():							#
   2751#	Re-perform the comparison so we can determine the condition	#
   2752# codes which were too much trouble to keep around during the locked	#
   2753# emulation. Then unlock each operands page by calling the "callout"	#
   2754# _real_unlock_page().							#
   2755#									#
   2756#########################################################################
   2757
   2758set ADDR1,	EXC_TEMP+0xc
   2759set ADDR2,	EXC_TEMP+0x0
   2760set DC2,	EXC_TEMP+0xa
   2761set DC1,	EXC_TEMP+0x8
   2762
   2763	global		_compandset2
   2764_compandset2:
   2765	mov.l		%d0,EXC_TEMP+0x4(%a6)		# store for possible restart
   2766	mov.l		%d0,%d1			# extension word in d0
   2767
   2768	rol.w		&0x4,%d0
   2769	andi.w		&0xf,%d0		# extract Rn2
   2770	mov.l		(EXC_DREGS,%a6,%d0.w*4),%a1 # fetch ADDR2
   2771	mov.l		%a1,ADDR2(%a6)
   2772
   2773	mov.l		%d1,%d0
   2774
   2775	lsr.w		&0x6,%d1
   2776	andi.w		&0x7,%d1		# extract Du2
   2777	mov.l		(EXC_DREGS,%a6,%d1.w*4),%d5 # fetch Update2 Op
   2778
   2779	andi.w		&0x7,%d0		# extract Dc2
   2780	mov.l		(EXC_DREGS,%a6,%d0.w*4),%d3 # fetch Compare2 Op
   2781	mov.w		%d0,DC2(%a6)
   2782
   2783	mov.w		EXC_EXTWORD(%a6),%d0
   2784	mov.l		%d0,%d1
   2785
   2786	rol.w		&0x4,%d0
   2787	andi.w		&0xf,%d0		# extract Rn1
   2788	mov.l		(EXC_DREGS,%a6,%d0.w*4),%a0 # fetch ADDR1
   2789	mov.l		%a0,ADDR1(%a6)
   2790
   2791	mov.l		%d1,%d0
   2792
   2793	lsr.w		&0x6,%d1
   2794	andi.w		&0x7,%d1		# extract Du1
   2795	mov.l		(EXC_DREGS,%a6,%d1.w*4),%d4 # fetch Update1 Op
   2796
   2797	andi.w		&0x7,%d0		# extract Dc1
   2798	mov.l		(EXC_DREGS,%a6,%d0.w*4),%d2 # fetch Compare1 Op
   2799	mov.w		%d0,DC1(%a6)
   2800
   2801	btst		&0x1,EXC_OPWORD(%a6)	# word or long?
   2802	sne		%d7
   2803
   2804	btst		&0x5,EXC_ISR(%a6)	# user or supervisor?
   2805	sne		%d6
   2806
   2807	mov.l		%a0,%a2
   2808	mov.l		%a1,%a3
   2809
   2810	mov.l		%d7,%d1			# pass size
   2811	mov.l		%d6,%d0			# pass mode
   2812	bsr.l		_real_lock_page		# lock page
   2813	mov.l		%a2,%a0
   2814	tst.l		%d0			# error?
   2815	bne.l		_cas_terminate2		# yes
   2816
   2817	mov.l		%d7,%d1			# pass size
   2818	mov.l		%d6,%d0			# pass mode
   2819	mov.l		%a3,%a0			# pass addr
   2820	bsr.l		_real_lock_page		# lock page
   2821	mov.l		%a3,%a0
   2822	tst.l		%d0			# error?
   2823	bne.b		cas_preterm		# yes
   2824
   2825	mov.l		%a2,%a0
   2826	mov.l		%a3,%a1
   2827
   2828	bra.l		_real_cas2
   2829
   2830# if the 2nd lock attempt fails, then we must still unlock the
   2831# first page(s).
   2832cas_preterm:
   2833	mov.l		%d0,-(%sp)		# save FSLW
   2834	mov.l		%d7,%d1			# pass size
   2835	mov.l		%d6,%d0			# pass mode
   2836	mov.l		%a2,%a0			# pass ADDR1
   2837	bsr.l		_real_unlock_page	# unlock first page(s)
   2838	mov.l		(%sp)+,%d0		# restore FSLW
   2839	mov.l		%a3,%a0			# pass failing addr
   2840	bra.l		_cas_terminate2
   2841
   2842#############################################################
   2843
   2844	global		_isp_cas2_finish
   2845_isp_cas2_finish:
   2846	btst		&0x1,EXC_OPWORD(%a6)
   2847	bne.b		cas2_finish_l
   2848
   2849	mov.w		EXC_CC(%a6),%cc		# load old ccodes
   2850	cmp.w		%d0,%d2
   2851	bne.b		cas2_finish_w_save
   2852	cmp.w		%d1,%d3
   2853cas2_finish_w_save:
   2854	mov.w		%cc,EXC_CC(%a6)		# save new ccodes
   2855
   2856	tst.b		%d4			# update compare reg?
   2857	bne.b		cas2_finish_w_done	# no
   2858
   2859	mov.w		DC2(%a6),%d3		# fetch Dc2
   2860	mov.w		%d1,(2+EXC_DREGS,%a6,%d3.w*4) # store new Compare2 Op
   2861
   2862	mov.w		DC1(%a6),%d2		# fetch Dc1
   2863	mov.w		%d0,(2+EXC_DREGS,%a6,%d2.w*4) # store new Compare1 Op
   2864
   2865cas2_finish_w_done:
   2866	btst		&0x5,EXC_ISR(%a6)
   2867	sne		%d2
   2868	mov.l		%d2,%d0			# pass mode
   2869	sf		%d1			# pass size
   2870	mov.l		ADDR1(%a6),%a0		# pass ADDR1
   2871	bsr.l		_real_unlock_page	# unlock page
   2872
   2873	mov.l		%d2,%d0			# pass mode
   2874	sf		%d1			# pass size
   2875	mov.l		ADDR2(%a6),%a0		# pass ADDR2
   2876	bsr.l		_real_unlock_page	# unlock page
   2877	rts
   2878
   2879cas2_finish_l:
   2880	mov.w		EXC_CC(%a6),%cc		# load old ccodes
   2881	cmp.l		%d0,%d2
   2882	bne.b		cas2_finish_l_save
   2883	cmp.l		%d1,%d3
   2884cas2_finish_l_save:
   2885	mov.w		%cc,EXC_CC(%a6)		# save new ccodes
   2886
   2887	tst.b		%d4			# update compare reg?
   2888	bne.b		cas2_finish_l_done	# no
   2889
   2890	mov.w		DC2(%a6),%d3		# fetch Dc2
   2891	mov.l		%d1,(EXC_DREGS,%a6,%d3.w*4) # store new Compare2 Op
   2892
   2893	mov.w		DC1(%a6),%d2		# fetch Dc1
   2894	mov.l		%d0,(EXC_DREGS,%a6,%d2.w*4) # store new Compare1 Op
   2895
   2896cas2_finish_l_done:
   2897	btst		&0x5,EXC_ISR(%a6)
   2898	sne		%d2
   2899	mov.l		%d2,%d0			# pass mode
   2900	st		%d1			# pass size
   2901	mov.l		ADDR1(%a6),%a0		# pass ADDR1
   2902	bsr.l		_real_unlock_page	# unlock page
   2903
   2904	mov.l		%d2,%d0			# pass mode
   2905	st		%d1			# pass size
   2906	mov.l		ADDR2(%a6),%a0		# pass ADDR2
   2907	bsr.l		_real_unlock_page	# unlock page
   2908	rts
   2909
   2910########
   2911	global		cr_cas2
   2912cr_cas2:
   2913	mov.l		EXC_TEMP+0x4(%a6),%d0
   2914	bra.w		_compandset2
   2915
   2916#########################################################################
   2917# XDEF ****************************************************************	#
   2918#	_compandset(): routine to emulate cas w/ misaligned <ea>	#
   2919#		       (internal to package)				#
   2920#	_isp_cas_finish(): routine called when cas emulation completes	#
   2921#			   (external and internal to package)		#
   2922#	_isp_cas_restart(): restart cas emulation after a fault		#
   2923#			    (external to package)			#
   2924#	_isp_cas_terminate(): create access error stack frame on fault	#
   2925#			      (external and internal to package)	#
   2926#	_isp_cas_inrange(): checks whether instr addess is within range	#
   2927#			    of core cas/cas2emulation code		#
   2928#			    (external to package)			#
   2929#									#
   2930# XREF ****************************************************************	#
   2931#	_calc_ea(): calculate effective address				#
   2932#									#
   2933# INPUT ***************************************************************	#
   2934# compandset():								#
   2935#	none								#
   2936# _isp_cas_restart():							#
   2937#	d6 = previous sfc/dfc						#
   2938# _isp_cas_finish():							#
   2939# _isp_cas_terminate():							#
   2940#	a0 = failing address						#
   2941#	d0 = FSLW							#
   2942#	d6 = previous sfc/dfc						#
   2943# _isp_cas_inrange():							#
   2944#	a0 = instruction address to be checked				#
   2945#									#
   2946# OUTPUT **************************************************************	#
   2947# compandset():								#
   2948#		none							#
   2949# _isp_cas_restart():							#
   2950#	a0 = effective address						#
   2951#	d7 = word or longword flag					#
   2952# _isp_cas_finish():							#
   2953#	a0 = effective address						#
   2954# _isp_cas_terminate():							#
   2955#	initial register set before emulation exception			#
   2956# _isp_cas_inrange():							#
   2957#	d0 = 0 => in range; -1 => out of range				#
   2958#									#
   2959# ALGORITHM ***********************************************************	#
   2960#									#
   2961# compandset():								#
   2962#	First, calculate the effective address. Then, decode the	#
   2963# instruction word and fetch the "compare" (DC) and "update" (Du)	#
   2964# operands.								#
   2965#	Next, call the external routine _real_lock_page() so that the	#
   2966# operating system can keep this page from being paged out while we're	#
   2967# in this routine. If this call fails, jump to _cas_terminate2().	#
   2968#	The routine then branches to _real_cas(). This external routine	#
   2969# that actually emulates cas can be supplied by the external os or	#
   2970# made to point directly back into the 060ISP which has a routine for	#
   2971# this purpose.								#
   2972#									#
   2973# _isp_cas_finish():							#
   2974#	Either way, after emulation, the package is re-entered at	#
   2975# _isp_cas_finish(). This routine re-compares the operands in order to	#
   2976# set the condition codes. Finally, these routines will call		#
   2977# _real_unlock_page() in order to unlock the pages that were previously	#
   2978# locked.								#
   2979#									#
   2980# _isp_cas_restart():							#
   2981#	This routine can be entered from an access error handler where	#
   2982# the emulation sequence should be re-started from the beginning.	#
   2983#									#
   2984# _isp_cas_terminate():							#
   2985#	This routine can be entered from an access error handler where	#
   2986# an emulation operand access failed and the operating system would	#
   2987# like an access error stack frame created instead of the current	#
   2988# unimplemented integer instruction frame.				#
   2989#	Also, the package enters here if a call to _real_lock_page()	#
   2990# fails.								#
   2991#									#
   2992# _isp_cas_inrange():							#
   2993#	Checks to see whether the instruction address passed to it in	#
   2994# a0 is within the software package cas/cas2 emulation routines. This	#
   2995# can be helpful for an operating system to determine whether an access	#
   2996# error during emulation was due to a cas/cas2 emulation access.	#
   2997#									#
   2998#########################################################################
   2999
   3000set DC,		EXC_TEMP+0x8
   3001set ADDR,	EXC_TEMP+0x4
   3002
   3003	global		_compandset
   3004_compandset:
   3005	btst		&0x1,EXC_OPWORD(%a6)	# word or long operation?
   3006	bne.b		compandsetl		# long
   3007
   3008compandsetw:
   3009	movq.l		&0x2,%d0		# size = 2 bytes
   3010	bsr.l		_calc_ea		# a0 = calculated <ea>
   3011	mov.l		%a0,ADDR(%a6)		# save <ea> for possible restart
   3012	sf		%d7			# clear d7 for word size
   3013	bra.b		compandsetfetch
   3014
   3015compandsetl:
   3016	movq.l		&0x4,%d0		# size = 4 bytes
   3017	bsr.l		_calc_ea		# a0 = calculated <ea>
   3018	mov.l		%a0,ADDR(%a6)		# save <ea> for possible restart
   3019	st		%d7			# set d7 for longword size
   3020
   3021compandsetfetch:
   3022	mov.w		EXC_EXTWORD(%a6),%d0	# fetch cas extension word
   3023	mov.l		%d0,%d1			# make a copy
   3024
   3025	lsr.w		&0x6,%d0
   3026	andi.w		&0x7,%d0		# extract Du
   3027	mov.l		(EXC_DREGS,%a6,%d0.w*4),%d2 # get update operand
   3028
   3029	andi.w		&0x7,%d1		# extract Dc
   3030	mov.l		(EXC_DREGS,%a6,%d1.w*4),%d4 # get compare operand
   3031	mov.w		%d1,DC(%a6)		# save Dc
   3032
   3033	btst		&0x5,EXC_ISR(%a6)	# which mode for exception?
   3034	sne		%d6			# set on supervisor mode
   3035
   3036	mov.l		%a0,%a2			# save temporarily
   3037	mov.l		%d7,%d1			# pass size
   3038	mov.l		%d6,%d0			# pass mode
   3039	bsr.l		_real_lock_page		# lock page
   3040	tst.l		%d0			# did error occur?
   3041	bne.w		_cas_terminate2		# yes, clean up the mess
   3042	mov.l		%a2,%a0			# pass addr in a0
   3043
   3044	bra.l		_real_cas
   3045
   3046########
   3047	global		_isp_cas_finish
   3048_isp_cas_finish:
   3049	btst		&0x1,EXC_OPWORD(%a6)
   3050	bne.b		cas_finish_l
   3051
   3052# just do the compare again since it's faster than saving the ccodes
   3053# from the locked routine...
   3054cas_finish_w:
   3055	mov.w		EXC_CC(%a6),%cc		# restore cc
   3056	cmp.w		%d0,%d4			# do word compare
   3057	mov.w		%cc,EXC_CC(%a6)		# save cc
   3058
   3059	tst.b		%d1			# update compare reg?
   3060	bne.b		cas_finish_w_done	# no
   3061
   3062	mov.w		DC(%a6),%d3
   3063	mov.w		%d0,(EXC_DREGS+2,%a6,%d3.w*4) # Dc = destination
   3064
   3065cas_finish_w_done:
   3066	mov.l		ADDR(%a6),%a0		# pass addr
   3067	sf		%d1			# pass size
   3068	btst		&0x5,EXC_ISR(%a6)
   3069	sne		%d0			# pass mode
   3070	bsr.l		_real_unlock_page	# unlock page
   3071	rts
   3072
   3073# just do the compare again since it's faster than saving the ccodes
   3074# from the locked routine...
   3075cas_finish_l:
   3076	mov.w		EXC_CC(%a6),%cc		# restore cc
   3077	cmp.l		%d0,%d4			# do longword compare
   3078	mov.w		%cc,EXC_CC(%a6)		# save cc
   3079
   3080	tst.b		%d1			# update compare reg?
   3081	bne.b		cas_finish_l_done	# no
   3082
   3083	mov.w		DC(%a6),%d3
   3084	mov.l		%d0,(EXC_DREGS,%a6,%d3.w*4) # Dc = destination
   3085
   3086cas_finish_l_done:
   3087	mov.l		ADDR(%a6),%a0		# pass addr
   3088	st		%d1			# pass size
   3089	btst		&0x5,EXC_ISR(%a6)
   3090	sne		%d0			# pass mode
   3091	bsr.l		_real_unlock_page	# unlock page
   3092	rts
   3093
   3094########
   3095
   3096	global		_isp_cas_restart
   3097_isp_cas_restart:
   3098	mov.l		%d6,%sfc		# restore previous sfc
   3099	mov.l		%d6,%dfc		# restore previous dfc
   3100
   3101	cmpi.b		EXC_OPWORD+1(%a6),&0xfc	# cas or cas2?
   3102	beq.l		cr_cas2			# cas2
   3103cr_cas:
   3104	mov.l		ADDR(%a6),%a0		# load <ea>
   3105	btst		&0x1,EXC_OPWORD(%a6)	# word or long operation?
   3106	sne		%d7			# set d7 accordingly
   3107	bra.w		compandsetfetch
   3108
   3109########
   3110
   3111# At this stage, it would be nice if d0 held the FSLW.
   3112	global		_isp_cas_terminate
   3113_isp_cas_terminate:
   3114	mov.l		%d6,%sfc		# restore previous sfc
   3115	mov.l		%d6,%dfc		# restore previous dfc
   3116
   3117	global		_cas_terminate2
   3118_cas_terminate2:
   3119	mov.l		%a0,%a2			# copy failing addr to a2
   3120
   3121	mov.l		%d0,-(%sp)
   3122	bsr.l		isp_restore		# restore An (if ()+ or -())
   3123	mov.l		(%sp)+,%d0
   3124
   3125	addq.l		&0x4,%sp		# remove sub return addr
   3126	subq.l		&0x8,%sp		# make room for bigger stack
   3127	subq.l		&0x8,%a6		# shift frame ptr down, too
   3128	mov.l		&26,%d1			# want to move 51 longwords
   3129	lea		0x8(%sp),%a0		# get address of old stack
   3130	lea		0x0(%sp),%a1		# get address of new stack
   3131cas_term_cont:
   3132	mov.l		(%a0)+,(%a1)+		# move a longword
   3133	dbra.w		%d1,cas_term_cont	# keep going
   3134
   3135	mov.w		&0x4008,EXC_IVOFF(%a6)	# put new stk fmt, voff
   3136	mov.l		%a2,EXC_IVOFF+0x2(%a6)	# put faulting addr on stack
   3137	mov.l		%d0,EXC_IVOFF+0x6(%a6)	# put FSLW on stack
   3138	movm.l		EXC_DREGS(%a6),&0x3fff	# restore user regs
   3139	unlk		%a6			# unlink stack frame
   3140	bra.l		_real_access
   3141
   3142########
   3143
   3144	global		_isp_cas_inrange
   3145_isp_cas_inrange:
   3146	clr.l		%d0			# clear return result
   3147	lea		_CASHI(%pc),%a1		# load end of CAS core code
   3148	cmp.l		%a1,%a0			# is PC in range?
   3149	blt.b		cin_no			# no
   3150	lea		_CASLO(%pc),%a1		# load begin of CAS core code
   3151	cmp.l		%a0,%a1			# is PC in range?
   3152	blt.b		cin_no			# no
   3153	rts					# yes; return d0 = 0
   3154cin_no:
   3155	mov.l		&-0x1,%d0		# out of range; return d0 = -1
   3156	rts
   3157
   3158#################################################################
   3159#################################################################
   3160#################################################################
   3161# This is the start of the cas and cas2 "core" emulation code.	#
   3162# This is the section that may need to be replaced by the host	#
   3163# OS if it is too operating system-specific.			#
   3164# Please refer to the package documentation to see how to	#
   3165# "replace" this section, if necessary.				#
   3166#################################################################
   3167#################################################################
   3168#################################################################
   3169
   3170#       ######      ##      ######     ####
   3171#       #	   #  #     #         #    #
   3172#	#	  ######    ######        #
   3173#	#	  #    #         #      #
   3174#       ######    #    #    ######    ######
   3175
   3176#########################################################################
   3177# XDEF ****************************************************************	#
   3178#	_isp_cas2(): "core" emulation code for the cas2 instruction	#
   3179#									#
   3180# XREF ****************************************************************	#
   3181#	_isp_cas2_finish() - only exit point for this emulation code;	#
   3182#			     do clean-up; calculate ccodes; store	#
   3183#			     Compare Ops if appropriate.		#
   3184#									#
   3185# INPUT ***************************************************************	#
   3186#	*see chart below*						#
   3187#									#
   3188# OUTPUT **************************************************************	#
   3189#	*see chart below*						#
   3190#									#
   3191# ALGORITHM ***********************************************************	#
   3192#	(1) Make several copies of the effective address.		#
   3193#	(2) Save current SR; Then mask off all maskable interrupts.	#
   3194#	(3) Save current SFC/DFC (ASSUMED TO BE EQUAL!!!); Then set	#
   3195#	    according to whether exception occurred in user or		#
   3196#	    supervisor mode.						#
   3197#	(4) Use "plpaw" instruction to pre-load ATC with effective	#
   3198#	    address pages(s). THIS SHOULD NOT FAULT!!! The relevant	#
   3199#	    page(s) should have already been made resident prior to	#
   3200#	    entering this routine.					#
   3201#	(5) Push the operand lines from the cache w/ "cpushl".		#
   3202#	    In the 68040, this was done within the locked region. In	#
   3203#	    the 68060, it is done outside of the locked region.		#
   3204#	(6) Use "plpar" instruction to do a re-load of ATC entries for	#
   3205#	    ADDR1 since ADDR2 entries may have pushed ADDR1 out of the	#
   3206#	    ATC.							#
   3207#	(7) Pre-fetch the core emulation instructions by executing	#
   3208#	    one branch within each physical line (16 bytes) of the code	#
   3209#	    before actually executing the code.				#
   3210#	(8) Load the BUSCR w/ the bus lock value.			#
   3211#	(9) Fetch the source operands using "moves".			#
   3212#	(10)Do the compares. If both equal, go to step (13).		#
   3213#	(11)Unequal. No update occurs. But, we do write the DST1 op	#
   3214#	    back to itself (as w/ the '040) so we can gracefully unlock	#
   3215#	    the bus (and assert LOCKE*) using BUSCR and the final move.	#
   3216#	(12)Exit.							#
   3217#	(13)Write update operand to the DST locations. Use BUSCR to	#
   3218#	    assert LOCKE* for the final write operation.		#
   3219#	(14)Exit.							#
   3220#									#
   3221#	The algorithm is actually implemented slightly differently	#
   3222# depending on the size of the operation and the misalignment of the	#
   3223# operands. A misaligned operand must be written in aligned chunks or	#
   3224# else the BUSCR register control gets confused.			#
   3225#									#
   3226#########################################################################
   3227
   3228#################################################################
   3229# THIS IS THE STATE OF THE INTEGER REGISTER FILE UPON		#
   3230# ENTERING _isp_cas2().						#
   3231#								#
   3232# D0 = xxxxxxxx							#
   3233# D1 = xxxxxxxx							#
   3234# D2 = cmp operand 1						#
   3235# D3 = cmp operand 2						#
   3236# D4 = update oper 1						#
   3237# D5 = update oper 2						#
   3238# D6 = 'xxxxxxff if supervisor mode; 'xxxxxx00 if user mode	#
   3239# D7 = 'xxxxxxff if longword operation; 'xxxxxx00 if word	#
   3240# A0 = ADDR1							#
   3241# A1 = ADDR2							#
   3242# A2 = xxxxxxxx							#
   3243# A3 = xxxxxxxx							#
   3244# A4 = xxxxxxxx							#
   3245# A5 = xxxxxxxx							#
   3246# A6 = frame pointer						#
   3247# A7 = stack pointer						#
   3248#################################################################
   3249
   3250#	align		0x1000
   3251# beginning label used by _isp_cas_inrange()
   3252	global		_CASLO
   3253_CASLO:
   3254
   3255	global		_isp_cas2
   3256_isp_cas2:
   3257	tst.b		%d6			# user or supervisor mode?
   3258	bne.b		cas2_supervisor		# supervisor
   3259cas2_user:
   3260	movq.l		&0x1,%d0		# load user data fc
   3261	bra.b		cas2_cont
   3262cas2_supervisor:
   3263	movq.l		&0x5,%d0		# load supervisor data fc
   3264cas2_cont:
   3265	tst.b		%d7			# word or longword?
   3266	beq.w		cas2w			# word
   3267
   3268####
   3269cas2l:
   3270	mov.l		%a0,%a2			# copy ADDR1
   3271	mov.l		%a1,%a3			# copy ADDR2
   3272	mov.l		%a0,%a4			# copy ADDR1
   3273	mov.l		%a1,%a5			# copy ADDR2
   3274
   3275	addq.l		&0x3,%a4		# ADDR1+3
   3276	addq.l		&0x3,%a5		# ADDR2+3
   3277	mov.l		%a2,%d1			# ADDR1
   3278
   3279# mask interrupts levels 0-6. save old mask value.
   3280	mov.w		%sr,%d7			# save current SR
   3281	ori.w		&0x0700,%sr		# inhibit interrupts
   3282
   3283# load the SFC and DFC with the appropriate mode.
   3284	movc		%sfc,%d6		# save old SFC/DFC
   3285	movc		%d0,%sfc		# store new SFC
   3286	movc		%d0,%dfc		# store new DFC
   3287
   3288# pre-load the operand ATC. no page faults should occur here because
   3289# _real_lock_page() should have taken care of this.
   3290	plpaw		(%a2)			# load atc for ADDR1
   3291	plpaw		(%a4)			# load atc for ADDR1+3
   3292	plpaw		(%a3)			# load atc for ADDR2
   3293	plpaw		(%a5)			# load atc for ADDR2+3
   3294
   3295# push the operand lines from the cache if they exist.
   3296	cpushl		%dc,(%a2)		# push line for ADDR1
   3297	cpushl		%dc,(%a4)		# push line for ADDR1+3
   3298	cpushl		%dc,(%a3)		# push line for ADDR2
   3299	cpushl		%dc,(%a5)		# push line for ADDR2+2
   3300
   3301	mov.l		%d1,%a2			# ADDR1
   3302	addq.l		&0x3,%d1
   3303	mov.l		%d1,%a4			# ADDR1+3
   3304# if ADDR1 was ATC resident before the above "plpaw" and was executed
   3305# and it was the next entry scheduled for replacement and ADDR2
   3306# shares the same set, then the "plpaw" for ADDR2 can push the ADDR1
   3307# entries from the ATC. so, we do a second set of "plpa"s.
   3308	plpar		(%a2)			# load atc for ADDR1
   3309	plpar		(%a4)			# load atc for ADDR1+3
   3310
   3311# load the BUSCR values.
   3312	mov.l		&0x80000000,%a2		# assert LOCK* buscr value
   3313	mov.l		&0xa0000000,%a3		# assert LOCKE* buscr value
   3314	mov.l		&0x00000000,%a4		# buscr unlock value
   3315
   3316# there are three possible mis-aligned cases for longword cas. they
   3317# are separated because the final write which asserts LOCKE* must
   3318# be aligned.
   3319	mov.l		%a0,%d0			# is ADDR1 misaligned?
   3320	andi.b		&0x3,%d0
   3321	beq.b		CAS2L_ENTER		# no
   3322	cmpi.b		%d0,&0x2
   3323	beq.w		CAS2L2_ENTER		# yes; word misaligned
   3324	bra.w		CAS2L3_ENTER		# yes; byte misaligned
   3325
   3326#
   3327# D0 = dst operand 1 <-
   3328# D1 = dst operand 2 <-
   3329# D2 = cmp operand 1
   3330# D3 = cmp operand 2
   3331# D4 = update oper 1
   3332# D5 = update oper 2
   3333# D6 = old SFC/DFC
   3334# D7 = old SR
   3335# A0 = ADDR1
   3336# A1 = ADDR2
   3337# A2 = bus LOCK*  value
   3338# A3 = bus LOCKE* value
   3339# A4 = bus unlock value
   3340# A5 = xxxxxxxx
   3341#
   3342	align		0x10
   3343CAS2L_START:
   3344	movc		%a2,%buscr		# assert LOCK*
   3345	movs.l		(%a1),%d1		# fetch Dest2[31:0]
   3346	movs.l		(%a0),%d0		# fetch Dest1[31:0]
   3347	bra.b		CAS2L_CONT
   3348CAS2L_ENTER:
   3349	bra.b		~+16
   3350
   3351CAS2L_CONT:
   3352	cmp.l		%d0,%d2			# Dest1 - Compare1
   3353	bne.b		CAS2L_NOUPDATE
   3354	cmp.l		%d1,%d3			# Dest2 - Compare2
   3355	bne.b		CAS2L_NOUPDATE
   3356	movs.l		%d5,(%a1)		# Update2[31:0] -> DEST2
   3357	bra.b		CAS2L_UPDATE
   3358	bra.b		~+16
   3359
   3360CAS2L_UPDATE:
   3361	movc		%a3,%buscr		# assert LOCKE*
   3362	movs.l		%d4,(%a0)		# Update1[31:0] -> DEST1
   3363	movc		%a4,%buscr		# unlock the bus
   3364	bra.b		cas2l_update_done
   3365	bra.b		~+16
   3366
   3367CAS2L_NOUPDATE:
   3368	movc		%a3,%buscr		# assert LOCKE*
   3369	movs.l		%d0,(%a0)		# Dest1[31:0] -> DEST1
   3370	movc		%a4,%buscr		# unlock the bus
   3371	bra.b		cas2l_noupdate_done
   3372	bra.b		~+16
   3373
   3374CAS2L_FILLER:
   3375	nop
   3376	nop
   3377	nop
   3378	nop
   3379	nop
   3380	nop
   3381	nop
   3382	bra.b		CAS2L_START
   3383
   3384####
   3385
   3386#################################################################
   3387# THIS MUST BE THE STATE OF THE INTEGER REGISTER FILE UPON	#
   3388# ENTERING _isp_cas2().						#
   3389#								#
   3390# D0 = destination[31:0] operand 1				#
   3391# D1 = destination[31:0] operand 2				#
   3392# D2 = cmp[31:0] operand 1					#
   3393# D3 = cmp[31:0] operand 2					#
   3394# D4 = 'xxxxxx11 -> no reg update; 'xxxxxx00 -> update required	#
   3395# D5 = xxxxxxxx							#
   3396# D6 = xxxxxxxx							#
   3397# D7 = xxxxxxxx							#
   3398# A0 = xxxxxxxx							#
   3399# A1 = xxxxxxxx							#
   3400# A2 = xxxxxxxx							#
   3401# A3 = xxxxxxxx							#
   3402# A4 = xxxxxxxx							#
   3403# A5 = xxxxxxxx							#
   3404# A6 = frame pointer						#
   3405# A7 = stack pointer						#
   3406#################################################################
   3407
   3408cas2l_noupdate_done:
   3409
   3410# restore previous SFC/DFC value.
   3411	movc		%d6,%sfc		# restore old SFC
   3412	movc		%d6,%dfc		# restore old DFC
   3413
   3414# restore previous interrupt mask level.
   3415	mov.w		%d7,%sr			# restore old SR
   3416
   3417	sf		%d4			# indicate no update was done
   3418	bra.l		_isp_cas2_finish
   3419
   3420cas2l_update_done:
   3421
   3422# restore previous SFC/DFC value.
   3423	movc		%d6,%sfc		# restore old SFC
   3424	movc		%d6,%dfc		# restore old DFC
   3425
   3426# restore previous interrupt mask level.
   3427	mov.w		%d7,%sr			# restore old SR
   3428
   3429	st		%d4			# indicate update was done
   3430	bra.l		_isp_cas2_finish
   3431####
   3432
   3433	align		0x10
   3434CAS2L2_START:
   3435	movc		%a2,%buscr		# assert LOCK*
   3436	movs.l		(%a1),%d1		# fetch Dest2[31:0]
   3437	movs.l		(%a0),%d0		# fetch Dest1[31:0]
   3438	bra.b		CAS2L2_CONT
   3439CAS2L2_ENTER:
   3440	bra.b		~+16
   3441
   3442CAS2L2_CONT:
   3443	cmp.l		%d0,%d2			# Dest1 - Compare1
   3444	bne.b		CAS2L2_NOUPDATE
   3445	cmp.l		%d1,%d3			# Dest2 - Compare2
   3446	bne.b		CAS2L2_NOUPDATE
   3447	movs.l		%d5,(%a1)		# Update2[31:0] -> Dest2
   3448	bra.b		CAS2L2_UPDATE
   3449	bra.b		~+16
   3450
   3451CAS2L2_UPDATE:
   3452	swap		%d4			# get Update1[31:16]
   3453	movs.w		%d4,(%a0)+		# Update1[31:16] -> DEST1
   3454	movc		%a3,%buscr		# assert LOCKE*
   3455	swap		%d4			# get Update1[15:0]
   3456	bra.b		CAS2L2_UPDATE2
   3457	bra.b		~+16
   3458
   3459CAS2L2_UPDATE2:
   3460	movs.w		%d4,(%a0)		# Update1[15:0] -> DEST1+0x2
   3461	movc		%a4,%buscr		# unlock the bus
   3462	bra.w		cas2l_update_done
   3463	nop
   3464	bra.b		~+16
   3465
   3466CAS2L2_NOUPDATE:
   3467	swap		%d0			# get Dest1[31:16]
   3468	movs.w		%d0,(%a0)+		# Dest1[31:16] -> DEST1
   3469	movc		%a3,%buscr		# assert LOCKE*
   3470	swap		%d0			# get Dest1[15:0]
   3471	bra.b		CAS2L2_NOUPDATE2
   3472	bra.b		~+16
   3473
   3474CAS2L2_NOUPDATE2:
   3475	movs.w		%d0,(%a0)		# Dest1[15:0] -> DEST1+0x2
   3476	movc		%a4,%buscr		# unlock the bus
   3477	bra.w		cas2l_noupdate_done
   3478	nop
   3479	bra.b		~+16
   3480
   3481CAS2L2_FILLER:
   3482	nop
   3483	nop
   3484	nop
   3485	nop
   3486	nop
   3487	nop
   3488	nop
   3489	bra.b		CAS2L2_START
   3490
   3491#################################
   3492
   3493	align		0x10
   3494CAS2L3_START:
   3495	movc		%a2,%buscr		# assert LOCK*
   3496	movs.l		(%a1),%d1		# fetch Dest2[31:0]
   3497	movs.l		(%a0),%d0		# fetch Dest1[31:0]
   3498	bra.b		CAS2L3_CONT
   3499CAS2L3_ENTER:
   3500	bra.b		~+16
   3501
   3502CAS2L3_CONT:
   3503	cmp.l		%d0,%d2			# Dest1 - Compare1
   3504	bne.b		CAS2L3_NOUPDATE
   3505	cmp.l		%d1,%d3			# Dest2 - Compare2
   3506	bne.b		CAS2L3_NOUPDATE
   3507	movs.l		%d5,(%a1)		# Update2[31:0] -> DEST2
   3508	bra.b		CAS2L3_UPDATE
   3509	bra.b		~+16
   3510
   3511CAS2L3_UPDATE:
   3512	rol.l		&0x8,%d4		# get Update1[31:24]
   3513	movs.b		%d4,(%a0)+		# Update1[31:24] -> DEST1
   3514	swap		%d4			# get Update1[23:8]
   3515	movs.w		%d4,(%a0)+		# Update1[23:8] -> DEST1+0x1
   3516	bra.b		CAS2L3_UPDATE2
   3517	bra.b		~+16
   3518
   3519CAS2L3_UPDATE2:
   3520	rol.l		&0x8,%d4		# get Update1[7:0]
   3521	movc		%a3,%buscr		# assert LOCKE*
   3522	movs.b		%d4,(%a0)		# Update1[7:0] -> DEST1+0x3
   3523	bra.b		CAS2L3_UPDATE3
   3524	nop
   3525	bra.b		~+16
   3526
   3527CAS2L3_UPDATE3:
   3528	movc		%a4,%buscr		# unlock the bus
   3529	bra.w		cas2l_update_done
   3530	nop
   3531	nop
   3532	nop
   3533	bra.b		~+16
   3534
   3535CAS2L3_NOUPDATE:
   3536	rol.l		&0x8,%d0		# get Dest1[31:24]
   3537	movs.b		%d0,(%a0)+		# Dest1[31:24] -> DEST1
   3538	swap		%d0			# get Dest1[23:8]
   3539	movs.w		%d0,(%a0)+		# Dest1[23:8] -> DEST1+0x1
   3540	bra.b		CAS2L3_NOUPDATE2
   3541	bra.b		~+16
   3542
   3543CAS2L3_NOUPDATE2:
   3544	rol.l		&0x8,%d0		# get Dest1[7:0]
   3545	movc		%a3,%buscr		# assert LOCKE*
   3546	movs.b		%d0,(%a0)		# Update1[7:0] -> DEST1+0x3
   3547	bra.b		CAS2L3_NOUPDATE3
   3548	nop
   3549	bra.b		~+16
   3550
   3551CAS2L3_NOUPDATE3:
   3552	movc		%a4,%buscr		# unlock the bus
   3553	bra.w		cas2l_noupdate_done
   3554	nop
   3555	nop
   3556	nop
   3557	bra.b		~+14
   3558
   3559CAS2L3_FILLER:
   3560	nop
   3561	nop
   3562	nop
   3563	nop
   3564	nop
   3565	nop
   3566	bra.w		CAS2L3_START
   3567
   3568#############################################################
   3569#############################################################
   3570
   3571cas2w:
   3572	mov.l		%a0,%a2			# copy ADDR1
   3573	mov.l		%a1,%a3			# copy ADDR2
   3574	mov.l		%a0,%a4			# copy ADDR1
   3575	mov.l		%a1,%a5			# copy ADDR2
   3576
   3577	addq.l		&0x1,%a4		# ADDR1+1
   3578	addq.l		&0x1,%a5		# ADDR2+1
   3579	mov.l		%a2,%d1			# ADDR1
   3580
   3581# mask interrupt levels 0-6. save old mask value.
   3582	mov.w		%sr,%d7			# save current SR
   3583	ori.w		&0x0700,%sr		# inhibit interrupts
   3584
   3585# load the SFC and DFC with the appropriate mode.
   3586	movc		%sfc,%d6		# save old SFC/DFC
   3587	movc		%d0,%sfc		# store new SFC
   3588	movc		%d0,%dfc		# store new DFC
   3589
   3590# pre-load the operand ATC. no page faults should occur because
   3591# _real_lock_page() should have taken care of this.
   3592	plpaw		(%a2)			# load atc for ADDR1
   3593	plpaw		(%a4)			# load atc for ADDR1+1
   3594	plpaw		(%a3)			# load atc for ADDR2
   3595	plpaw		(%a5)			# load atc for ADDR2+1
   3596
   3597# push the operand cache lines from the cache if they exist.
   3598	cpushl		%dc,(%a2)		# push line for ADDR1
   3599	cpushl		%dc,(%a4)		# push line for ADDR1+1
   3600	cpushl		%dc,(%a3)		# push line for ADDR2
   3601	cpushl		%dc,(%a5)		# push line for ADDR2+1
   3602
   3603	mov.l		%d1,%a2			# ADDR1
   3604	addq.l		&0x3,%d1
   3605	mov.l		%d1,%a4			# ADDR1+3
   3606# if ADDR1 was ATC resident before the above "plpaw" and was executed
   3607# and it was the next entry scheduled for replacement and ADDR2
   3608# shares the same set, then the "plpaw" for ADDR2 can push the ADDR1
   3609# entries from the ATC. so, we do a second set of "plpa"s.
   3610	plpar		(%a2)			# load atc for ADDR1
   3611	plpar		(%a4)			# load atc for ADDR1+3
   3612
   3613# load the BUSCR values.
   3614	mov.l		&0x80000000,%a2		# assert LOCK* buscr value
   3615	mov.l		&0xa0000000,%a3		# assert LOCKE* buscr value
   3616	mov.l		&0x00000000,%a4		# buscr unlock value
   3617
   3618# there are two possible mis-aligned cases for word cas. they
   3619# are separated because the final write which asserts LOCKE* must
   3620# be aligned.
   3621	mov.l		%a0,%d0			# is ADDR1 misaligned?
   3622	btst		&0x0,%d0
   3623	bne.w		CAS2W2_ENTER		# yes
   3624	bra.b		CAS2W_ENTER		# no
   3625
   3626#
   3627# D0 = dst operand 1 <-
   3628# D1 = dst operand 2 <-
   3629# D2 = cmp operand 1
   3630# D3 = cmp operand 2
   3631# D4 = update oper 1
   3632# D5 = update oper 2
   3633# D6 = old SFC/DFC
   3634# D7 = old SR
   3635# A0 = ADDR1
   3636# A1 = ADDR2
   3637# A2 = bus LOCK*  value
   3638# A3 = bus LOCKE* value
   3639# A4 = bus unlock value
   3640# A5 = xxxxxxxx
   3641#
   3642	align		0x10
   3643CAS2W_START:
   3644	movc		%a2,%buscr		# assert LOCK*
   3645	movs.w		(%a1),%d1		# fetch Dest2[15:0]
   3646	movs.w		(%a0),%d0		# fetch Dest1[15:0]
   3647	bra.b		CAS2W_CONT2
   3648CAS2W_ENTER:
   3649	bra.b		~+16
   3650
   3651CAS2W_CONT2:
   3652	cmp.w		%d0,%d2			# Dest1 - Compare1
   3653	bne.b		CAS2W_NOUPDATE
   3654	cmp.w		%d1,%d3			# Dest2 - Compare2
   3655	bne.b		CAS2W_NOUPDATE
   3656	movs.w		%d5,(%a1)		# Update2[15:0] -> DEST2
   3657	bra.b		CAS2W_UPDATE
   3658	bra.b		~+16
   3659
   3660CAS2W_UPDATE:
   3661	movc		%a3,%buscr		# assert LOCKE*
   3662	movs.w		%d4,(%a0)		# Update1[15:0] -> DEST1
   3663	movc		%a4,%buscr		# unlock the bus
   3664	bra.b		cas2w_update_done
   3665	bra.b		~+16
   3666
   3667CAS2W_NOUPDATE:
   3668	movc		%a3,%buscr		# assert LOCKE*
   3669	movs.w		%d0,(%a0)		# Dest1[15:0] -> DEST1
   3670	movc		%a4,%buscr		# unlock the bus
   3671	bra.b		cas2w_noupdate_done
   3672	bra.b		~+16
   3673
   3674CAS2W_FILLER:
   3675	nop
   3676	nop
   3677	nop
   3678	nop
   3679	nop
   3680	nop
   3681	nop
   3682	bra.b		CAS2W_START
   3683
   3684####
   3685
   3686#################################################################
   3687# THIS MUST BE THE STATE OF THE INTEGER REGISTER FILE UPON	#
   3688# ENTERING _isp_cas2().						#
   3689#								#
   3690# D0 = destination[15:0] operand 1				#
   3691# D1 = destination[15:0] operand 2				#
   3692# D2 = cmp[15:0] operand 1					#
   3693# D3 = cmp[15:0] operand 2					#
   3694# D4 = 'xxxxxx11 -> no reg update; 'xxxxxx00 -> update required	#
   3695# D5 = xxxxxxxx							#
   3696# D6 = xxxxxxxx							#
   3697# D7 = xxxxxxxx							#
   3698# A0 = xxxxxxxx							#
   3699# A1 = xxxxxxxx							#
   3700# A2 = xxxxxxxx							#
   3701# A3 = xxxxxxxx							#
   3702# A4 = xxxxxxxx							#
   3703# A5 = xxxxxxxx							#
   3704# A6 = frame pointer						#
   3705# A7 = stack pointer						#
   3706#################################################################
   3707
   3708cas2w_noupdate_done:
   3709
   3710# restore previous SFC/DFC value.
   3711	movc		%d6,%sfc		# restore old SFC
   3712	movc		%d6,%dfc		# restore old DFC
   3713
   3714# restore previous interrupt mask level.
   3715	mov.w		%d7,%sr			# restore old SR
   3716
   3717	sf		%d4			# indicate no update was done
   3718	bra.l		_isp_cas2_finish
   3719
   3720cas2w_update_done:
   3721
   3722# restore previous SFC/DFC value.
   3723	movc		%d6,%sfc		# restore old SFC
   3724	movc		%d6,%dfc		# restore old DFC
   3725
   3726# restore previous interrupt mask level.
   3727	mov.w		%d7,%sr			# restore old SR
   3728
   3729	st		%d4			# indicate update was done
   3730	bra.l		_isp_cas2_finish
   3731####
   3732
   3733	align		0x10
   3734CAS2W2_START:
   3735	movc		%a2,%buscr		# assert LOCK*
   3736	movs.w		(%a1),%d1		# fetch Dest2[15:0]
   3737	movs.w		(%a0),%d0		# fetch Dest1[15:0]
   3738	bra.b		CAS2W2_CONT2
   3739CAS2W2_ENTER:
   3740	bra.b		~+16
   3741
   3742CAS2W2_CONT2:
   3743	cmp.w		%d0,%d2			# Dest1 - Compare1
   3744	bne.b		CAS2W2_NOUPDATE
   3745	cmp.w		%d1,%d3			# Dest2 - Compare2
   3746	bne.b		CAS2W2_NOUPDATE
   3747	movs.w		%d5,(%a1)		# Update2[15:0] -> DEST2
   3748	bra.b		CAS2W2_UPDATE
   3749	bra.b		~+16
   3750
   3751CAS2W2_UPDATE:
   3752	ror.l		&0x8,%d4		# get Update1[15:8]
   3753	movs.b		%d4,(%a0)+		# Update1[15:8] -> DEST1
   3754	movc		%a3,%buscr		# assert LOCKE*
   3755	rol.l		&0x8,%d4		# get Update1[7:0]
   3756	bra.b		CAS2W2_UPDATE2
   3757	bra.b		~+16
   3758
   3759CAS2W2_UPDATE2:
   3760	movs.b		%d4,(%a0)		# Update1[7:0] -> DEST1+0x1
   3761	movc		%a4,%buscr		# unlock the bus
   3762	bra.w		cas2w_update_done
   3763	nop
   3764	bra.b		~+16
   3765
   3766CAS2W2_NOUPDATE:
   3767	ror.l		&0x8,%d0		# get Dest1[15:8]
   3768	movs.b		%d0,(%a0)+		# Dest1[15:8] -> DEST1
   3769	movc		%a3,%buscr		# assert LOCKE*
   3770	rol.l		&0x8,%d0		# get Dest1[7:0]
   3771	bra.b		CAS2W2_NOUPDATE2
   3772	bra.b		~+16
   3773
   3774CAS2W2_NOUPDATE2:
   3775	movs.b		%d0,(%a0)		# Dest1[7:0] -> DEST1+0x1
   3776	movc		%a4,%buscr		# unlock the bus
   3777	bra.w		cas2w_noupdate_done
   3778	nop
   3779	bra.b		~+16
   3780
   3781CAS2W2_FILLER:
   3782	nop
   3783	nop
   3784	nop
   3785	nop
   3786	nop
   3787	nop
   3788	nop
   3789	bra.b		CAS2W2_START
   3790
   3791#       ######      ##      ######
   3792#       #	   #  #     #
   3793#	#	  ######    ######
   3794#	#	  #    #         #
   3795#       ######    #    #    ######
   3796
   3797#########################################################################
   3798# XDEF ****************************************************************	#
   3799#	_isp_cas(): "core" emulation code for the cas instruction	#
   3800#									#
   3801# XREF ****************************************************************	#
   3802#	_isp_cas_finish() - only exit point for this emulation code;	#
   3803#			    do clean-up					#
   3804#									#
   3805# INPUT ***************************************************************	#
   3806#	*see entry chart below*						#
   3807#									#
   3808# OUTPUT **************************************************************	#
   3809#	*see exit chart below*						#
   3810#									#
   3811# ALGORITHM ***********************************************************	#
   3812#	(1) Make several copies of the effective address.		#
   3813#	(2) Save current SR; Then mask off all maskable interrupts.	#
   3814#	(3) Save current DFC/SFC (ASSUMED TO BE EQUAL!!!); Then set	#
   3815#	    SFC/DFC according to whether exception occurred in user or	#
   3816#	    supervisor mode.						#
   3817#	(4) Use "plpaw" instruction to pre-load ATC with effective	#
   3818#	    address page(s). THIS SHOULD NOT FAULT!!! The relevant	#
   3819#	    page(s) should have been made resident prior to entering	#
   3820#	    this routine.						#
   3821#	(5) Push the operand lines from the cache w/ "cpushl".		#
   3822#	    In the 68040, this was done within the locked region. In	#
   3823#	    the 68060, it is done outside of the locked region.		#
   3824#	(6) Pre-fetch the core emulation instructions by executing one	#
   3825#	    branch within each physical line (16 bytes) of the code	#
   3826#	    before actually executing the code.				#
   3827#	(7) Load the BUSCR with the bus lock value.			#
   3828#	(8) Fetch the source operand.					#
   3829#	(9) Do the compare. If equal, go to step (12).			#
   3830#	(10)Unequal. No update occurs. But, we do write the DST op back	#
   3831#	    to itself (as w/ the '040) so we can gracefully unlock	#
   3832#	    the bus (and assert LOCKE*) using BUSCR and the final move.	#
   3833#	(11)Exit.							#
   3834#	(12)Write update operand to the DST location. Use BUSCR to	#
   3835#	    assert LOCKE* for the final write operation.		#
   3836#	(13)Exit.							#
   3837#									#
   3838#	The algorithm is actually implemented slightly differently	#
   3839# depending on the size of the operation and the misalignment of the	#
   3840# operand. A misaligned operand must be written in aligned chunks or	#
   3841# else the BUSCR register control gets confused.			#
   3842#									#
   3843#########################################################################
   3844
   3845#########################################################
   3846# THIS IS THE STATE OF THE INTEGER REGISTER FILE UPON	#
   3847# ENTERING _isp_cas().					#
   3848#							#
   3849# D0 = xxxxxxxx						#
   3850# D1 = xxxxxxxx						#
   3851# D2 = update operand					#
   3852# D3 = xxxxxxxx						#
   3853# D4 = compare operand					#
   3854# D5 = xxxxxxxx						#
   3855# D6 = supervisor ('xxxxxxff) or user mode ('xxxxxx00)	#
   3856# D7 = longword ('xxxxxxff) or word size ('xxxxxx00)	#
   3857# A0 = ADDR						#
   3858# A1 = xxxxxxxx						#
   3859# A2 = xxxxxxxx						#
   3860# A3 = xxxxxxxx						#
   3861# A4 = xxxxxxxx						#
   3862# A5 = xxxxxxxx						#
   3863# A6 = frame pointer					#
   3864# A7 = stack pointer					#
   3865#########################################################
   3866
   3867	global		_isp_cas
   3868_isp_cas:
   3869	tst.b		%d6			# user or supervisor mode?
   3870	bne.b		cas_super		# supervisor
   3871cas_user:
   3872	movq.l		&0x1,%d0		# load user data fc
   3873	bra.b		cas_cont
   3874cas_super:
   3875	movq.l		&0x5,%d0		# load supervisor data fc
   3876
   3877cas_cont:
   3878	tst.b		%d7			# word or longword?
   3879	bne.w		casl			# longword
   3880
   3881####
   3882casw:
   3883	mov.l		%a0,%a1			# make copy for plpaw1
   3884	mov.l		%a0,%a2			# make copy for plpaw2
   3885	addq.l		&0x1,%a2		# plpaw2 points to end of word
   3886
   3887	mov.l		%d2,%d3			# d3 = update[7:0]
   3888	lsr.w		&0x8,%d2		# d2 = update[15:8]
   3889
   3890# mask interrupt levels 0-6. save old mask value.
   3891	mov.w		%sr,%d7			# save current SR
   3892	ori.w		&0x0700,%sr		# inhibit interrupts
   3893
   3894# load the SFC and DFC with the appropriate mode.
   3895	movc		%sfc,%d6		# save old SFC/DFC
   3896	movc		%d0,%sfc		# load new sfc
   3897	movc		%d0,%dfc		# load new dfc
   3898
   3899# pre-load the operand ATC. no page faults should occur here because
   3900# _real_lock_page() should have taken care of this.
   3901	plpaw		(%a1)			# load atc for ADDR
   3902	plpaw		(%a2)			# load atc for ADDR+1
   3903
   3904# push the operand lines from the cache if they exist.
   3905	cpushl		%dc,(%a1)		# push dirty data
   3906	cpushl		%dc,(%a2)		# push dirty data
   3907
   3908# load the BUSCR values.
   3909	mov.l		&0x80000000,%a1		# assert LOCK* buscr value
   3910	mov.l		&0xa0000000,%a2		# assert LOCKE* buscr value
   3911	mov.l		&0x00000000,%a3		# buscr unlock value
   3912
   3913# pre-load the instruction cache for the following algorithm.
   3914# this will minimize the number of cycles that LOCK* will be asserted.
   3915	bra.b		CASW_ENTER		# start pre-loading icache
   3916
   3917#
   3918# D0 = dst operand <-
   3919# D1 = update[15:8] operand
   3920# D2 = update[7:0]  operand
   3921# D3 = xxxxxxxx
   3922# D4 = compare[15:0] operand
   3923# D5 = xxxxxxxx
   3924# D6 = old SFC/DFC
   3925# D7 = old SR
   3926# A0 = ADDR
   3927# A1 = bus LOCK*  value
   3928# A2 = bus LOCKE* value
   3929# A3 = bus unlock value
   3930# A4 = xxxxxxxx
   3931# A5 = xxxxxxxx
   3932#
   3933	align		0x10
   3934CASW_START:
   3935	movc		%a1,%buscr		# assert LOCK*
   3936	movs.w		(%a0),%d0		# fetch Dest[15:0]
   3937	cmp.w		%d0,%d4			# Dest - Compare
   3938	bne.b		CASW_NOUPDATE
   3939	bra.b		CASW_UPDATE
   3940CASW_ENTER:
   3941	bra.b		~+16
   3942
   3943CASW_UPDATE:
   3944	movs.b		%d2,(%a0)+		# Update[15:8] -> DEST
   3945	movc		%a2,%buscr		# assert LOCKE*
   3946	movs.b		%d3,(%a0)		# Update[7:0] -> DEST+0x1
   3947	bra.b		CASW_UPDATE2
   3948	bra.b		~+16
   3949
   3950CASW_UPDATE2:
   3951	movc		%a3,%buscr		# unlock the bus
   3952	bra.b		casw_update_done
   3953	nop
   3954	nop
   3955	nop
   3956	nop
   3957	bra.b		~+16
   3958
   3959CASW_NOUPDATE:
   3960	ror.l		&0x8,%d0		# get Dest[15:8]
   3961	movs.b		%d0,(%a0)+		# Dest[15:8] -> DEST
   3962	movc		%a2,%buscr		# assert LOCKE*
   3963	rol.l		&0x8,%d0		# get Dest[7:0]
   3964	bra.b		CASW_NOUPDATE2
   3965	bra.b		~+16
   3966
   3967CASW_NOUPDATE2:
   3968	movs.b		%d0,(%a0)		# Dest[7:0] -> DEST+0x1
   3969	movc		%a3,%buscr		# unlock the bus
   3970	bra.b		casw_noupdate_done
   3971	nop
   3972	nop
   3973	bra.b		~+16
   3974
   3975CASW_FILLER:
   3976	nop
   3977	nop
   3978	nop
   3979	nop
   3980	nop
   3981	nop
   3982	nop
   3983	bra.b		CASW_START
   3984
   3985#################################################################
   3986# THIS MUST BE THE STATE OF THE INTEGER REGISTER FILE UPON	#
   3987# CALLING _isp_cas_finish().					#
   3988#								#
   3989# D0 = destination[15:0] operand				#
   3990# D1 = 'xxxxxx11 -> no reg update; 'xxxxxx00 -> update required	#
   3991# D2 = xxxxxxxx							#
   3992# D3 = xxxxxxxx							#
   3993# D4 = compare[15:0] operand					#
   3994# D5 = xxxxxxxx							#
   3995# D6 = xxxxxxxx							#
   3996# D7 = xxxxxxxx							#
   3997# A0 = xxxxxxxx							#
   3998# A1 = xxxxxxxx							#
   3999# A2 = xxxxxxxx							#
   4000# A3 = xxxxxxxx							#
   4001# A4 = xxxxxxxx							#
   4002# A5 = xxxxxxxx							#
   4003# A6 = frame pointer						#
   4004# A7 = stack pointer						#
   4005#################################################################
   4006
   4007casw_noupdate_done:
   4008
   4009# restore previous SFC/DFC value.
   4010	movc		%d6,%sfc		# restore old SFC
   4011	movc		%d6,%dfc		# restore old DFC
   4012
   4013# restore previous interrupt mask level.
   4014	mov.w		%d7,%sr			# restore old SR
   4015
   4016	sf		%d1			# indicate no update was done
   4017	bra.l		_isp_cas_finish
   4018
   4019casw_update_done:
   4020
   4021# restore previous SFC/DFC value.
   4022	movc		%d6,%sfc		# restore old SFC
   4023	movc		%d6,%dfc		# restore old DFC
   4024
   4025# restore previous interrupt mask level.
   4026	mov.w		%d7,%sr			# restore old SR
   4027
   4028	st		%d1			# indicate update was done
   4029	bra.l		_isp_cas_finish
   4030
   4031################
   4032
   4033# there are two possible mis-aligned cases for longword cas. they
   4034# are separated because the final write which asserts LOCKE* must
   4035# be an aligned write.
   4036casl:
   4037	mov.l		%a0,%a1			# make copy for plpaw1
   4038	mov.l		%a0,%a2			# make copy for plpaw2
   4039	addq.l		&0x3,%a2		# plpaw2 points to end of longword
   4040
   4041	mov.l		%a0,%d1			# byte or word misaligned?
   4042	btst		&0x0,%d1
   4043	bne.w		casl2			# byte misaligned
   4044
   4045	mov.l		%d2,%d3			# d3 = update[15:0]
   4046	swap		%d2			# d2 = update[31:16]
   4047
   4048# mask interrupts levels 0-6. save old mask value.
   4049	mov.w		%sr,%d7			# save current SR
   4050	ori.w		&0x0700,%sr		# inhibit interrupts
   4051
   4052# load the SFC and DFC with the appropriate mode.
   4053	movc		%sfc,%d6		# save old SFC/DFC
   4054	movc		%d0,%sfc		# load new sfc
   4055	movc		%d0,%dfc		# load new dfc
   4056
   4057# pre-load the operand ATC. no page faults should occur here because
   4058# _real_lock_page() should have taken care of this.
   4059	plpaw		(%a1)			# load atc for ADDR
   4060	plpaw		(%a2)			# load atc for ADDR+3
   4061
   4062# push the operand lines from the cache if they exist.
   4063	cpushl		%dc,(%a1)		# push dirty data
   4064	cpushl		%dc,(%a2)		# push dirty data
   4065
   4066# load the BUSCR values.
   4067	mov.l		&0x80000000,%a1		# assert LOCK* buscr value
   4068	mov.l		&0xa0000000,%a2		# assert LOCKE* buscr value
   4069	mov.l		&0x00000000,%a3		# buscr unlock value
   4070
   4071	bra.b		CASL_ENTER		# start pre-loading icache
   4072
   4073#
   4074# D0 = dst operand <-
   4075# D1 = xxxxxxxx
   4076# D2 = update[31:16] operand
   4077# D3 = update[15:0]  operand
   4078# D4 = compare[31:0] operand
   4079# D5 = xxxxxxxx
   4080# D6 = old SFC/DFC
   4081# D7 = old SR
   4082# A0 = ADDR
   4083# A1 = bus LOCK*  value
   4084# A2 = bus LOCKE* value
   4085# A3 = bus unlock value
   4086# A4 = xxxxxxxx
   4087# A5 = xxxxxxxx
   4088#
   4089	align		0x10
   4090CASL_START:
   4091	movc		%a1,%buscr		# assert LOCK*
   4092	movs.l		(%a0),%d0		# fetch Dest[31:0]
   4093	cmp.l		%d0,%d4			# Dest - Compare
   4094	bne.b		CASL_NOUPDATE
   4095	bra.b		CASL_UPDATE
   4096CASL_ENTER:
   4097	bra.b		~+16
   4098
   4099CASL_UPDATE:
   4100	movs.w		%d2,(%a0)+		# Update[31:16] -> DEST
   4101	movc		%a2,%buscr		# assert LOCKE*
   4102	movs.w		%d3,(%a0)		# Update[15:0] -> DEST+0x2
   4103	bra.b		CASL_UPDATE2
   4104	bra.b		~+16
   4105
   4106CASL_UPDATE2:
   4107	movc		%a3,%buscr		# unlock the bus
   4108	bra.b		casl_update_done
   4109	nop
   4110	nop
   4111	nop
   4112	nop
   4113	bra.b		~+16
   4114
   4115CASL_NOUPDATE:
   4116	swap		%d0			# get Dest[31:16]
   4117	movs.w		%d0,(%a0)+		# Dest[31:16] -> DEST
   4118	swap		%d0			# get Dest[15:0]
   4119	movc		%a2,%buscr		# assert LOCKE*
   4120	bra.b		CASL_NOUPDATE2
   4121	bra.b		~+16
   4122
   4123CASL_NOUPDATE2:
   4124	movs.w		%d0,(%a0)		# Dest[15:0] -> DEST+0x2
   4125	movc		%a3,%buscr		# unlock the bus
   4126	bra.b		casl_noupdate_done
   4127	nop
   4128	nop
   4129	bra.b		~+16
   4130
   4131CASL_FILLER:
   4132	nop
   4133	nop
   4134	nop
   4135	nop
   4136	nop
   4137	nop
   4138	nop
   4139	bra.b		CASL_START
   4140
   4141#################################################################
   4142# THIS MUST BE THE STATE OF THE INTEGER REGISTER FILE UPON	#
   4143# CALLING _isp_cas_finish().					#
   4144#								#
   4145# D0 = destination[31:0] operand				#
   4146# D1 = 'xxxxxx11 -> no reg update; 'xxxxxx00 -> update required	#
   4147# D2 = xxxxxxxx							#
   4148# D3 = xxxxxxxx							#
   4149# D4 = compare[31:0] operand					#
   4150# D5 = xxxxxxxx							#
   4151# D6 = xxxxxxxx							#
   4152# D7 = xxxxxxxx							#
   4153# A0 = xxxxxxxx							#
   4154# A1 = xxxxxxxx							#
   4155# A2 = xxxxxxxx							#
   4156# A3 = xxxxxxxx							#
   4157# A4 = xxxxxxxx							#
   4158# A5 = xxxxxxxx							#
   4159# A6 = frame pointer						#
   4160# A7 = stack pointer						#
   4161#################################################################
   4162
   4163casl_noupdate_done:
   4164
   4165# restore previous SFC/DFC value.
   4166	movc		%d6,%sfc		# restore old SFC
   4167	movc		%d6,%dfc		# restore old DFC
   4168
   4169# restore previous interrupt mask level.
   4170	mov.w		%d7,%sr			# restore old SR
   4171
   4172	sf		%d1			# indicate no update was done
   4173	bra.l		_isp_cas_finish
   4174
   4175casl_update_done:
   4176
   4177# restore previous SFC/DFC value.
   4178	movc		%d6,%sfc		# restore old SFC
   4179	movc		%d6,%dfc		# restore old DFC
   4180
   4181# restore previous interrupts mask level.
   4182	mov.w		%d7,%sr			# restore old SR
   4183
   4184	st		%d1			# indicate update was done
   4185	bra.l		_isp_cas_finish
   4186
   4187#######################################
   4188casl2:
   4189	mov.l		%d2,%d5			# d5 = Update[7:0]
   4190	lsr.l		&0x8,%d2
   4191	mov.l		%d2,%d3			# d3 = Update[23:8]
   4192	swap		%d2			# d2 = Update[31:24]
   4193
   4194# mask interrupts levels 0-6. save old mask value.
   4195	mov.w		%sr,%d7			# save current SR
   4196	ori.w		&0x0700,%sr		# inhibit interrupts
   4197
   4198# load the SFC and DFC with the appropriate mode.
   4199	movc		%sfc,%d6		# save old SFC/DFC
   4200	movc		%d0,%sfc		# load new sfc
   4201	movc		%d0,%dfc		# load new dfc
   4202
   4203# pre-load the operand ATC. no page faults should occur here because
   4204# _real_lock_page() should have taken care of this already.
   4205	plpaw		(%a1)			# load atc for ADDR
   4206	plpaw		(%a2)			# load atc for ADDR+3
   4207
   4208# puch the operand lines from the cache if they exist.
   4209	cpushl		%dc,(%a1)		# push dirty data
   4210	cpushl		%dc,(%a2)		# push dirty data
   4211
   4212# load the BUSCR values.
   4213	mov.l		&0x80000000,%a1		# assert LOCK* buscr value
   4214	mov.l		&0xa0000000,%a2		# assert LOCKE* buscr value
   4215	mov.l		&0x00000000,%a3		# buscr unlock value
   4216
   4217# pre-load the instruction cache for the following algorithm.
   4218# this will minimize the number of cycles that LOCK* will be asserted.
   4219	bra.b		CASL2_ENTER		# start pre-loading icache
   4220
   4221#
   4222# D0 = dst operand <-
   4223# D1 = xxxxxxxx
   4224# D2 = update[31:24] operand
   4225# D3 = update[23:8]  operand
   4226# D4 = compare[31:0] operand
   4227# D5 = update[7:0]  operand
   4228# D6 = old SFC/DFC
   4229# D7 = old SR
   4230# A0 = ADDR
   4231# A1 = bus LOCK*  value
   4232# A2 = bus LOCKE* value
   4233# A3 = bus unlock value
   4234# A4 = xxxxxxxx
   4235# A5 = xxxxxxxx
   4236#
   4237	align		0x10
   4238CASL2_START:
   4239	movc		%a1,%buscr		# assert LOCK*
   4240	movs.l		(%a0),%d0		# fetch Dest[31:0]
   4241	cmp.l		%d0,%d4			# Dest - Compare
   4242	bne.b		CASL2_NOUPDATE
   4243	bra.b		CASL2_UPDATE
   4244CASL2_ENTER:
   4245	bra.b		~+16
   4246
   4247CASL2_UPDATE:
   4248	movs.b		%d2,(%a0)+		# Update[31:24] -> DEST
   4249	movs.w		%d3,(%a0)+		# Update[23:8] -> DEST+0x1
   4250	movc		%a2,%buscr		# assert LOCKE*
   4251	bra.b		CASL2_UPDATE2
   4252	bra.b		~+16
   4253
   4254CASL2_UPDATE2:
   4255	movs.b		%d5,(%a0)		# Update[7:0] -> DEST+0x3
   4256	movc		%a3,%buscr		# unlock the bus
   4257	bra.w		casl_update_done
   4258	nop
   4259	bra.b		~+16
   4260
   4261CASL2_NOUPDATE:
   4262	rol.l		&0x8,%d0		# get Dest[31:24]
   4263	movs.b		%d0,(%a0)+		# Dest[31:24] -> DEST
   4264	swap		%d0			# get Dest[23:8]
   4265	movs.w		%d0,(%a0)+		# Dest[23:8] -> DEST+0x1
   4266	bra.b		CASL2_NOUPDATE2
   4267	bra.b		~+16
   4268
   4269CASL2_NOUPDATE2:
   4270	rol.l		&0x8,%d0		# get Dest[7:0]
   4271	movc		%a2,%buscr		# assert LOCKE*
   4272	movs.b		%d0,(%a0)		# Dest[7:0] -> DEST+0x3
   4273	bra.b		CASL2_NOUPDATE3
   4274	nop
   4275	bra.b		~+16
   4276
   4277CASL2_NOUPDATE3:
   4278	movc		%a3,%buscr		# unlock the bus
   4279	bra.w		casl_noupdate_done
   4280	nop
   4281	nop
   4282	nop
   4283	bra.b		~+16
   4284
   4285CASL2_FILLER:
   4286	nop
   4287	nop
   4288	nop
   4289	nop
   4290	nop
   4291	nop
   4292	nop
   4293	bra.b		CASL2_START
   4294
   4295####
   4296####
   4297# end label used by _isp_cas_inrange()
   4298	global		_CASHI
   4299_CASHI: