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