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; | ... | ... |