Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/m68k/ifpsp060/src/isp.S
10820 views
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:
4300
4301