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