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