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