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