root/arch/m68k/ifpsp060/src/isp.S

/* [<][>][^][v][top][bottom][index][help] */
   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 register, 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 effective      #
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:

/* [<][>][^][v][top][bottom][index][help] */