Commit 27362c82e9df7770554943ceda36ec4e5638c49d
1 parent
55480af8
added pusha/popa/rdtsc/bcd ops
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@27 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
5 changed files
with
314 additions
and
9 deletions
TODO
cpu-i386.h
linux-user/main.c
| ... | ... | @@ -87,7 +87,7 @@ int cpu_x86_inl(int addr) |
| 87 | 87 | |
| 88 | 88 | void usage(void) |
| 89 | 89 | { |
| 90 | - printf("gemu version" GEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" | |
| 90 | + printf("gemu version " GEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" | |
| 91 | 91 | "usage: gemu [-d] program [arguments...]\n" |
| 92 | 92 | "Linux x86 emulator\n" |
| 93 | 93 | ); | ... | ... |
op-i386.c
| ... | ... | @@ -628,6 +628,236 @@ void op_addl_ESP_im(void) |
| 628 | 628 | ESP += PARAM1; |
| 629 | 629 | } |
| 630 | 630 | |
| 631 | +void op_pushal(void) | |
| 632 | +{ | |
| 633 | + uint8_t *sp; | |
| 634 | + sp = (void *)(ESP - 32); | |
| 635 | + stl(sp, EDI); | |
| 636 | + stl(sp + 4, ESI); | |
| 637 | + stl(sp + 8, EBP); | |
| 638 | + stl(sp + 12, ESP); | |
| 639 | + stl(sp + 16, EBX); | |
| 640 | + stl(sp + 20, EDX); | |
| 641 | + stl(sp + 24, ECX); | |
| 642 | + stl(sp + 28, EAX); | |
| 643 | + ESP = (unsigned long)sp; | |
| 644 | +} | |
| 645 | + | |
| 646 | +void op_pushaw(void) | |
| 647 | +{ | |
| 648 | + uint8_t *sp; | |
| 649 | + sp = (void *)(ESP - 16); | |
| 650 | + stw(sp, EDI); | |
| 651 | + stw(sp + 2, ESI); | |
| 652 | + stw(sp + 4, EBP); | |
| 653 | + stw(sp + 6, ESP); | |
| 654 | + stw(sp + 8, EBX); | |
| 655 | + stw(sp + 10, EDX); | |
| 656 | + stw(sp + 12, ECX); | |
| 657 | + stw(sp + 14, EAX); | |
| 658 | + ESP = (unsigned long)sp; | |
| 659 | +} | |
| 660 | + | |
| 661 | +void op_popal(void) | |
| 662 | +{ | |
| 663 | + uint8_t *sp; | |
| 664 | + sp = (void *)ESP; | |
| 665 | + EDI = ldl(sp); | |
| 666 | + ESI = ldl(sp + 4); | |
| 667 | + EBP = ldl(sp + 8); | |
| 668 | + EBX = ldl(sp + 16); | |
| 669 | + EDX = ldl(sp + 20); | |
| 670 | + ECX = ldl(sp + 24); | |
| 671 | + EAX = ldl(sp + 28); | |
| 672 | + ESP = (unsigned long)sp + 32; | |
| 673 | +} | |
| 674 | + | |
| 675 | +void op_popaw(void) | |
| 676 | +{ | |
| 677 | + uint8_t *sp; | |
| 678 | + sp = (void *)ESP; | |
| 679 | + EDI = ldl(sp); | |
| 680 | + ESI = ldl(sp + 2); | |
| 681 | + EBP = ldl(sp + 4); | |
| 682 | + EBX = ldl(sp + 8); | |
| 683 | + EDX = ldl(sp + 10); | |
| 684 | + ECX = ldl(sp + 12); | |
| 685 | + EAX = ldl(sp + 14); | |
| 686 | + ESP = (unsigned long)sp + 16; | |
| 687 | +} | |
| 688 | + | |
| 689 | +void op_enterl(void) | |
| 690 | +{ | |
| 691 | + unsigned int bp, frame_temp, level; | |
| 692 | + uint8_t *sp; | |
| 693 | + | |
| 694 | + sp = (void *)ESP; | |
| 695 | + bp = EBP; | |
| 696 | + sp -= 4; | |
| 697 | + stl(sp, bp); | |
| 698 | + frame_temp = (unsigned int)sp; | |
| 699 | + level = PARAM2; | |
| 700 | + if (level) { | |
| 701 | + while (level--) { | |
| 702 | + bp -= 4; | |
| 703 | + sp -= 4; | |
| 704 | + stl(sp, bp); | |
| 705 | + } | |
| 706 | + sp -= 4; | |
| 707 | + stl(sp, frame_temp); | |
| 708 | + } | |
| 709 | + EBP = frame_temp; | |
| 710 | + sp -= PARAM1; | |
| 711 | + ESP = (int)sp; | |
| 712 | +} | |
| 713 | + | |
| 714 | +/* rdtsc */ | |
| 715 | +#ifndef __i386__ | |
| 716 | +uint64_t emu_time; | |
| 717 | +#endif | |
| 718 | +void op_rdtsc(void) | |
| 719 | +{ | |
| 720 | + uint64_t val; | |
| 721 | +#ifdef __i386__ | |
| 722 | + asm("rdtsc" : "=A" (val)); | |
| 723 | +#else | |
| 724 | + /* better than nothing: the time increases */ | |
| 725 | + val = emu_time++; | |
| 726 | +#endif | |
| 727 | + EAX = val; | |
| 728 | + EDX = val >> 32; | |
| 729 | +} | |
| 730 | + | |
| 731 | +/* bcd */ | |
| 732 | + | |
| 733 | +/* XXX: exception */ | |
| 734 | +void OPPROTO op_aam(void) | |
| 735 | +{ | |
| 736 | + int base = PARAM1; | |
| 737 | + int al, ah; | |
| 738 | + al = EAX & 0xff; | |
| 739 | + ah = al / base; | |
| 740 | + al = al % base; | |
| 741 | + EAX = (EAX & ~0xffff) | al | (ah << 8); | |
| 742 | + CC_DST = al; | |
| 743 | +} | |
| 744 | + | |
| 745 | +void OPPROTO op_aad(void) | |
| 746 | +{ | |
| 747 | + int base = PARAM1; | |
| 748 | + int al, ah; | |
| 749 | + al = EAX & 0xff; | |
| 750 | + ah = (EAX >> 8) & 0xff; | |
| 751 | + al = ((ah * base) + al) & 0xff; | |
| 752 | + EAX = (EAX & ~0xffff) | al; | |
| 753 | + CC_DST = al; | |
| 754 | +} | |
| 755 | + | |
| 756 | +void OPPROTO op_aaa(void) | |
| 757 | +{ | |
| 758 | + int icarry; | |
| 759 | + int al, ah, af; | |
| 760 | + int eflags; | |
| 761 | + | |
| 762 | + eflags = cc_table[CC_OP].compute_all(); | |
| 763 | + af = eflags & CC_A; | |
| 764 | + al = EAX & 0xff; | |
| 765 | + ah = (EAX >> 8) & 0xff; | |
| 766 | + | |
| 767 | + icarry = (al > 0xf9); | |
| 768 | + if (((al & 0x0f) > 9 ) || af) { | |
| 769 | + al = (al + 6) & 0x0f; | |
| 770 | + ah = (ah + 1 + icarry) & 0xff; | |
| 771 | + eflags |= CC_C | CC_A; | |
| 772 | + } else { | |
| 773 | + eflags &= ~(CC_C | CC_A); | |
| 774 | + al &= 0x0f; | |
| 775 | + } | |
| 776 | + EAX = (EAX & ~0xffff) | al | (ah << 8); | |
| 777 | + CC_SRC = eflags; | |
| 778 | +} | |
| 779 | + | |
| 780 | +void OPPROTO op_aas(void) | |
| 781 | +{ | |
| 782 | + int icarry; | |
| 783 | + int al, ah, af; | |
| 784 | + int eflags; | |
| 785 | + | |
| 786 | + eflags = cc_table[CC_OP].compute_all(); | |
| 787 | + af = eflags & CC_A; | |
| 788 | + al = EAX & 0xff; | |
| 789 | + ah = (EAX >> 8) & 0xff; | |
| 790 | + | |
| 791 | + icarry = (al < 6); | |
| 792 | + if (((al & 0x0f) > 9 ) || af) { | |
| 793 | + al = (al - 6) & 0x0f; | |
| 794 | + ah = (ah - 1 - icarry) & 0xff; | |
| 795 | + eflags |= CC_C | CC_A; | |
| 796 | + } else { | |
| 797 | + eflags &= ~(CC_C | CC_A); | |
| 798 | + al &= 0x0f; | |
| 799 | + } | |
| 800 | + EAX = (EAX & ~0xffff) | al | (ah << 8); | |
| 801 | + CC_SRC = eflags; | |
| 802 | +} | |
| 803 | + | |
| 804 | +void OPPROTO op_daa(void) | |
| 805 | +{ | |
| 806 | + int al, af, cf; | |
| 807 | + int eflags; | |
| 808 | + | |
| 809 | + eflags = cc_table[CC_OP].compute_all(); | |
| 810 | + cf = eflags & CC_C; | |
| 811 | + af = eflags & CC_A; | |
| 812 | + al = EAX & 0xff; | |
| 813 | + | |
| 814 | + eflags = 0; | |
| 815 | + if (((al & 0x0f) > 9 ) || af) { | |
| 816 | + al = (al + 6) & 0xff; | |
| 817 | + eflags |= CC_A; | |
| 818 | + } | |
| 819 | + if ((al > 0x9f) || cf) { | |
| 820 | + al = (al + 0x60) & 0xff; | |
| 821 | + eflags |= CC_C; | |
| 822 | + } | |
| 823 | + EAX = (EAX & ~0xff) | al; | |
| 824 | + /* well, speed is not an issue here, so we compute the flags by hand */ | |
| 825 | + eflags |= (al == 0) << 6; /* zf */ | |
| 826 | + eflags |= parity_table[al]; /* pf */ | |
| 827 | + eflags |= (al & 0x80); /* sf */ | |
| 828 | + CC_SRC = eflags; | |
| 829 | +} | |
| 830 | + | |
| 831 | +void OPPROTO op_das(void) | |
| 832 | +{ | |
| 833 | + int al, al1, af, cf; | |
| 834 | + int eflags; | |
| 835 | + | |
| 836 | + eflags = cc_table[CC_OP].compute_all(); | |
| 837 | + cf = eflags & CC_C; | |
| 838 | + af = eflags & CC_A; | |
| 839 | + al = EAX & 0xff; | |
| 840 | + | |
| 841 | + eflags = 0; | |
| 842 | + al1 = al; | |
| 843 | + if (((al & 0x0f) > 9 ) || af) { | |
| 844 | + eflags |= CC_A; | |
| 845 | + if (al < 6 || cf) | |
| 846 | + eflags |= CC_C; | |
| 847 | + al = (al - 6) & 0xff; | |
| 848 | + } | |
| 849 | + if ((al1 > 0x99) || cf) { | |
| 850 | + al = (al - 0x60) & 0xff; | |
| 851 | + eflags |= CC_C; | |
| 852 | + } | |
| 853 | + EAX = (EAX & ~0xff) | al; | |
| 854 | + /* well, speed is not an issue here, so we compute the flags by hand */ | |
| 855 | + eflags |= (al == 0) << 6; /* zf */ | |
| 856 | + eflags |= parity_table[al]; /* pf */ | |
| 857 | + eflags |= (al & 0x80); /* sf */ | |
| 858 | + CC_SRC = eflags; | |
| 859 | +} | |
| 860 | + | |
| 631 | 861 | /* flags handling */ |
| 632 | 862 | |
| 633 | 863 | /* slow jumps cases (compute x86 flags) */ |
| ... | ... | @@ -836,6 +1066,13 @@ void OPPROTO op_cmc(void) |
| 836 | 1066 | CC_SRC = eflags; |
| 837 | 1067 | } |
| 838 | 1068 | |
| 1069 | +void OPPROTO op_salc(void) | |
| 1070 | +{ | |
| 1071 | + int cf; | |
| 1072 | + cf = cc_table[CC_OP].compute_c(); | |
| 1073 | + EAX = (EAX & ~0xff) | ((-cf) & 0xff); | |
| 1074 | +} | |
| 1075 | + | |
| 839 | 1076 | static int compute_all_eflags(void) |
| 840 | 1077 | { |
| 841 | 1078 | return CC_SRC; | ... | ... |
translate-i386.c
| ... | ... | @@ -1511,6 +1511,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) |
| 1511 | 1511 | gen_op_popl_T0(); |
| 1512 | 1512 | gen_op_mov_reg_T0[OT_LONG][b & 7](); |
| 1513 | 1513 | break; |
| 1514 | + case 0x60: /* pusha */ | |
| 1515 | + if (s->dflag) | |
| 1516 | + gen_op_pushal(); | |
| 1517 | + else | |
| 1518 | + gen_op_pushaw(); | |
| 1519 | + break; | |
| 1520 | + case 0x61: /* popa */ | |
| 1521 | + if (s->dflag) | |
| 1522 | + gen_op_popal(); | |
| 1523 | + else | |
| 1524 | + gen_op_popaw(); | |
| 1525 | + break; | |
| 1514 | 1526 | case 0x68: /* push Iv */ |
| 1515 | 1527 | case 0x6a: |
| 1516 | 1528 | ot = dflag ? OT_LONG : OT_WORD; |
| ... | ... | @@ -1527,6 +1539,16 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) |
| 1527 | 1539 | gen_op_popl_T0(); |
| 1528 | 1540 | gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); |
| 1529 | 1541 | break; |
| 1542 | + case 0xc8: /* enter */ | |
| 1543 | + { | |
| 1544 | + int level; | |
| 1545 | + val = lduw(s->pc); | |
| 1546 | + s->pc += 2; | |
| 1547 | + level = ldub(s->pc++); | |
| 1548 | + level &= 0x1f; | |
| 1549 | + gen_op_enterl(val, level); | |
| 1550 | + } | |
| 1551 | + break; | |
| 1530 | 1552 | case 0xc9: /* leave */ |
| 1531 | 1553 | gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); |
| 1532 | 1554 | gen_op_mov_reg_T0[OT_LONG][R_ESP](); |
| ... | ... | @@ -2485,6 +2507,42 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) |
| 2485 | 2507 | s->cc_op = CC_OP_LOGICB + ot; |
| 2486 | 2508 | break; |
| 2487 | 2509 | /************************/ |
| 2510 | + /* bcd */ | |
| 2511 | + case 0x27: /* daa */ | |
| 2512 | + if (s->cc_op != CC_OP_DYNAMIC) | |
| 2513 | + gen_op_set_cc_op(s->cc_op); | |
| 2514 | + gen_op_daa(); | |
| 2515 | + s->cc_op = CC_OP_EFLAGS; | |
| 2516 | + break; | |
| 2517 | + case 0x2f: /* das */ | |
| 2518 | + if (s->cc_op != CC_OP_DYNAMIC) | |
| 2519 | + gen_op_set_cc_op(s->cc_op); | |
| 2520 | + gen_op_das(); | |
| 2521 | + s->cc_op = CC_OP_EFLAGS; | |
| 2522 | + break; | |
| 2523 | + case 0x37: /* aaa */ | |
| 2524 | + if (s->cc_op != CC_OP_DYNAMIC) | |
| 2525 | + gen_op_set_cc_op(s->cc_op); | |
| 2526 | + gen_op_aaa(); | |
| 2527 | + s->cc_op = CC_OP_EFLAGS; | |
| 2528 | + break; | |
| 2529 | + case 0x3f: /* aas */ | |
| 2530 | + if (s->cc_op != CC_OP_DYNAMIC) | |
| 2531 | + gen_op_set_cc_op(s->cc_op); | |
| 2532 | + gen_op_aas(); | |
| 2533 | + s->cc_op = CC_OP_EFLAGS; | |
| 2534 | + break; | |
| 2535 | + case 0xd4: /* aam */ | |
| 2536 | + val = ldub(s->pc++); | |
| 2537 | + gen_op_aam(val); | |
| 2538 | + s->cc_op = CC_OP_LOGICB; | |
| 2539 | + break; | |
| 2540 | + case 0xd5: /* aad */ | |
| 2541 | + val = ldub(s->pc++); | |
| 2542 | + gen_op_aad(val); | |
| 2543 | + s->cc_op = CC_OP_LOGICB; | |
| 2544 | + break; | |
| 2545 | + /************************/ | |
| 2488 | 2546 | /* misc */ |
| 2489 | 2547 | case 0x90: /* nop */ |
| 2490 | 2548 | break; |
| ... | ... | @@ -2505,19 +2563,26 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) |
| 2505 | 2563 | *is_jmp_ptr = 1; |
| 2506 | 2564 | break; |
| 2507 | 2565 | case 0x1c8 ... 0x1cf: /* bswap reg */ |
| 2508 | - reg = b & 7; | |
| 2509 | - gen_op_mov_TN_reg[OT_LONG][0][reg](); | |
| 2510 | - gen_op_bswapl_T0(); | |
| 2511 | - gen_op_mov_reg_T0[OT_LONG][reg](); | |
| 2512 | - break; | |
| 2513 | - | |
| 2566 | + reg = b & 7; | |
| 2567 | + gen_op_mov_TN_reg[OT_LONG][0][reg](); | |
| 2568 | + gen_op_bswapl_T0(); | |
| 2569 | + gen_op_mov_reg_T0[OT_LONG][reg](); | |
| 2570 | + break; | |
| 2571 | + case 0xd6: /* salc */ | |
| 2572 | + if (s->cc_op != CC_OP_DYNAMIC) | |
| 2573 | + gen_op_set_cc_op(s->cc_op); | |
| 2574 | + gen_op_salc(); | |
| 2575 | + break; | |
| 2576 | + case 0x1a2: /* rdtsc */ | |
| 2577 | + gen_op_rdtsc(); | |
| 2578 | + break; | |
| 2514 | 2579 | #if 0 |
| 2515 | 2580 | case 0x1a2: /* cpuid */ |
| 2516 | 2581 | gen_insn0(OP_ASM); |
| 2517 | 2582 | break; |
| 2518 | 2583 | #endif |
| 2519 | 2584 | default: |
| 2520 | - error("unknown opcode %x", b); | |
| 2585 | + error("unknown opcode 0x%x", b); | |
| 2521 | 2586 | return -1; |
| 2522 | 2587 | } |
| 2523 | 2588 | return (long)s->pc; | ... | ... |