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