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