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