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
1 | +- daa/das | ||
1 | - optimize translated cache chaining (DLL PLT like system) | 2 | - optimize translated cache chaining (DLL PLT like system) |
3 | +- segment ops (minimal LDT/GDT support for wine) | ||
4 | +- improved 16 bit support | ||
2 | - optimize inverse flags propagation (easy by generating intermediate | 5 | - optimize inverse flags propagation (easy by generating intermediate |
3 | micro operation array). | 6 | micro operation array). |
4 | - signals | 7 | - signals |
cpu-i386.h
linux-user/main.c
@@ -87,7 +87,7 @@ int cpu_x86_inl(int addr) | @@ -87,7 +87,7 @@ int cpu_x86_inl(int addr) | ||
87 | 87 | ||
88 | void usage(void) | 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 | "usage: gemu [-d] program [arguments...]\n" | 91 | "usage: gemu [-d] program [arguments...]\n" |
92 | "Linux x86 emulator\n" | 92 | "Linux x86 emulator\n" |
93 | ); | 93 | ); |
op-i386.c
@@ -628,6 +628,236 @@ void op_addl_ESP_im(void) | @@ -628,6 +628,236 @@ void op_addl_ESP_im(void) | ||
628 | ESP += PARAM1; | 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 | /* flags handling */ | 861 | /* flags handling */ |
632 | 862 | ||
633 | /* slow jumps cases (compute x86 flags) */ | 863 | /* slow jumps cases (compute x86 flags) */ |
@@ -836,6 +1066,13 @@ void OPPROTO op_cmc(void) | @@ -836,6 +1066,13 @@ void OPPROTO op_cmc(void) | ||
836 | CC_SRC = eflags; | 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 | static int compute_all_eflags(void) | 1076 | static int compute_all_eflags(void) |
840 | { | 1077 | { |
841 | return CC_SRC; | 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,6 +1511,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) | ||
1511 | gen_op_popl_T0(); | 1511 | gen_op_popl_T0(); |
1512 | gen_op_mov_reg_T0[OT_LONG][b & 7](); | 1512 | gen_op_mov_reg_T0[OT_LONG][b & 7](); |
1513 | break; | 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 | case 0x68: /* push Iv */ | 1526 | case 0x68: /* push Iv */ |
1515 | case 0x6a: | 1527 | case 0x6a: |
1516 | ot = dflag ? OT_LONG : OT_WORD; | 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,6 +1539,16 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) | ||
1527 | gen_op_popl_T0(); | 1539 | gen_op_popl_T0(); |
1528 | gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); | 1540 | gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); |
1529 | break; | 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 | case 0xc9: /* leave */ | 1552 | case 0xc9: /* leave */ |
1531 | gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); | 1553 | gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); |
1532 | gen_op_mov_reg_T0[OT_LONG][R_ESP](); | 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,6 +2507,42 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) | ||
2485 | s->cc_op = CC_OP_LOGICB + ot; | 2507 | s->cc_op = CC_OP_LOGICB + ot; |
2486 | break; | 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 | /* misc */ | 2546 | /* misc */ |
2489 | case 0x90: /* nop */ | 2547 | case 0x90: /* nop */ |
2490 | break; | 2548 | break; |
@@ -2505,19 +2563,26 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) | @@ -2505,19 +2563,26 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) | ||
2505 | *is_jmp_ptr = 1; | 2563 | *is_jmp_ptr = 1; |
2506 | break; | 2564 | break; |
2507 | case 0x1c8 ... 0x1cf: /* bswap reg */ | 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 | #if 0 | 2579 | #if 0 |
2515 | case 0x1a2: /* cpuid */ | 2580 | case 0x1a2: /* cpuid */ |
2516 | gen_insn0(OP_ASM); | 2581 | gen_insn0(OP_ASM); |
2517 | break; | 2582 | break; |
2518 | #endif | 2583 | #endif |
2519 | default: | 2584 | default: |
2520 | - error("unknown opcode %x", b); | 2585 | + error("unknown opcode 0x%x", b); |
2521 | return -1; | 2586 | return -1; |
2522 | } | 2587 | } |
2523 | return (long)s->pc; | 2588 | return (long)s->pc; |