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