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