1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 * Yabause - linkage_x86.s * 3 * Copyright (C) 2009-2011 Ari64 * 4 * * 5 * This program is free software; you can redistribute it and/or modify * 6 * it under the terms of the GNU General Public License as published by * 7 * the Free Software Foundation; either version 2 of the License, or * 8 * (at your option) any later version. * 9 * * 10 * This program is distributed in the hope that it will be useful, * 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 * GNU General Public License for more details. * 14 * * 15 * You should have received a copy of the GNU General Public License * 16 * along with this program; if not, write to the * 17 * Free Software Foundation, Inc., * 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * 19 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 20 .file "linkage_x86.s" 21 .bss 22 .align 4 23 .section .rodata 24 .text 25.globl YabauseDynarecOneFrameExec 26 .type YabauseDynarecOneFrameExec, @function 27YabauseDynarecOneFrameExec: 28 push %ebp 29 mov %esp,%ebp 30 mov master_ip, %eax 31 xor %ecx, %ecx 32 push %edi 33 push %esi 34 push %ebx 35 push %ecx /* zero */ 36 push %ecx 37 push %ecx 38 push %ecx 39 push %ecx /* put m68k here (?) */ 40 push %ecx 41 call .+5 /* 40+4=44 */ 42 mov %eax,-40(%ebp) /* overwrite return address */ 43/* Stack frame: 44 arg2 - m68kcenticycles (+8/+12) 45 arg1 - m68kcycles (+4/+8) 46 return address (0) 47 ebp (4/0) 48 save edi (8/4) 49 save esi (12/8) 50 save ebx (16/12) 51 decilinecount (20/16) 52 decilinecycles (24/20) 53 sh2cycles (28/24) 54 scucycles (32/28) 55 ... (36/32) 56 ... (40/36) 57 ret address/master_ip (44/40) (alternate esp at call) 58 save %eax (48/44) 59 save %ecx (52/48) 60 save %edx (56/52) 61 ... (esp at call) 62 next return address (64/60) 63 total = 64 */ 64/* usecinc? 65 cyclesinc?*/ 66 67newline: 68/* const u32 decilinecycles = yabsys.DecilineStop >> YABSYS_TIMING_BITS; */ 69/* const u32 cyclesinc = yabsys.DecilineStop * 10; */ 70 mov decilinestop_p, %eax 71 mov yabsys_timing_bits, %ecx 72 mov (%eax), %eax 73 lea (%eax,%eax,4), %ebx /* decilinestop*5 */ 74 shr %cl, %eax /* decilinecycles */ 75 shl %ebx /* cyclesinc=decilinestop*10 */ 76 lea (%eax,%eax,8), %edx /* decilinecycles*9 */ 77 /* yabsys.SH2CycleFrac += cyclesinc;*/ 78 /* sh2cycles = (yabsys.SH2CycleFrac >> (YABSYS_TIMING_BITS + 1)) << 1;*/ 79 /* yabsys.SH2CycleFrac &= ((YABSYS_TIMING_MASK << 1) | 1);*/ 80 mov SH2CycleFrac_p, %esi 81 mov yabsys_timing_mask, %edi 82 inc %ecx /* yabsys_timing_bits+1 */ 83 add (%esi), %ebx /* SH2CycleFrac */ 84 stc 85 adc %edi, %edi /* ((YABSYS_TIMING_MASK << 1) | 1) */ 86 mov %eax, -20(%ebp) /* decilinecycles */ 87 and %ebx, %edi 88 mov %edi, (%esi) /* SH2CycleFrac */ 89 shr %cl, %ebx 90 mov %ebx, -28(%ebp) /* scucycles */ 91 add %ebx, %ebx /* sh2cycles */ 92 mov MSH2, %eax 93 mov NumberOfInterruptsOffset, %ecx 94 sub %edx, %ebx /* sh2cycles(full line) - decilinecycles*9 */ 95 mov %ebx, -24(%ebp) /* sh2cycles */ 96 cmp $0, (%eax, %ecx) 97 jne master_handle_interrupts 98 mov master_cc, %esi 99 sub %ebx, %esi 100 ret /* jmp master_ip */ 101 .size YabauseDynarecOneFrameExec, .-YabauseDynarecOneFrameExec 102 103.globl master_handle_interrupts 104 .type master_handle_interrupts, @function 105master_handle_interrupts: 106 mov -40(%ebp), %eax /* get return address */ 107 mov %eax, master_ip 108 call DynarecMasterHandleInterrupts 109 mov master_ip, %eax 110 mov master_cc, %esi 111 mov %eax,-40(%ebp) /* overwrite return address */ 112 sub %ebx, %esi 113 ret /* jmp master_ip */ 114 .size master_handle_interrupts, .-master_handle_interrupts 115 116.globl slave_entry 117 .type slave_entry, @function 118slave_entry: 119 mov 16(%esp), %ebx /* sh2cycles */ 120 mov %esi, master_cc 121 sub $12, %esp 122 push %ebx 123 call FRTExec 124 mov %ebx, (%esp) 125 call WDTExec 126 mov slave_ip, %edx 127 add $16, %esp 128 test %edx, %edx 129 je cc_interrupt_master /* slave not running */ 130 mov SSH2, %eax 131 mov NumberOfInterruptsOffset, %ecx 132 cmp $0, (%eax, %ecx) 133 jne slave_handle_interrupts 134 mov slave_cc, %esi 135 sub %ebx, %esi 136 jmp *%edx /* jmp *slave_ip */ 137 .size slave_entry, .-slave_entry 138 139.globl slave_handle_interrupts 140 .type slave_handle_interrupts, @function 141slave_handle_interrupts: 142 call DynarecSlaveHandleInterrupts 143 mov slave_ip, %edx 144 mov slave_cc, %esi 145 sub %ebx, %esi 146 jmp *%edx /* jmp *slave_ip */ 147 .size slave_handle_interrupts, .-slave_handle_interrupts 148 149.globl cc_interrupt 150 .type cc_interrupt, @function 151cc_interrupt: /* slave */ 152 mov 16(%esp), %ebx /* sh2cycles */ 153 mov %ebp, slave_ip 154 mov %esi, slave_cc 155 add $-12, %esp 156 push %ebx 157 call FRTExec 158 mov %ebx, (%esp) 159 call WDTExec 160 add $16, %esp 161 .size cc_interrupt, .-cc_interrupt 162.globl cc_interrupt_master 163 .type cc_interrupt_master, @function 164cc_interrupt_master: 165 lea 40(%esp), %ebp 166 mov -16(%ebp), %eax /* decilinecount */ 167 mov -20(%ebp), %ebx /* decilinecycles */ 168 inc %eax 169 cmp $9, %eax 170 ja .A3 171 mov %eax, -16(%ebp) /* decilinecount++ */ 172 je .A2 173 mov %ebx, -24(%ebp) /* sh2cycles */ 174.A1: 175 mov master_cc, %esi 176 mov MSH2, %eax 177 mov NumberOfInterruptsOffset, %ecx 178 cmp $0, (%eax, %ecx) 179 jne master_handle_interrupts 180 sub %ebx, %esi 181 ret /* jmp master_ip */ 182.A2: 183 call Vdp2HBlankIN 184 jmp .A1 185.A3: 186 mov -28(%ebp), %ebx /* scucycles */ 187 add $-12, %esp 188 push %ebx 189 call ScuExec 190 call M68KSync 191 call Vdp2HBlankOUT 192 call ScspExec 193 mov linecount_p, %ebx 194 mov maxlinecount_p, %eax 195 mov vblanklinecount_p, %ecx 196 mov (%ebx), %edx 197 mov (%eax), %eax 198 mov (%ecx), %ecx 199 inc %edx 200 andl $0, -16(%ebp) /* decilinecount=0 */ 201 cmp %eax, %edx /* max ? */ 202 je nextframe 203 mov %edx, (%ebx) /* linecount++ */ 204 cmp %ecx, %edx /* vblank ? */ 205 je vblankin 206nextline: 207 add $16, %esp 208 call finishline 209 jmp newline 210finishline: /* CHECK - Stack align? */ 211 /*const u32 usecinc = yabsys.DecilineUsec * 10;*/ 212 mov decilineusec_p, %eax 213 mov UsecFrac_p, %ebx 214 mov yabsys_timing_bits, %ecx 215 mov (%eax), %eax 216 mov (%ebx), %edx 217 lea (%eax,%eax,4), %esi 218 mov yabsys_timing_mask, %edi 219 add %esi, %esi 220 /*yabsys.UsecFrac += usecinc;*/ 221 add %edx, %esi 222 add $-8, %esp /* Align stack */ 223 /*SmpcExec(yabsys.UsecFrac >> YABSYS_TIMING_BITS); 224 /*Cs2Exec(yabsys.UsecFrac >> YABSYS_TIMING_BITS); 225 /*yabsys.UsecFrac &= YABSYS_TIMING_MASK;*/ 226 mov %esi, (%ebx) /* UsecFrac */ 227 shr %cl, %esi 228 push %esi 229 call SmpcExec 230 /* SmpcExec may modify UsecFrac; must reload it */ 231 mov (%ebx), %esi /* UsecFrac */ 232 mov yabsys_timing_bits, %ecx 233 and %esi, %edi 234 shr %cl, %esi 235 mov %esi, (%esp) 236 call Cs2Exec 237 mov %edi, (%ebx) /* UsecFrac */ 238 mov saved_centicycles, %ecx 239 mov 12(%ebp), %ebx /* m68kcenticycles */ 240 mov 8(%ebp), %eax /* m68kcycles */ 241 add %ebx, %ecx 242 mov %ecx, %ebx 243 add $-100, %ecx 244 cmovnc %ebx, %ecx 245 adc $0, %eax 246 mov %ecx, saved_centicycles 247 mov %eax, (%esp) /* cycles */ 248 call M68KExec 249 add $12, %esp 250 ret 251vblankin: 252 call SmpcINTBACKEnd 253 call Vdp2VBlankIN 254 call CheatDoPatches 255 jmp nextline 256nextframe: 257 call Vdp2VBlankOUT 258 andl $0, (%ebx) /* linecount = 0 */ 259 call finishline 260 call M68KSync 261 mov rccount, %esi 262 inc %esi 263 andl $0, invalidate_count 264 and $0x3f, %esi 265 cmpl $0, restore_candidate(,%esi,4) 266 mov %esi, rccount 267 jne .A5 268.A4: 269 mov 16(%esp), %eax 270 add $44, %esp 271 mov %eax, master_ip 272 pop %ebx 273 pop %esi 274 pop %edi 275 pop %ebp 276 ret 277.A5: 278 /* Move 'dirty' blocks to the 'clean' list */ 279 mov restore_candidate(,%esi,4), %ebx 280 mov %esi, %ebp 281 andl $0, restore_candidate(,%esi,4) 282 shl $5, %ebp 283.A6: 284 shr $1, %ebx 285 jnc .A7 286 mov %ebp, (%esp) 287 call clean_blocks 288.A7: 289 inc %ebp 290 test $31, %ebp 291 jne .A6 292 jmp .A4 293 .size cc_interrupt_master, .-cc_interrupt_master 294 295.globl dyna_linker 296 .type dyna_linker, @function 297dyna_linker: 298 /* eax = virtual target address */ 299 /* ebx = instruction to patch */ 300 mov %eax, %ecx 301 mov $1023, %edx 302 shr $12, %ecx 303 and %ecx, %edx 304 and $0xDFFFF, %ecx 305 or $1024, %edx 306 cmp %edx, %ecx 307 cmova %edx, %ecx 308 /* jump_in lookup */ 309 mov jump_in(,%ecx,4), %edx 310.B1: 311 test %edx, %edx 312 je .B3 313 mov (%edx), %edi 314 xor %eax, %edi 315 je .B2 316 movl 12(%edx), %edx 317 jmp .B1 318.B2: 319 mov (%ebx), %edi 320 mov %esi, %ebp 321 lea 4(%ebx,%edi,1), %esi 322 mov %eax, %edi 323 pusha 324 call add_link 325 popa 326 mov 8(%edx), %edi 327 mov %ebp, %esi 328 lea -4(%edi), %edx 329 subl %ebx, %edx 330 movl %edx, (%ebx) 331 jmp *%edi 332.B3: 333 /* hash_table lookup */ 334 mov %eax, %edi 335 shr $16, %edi 336 xor %eax, %edi 337 movzwl %di, %edi 338 shl $4, %edi 339 cmp hash_table(%edi), %eax 340 jne .B5 341.B4: 342 mov hash_table+4(%edi), %edx 343 jmp *%edx 344.B5: 345 cmp hash_table+8(%edi), %eax 346 lea 8(%edi), %edi 347 je .B4 348 /* jump_dirty lookup */ 349 mov jump_dirty(,%ecx,4), %edx 350.B6: 351 testl %edx, %edx 352 je .B8 353 mov (%edx), %ecx 354 xor %eax, %ecx 355 je .B7 356 movl 12(%edx), %edx 357 jmp .B6 358.B7: 359 mov 8(%edx), %edx 360 /* hash_table insert */ 361 mov hash_table-8(%edi), %ebx 362 mov hash_table-4(%edi), %ecx 363 mov %eax, hash_table-8(%edi) 364 mov %edx, hash_table-4(%edi) 365 mov %ebx, hash_table(%edi) 366 mov %ecx, hash_table+4(%edi) 367 jmp *%edx 368.B8: 369 mov %eax, %edi 370 pusha 371 call sh2_recompile_block 372 test %eax, %eax 373 popa 374 je dyna_linker 375 /* shouldn't happen */ 376 int3 377 .size dyna_linker, .-dyna_linker 378 379.globl jump_vaddr_eax_master 380 .type jump_vaddr_eax_master, @function 381jump_vaddr_eax_master: 382 mov %eax, %edi 383 jmp jump_vaddr_edi_master 384 .size jump_vaddr_eax_master, .-jump_vaddr_eax_master 385.globl jump_vaddr_ecx_master 386 .type jump_vaddr_ecx_master, @function 387jump_vaddr_ecx_master: 388 mov %ecx, %edi 389 jmp jump_vaddr_edi_master 390 .size jump_vaddr_ecx_master, .-jump_vaddr_ecx_master 391.globl jump_vaddr_edx_master 392 .type jump_vaddr_edx_master, @function 393jump_vaddr_edx_master: 394 mov %edx, %edi 395 jmp jump_vaddr_edi_master 396 .size jump_vaddr_edx_master, .-jump_vaddr_edx_master 397.globl jump_vaddr_ebx_master 398 .type jump_vaddr_ebx_master, @function 399jump_vaddr_ebx_master: 400 mov %ebx, %edi 401 jmp jump_vaddr_edi_master 402 .size jump_vaddr_ebx_master, .-jump_vaddr_ebx_master 403.globl jump_vaddr_ebp_master 404 .type jump_vaddr_ebp_master, @function 405jump_vaddr_ebp_master: 406 mov %ebp, %edi 407 jmp jump_vaddr_edi_master 408 .size jump_vaddr_ebp_master, .-jump_vaddr_ebp_master 409.globl jump_vaddr_eax_slave 410 .type jump_vaddr_eax_slave, @function 411jump_vaddr_eax_slave: 412 mov %eax, %edi 413 jmp jump_vaddr_edi_slave 414 .size jump_vaddr_eax_slave, .-jump_vaddr_eax_slave 415.globl jump_vaddr_ecx_slave 416 .type jump_vaddr_ecx_slave, @function 417jump_vaddr_ecx_slave: 418 mov %ecx, %edi 419 jmp jump_vaddr_edi_slave 420 .size jump_vaddr_ecx_slave, .-jump_vaddr_ecx_slave 421.globl jump_vaddr_edx_slave 422 .type jump_vaddr_edx_slave, @function 423jump_vaddr_edx_slave: 424 mov %edx, %edi 425 jmp jump_vaddr_edi_slave 426 .size jump_vaddr_edx_slave, .-jump_vaddr_edx_slave 427.globl jump_vaddr_ebx_slave 428 .type jump_vaddr_ebx_slave, @function 429jump_vaddr_ebx_slave: 430 mov %ebx, %edi 431 jmp jump_vaddr_edi_slave 432 .size jump_vaddr_ebx_slave, .-jump_vaddr_ebx_slave 433.globl jump_vaddr_ebp_slave 434 .type jump_vaddr_ebp_slave, @function 435jump_vaddr_ebp_slave: 436 mov %ebp, %edi 437 .size jump_vaddr_ebp_slave, .-jump_vaddr_ebp_slave 438.globl jump_vaddr_edi_slave 439 .type jump_vaddr_edi_slave, @function 440jump_vaddr_edi_slave: 441 or $1, %edi 442 .size jump_vaddr_edi_slave, .-jump_vaddr_edi_slave 443.globl jump_vaddr_edi_master 444 .type jump_vaddr_edi_master, @function 445jump_vaddr_edi_master: 446 mov %edi, %eax 447 .size jump_vaddr_edi_master, .-jump_vaddr_edi_master 448 449.globl jump_vaddr 450 .type jump_vaddr, @function 451jump_vaddr: 452 /* Check hash table */ 453 shr $16, %eax 454 xor %edi, %eax 455 movzwl %ax, %eax 456 shl $4, %eax 457 cmp hash_table(%eax), %edi 458 jne .C2 459.C1: 460 mov hash_table+4(%eax), %edi 461 jmp *%edi 462.C2: 463 cmp hash_table+8(%eax), %edi 464 lea 8(%eax), %eax 465 je .C1 466 /* No hit on hash table, call compiler */ 467 push %edi 468 call get_addr 469 add $4, %esp 470 jmp *%eax 471 .size jump_vaddr, .-jump_vaddr 472 473.globl verify_code 474 .type verify_code, @function 475verify_code: 476 /* eax = source */ 477 /* ebx = target */ 478 /* ecx = length */ 479 mov -4(%eax,%ecx,1), %edi 480 xor -4(%ebx,%ecx,1), %edi 481 jne .D5 482 mov %ecx, %edx 483 add $-4, %ecx 484 je .D3 485 test $4, %edx 486 cmove %edx, %ecx 487 push %esi 488.D2: 489 mov -4(%eax,%ecx,1), %edx 490 mov -4(%ebx,%ecx,1), %ebp 491 mov -8(%eax,%ecx,1), %esi 492 xor %edx, %ebp 493 mov -8(%ebx,%ecx,1), %edi 494 jne .D4 495 xor %esi, %edi 496 jne .D4 497 add $-8, %ecx 498 jne .D2 499 pop %esi 500.D3: 501 ret 502.D4: 503 pop %esi 504.D5: 505 add $4, %esp /* pop return address, we're not returning */ 506 call get_addr 507 add $4, %esp /* pop virtual address */ 508 jmp *%eax 509 .size verify_code, .-verify_code 510 511.globl WriteInvalidateLong 512 .type WriteInvalidateLong, @function 513WriteInvalidateLong: 514 mov %eax, %ecx 515 shr $12, %ecx 516 bt %ecx, cached_code 517 jnc MappedMemoryWriteLongNocache 518 push %eax 519 push %edx 520 push %eax 521 call invalidate_addr 522 pop %eax 523 pop %edx 524 pop %eax 525 jmp MappedMemoryWriteLongNocache 526 .size WriteInvalidateLong, .-WriteInvalidateLong 527.globl WriteInvalidateWord 528 .type WriteInvalidateWord, @function 529WriteInvalidateWord: 530 mov %eax, %ecx 531 shr $12, %ecx 532 bt %ecx, cached_code 533 jnc MappedMemoryWriteWordNocache 534 push %eax 535 push %edx 536 push %eax 537 call invalidate_addr 538 pop %eax 539 pop %edx 540 pop %eax 541 jmp MappedMemoryWriteWordNocache 542 .size WriteInvalidateWord, .-WriteInvalidateWord 543.globl WriteInvalidateByteSwapped 544 .type WriteInvalidateByteSwapped, @function 545WriteInvalidateByteSwapped: 546 xor $1, %eax 547 .size WriteInvalidateByteSwapped, .-WriteInvalidateByteSwapped 548.globl WriteInvalidateByte 549 .type WriteInvalidateByte, @function 550WriteInvalidateByte: 551 mov %eax, %ecx 552 shr $12, %ecx 553 bt %ecx, cached_code 554 jnc MappedMemoryWriteByteNocache 555 push %eax 556 push %edx 557 push %eax 558 call invalidate_addr 559 pop %eax 560 pop %edx 561 pop %eax 562 jmp MappedMemoryWriteByteNocache 563 .size WriteInvalidateByte, .-WriteInvalidateByte 564 565.globl div1 566 .type div1, @function 567div1: 568 /* eax = dividend */ 569 /* ecx = divisor */ 570 /* edx = sr */ 571 bt $9, %edx /* M bit */ 572 jc div1_negative_divisor 573 bts $0, %edx /* Get T bit and set */ 574 adc %eax, %eax /* rn=(rn<<1)+T */ 575 adc %ebx, %ebx /* New Q in ebx */ 576 mov %ecx, %ebp 577 btr $8, %edx /* Get Q bit and clear it */ 578 cmc 579 sbb %edi, %edi /* 0xFFFFFFFF if old_Q clear, 0 otherwise */ 580 sbb $0, %ebp 581 xor %edi, %ebp 582 add %ebp, %eax /* rn+rm if old_Q, rn-rm if !old_Q */ 583 /* carry set if rn < old_rn */ 584 adc %edi, %ebx /* low bit = (rn<old_rn)^new_Q^!old_Q */ 585 /* inverted for old_Q==0, ie (rn>=old_rn)^new_Q */ 586 not %edi /* if old_Q clear, edi=0 */ 587 or %ebp, %edi /* zero if old_Q==0 && rn==old_rn */ 588 neg %edi /* clear carry if edi==0 */ 589 adc $-1, %ebx /* invert result for old_Q==0 && rn==old_rn */ 590 and $1, %ebx 591 xor %ebx, %edx /* New T = (Q==M) */ 592 shl $8, %ebx 593 or %ebx, %edx /* save new Q */ 594/* 595 push %edx 596 push %eax 597 push %ecx 598 call debug_division 599 pop %ecx 600 pop %eax 601 pop %edx 602*/ 603 ret 604div1_negative_divisor: 605 btr $0, %edx /* Get T bit and clear */ 606 adc %eax, %eax /* rn=(rn<<1)+T */ 607 adc %ebx, %ebx /* New Q in ebx */ 608 mov %ecx, %ebp 609 btr $8, %edx /* Get Q bit and clear it */ 610 sbb %edi, %edi /* 0xFFFFFFFF if old_Q set, 0 otherwise */ 611 sbb $0, %ebp 612 xor %edi, %ebp 613 not %edi /* if old_Q clear, edi=-1 */ 614 add %ebp, %eax /* rn+rm if !old_Q, rn-rm if old_Q */ 615 /* carry set if rn < old_rn */ 616 adc %edi, %ebx /* low bit = (rn<old_rn)^new_Q^!old_Q */ 617 /* inverted for old_Q==0, ie (rn>=old_rn)^new_Q */ 618 or %ebp, %edi /* zero if old_Q==1 && rn==old_rn */ 619 neg %edi /* clear carry if edi==0 */ 620 adc $-1, %ebx /* invert result for old_Q==1 && rn==old_rn */ 621 and $1, %ebx 622 xor %ebx, %edx /* New T = (Q==M) */ 623 shl $8, %ebx 624 or %ebx, %edx /* save new Q */ 625 ret 626 .size div1, .-div1 627 628.globl macl 629 .type macl, @function 630macl: 631 /* ebx = sr */ 632 /* ebp = multiplicand address */ 633 /* edi = multiplicand address */ 634 /* eax = return MACL */ 635 /* edx = return MACH */ 636 push %edx /* MACH */ 637 push %eax /* MACL */ 638 mov %edi, %eax 639 call MappedMemoryReadLongNocache 640 mov %eax, %esi 641 mov %ebp, %eax 642 call MappedMemoryReadLongNocache 643 add $4, %ebp 644 add $4, %edi 645 imul %esi 646 add (%esp), %eax /* MACL */ 647 adc 4(%esp), %edx /* MACH */ 648 add $8, %esp 649 test $0x2, %bl 650 jne macl_saturation 651 ret 652macl_saturation: 653 mov $0xFFFF8000, %esi 654 xor %ecx, %ecx 655 cmp %esi, %edx 656 cmovl %esi, %edx 657 cmovl %ecx, %eax 658 not %esi 659 not %ecx 660 cmp %esi, %edx 661 cmovg %esi, %edx 662 cmovg %ecx, %eax 663 ret 664 .size macl, .-macl 665 666.globl macw 667 .type macw, @function 668macw: 669 /* ebx = sr */ 670 /* ebp = multiplicand address */ 671 /* edi = multiplicand address */ 672 /* eax = return MACL */ 673 /* edx = return MACH */ 674 push %edx /* MACH */ 675 push %eax /* MACL */ 676 mov %edi, %eax 677 call MappedMemoryReadWordNocache 678 movswl %ax, %esi 679 mov %ebp, %eax 680 call MappedMemoryReadWordNocache 681 movswl %ax, %eax 682 add $2, %ebp 683 add $2, %edi 684 imul %esi 685 test $0x2, %bl 686 jne macw_saturation 687 add (%esp), %eax /* MACL */ 688 adc 4(%esp), %edx /* MACH */ 689 add $8, %esp 690 ret 691macw_saturation: 692 mov (%esp), %esi 693 sar $31, %esi 694 add (%esp), %eax /* MACL */ 695 adc %esi, %edx 696 mov $0x80000000, %esi 697 mov $0x7FFFFFFF, %ecx 698 add %eax, %esi 699 adc $0, %edx 700 cmovne %ecx, %eax 701 not %ecx 702 cmovl %ecx, %eax 703 pop %edx 704 pop %edx 705 ret 706 .size macw, .-macw 707 708.globl master_handle_bios 709 .type master_handle_bios, @function 710master_handle_bios: 711 mov (%esp), %edx /* get return address */ 712 mov %eax, master_pc 713 mov %esi, master_cc 714 mov %edx, master_ip 715 mov MSH2, %eax 716 call BiosHandleFunc 717 mov master_ip, %edx 718 mov master_cc, %esi 719 mov %edx, (%esp) 720 ret /* jmp *master_ip */ 721 .size master_handle_bios, .-master_handle_bios 722 723.globl slave_handle_bios 724 .type slave_handle_bios, @function 725slave_handle_bios: 726 pop %edx /* get return address */ 727 mov %eax, slave_pc 728 mov %esi, slave_cc 729 mov %edx, slave_ip 730 mov SSH2, %eax 731 call BiosHandleFunc 732 mov slave_ip, %edx 733 mov slave_cc, %esi 734 jmp *%edx /* jmp *slave_ip */ 735 .size slave_handle_bios, .-slave_handle_bios 736 737.globl breakpoint 738 .type breakpoint, @function 739breakpoint: 740 ret 741 /* Set breakpoint here for debugging */ 742 .size breakpoint, .-breakpoint 743