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
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
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 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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.
53 set _off_divbyzero
, 0x04
77 # Here's the table of ENTRY POINTS for those linking the package.
90 bra.
l _isp_cas2_finish
93 bra.
l _isp_cas_inrange
96 bra.
l _isp_cas_terminate
99 bra.
l _isp_cas_restart
104 #############################################################
109 mov.
l (_060ISP_TABLE-
0x80+_off_chk
,%pc
),%d0
110 pea.
l (_060ISP_TABLE-
0x80,%pc
,%d0
)
114 global _real_divbyzero
117 mov.
l (_060ISP_TABLE-
0x80+_off_divbyzero
,%pc
),%d0
118 pea.
l (_060ISP_TABLE-
0x80,%pc
,%d0
)
125 mov.
l (_060ISP_TABLE-
0x80+_off_trace
,%pc
),%d0
126 pea.
l (_060ISP_TABLE-
0x80,%pc
,%d0
)
133 mov.
l (_060ISP_TABLE-
0x80+_off_access
,%pc
),%d0
134 pea.
l (_060ISP_TABLE-
0x80,%pc
,%d0
)
141 mov.
l (_060ISP_TABLE-
0x80+_off_done
,%pc
),%d0
142 pea.
l (_060ISP_TABLE-
0x80,%pc
,%d0
)
146 #######################################
151 mov.
l (_060ISP_TABLE-
0x80+_off_cas
,%pc
),%d0
152 pea.
l (_060ISP_TABLE-
0x80,%pc
,%d0
)
159 mov.
l (_060ISP_TABLE-
0x80+_off_cas2
,%pc
),%d0
160 pea.
l (_060ISP_TABLE-
0x80,%pc
,%d0
)
164 global _real_lock_page
167 mov.
l (_060ISP_TABLE-
0x80+_off_lock
,%pc
),%d0
168 pea.
l (_060ISP_TABLE-
0x80,%pc
,%d0
)
172 global _real_unlock_page
175 mov.
l (_060ISP_TABLE-
0x80+_off_unlock
,%pc
),%d0
176 pea.
l (_060ISP_TABLE-
0x80,%pc
,%d0
)
180 #######################################
185 mov.
l (_060ISP_TABLE-
0x80+_off_imr
,%pc
),%d0
186 pea.
l (_060ISP_TABLE-
0x80,%pc
,%d0
)
193 mov.
l (_060ISP_TABLE-
0x80+_off_dmr
,%pc
),%d0
194 pea.
l (_060ISP_TABLE-
0x80,%pc
,%d0
)
201 mov.
l (_060ISP_TABLE-
0x80+_off_dmw
,%pc
),%d0
202 pea.
l (_060ISP_TABLE-
0x80,%pc
,%d0
)
206 global _imem_read_word
209 mov.
l (_060ISP_TABLE-
0x80+_off_irw
,%pc
),%d0
210 pea.
l (_060ISP_TABLE-
0x80,%pc
,%d0
)
214 global _imem_read_long
217 mov.
l (_060ISP_TABLE-
0x80+_off_irl
,%pc
),%d0
218 pea.
l (_060ISP_TABLE-
0x80,%pc
,%d0
)
222 global _dmem_read_byte
225 mov.
l (_060ISP_TABLE-
0x80+_off_drb
,%pc
),%d0
226 pea.
l (_060ISP_TABLE-
0x80,%pc
,%d0
)
230 global _dmem_read_word
233 mov.
l (_060ISP_TABLE-
0x80+_off_drw
,%pc
),%d0
234 pea.
l (_060ISP_TABLE-
0x80,%pc
,%d0
)
238 global _dmem_read_long
241 mov.
l (_060ISP_TABLE-
0x80+_off_drl
,%pc
),%d0
242 pea.
l (_060ISP_TABLE-
0x80,%pc
,%d0
)
246 global _dmem_write_byte
249 mov.
l (_060ISP_TABLE-
0x80+_off_dwb
,%pc
),%d0
250 pea.
l (_060ISP_TABLE-
0x80,%pc
,%d0
)
254 global _dmem_write_word
257 mov.
l (_060ISP_TABLE-
0x80+_off_dww
,%pc
),%d0
258 pea.
l (_060ISP_TABLE-
0x80,%pc
,%d0
)
262 global _dmem_write_long
265 mov.
l (_060ISP_TABLE-
0x80+_off_dwl
,%pc
),%d0
266 pea.
l (_060ISP_TABLE-
0x80,%pc
,%d0
)
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
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 #
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 #
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 #
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 #
394 # If none of these occur, then a normal exit is made through #
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 #########################################################################
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
417 mov.
l %usp
,%a0
# fetch user stack pointer
418 mov.
l %a0
,EXC_A7
(%a6
) # store a7
422 mov.
l %a0
,EXC_A7
(%a6
) # store corrected sp
424 ###############################################################################
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.
484 btst
&0x16,%d0
# test for div64
485 bne.
b uieh_div64
# go handle div64
488 # mul64() may use ()+ addressing and may, therefore, alter a7
490 bsr.
l _mul64
# _mul64()
492 btst
&0x5,EXC_ISR
(%a6
) # supervisor mode?
494 btst
&mia7_bit
,SPCOND_FLG
(%a6
) # was a7 changed?
496 btst
&0x7,EXC_ISR
(%a6
) # is trace enabled?
497 bne.w uieh_trace_a7
# yes
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
510 btst
&idbyz_bit
,SPCOND_FLG
(%a6
) # did divide-by-zero occur?
511 bne.w uieh_divbyzero
# yes
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:
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
529 # now, w/ group2, make movep's decode the fastest since it will
530 # most likely be used the most.
533 btst
&0x18,%d0
# test for not movep
537 bsr.
l _moveperipheral
# _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
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.
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?
566 bsr.
l _compandset2
# _cas2()
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
579 ###########################################################################
582 # the required emulation has been completed. now, clean up the necessary stack
583 # info and prepare for rte
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
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
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 # ***************** *****************
623 # ***************** * PC *
624 # ->* Old * *****************
625 # from link -->* A6 * * SR *
626 # ***************** *****************
627 # /* A7 * * New * <-- for final unlink
629 # link frame < ***************** *****************
631 # \***************** *****************
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
)
644 # UIEH FRAME CHK FRAME
645 # ***************** *****************
646 # * 0x0 * 0x0f4 * * Current *
647 # ***************** * PC *
648 # * Current * *****************
649 # * PC * * 0x2 * 0x018 *
650 # ***************** *****************
652 # ***************** * PC *
653 # (4 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()".
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
677 # UIEH FRAME DIVBYZERO FRAME
678 # ***************** *****************
679 # * 0x0 * 0x0f4 * * Current *
680 # ***************** * PC *
681 # * Current * *****************
682 # * PC * * 0x2 * 0x014 *
683 # ***************** *****************
685 # ***************** * PC *
686 # (4 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()".
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
715 # ***************** *****************
716 # * 0x0 * 0x0f4 * * 0x2 * 0x014 *
717 # ***************** *****************
718 # * Current * * Next *
720 # ***************** *****************
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.
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
751 # ***************** *****************
752 # * 0x0 * 0x0f4 * * 0x2 * 0x024 *
753 # ***************** *****************
754 # * Current * * Next *
756 # ***************** *****************
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.
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
788 # UIEH FRAME *****************
789 # ***************** * Next *
790 # * 0x0 * 0x0f4 * * PC *
791 # ***************** *****************
793 # * PC * *****************
794 # ***************** (4 words)
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
812 # this is the exit point if a data read or write fails.
813 # a0 = failing address
816 mov.
l %a0
,(%a6
) # save address
817 mov.
l %d0
,-0x4(%a6
) # save partial fslw
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
831 # this is the exit point if an instruction word read fails.
837 # software emulation error = true
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
849 btst
&0x5,(%sp
) # user or supervisor?
850 beq.
b isp_acc_exit2
# user
851 bset
&0x2,0xd(%sp
) # set supervisor TM bit
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.
858 cmpi.
b SPCOND_FLG
(%a6
),&restore_flg
# do we need a restore?
859 bne.
b isp_restore_done
# no
861 mov.
b EXC_SAVREG
(%a6
),%d0
# regno to restore
862 mov.
l EXC_SAVVAL
(%a6
),(EXC_AREGS
,%a6
,%d0.
l*4) # restore value
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 #
884 # elsif exiting though isp_iacc... #
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 #
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 #
905 # (d16,An) - fetch An value from stack; read d16 using #
906 # _imem_read_word(); fetch may fail -> branch to #
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 #
912 # (d16,PC) - fetch stacked PC value; read d16 using #
913 # _imem_read_word(); fetch may fail -> branch to #
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 #########################################################################
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
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 ###################################
1015 mov.
l EXC_A0
(%a6
),%a0
# Get current a0
1019 mov.
l EXC_A1
(%a6
),%a0
# Get current a1
1023 mov.
l EXC_A2
(%a6
),%a0
# Get current a2
1027 mov.
l EXC_A3
(%a6
),%a0
# Get current a3
1031 mov.
l EXC_A4
(%a6
),%a0
# Get current a4
1035 mov.
l EXC_A5
(%a6
),%a0
# Get current a5
1039 mov.
l EXC_A6
(%a6
),%a0
# Get current a6
1043 mov.
l EXC_A7
(%a6
),%a0
# Get current a7
1046 #####################################################
1047 # Address register indirect w/ postincrement: (An)+ #
1048 #####################################################
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
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
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
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
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
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
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
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 ####################################################
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
1145 mov.
b &0x0,EXC_SAVREG
(%a6
) # save regno, too
1146 mov.
b &restore_flg
,SPCOND_FLG
(%a6
) # set flag
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
1156 mov.
b &0x1,EXC_SAVREG
(%a6
) # save regno, too
1157 mov.
b &restore_flg
,SPCOND_FLG
(%a6
) # set flag
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
1167 mov.
b &0x2,EXC_SAVREG
(%a6
) # save regno, too
1168 mov.
b &restore_flg
,SPCOND_FLG
(%a6
) # set flag
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
1178 mov.
b &0x3,EXC_SAVREG
(%a6
) # save regno, too
1179 mov.
b &restore_flg
,SPCOND_FLG
(%a6
) # set flag
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
1189 mov.
b &0x4,EXC_SAVREG
(%a6
) # save regno, too
1190 mov.
b &restore_flg
,SPCOND_FLG
(%a6
) # set flag
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
1200 mov.
b &0x5,EXC_SAVREG
(%a6
) # save regno, too
1201 mov.
b &restore_flg
,SPCOND_FLG
(%a6
) # set flag
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
1211 mov.
b &0x6,EXC_SAVREG
(%a6
) # save regno, too
1212 mov.
b &restore_flg
,SPCOND_FLG
(%a6
) # set flag
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
1224 ########################################################
1225 # Address register indirect w/ displacement: (d16, An) #
1226 ########################################################
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
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
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
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
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
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
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
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 ########################################################################
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
1341 mov.
l (EXC_AREGS
,%a6
,%d1.w
*4),%a0
# put base in a0
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
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?
1364 ext.
l %d1
# sign extend word index
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 #########################################################################
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 ###########################
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 ##########################
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 #######################################################
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 ##########################################################
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
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
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
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 " " )
1505 btst
&0x6,%d5
# is the index suppressed?
1507 clr.
l %d2
# yes, so index = 0
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?
1516 bfextu
%d5
{&21:&2},%d0
1519 btst
&0x7,%d5
# is the bd suppressed?
1523 bfextu
%d5
{&26:&2},%d0
# get bd size
1524 # beq.l _error # if (size == 0) it's reserved
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
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
1548 add.l %d0
,%d3
# base += bd
1550 bfextu
%d5
{&30:&2},%d0
# is od suppressed?
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
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
1580 btst
&0x2,%d5
# pre or post indexing?
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
1594 add.l %d2
,%d3
# preindexing
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
1605 add.l %d2
,%d3
# ea = (base + bd) + index
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.
1620 # software emulation error = true
1622 mov.
l %d3
,%a0
# pass failing address
1623 mov.
l &0x01010001,%d0
# pass fslw
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 *************************************************************** #
1638 # OUTPUT ************************************************************** #
1639 # If exiting through isp_dacc... #
1640 # a0 = failing address #
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
1662 mov.w EXC_OPWORD
(%a6
),%d1
# fetch the opcode word
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)
1674 # reg2mem: fetch dx, then write it to memory
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?
1688 mov.
l %d0
,%d2
# store data
1689 mov.
l %a0
,%a2
# store addr
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
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
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
1723 bsr.
l _dmem_write_byte
# os : write lo
1725 tst.
l %d1
# dfetch error?
1726 bne.w movp_write_err
# yes
1733 mov.
l %d0
,%d2
# store data
1734 mov.
l %a0
,%a2
# store addr
1737 bsr.
l _dmem_write_byte
# os : write hi
1739 tst.
l %d1
# dfetch error?
1740 bne.w movp_write_err
# yes
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.
1756 btst
&0x6,%d1
# word or long operation?
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
1770 add.w
&0x2,%a2
# incr addr by 2 bytes
1773 bsr.
l _dmem_read_byte
# read second byte
1775 tst.
l %d1
# dfetch error?
1776 bne.w movp_read_err
# yes
1779 mov.
b %d0
,%d2
# append bytes
1781 add.w
&0x2,%a2
# incr addr by 2 bytes
1784 bsr.
l _dmem_read_byte
# read second byte
1786 tst.
l %d1
# dfetch error?
1787 bne.w movp_read_err
# yes
1790 mov.
b %d0
,%d2
# append bytes
1792 add.w
&0x2,%a2
# incr addr by 2 bytes
1795 bsr.
l _dmem_read_byte
# read second byte
1797 tst.
l %d1
# dfetch error?
1798 bne.w movp_read_err
# yes
1801 mov.
b %d0
,%d2
# append bytes
1803 mov.
b EXC_OPWORD
(%a6
),%d1
1805 and.w
&0x7,%d1
# extract Dx from opcode word
1807 mov.
l %d2
,(EXC_DREGS
,%a6
,%d1.w
*4) # store dx
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
1822 add.w
&0x2,%a2
# incr addr by 2 bytes
1825 bsr.
l _dmem_read_byte
# read second byte
1827 tst.
l %d1
# dfetch error?
1828 bne.w movp_read_err
# yes
1831 mov.
b %d0
,%d2
# append bytes
1833 mov.
b EXC_OPWORD
(%a6
),%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.
1848 # software emulation error = true
1850 mov.
l %a2
,%a0
# pass failing address
1851 mov.
l &0x00a10001,%d0
# pass fslw
1858 # software emulation error = true
1860 mov.
l %a2
,%a0
# pass failing address
1861 mov.
l &0x01210001,%d0
# pass fslw
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 *************************************************************** #
1877 # OUTPUT ************************************************************** #
1878 # If exiting through isp_dacc... #
1879 # a0 = failing address #
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 #########################################################################
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.
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
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.
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.
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
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.
2017 btst
&0x0, %d4
# is 'N' bit set?
2018 bne.
b chk2_trap
# yes;chk2 should 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.
2031 # software emulation error = true
2033 mov.
l %a2
,%a0
# pass failing address
2034 mov.
l &0x01010001,%d0
# pass fslw
2041 # software emulation error = true
2043 mov.
l %a2
,%a0
# pass failing address
2044 mov.
l &0x01410001,%d0
# pass fslw
2047 #########################################################################
2048 # XDEF **************************************************************** #
2049 # _div64(): routine to emulate div{u,s}.l <ea>,Dr:Dq #
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 *************************************************************** #
2061 # OUTPUT ************************************************************** #
2062 # If exiting through isp_dacc... #
2063 # a0 = failing address #
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
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
2104 mov.
l (EXC_DREGS
,%a6
,%d0.w
*4), %d7
# fetch divisor from register
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
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
2130 neg.l %d7
# complement negative divisor
2132 # save the sign of the dividend
2133 # make dividend unsigned if it's negative
2135 tst.
l %d5
# chk sign of hi(dividend)
2136 slt NDIVIDEND
(%a6
) # save sign of dividend
2139 mov.w
&0x0, %cc
# clear 'X' cc bit
2140 negx.
l %d6
# complement signed dividend
2143 # extract some special cases:
2144 # - is (dividend == 0) ?
2145 # - is (hi(dividend) == 0 && (divisor <= lo(dividend))) ? (32-bit div)
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.
2160 tdivu.
l %d7
, %d5
:%d6
# it's only a 32/32 bit div!
2165 # last special case:
2166 # - is hi(dividend) >= divisor ? if yes, then overflow
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.
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)
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?
2192 neg.l %d6
# make (-quot) 2's comp
2197 btst
&0x1f, %d6
# will (+quot) fit in 32 bits?
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
2217 bset
&0x1, EXC_CC+
1(%a6
) # 'V' set on overflow
2218 bclr &0x0, EXC_CC+
1(%a6
) # 'C' cleared on overflow
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 #
2241 #########################################################################
2243 # if the divisor msw is 0, use simpler algorithm then the full blown
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:
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
2265 mov.w
%d5
, %d1
# first quotient word
2267 mov.w
%d6
, %d5
# rb + u4
2272 mov.w
%d5
, %d1
# 2nd quotient 'digit'
2274 swap
%d5
# now remainder
2275 mov.
l %d1
, %d6
# and quotient
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
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
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
2306 cmp.w
%d2
, %d3
# V1 = U1 ?
2308 mov.w
&0xffff, %d1
# use max trial quotient word
2313 divu.w
%d3
, %d1
# use quotient of mslw/msw
2315 andi.l &0x0000ffff, %d1
# zero any remainder
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.
2322 clr.w
%d6
# word u3 left
2323 swap
%d6
# in lsw position
2324 ddadj1
: mov.
l %d7
, %d3
2326 mulu.w
%d7
, %d2
# V2q
2328 mulu.w
%d1
, %d3
# V1q
2329 mov.
l %d5
, %d4
# U1U2
2330 sub.l %d3
, %d4
# U1U2 - V1q
2335 mov.w
%d6
,%d4
# insert lower word (U3)
2337 tst.w
%d0
# is upper word set?
2340 # add.l %d6, %d4 # (U1U2 - V1q) + U3
2343 bls.
b ddadjd1
# is V2q > (U1U2-V1q) + U3 ?
2344 subq.
l &0x1, %d1
# yes, decrement and recheck
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)
2351 swap
%d6
# shift answer to ms 3 words
2354 mov.
l %d5
, %d2
# now %d2,%d3 are trial*divisor
2356 mov.
l (%sp
)+, %d5
# restore dividend
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.
2368 clr.w
%d3
# %d3 now ls word of divisor
2369 add.l %d3
, %d6
# aligned with 3rd word of dividend
2372 clr.w
%d3
# %d3 now ms word of divisor
2373 swap
%d3
# aligned with 2nd word of dividend
2376 tst.
b DDSECOND
(%a6
) # both q words done?
2378 # first quotient digit now correct. store digit and shift the
2379 # (subtracted) dividend
2380 mov.w
%d1
, DDQUOTIENT
(%a6
)
2386 st DDSECOND
(%a6
) # second digit
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.
2395 mov.
l DDNORMAL
(%a6
), %d7
# get norm shift count
2397 subq.
l &0x1, %d7
# set for loop count
2399 lsr.
l &0x1, %d5
# shift into %d6
2403 mov.
l %d6
, %d5
# remainder
2404 mov.
l DDQUOTIENT
(%a6
), %d6
# quotient
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
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
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
2431 clr.w
%d2
# lsw of two mixed products used,
2432 swap
%d5
# now use msws of longwords
2435 add.l %d3
, %d5
# %d5 now ms 32 bits of final product
2441 bsr.
l _calc_ea
# calc <ea>
2443 cmpi.
b SPCOND_FLG
(%a6
),&immed_flg
# immediate addressing mode?
2447 bsr.
l _dmem_read_long
# fetch divisor from <ea>
2449 tst.
l %d1
# dfetch error?
2450 bne.
b div64_err
# yes
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.
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
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.
2479 # software emulation error = true
2481 bsr.
l isp_restore
# restore addr reg
2482 mov.
l %a2
,%a0
# pass failing address
2483 mov.
l &0x01010001,%d0
# pass fslw
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 *************************************************************** #
2499 # OUTPUT ************************************************************** #
2500 # If exiting through isp_dacc... #
2501 # a0 = failing address #
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 #########################################################################
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.
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.
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.
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 #########################################################################
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 #########################################################################
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
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.
2642 mov.
l %d3
, (EXC_DREGS
,%a6
,%d2.w
*4) # save lo(result)
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
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.
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
2671 # multiplier operand is in memory at the effective address.
2672 # must calculate the <ea> and go fetch the 32-bit operand.
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
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.
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
2701 bra.w mul64_multiplicand
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.
2714 # software emulation error = true
2716 bsr.
l isp_restore
# restore addr reg
2717 mov.
l %a2
,%a0
# pass failing address
2718 mov.
l &0x01010001,%d0
# pass fslw
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 *************************************************************** #
2737 # d0 = instruction extension word #
2739 # _isp_cas2_finish(): #
2740 # see cas2 core emulation code #
2742 # OUTPUT ************************************************************** #
2744 # see cas2 core emulation code #
2746 # _isp_cas_finish(): #
2747 # None (register file or memroy changed as appropriate) #
2749 # ALGORITHM *********************************************************** #
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
2775 mov.
l %d0
,EXC_TEMP+
0x4(%a6
) # store for possible restart
2776 mov.
l %d0
,%d1
# extension word in 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
)
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
2793 mov.w EXC_EXTWORD
(%a6
),%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
)
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
2811 btst
&0x1,EXC_OPWORD
(%a6
) # word or long?
2814 btst
&0x5,EXC_ISR
(%a6
) # user or supervisor?
2820 mov.
l %d7
,%d1
# pass size
2821 mov.
l %d6
,%d0
# pass mode
2822 bsr.
l _real_lock_page
# lock page
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
2833 bne.
b cas_preterm
# yes
2840 # if the 2nd lock attempt fails, then we must still unlock the
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
2856 btst
&0x1,EXC_OPWORD
(%a6
)
2859 mov.w EXC_CC
(%a6
),%cc
# load old ccodes
2861 bne.
b 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
2876 btst
&0x5,EXC_ISR
(%a6
)
2878 mov.
l %d2
,%d0
# pass mode
2880 mov.
l ADDR1
(%a6
),%a0
# pass ADDR1
2881 bsr.
l _real_unlock_page
# unlock page
2883 mov.
l %d2
,%d0
# pass mode
2885 mov.
l ADDR2
(%a6
),%a0
# pass ADDR2
2886 bsr.
l _real_unlock_page
# unlock page
2890 mov.w EXC_CC
(%a6
),%cc
# load old ccodes
2892 bne.
b 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
2907 btst
&0x5,EXC_ISR
(%a6
)
2909 mov.
l %d2
,%d0
# pass mode
2911 mov.
l ADDR1
(%a6
),%a0
# pass ADDR1
2912 bsr.
l _real_unlock_page
# unlock page
2914 mov.
l %d2
,%d0
# pass mode
2916 mov.
l ADDR2
(%a6
),%a0
# pass ADDR2
2917 bsr.
l _real_unlock_page
# unlock page
2923 mov.
l EXC_TEMP+
0x4(%a6
),%d0
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 *************************************************************** #
2946 # _isp_cas_restart(): #
2947 # d6 = previous sfc/dfc #
2948 # _isp_cas_finish(): #
2949 # _isp_cas_terminate(): #
2950 # a0 = failing address #
2952 # d6 = previous sfc/dfc #
2953 # _isp_cas_inrange(): #
2954 # a0 = instruction address to be checked #
2956 # OUTPUT ************************************************************** #
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 *********************************************************** #
2972 # First, calculate the effective address. Then, decode the #
2973 # instruction word and fetch the "compare" (DC) and "update" (Du) #
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 #
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 #
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() #
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
3015 btst
&0x1,EXC_OPWORD
(%a6
) # word or long operation?
3016 bne.
b compandsetl
# long
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
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
3032 mov.w EXC_EXTWORD
(%a6
),%d0
# fetch cas extension word
3033 mov.
l %d0
,%d1
# make a copy
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
3057 global _isp_cas_finish
3059 btst
&0x1,EXC_OPWORD
(%a6
)
3062 # just do the compare again since it's faster than saving the ccodes
3063 # from the locked routine...
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
3073 mov.w
%d0
,(EXC_DREGS+
2,%a6
,%d3.w
*4) # Dc = destination
3076 mov.
l ADDR
(%a6
),%a0
# pass addr
3078 btst
&0x5,EXC_ISR
(%a6
)
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...
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
3094 mov.
l %d0
,(EXC_DREGS
,%a6
,%d3.w
*4) # Dc = destination
3097 mov.
l ADDR
(%a6
),%a0
# pass addr
3099 btst
&0x5,EXC_ISR
(%a6
)
3101 bsr.
l _real_unlock_page
# unlock page
3106 global _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
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
3121 # At this stage, it would be nice if d0 held the FSLW.
3122 global _isp_cas_terminate
3124 mov.
l %d6
,%sfc
# restore previous sfc
3125 mov.
l %d6
,%dfc
# restore previous dfc
3127 global _cas_terminate2
3129 mov.
l %a0
,%a2
# copy failing addr to a2
3132 bsr.
l isp_restore
# restore An (if ()+ or -())
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
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
3154 global _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?
3160 lea _CASLO
(%pc
),%a1
# load begin of CAS core code
3161 cmp.
l %a0
,%a1
# is PC in range?
3163 rts
# yes; return d0 = 0
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 # ###### ## ###### ####
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 #
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. #
3227 # (13)Write update operand to the DST locations. Use BUSCR to #
3228 # assert LOCKE* for the final write operation. #
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(). #
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 #
3256 # A6 = frame pointer #
3257 # A7 = stack pointer #
3258 #################################################################
3261 # beginning label used by _isp_cas_inrange()
3267 tst.
b %d6
# user or supervisor mode?
3268 bne.
b cas2_supervisor
# supervisor
3270 movq.
l &0x1,%d0
# load user data fc
3273 movq.
l &0x5,%d0
# load supervisor data fc
3275 tst.
b %d7
# word or longword?
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
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
3329 mov.
l %a0
,%d0
# is ADDR1 misaligned?
3331 beq.
b CAS2L_ENTER
# no
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
3347 # A2 = bus LOCK* value
3348 # A3 = bus LOCKE* value
3349 # A4 = bus unlock value
3354 movc
%a2
,%buscr
# assert LOCK*
3355 movs.
l (%a1
),%d1
# fetch Dest2[31:0]
3356 movs.
l (%a0
),%d0
# fetch Dest1[31:0]
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
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
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
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 #
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
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
3445 movc
%a2
,%buscr
# assert LOCK*
3446 movs.
l (%a1
),%d1
# fetch Dest2[31:0]
3447 movs.
l (%a0
),%d0
# fetch Dest1[31:0]
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
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
3470 movs.w
%d4
,(%a0
) # Update1[15:0] -> DEST1+0x2
3471 movc
%a4
,%buscr
# unlock the bus
3472 bra.w cas2l_update_done
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
3485 movs.w
%d0
,(%a0
) # Dest1[15:0] -> DEST1+0x2
3486 movc
%a4
,%buscr
# unlock the bus
3487 bra.w cas2l_noupdate_done
3501 #################################
3505 movc
%a2
,%buscr
# assert LOCK*
3506 movs.
l (%a1
),%d1
# fetch Dest2[31:0]
3507 movs.
l (%a0
),%d0
# fetch Dest1[31:0]
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
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
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
3538 movc
%a4
,%buscr
# unlock the bus
3539 bra.w cas2l_update_done
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
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
3562 movc
%a4
,%buscr
# unlock the bus
3563 bra.w cas2l_noupdate_done
3578 #############################################################
3579 #############################################################
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
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
3631 mov.
l %a0
,%d0
# is ADDR1 misaligned?
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
3647 # A2 = bus LOCK* value
3648 # A3 = bus LOCKE* value
3649 # A4 = bus unlock value
3654 movc
%a2
,%buscr
# assert LOCK*
3655 movs.w
(%a1
),%d1
# fetch Dest2[15:0]
3656 movs.w
(%a0
),%d0
# fetch Dest1[15:0]
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
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
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
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 #
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
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
3745 movc
%a2
,%buscr
# assert LOCK*
3746 movs.w
(%a1
),%d1
# fetch Dest2[15:0]
3747 movs.w
(%a0
),%d0
# fetch Dest1[15:0]
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
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
3770 movs.
b %d4
,(%a0
) # Update1[7:0] -> DEST1+0x1
3771 movc
%a4
,%buscr
# unlock the bus
3772 bra.w cas2w_update_done
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
3785 movs.
b %d0
,(%a0
) # Dest1[7:0] -> DEST1+0x1
3786 movc
%a4
,%buscr
# unlock the bus
3787 bra.w cas2w_noupdate_done
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; #
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 #
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. #
3844 # (12)Write update operand to the DST location. Use BUSCR to #
3845 # assert LOCKE* for the final write operation. #
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(). #
3861 # D2 = update operand #
3863 # D4 = compare operand #
3865 # D6 = supervisor ('xxxxxxff) or user mode ('xxxxxx00) #
3866 # D7 = longword ('xxxxxxff) or word size ('xxxxxx00) #
3873 # A6 = frame pointer #
3874 # A7 = stack pointer #
3875 #########################################################
3879 tst.
b %d6
# user or supervisor mode?
3880 bne.
b cas_super
# supervisor
3882 movq.
l &0x1,%d0
# load user data fc
3885 movq.
l &0x5,%d0
# load supervisor data fc
3888 tst.
b %d7
# word or longword?
3889 bne.w casl
# longword
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
3932 # D4 = compare[15:0] operand
3937 # A1 = bus LOCK* value
3938 # A2 = bus LOCKE* value
3939 # A3 = bus unlock value
3945 movc
%a1
,%buscr
# assert LOCK*
3946 movs.w
(%a0
),%d0
# fetch Dest[15:0]
3947 cmp.w
%d0
,%d4
# Dest - Compare
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
3961 movc
%a3
,%buscr
# unlock the bus
3962 bra.
b casw_update_done
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
3978 movs.
b %d0
,(%a0
) # Dest[7:0] -> DEST+0x1
3979 movc
%a3
,%buscr
# unlock the bus
3980 bra.
b casw_noupdate_done
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 #
4003 # D4 = compare[15:0] operand #
4013 # A6 = frame pointer #
4014 # A7 = stack pointer #
4015 #################################################################
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
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
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.
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?
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 <-
4086 # D2 = update[31:16] operand
4087 # D3 = update[15:0] operand
4088 # D4 = compare[31:0] operand
4093 # A1 = bus LOCK* value
4094 # A2 = bus LOCKE* value
4095 # A3 = bus unlock value
4101 movc
%a1
,%buscr
# assert LOCK*
4102 movs.
l (%a0
),%d0
# fetch Dest[31:0]
4103 cmp.
l %d0
,%d4
# Dest - Compare
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
4117 movc
%a3
,%buscr
# unlock the bus
4118 bra.
b casl_update_done
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
4134 movs.w
%d0
,(%a0
) # Dest[15:0] -> DEST+0x2
4135 movc
%a3
,%buscr
# unlock the bus
4136 bra.
b casl_noupdate_done
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 #
4159 # D4 = compare[31:0] operand #
4169 # A6 = frame pointer #
4170 # A7 = stack pointer #
4171 #################################################################
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
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 #######################################
4199 mov.
l %d2
,%d5
# d5 = Update[7:0]
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 <-
4234 # D2 = update[31:24] operand
4235 # D3 = update[23:8] operand
4236 # D4 = compare[31:0] operand
4237 # D5 = update[7:0] operand
4241 # A1 = bus LOCK* value
4242 # A2 = bus LOCKE* value
4243 # A3 = bus unlock value
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
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*
4265 movs.
b %d5
,(%a0
) # Update[7:0] -> DEST+0x3
4266 movc
%a3
,%buscr
# unlock the bus
4267 bra.w casl_update_done
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
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
4288 movc
%a3
,%buscr
# unlock the bus
4289 bra.w casl_noupdate_done
4307 # end label used by _isp_cas_inrange()