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