Commit acf930aaa3763be08a41f2478b3e0b252f545cd0
1 parent
2b8bdefc
ColdFire EMAC support.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2895 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
6 changed files
with
763 additions
and
3 deletions
cpu-exec.c
| ... | ... | @@ -196,7 +196,9 @@ static inline TranslationBlock *tb_find_fast(void) |
| 196 | 196 | cs_base = 0; |
| 197 | 197 | pc = env->PC; |
| 198 | 198 | #elif defined(TARGET_M68K) |
| 199 | - flags = (env->fpcr & M68K_FPCR_PREC) | (env->sr & SR_S); | |
| 199 | + flags = (env->fpcr & M68K_FPCR_PREC) /* Bit 6 */ | |
| 200 | + | (env->sr & SR_S) /* Bit 13 */ | |
| 201 | + | ((env->macsr >> 4) & 0xf); /* Bits 0-3 */ | |
| 200 | 202 | cs_base = 0; |
| 201 | 203 | pc = env->pc; |
| 202 | 204 | #elif defined(TARGET_SH4) | ... | ... |
target-m68k/cpu.h
| ... | ... | @@ -71,6 +71,14 @@ typedef struct CPUM68KState { |
| 71 | 71 | uint32_t fpsr; |
| 72 | 72 | float_status fp_status; |
| 73 | 73 | |
| 74 | + uint64_t mactmp; | |
| 75 | + /* EMAC Hardware deals with 48-bit values composed of one 32-bit and | |
| 76 | + two 8-bit parts. We store a single 64-bit value and | |
| 77 | + rearrange/extend this when changing modes. */ | |
| 78 | + uint64_t macc[4]; | |
| 79 | + uint32_t macsr; | |
| 80 | + uint32_t mac_mask; | |
| 81 | + | |
| 74 | 82 | /* Temporary storage for DIV helpers. */ |
| 75 | 83 | uint32_t div1; |
| 76 | 84 | uint32_t div2; |
| ... | ... | @@ -143,11 +151,22 @@ enum { |
| 143 | 151 | #define SR_S 0x2000 |
| 144 | 152 | #define SR_T 0x8000 |
| 145 | 153 | |
| 154 | +#define MACSR_PAV0 0x100 | |
| 155 | +#define MACSR_OMC 0x080 | |
| 156 | +#define MACSR_SU 0x040 | |
| 157 | +#define MACSR_FI 0x020 | |
| 158 | +#define MACSR_RT 0x010 | |
| 159 | +#define MACSR_N 0x008 | |
| 160 | +#define MACSR_Z 0x004 | |
| 161 | +#define MACSR_V 0x002 | |
| 162 | +#define MACSR_EV 0x001 | |
| 163 | + | |
| 146 | 164 | typedef struct m68k_def_t m68k_def_t; |
| 147 | 165 | |
| 148 | 166 | int cpu_m68k_set_model(CPUM68KState *env, const char * name); |
| 149 | 167 | |
| 150 | 168 | void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector); |
| 169 | +void m68k_set_macsr(CPUM68KState *env, uint32_t val); | |
| 151 | 170 | |
| 152 | 171 | #define M68K_FPCR_PREC (1 << 6) |
| 153 | 172 | ... | ... |
target-m68k/helper.c
| ... | ... | @@ -69,7 +69,6 @@ int cpu_m68k_set_model(CPUM68KState *env, const char * name) |
| 69 | 69 | m68k_set_feature(env, M68K_FEATURE_CF_ISA_B); |
| 70 | 70 | m68k_set_feature(env, M68K_FEATURE_CF_ISA_C); |
| 71 | 71 | m68k_set_feature(env, M68K_FEATURE_CF_FPU); |
| 72 | - m68k_set_feature(env, M68K_FEATURE_CF_MAC); | |
| 73 | 72 | m68k_set_feature(env, M68K_FEATURE_CF_EMAC); |
| 74 | 73 | break; |
| 75 | 74 | case M68K_CPUID_ANY: |
| ... | ... | @@ -77,7 +76,8 @@ int cpu_m68k_set_model(CPUM68KState *env, const char * name) |
| 77 | 76 | m68k_set_feature(env, M68K_FEATURE_CF_ISA_B); |
| 78 | 77 | m68k_set_feature(env, M68K_FEATURE_CF_ISA_C); |
| 79 | 78 | m68k_set_feature(env, M68K_FEATURE_CF_FPU); |
| 80 | - m68k_set_feature(env, M68K_FEATURE_CF_MAC); | |
| 79 | + /* MAC and EMAC are mututally exclusive, so pick EMAC. | |
| 80 | + It's mostly backwards compatible. */ | |
| 81 | 81 | m68k_set_feature(env, M68K_FEATURE_CF_EMAC); |
| 82 | 82 | m68k_set_feature(env, M68K_FEATURE_EXT_FULL); |
| 83 | 83 | break; |
| ... | ... | @@ -227,6 +227,40 @@ void helper_movec(CPUM68KState *env, int reg, uint32_t val) |
| 227 | 227 | } |
| 228 | 228 | } |
| 229 | 229 | |
| 230 | +void m68k_set_macsr(CPUM68KState *env, uint32_t val) | |
| 231 | +{ | |
| 232 | + uint32_t acc; | |
| 233 | + int8_t exthigh; | |
| 234 | + uint8_t extlow; | |
| 235 | + uint64_t regval; | |
| 236 | + int i; | |
| 237 | + if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) { | |
| 238 | + for (i = 0; i < 4; i++) { | |
| 239 | + regval = env->macc[i]; | |
| 240 | + exthigh = regval >> 40; | |
| 241 | + if (env->macsr & MACSR_FI) { | |
| 242 | + acc = regval >> 8; | |
| 243 | + extlow = regval; | |
| 244 | + } else { | |
| 245 | + acc = regval; | |
| 246 | + extlow = regval >> 32; | |
| 247 | + } | |
| 248 | + if (env->macsr & MACSR_FI) { | |
| 249 | + regval = (((uint64_t)acc) << 8) | extlow; | |
| 250 | + regval |= ((int64_t)exthigh) << 40; | |
| 251 | + } else if (env->macsr & MACSR_SU) { | |
| 252 | + regval = acc | (((int64_t)extlow) << 32); | |
| 253 | + regval |= ((int64_t)exthigh) << 40; | |
| 254 | + } else { | |
| 255 | + regval = acc | (((uint64_t)extlow) << 32); | |
| 256 | + regval |= ((uint64_t)(uint8_t)exthigh) << 40; | |
| 257 | + } | |
| 258 | + env->macc[i] = regval; | |
| 259 | + } | |
| 260 | + } | |
| 261 | + env->macsr = val; | |
| 262 | +} | |
| 263 | + | |
| 230 | 264 | /* MMU */ |
| 231 | 265 | |
| 232 | 266 | /* TODO: This will need fixing once the MMU is implemented. */ | ... | ... |
target-m68k/op.c
| ... | ... | @@ -285,6 +285,16 @@ OP(shr_cc) |
| 285 | 285 | FORCE_RET(); |
| 286 | 286 | } |
| 287 | 287 | |
| 288 | +OP(sar32) | |
| 289 | +{ | |
| 290 | + int32_t op2 = get_op(PARAM2); | |
| 291 | + uint32_t op3 = get_op(PARAM3); | |
| 292 | + uint32_t result; | |
| 293 | + result = op2 >> op3; | |
| 294 | + set_op(PARAM1, result); | |
| 295 | + FORCE_RET(); | |
| 296 | +} | |
| 297 | + | |
| 288 | 298 | OP(sar_cc) |
| 289 | 299 | { |
| 290 | 300 | int32_t op1 = get_op(PARAM1); |
| ... | ... | @@ -651,3 +661,410 @@ OP(movec) |
| 651 | 661 | #define MEMSUFFIX _kernel |
| 652 | 662 | #include "op_mem.h" |
| 653 | 663 | #endif |
| 664 | + | |
| 665 | +/* MAC unit. */ | |
| 666 | +/* TODO: The MAC instructions use 64-bit arithmetic fairly extensively. | |
| 667 | + This results in fairly large ops (and sometimes other issues) on 32-bit | |
| 668 | + hosts. Maybe move most of them into helpers. */ | |
| 669 | +OP(macmuls) | |
| 670 | +{ | |
| 671 | + uint32_t op1 = get_op(PARAM1); | |
| 672 | + uint32_t op2 = get_op(PARAM2); | |
| 673 | + int64_t product; | |
| 674 | + int64_t res; | |
| 675 | + | |
| 676 | + product = (uint64_t)op1 * op2; | |
| 677 | + res = (product << 24) >> 24; | |
| 678 | + if (res != product) { | |
| 679 | + env->macsr |= MACSR_V; | |
| 680 | + if (env->macsr & MACSR_OMC) { | |
| 681 | + /* Make sure the accumulate operation overflows. */ | |
| 682 | + if (product < 0) | |
| 683 | + res = ~(1ll << 50); | |
| 684 | + else | |
| 685 | + res = 1ll << 50; | |
| 686 | + } | |
| 687 | + } | |
| 688 | + env->mactmp = res; | |
| 689 | + FORCE_RET(); | |
| 690 | +} | |
| 691 | + | |
| 692 | +OP(macmulu) | |
| 693 | +{ | |
| 694 | + uint32_t op1 = get_op(PARAM1); | |
| 695 | + uint32_t op2 = get_op(PARAM2); | |
| 696 | + uint64_t product; | |
| 697 | + | |
| 698 | + product = (uint64_t)op1 * op2; | |
| 699 | + if (product & (0xffffffull << 40)) { | |
| 700 | + env->macsr |= MACSR_V; | |
| 701 | + if (env->macsr & MACSR_OMC) { | |
| 702 | + /* Make sure the accumulate operation overflows. */ | |
| 703 | + product = 1ll << 50; | |
| 704 | + } else { | |
| 705 | + product &= ((1ull << 40) - 1); | |
| 706 | + } | |
| 707 | + } | |
| 708 | + env->mactmp = product; | |
| 709 | + FORCE_RET(); | |
| 710 | +} | |
| 711 | + | |
| 712 | +OP(macmulf) | |
| 713 | +{ | |
| 714 | + int32_t op1 = get_op(PARAM1); | |
| 715 | + int32_t op2 = get_op(PARAM2); | |
| 716 | + uint64_t product; | |
| 717 | + uint32_t remainder; | |
| 718 | + | |
| 719 | + product = (uint64_t)op1 * op2; | |
| 720 | + if (env->macsr & MACSR_RT) { | |
| 721 | + remainder = product & 0xffffff; | |
| 722 | + product >>= 24; | |
| 723 | + if (remainder > 0x800000) | |
| 724 | + product++; | |
| 725 | + else if (remainder == 0x800000) | |
| 726 | + product += (product & 1); | |
| 727 | + } else { | |
| 728 | + product >>= 24; | |
| 729 | + } | |
| 730 | + env->mactmp = product; | |
| 731 | + FORCE_RET(); | |
| 732 | +} | |
| 733 | + | |
| 734 | +OP(macshl) | |
| 735 | +{ | |
| 736 | + env->mactmp <<= 1; | |
| 737 | +} | |
| 738 | + | |
| 739 | +OP(macshr) | |
| 740 | +{ | |
| 741 | + env->mactmp >>= 1; | |
| 742 | +} | |
| 743 | + | |
| 744 | +OP(macadd) | |
| 745 | +{ | |
| 746 | + int acc = PARAM1; | |
| 747 | + env->macc[acc] += env->mactmp; | |
| 748 | + FORCE_RET(); | |
| 749 | +} | |
| 750 | + | |
| 751 | +OP(macsub) | |
| 752 | +{ | |
| 753 | + int acc = PARAM1; | |
| 754 | + env->macc[acc] -= env->mactmp; | |
| 755 | + FORCE_RET(); | |
| 756 | +} | |
| 757 | + | |
| 758 | +OP(macsats) | |
| 759 | +{ | |
| 760 | + int acc = PARAM1; | |
| 761 | + int64_t sum; | |
| 762 | + int64_t result; | |
| 763 | + | |
| 764 | + sum = env->macc[acc]; | |
| 765 | + result = (sum << 16) >> 16; | |
| 766 | + if (result != sum) { | |
| 767 | + env->macsr |= MACSR_V; | |
| 768 | + } | |
| 769 | + if (env->macsr & MACSR_V) { | |
| 770 | + env->macsr |= MACSR_PAV0 << acc; | |
| 771 | + if (env->macsr & MACSR_OMC) { | |
| 772 | + /* The result is saturated to 32 bits, despite overflow occuring | |
| 773 | + at 48 bits. Seems weird, but that's what the hardware docs | |
| 774 | + say. */ | |
| 775 | + result = (result >> 63) ^ 0x7fffffff; | |
| 776 | + } | |
| 777 | + } | |
| 778 | + env->macc[acc] = result; | |
| 779 | + FORCE_RET(); | |
| 780 | +} | |
| 781 | + | |
| 782 | +OP(macsatu) | |
| 783 | +{ | |
| 784 | + int acc = PARAM1; | |
| 785 | + uint64_t sum; | |
| 786 | + | |
| 787 | + sum = env->macc[acc]; | |
| 788 | + if (sum & (0xffffull << 48)) { | |
| 789 | + env->macsr |= MACSR_V; | |
| 790 | + } | |
| 791 | + if (env->macsr & MACSR_V) { | |
| 792 | + env->macsr |= MACSR_PAV0 << acc; | |
| 793 | + if (env->macsr & MACSR_OMC) { | |
| 794 | + if (sum > (1ull << 53)) | |
| 795 | + sum = 0; | |
| 796 | + else | |
| 797 | + sum = (1ull << 48) - 1; | |
| 798 | + } else { | |
| 799 | + sum &= ((1ull << 48) - 1); | |
| 800 | + } | |
| 801 | + } | |
| 802 | + FORCE_RET(); | |
| 803 | +} | |
| 804 | + | |
| 805 | +OP(macsatf) | |
| 806 | +{ | |
| 807 | + int acc = PARAM1; | |
| 808 | + int64_t sum; | |
| 809 | + int64_t result; | |
| 810 | + | |
| 811 | + sum = env->macc[acc]; | |
| 812 | + result = (sum << 16) >> 16; | |
| 813 | + if (result != sum) { | |
| 814 | + env->macsr |= MACSR_V; | |
| 815 | + } | |
| 816 | + if (env->macsr & MACSR_V) { | |
| 817 | + env->macsr |= MACSR_PAV0 << acc; | |
| 818 | + if (env->macsr & MACSR_OMC) { | |
| 819 | + result = (result >> 63) ^ 0x7fffffffffffll; | |
| 820 | + } | |
| 821 | + } | |
| 822 | + env->macc[acc] = result; | |
| 823 | + FORCE_RET(); | |
| 824 | +} | |
| 825 | + | |
| 826 | +OP(mac_clear_flags) | |
| 827 | +{ | |
| 828 | + env->macsr &= ~(MACSR_V | MACSR_Z | MACSR_N | MACSR_EV); | |
| 829 | +} | |
| 830 | + | |
| 831 | +OP(mac_set_flags) | |
| 832 | +{ | |
| 833 | + int acc = PARAM1; | |
| 834 | + uint64_t val; | |
| 835 | + val = env->macc[acc]; | |
| 836 | + if (val == 0) | |
| 837 | + env->macsr |= MACSR_Z; | |
| 838 | + else if (val & (1ull << 47)); | |
| 839 | + env->macsr |= MACSR_N; | |
| 840 | + if (env->macsr & (MACSR_PAV0 << acc)) { | |
| 841 | + env->macsr |= MACSR_V; | |
| 842 | + } | |
| 843 | + if (env->macsr & MACSR_FI) { | |
| 844 | + val = ((int64_t)val) >> 40; | |
| 845 | + if (val != 0 && val != -1) | |
| 846 | + env->macsr |= MACSR_EV; | |
| 847 | + } else if (env->macsr & MACSR_SU) { | |
| 848 | + val = ((int64_t)val) >> 32; | |
| 849 | + if (val != 0 && val != -1) | |
| 850 | + env->macsr |= MACSR_EV; | |
| 851 | + } else { | |
| 852 | + if ((val >> 32) != 0) | |
| 853 | + env->macsr |= MACSR_EV; | |
| 854 | + } | |
| 855 | + FORCE_RET(); | |
| 856 | +} | |
| 857 | + | |
| 858 | +OP(get_macf) | |
| 859 | +{ | |
| 860 | + int acc = PARAM2; | |
| 861 | + int64_t val; | |
| 862 | + int rem; | |
| 863 | + uint32_t result; | |
| 864 | + | |
| 865 | + val = env->macc[acc]; | |
| 866 | + if (env->macsr & MACSR_SU) { | |
| 867 | + /* 16-bit rounding. */ | |
| 868 | + rem = val & 0xffffff; | |
| 869 | + val = (val >> 24) & 0xffffu; | |
| 870 | + if (rem > 0x800000) | |
| 871 | + val++; | |
| 872 | + else if (rem == 0x800000) | |
| 873 | + val += (val & 1); | |
| 874 | + } else if (env->macsr & MACSR_RT) { | |
| 875 | + /* 32-bit rounding. */ | |
| 876 | + rem = val & 0xff; | |
| 877 | + val >>= 8; | |
| 878 | + if (rem > 0x80) | |
| 879 | + val++; | |
| 880 | + else if (rem == 0x80) | |
| 881 | + val += (val & 1); | |
| 882 | + } else { | |
| 883 | + /* No rounding. */ | |
| 884 | + val >>= 8; | |
| 885 | + } | |
| 886 | + if (env->macsr & MACSR_OMC) { | |
| 887 | + /* Saturate. */ | |
| 888 | + if (env->macsr & MACSR_SU) { | |
| 889 | + if (val != (uint16_t) val) { | |
| 890 | + result = ((val >> 63) ^ 0x7fff) & 0xffff; | |
| 891 | + } else { | |
| 892 | + result = val & 0xffff; | |
| 893 | + } | |
| 894 | + } else { | |
| 895 | + if (val != (uint32_t)val) { | |
| 896 | + result = ((uint32_t)(val >> 63) & 0x7fffffff); | |
| 897 | + } else { | |
| 898 | + result = (uint32_t)val; | |
| 899 | + } | |
| 900 | + } | |
| 901 | + } else { | |
| 902 | + /* No saturation. */ | |
| 903 | + if (env->macsr & MACSR_SU) { | |
| 904 | + result = val & 0xffff; | |
| 905 | + } else { | |
| 906 | + result = (uint32_t)val; | |
| 907 | + } | |
| 908 | + } | |
| 909 | + set_op(PARAM1, result); | |
| 910 | + FORCE_RET(); | |
| 911 | +} | |
| 912 | + | |
| 913 | +OP(get_maci) | |
| 914 | +{ | |
| 915 | + int acc = PARAM2; | |
| 916 | + set_op(PARAM1, (uint32_t)env->macc[acc]); | |
| 917 | + FORCE_RET(); | |
| 918 | +} | |
| 919 | + | |
| 920 | +OP(get_macs) | |
| 921 | +{ | |
| 922 | + int acc = PARAM2; | |
| 923 | + int64_t val = env->macc[acc]; | |
| 924 | + uint32_t result; | |
| 925 | + if (val == (int32_t)val) { | |
| 926 | + result = (int32_t)val; | |
| 927 | + } else { | |
| 928 | + result = (val >> 61) ^ 0x7fffffff; | |
| 929 | + } | |
| 930 | + set_op(PARAM1, result); | |
| 931 | + FORCE_RET(); | |
| 932 | +} | |
| 933 | + | |
| 934 | +OP(get_macu) | |
| 935 | +{ | |
| 936 | + int acc = PARAM2; | |
| 937 | + uint64_t val = env->macc[acc]; | |
| 938 | + uint32_t result; | |
| 939 | + if ((val >> 32) == 0) { | |
| 940 | + result = (uint32_t)val; | |
| 941 | + } else { | |
| 942 | + result = 0xffffffffu; | |
| 943 | + } | |
| 944 | + set_op(PARAM1, result); | |
| 945 | + FORCE_RET(); | |
| 946 | +} | |
| 947 | + | |
| 948 | +OP(clear_mac) | |
| 949 | +{ | |
| 950 | + int acc = PARAM1; | |
| 951 | + | |
| 952 | + env->macc[acc] = 0; | |
| 953 | + env->macsr &= ~(MACSR_PAV0 << acc); | |
| 954 | + FORCE_RET(); | |
| 955 | +} | |
| 956 | + | |
| 957 | +OP(move_mac) | |
| 958 | +{ | |
| 959 | + int dest = PARAM1; | |
| 960 | + int src = PARAM2; | |
| 961 | + uint32_t mask; | |
| 962 | + env->macc[dest] = env->macc[src]; | |
| 963 | + mask = MACSR_PAV0 << dest; | |
| 964 | + if (env->macsr & (MACSR_PAV0 << src)) | |
| 965 | + env->macsr |= mask; | |
| 966 | + else | |
| 967 | + env->macsr &= ~mask; | |
| 968 | + FORCE_RET(); | |
| 969 | +} | |
| 970 | + | |
| 971 | +OP(get_mac_extf) | |
| 972 | +{ | |
| 973 | + uint32_t val; | |
| 974 | + int acc = PARAM2; | |
| 975 | + val = env->macc[acc] & 0x00ff; | |
| 976 | + val = (env->macc[acc] >> 32) & 0xff00; | |
| 977 | + val |= (env->macc[acc + 1] << 16) & 0x00ff0000; | |
| 978 | + val |= (env->macc[acc + 1] >> 16) & 0xff000000; | |
| 979 | + set_op(PARAM1, val); | |
| 980 | + FORCE_RET(); | |
| 981 | +} | |
| 982 | + | |
| 983 | +OP(get_mac_exti) | |
| 984 | +{ | |
| 985 | + uint32_t val; | |
| 986 | + int acc = PARAM2; | |
| 987 | + val = (env->macc[acc] >> 32) & 0xffff; | |
| 988 | + val |= (env->macc[acc + 1] >> 16) & 0xffff0000; | |
| 989 | + set_op(PARAM1, val); | |
| 990 | + FORCE_RET(); | |
| 991 | +} | |
| 992 | + | |
| 993 | +OP(set_macf) | |
| 994 | +{ | |
| 995 | + int acc = PARAM2; | |
| 996 | + int32_t val = get_op(PARAM1); | |
| 997 | + env->macc[acc] = ((int64_t)val) << 8; | |
| 998 | + env->macsr &= ~(MACSR_PAV0 << acc); | |
| 999 | + FORCE_RET(); | |
| 1000 | +} | |
| 1001 | + | |
| 1002 | +OP(set_macs) | |
| 1003 | +{ | |
| 1004 | + int acc = PARAM2; | |
| 1005 | + int32_t val = get_op(PARAM1); | |
| 1006 | + env->macc[acc] = val; | |
| 1007 | + env->macsr &= ~(MACSR_PAV0 << acc); | |
| 1008 | + FORCE_RET(); | |
| 1009 | +} | |
| 1010 | + | |
| 1011 | +OP(set_macu) | |
| 1012 | +{ | |
| 1013 | + int acc = PARAM2; | |
| 1014 | + uint32_t val = get_op(PARAM1); | |
| 1015 | + env->macc[acc] = val; | |
| 1016 | + env->macsr &= ~(MACSR_PAV0 << acc); | |
| 1017 | + FORCE_RET(); | |
| 1018 | +} | |
| 1019 | + | |
| 1020 | +OP(set_mac_extf) | |
| 1021 | +{ | |
| 1022 | + int acc = PARAM2; | |
| 1023 | + int32_t val = get_op(PARAM1); | |
| 1024 | + int64_t res; | |
| 1025 | + int32_t tmp; | |
| 1026 | + res = env->macc[acc] & 0xffffffff00ull; | |
| 1027 | + tmp = (int16_t)(val & 0xff00); | |
| 1028 | + res |= ((int64_t)tmp) << 32; | |
| 1029 | + res |= val & 0xff; | |
| 1030 | + env->macc[acc] = res; | |
| 1031 | + res = env->macc[acc + 1] & 0xffffffff00ull; | |
| 1032 | + tmp = (val & 0xff000000); | |
| 1033 | + res |= ((int64_t)tmp) << 16; | |
| 1034 | + res |= (val >> 16) & 0xff; | |
| 1035 | + env->macc[acc + 1] = res; | |
| 1036 | +} | |
| 1037 | + | |
| 1038 | +OP(set_mac_exts) | |
| 1039 | +{ | |
| 1040 | + int acc = PARAM2; | |
| 1041 | + int32_t val = get_op(PARAM1); | |
| 1042 | + int64_t res; | |
| 1043 | + int32_t tmp; | |
| 1044 | + res = (uint32_t)env->macc[acc]; | |
| 1045 | + tmp = (int16_t)val; | |
| 1046 | + res |= ((int64_t)tmp) << 32; | |
| 1047 | + env->macc[acc] = res; | |
| 1048 | + res = (uint32_t)env->macc[acc + 1]; | |
| 1049 | + tmp = val & 0xffff0000; | |
| 1050 | + res |= (int64_t)tmp << 16; | |
| 1051 | + env->macc[acc + 1] = res; | |
| 1052 | +} | |
| 1053 | + | |
| 1054 | +OP(set_mac_extu) | |
| 1055 | +{ | |
| 1056 | + int acc = PARAM2; | |
| 1057 | + int32_t val = get_op(PARAM1); | |
| 1058 | + uint64_t res; | |
| 1059 | + res = (uint32_t)env->macc[acc]; | |
| 1060 | + res |= ((uint64_t)(val & 0xffff)) << 32; | |
| 1061 | + env->macc[acc] = res; | |
| 1062 | + res = (uint32_t)env->macc[acc + 1]; | |
| 1063 | + res |= (uint64_t)(val & 0xffff0000) << 16; | |
| 1064 | + env->macc[acc + 1] = res; | |
| 1065 | +} | |
| 1066 | + | |
| 1067 | +OP(set_macsr) | |
| 1068 | +{ | |
| 1069 | + m68k_set_macsr(env, get_op(PARAM1)); | |
| 1070 | +} | ... | ... |
target-m68k/qregs.def
target-m68k/translate.c
| ... | ... | @@ -2433,6 +2433,279 @@ DISAS_INSN(fsave) |
| 2433 | 2433 | qemu_assert(0, "FSAVE not implemented"); |
| 2434 | 2434 | } |
| 2435 | 2435 | |
| 2436 | +static inline int gen_mac_extract_word(DisasContext *s, int val, int upper) | |
| 2437 | +{ | |
| 2438 | + int tmp = gen_new_qreg(QMODE_I32); | |
| 2439 | + if (s->env->macsr & MACSR_FI) { | |
| 2440 | + if (upper) | |
| 2441 | + gen_op_and32(tmp, val, gen_im32(0xffff0000)); | |
| 2442 | + else | |
| 2443 | + gen_op_shl32(tmp, val, gen_im32(16)); | |
| 2444 | + } else if (s->env->macsr & MACSR_SU) { | |
| 2445 | + if (upper) | |
| 2446 | + gen_op_sar32(tmp, val, gen_im32(16)); | |
| 2447 | + else | |
| 2448 | + gen_op_ext16s32(tmp, val); | |
| 2449 | + } else { | |
| 2450 | + if (upper) | |
| 2451 | + gen_op_shr32(tmp, val, gen_im32(16)); | |
| 2452 | + else | |
| 2453 | + gen_op_ext16u32(tmp, val); | |
| 2454 | + } | |
| 2455 | + return tmp; | |
| 2456 | +} | |
| 2457 | + | |
| 2458 | +DISAS_INSN(mac) | |
| 2459 | +{ | |
| 2460 | + int rx; | |
| 2461 | + int ry; | |
| 2462 | + uint16_t ext; | |
| 2463 | + int acc; | |
| 2464 | + int l1; | |
| 2465 | + int tmp; | |
| 2466 | + int addr; | |
| 2467 | + int loadval; | |
| 2468 | + int dual; | |
| 2469 | + int saved_flags = -1; | |
| 2470 | + | |
| 2471 | + ext = lduw_code(s->pc); | |
| 2472 | + s->pc += 2; | |
| 2473 | + | |
| 2474 | + acc = ((insn >> 7) & 1) | ((ext >> 3) & 2); | |
| 2475 | + dual = ((insn & 0x30) != 0 && (ext & 3) != 0); | |
| 2476 | + if (insn & 0x30) { | |
| 2477 | + /* MAC with load. */ | |
| 2478 | + tmp = gen_lea(s, insn, OS_LONG); | |
| 2479 | + addr = gen_new_qreg(QMODE_I32); | |
| 2480 | + gen_op_and32(addr, tmp, QREG_MAC_MASK); | |
| 2481 | + /* Load the value now to ensure correct exception behavior. | |
| 2482 | + Perform writeback after reading the MAC inputs. */ | |
| 2483 | + loadval = gen_load(s, OS_LONG, addr, 0); | |
| 2484 | + | |
| 2485 | + acc ^= 1; | |
| 2486 | + rx = (ext & 0x8000) ? AREG(ext, 12) : DREG(insn, 12); | |
| 2487 | + ry = (ext & 8) ? AREG(ext, 0) : DREG(ext, 0); | |
| 2488 | + } else { | |
| 2489 | + loadval = addr = -1; | |
| 2490 | + rx = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9); | |
| 2491 | + ry = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0); | |
| 2492 | + } | |
| 2493 | + | |
| 2494 | + gen_op_mac_clear_flags(); | |
| 2495 | + l1 = -1; | |
| 2496 | + if ((s->env->macsr & MACSR_OMC) != 0 && !dual) { | |
| 2497 | + /* Skip the multiply if we know we will ignore it. */ | |
| 2498 | + l1 = gen_new_label(); | |
| 2499 | + tmp = gen_new_qreg(QMODE_I32); | |
| 2500 | + gen_op_and32(tmp, QREG_MACSR, gen_im32(1 << (acc + 8))); | |
| 2501 | + gen_op_jmp_nz32(tmp, l1); | |
| 2502 | + } | |
| 2503 | + | |
| 2504 | + if ((ext & 0x0800) == 0) { | |
| 2505 | + /* Word. */ | |
| 2506 | + rx = gen_mac_extract_word(s, rx, (ext & 0x80) != 0); | |
| 2507 | + ry = gen_mac_extract_word(s, ry, (ext & 0x40) != 0); | |
| 2508 | + } | |
| 2509 | + if (s->env->macsr & MACSR_FI) { | |
| 2510 | + gen_op_macmulf(rx, ry); | |
| 2511 | + } else { | |
| 2512 | + if (s->env->macsr & MACSR_SU) | |
| 2513 | + gen_op_macmuls(rx, ry); | |
| 2514 | + else | |
| 2515 | + gen_op_macmulu(rx, ry); | |
| 2516 | + switch ((ext >> 9) & 3) { | |
| 2517 | + case 1: | |
| 2518 | + gen_op_macshl(); | |
| 2519 | + break; | |
| 2520 | + case 3: | |
| 2521 | + gen_op_macshr(); | |
| 2522 | + break; | |
| 2523 | + } | |
| 2524 | + } | |
| 2525 | + | |
| 2526 | + if (dual) { | |
| 2527 | + /* Save the overflow flag from the multiply. */ | |
| 2528 | + saved_flags = gen_new_qreg(QMODE_I32); | |
| 2529 | + gen_op_mov32(saved_flags, QREG_MACSR); | |
| 2530 | + } | |
| 2531 | + | |
| 2532 | + if ((s->env->macsr & MACSR_OMC) != 0 && dual) { | |
| 2533 | + /* Skip the accumulate if the value is already saturated. */ | |
| 2534 | + l1 = gen_new_label(); | |
| 2535 | + tmp = gen_new_qreg(QMODE_I32); | |
| 2536 | + gen_op_and32(tmp, QREG_MACSR, gen_im32(MACSR_PAV0 << acc)); | |
| 2537 | + gen_op_jmp_nz32(tmp, l1); | |
| 2538 | + } | |
| 2539 | + | |
| 2540 | + if (insn & 0x100) | |
| 2541 | + gen_op_macsub(acc); | |
| 2542 | + else | |
| 2543 | + gen_op_macadd(acc); | |
| 2544 | + | |
| 2545 | + if (s->env->macsr & MACSR_FI) | |
| 2546 | + gen_op_macsatf(acc); | |
| 2547 | + else if (s->env->macsr & MACSR_SU) | |
| 2548 | + gen_op_macsats(acc); | |
| 2549 | + else | |
| 2550 | + gen_op_macsatu(acc); | |
| 2551 | + | |
| 2552 | + if (l1 != -1) | |
| 2553 | + gen_set_label(l1); | |
| 2554 | + | |
| 2555 | + if (dual) { | |
| 2556 | + /* Dual accumulate variant. */ | |
| 2557 | + acc = (ext >> 2) & 3; | |
| 2558 | + /* Restore the overflow flag from the multiplier. */ | |
| 2559 | + gen_op_mov32(QREG_MACSR, saved_flags); | |
| 2560 | + if ((s->env->macsr & MACSR_OMC) != 0) { | |
| 2561 | + /* Skip the accumulate if the value is already saturated. */ | |
| 2562 | + l1 = gen_new_label(); | |
| 2563 | + tmp = gen_new_qreg(QMODE_I32); | |
| 2564 | + gen_op_and32(tmp, QREG_MACSR, gen_im32(MACSR_PAV0 << acc)); | |
| 2565 | + gen_op_jmp_nz32(tmp, l1); | |
| 2566 | + } | |
| 2567 | + if (ext & 2) | |
| 2568 | + gen_op_macsub(acc); | |
| 2569 | + else | |
| 2570 | + gen_op_macadd(acc); | |
| 2571 | + if (s->env->macsr & MACSR_FI) | |
| 2572 | + gen_op_macsatf(acc); | |
| 2573 | + else if (s->env->macsr & MACSR_SU) | |
| 2574 | + gen_op_macsats(acc); | |
| 2575 | + else | |
| 2576 | + gen_op_macsatu(acc); | |
| 2577 | + if (l1 != -1) | |
| 2578 | + gen_set_label(l1); | |
| 2579 | + } | |
| 2580 | + gen_op_mac_set_flags(acc); | |
| 2581 | + | |
| 2582 | + if (insn & 0x30) { | |
| 2583 | + int rw; | |
| 2584 | + rw = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9); | |
| 2585 | + gen_op_mov32(rw, loadval); | |
| 2586 | + /* FIXME: Should address writeback happen with the masked or | |
| 2587 | + unmasked value? */ | |
| 2588 | + switch ((insn >> 3) & 7) { | |
| 2589 | + case 3: /* Post-increment. */ | |
| 2590 | + gen_op_add32(AREG(insn, 0), addr, gen_im32(4)); | |
| 2591 | + break; | |
| 2592 | + case 4: /* Pre-decrement. */ | |
| 2593 | + gen_op_mov32(AREG(insn, 0), addr); | |
| 2594 | + } | |
| 2595 | + } | |
| 2596 | +} | |
| 2597 | + | |
| 2598 | +DISAS_INSN(from_mac) | |
| 2599 | +{ | |
| 2600 | + int rx; | |
| 2601 | + int acc; | |
| 2602 | + | |
| 2603 | + rx = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0); | |
| 2604 | + acc = (insn >> 9) & 3; | |
| 2605 | + if (s->env->macsr & MACSR_FI) { | |
| 2606 | + gen_op_get_macf(rx, acc); | |
| 2607 | + } else if ((s->env->macsr & MACSR_OMC) == 0) { | |
| 2608 | + gen_op_get_maci(rx, acc); | |
| 2609 | + } else if (s->env->macsr & MACSR_SU) { | |
| 2610 | + gen_op_get_macs(rx, acc); | |
| 2611 | + } else { | |
| 2612 | + gen_op_get_macu(rx, acc); | |
| 2613 | + } | |
| 2614 | + if (insn & 0x40) | |
| 2615 | + gen_op_clear_mac(acc); | |
| 2616 | +} | |
| 2617 | + | |
| 2618 | +DISAS_INSN(move_mac) | |
| 2619 | +{ | |
| 2620 | + int src; | |
| 2621 | + int dest; | |
| 2622 | + src = insn & 3; | |
| 2623 | + dest = (insn >> 9) & 3; | |
| 2624 | + gen_op_move_mac(dest, src); | |
| 2625 | + gen_op_mac_clear_flags(); | |
| 2626 | + gen_op_mac_set_flags(dest); | |
| 2627 | +} | |
| 2628 | + | |
| 2629 | +DISAS_INSN(from_macsr) | |
| 2630 | +{ | |
| 2631 | + int reg; | |
| 2632 | + | |
| 2633 | + reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0); | |
| 2634 | + gen_op_mov32(reg, QREG_MACSR); | |
| 2635 | +} | |
| 2636 | + | |
| 2637 | +DISAS_INSN(from_mask) | |
| 2638 | +{ | |
| 2639 | + int reg; | |
| 2640 | + reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0); | |
| 2641 | + gen_op_mov32(reg, QREG_MAC_MASK); | |
| 2642 | +} | |
| 2643 | + | |
| 2644 | +DISAS_INSN(from_mext) | |
| 2645 | +{ | |
| 2646 | + int reg; | |
| 2647 | + int acc; | |
| 2648 | + reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0); | |
| 2649 | + acc = (insn & 0x400) ? 2 : 0; | |
| 2650 | + if (s->env->macsr & MACSR_FI) | |
| 2651 | + gen_op_get_mac_extf(reg, acc); | |
| 2652 | + else | |
| 2653 | + gen_op_get_mac_exti(reg, acc); | |
| 2654 | +} | |
| 2655 | + | |
| 2656 | +DISAS_INSN(macsr_to_ccr) | |
| 2657 | +{ | |
| 2658 | + gen_op_mov32(QREG_CC_X, gen_im32(0)); | |
| 2659 | + gen_op_and32(QREG_CC_DEST, QREG_MACSR, gen_im32(0xf)); | |
| 2660 | + s->cc_op = CC_OP_FLAGS; | |
| 2661 | +} | |
| 2662 | + | |
| 2663 | +DISAS_INSN(to_mac) | |
| 2664 | +{ | |
| 2665 | + int acc; | |
| 2666 | + int val; | |
| 2667 | + acc = (insn >>9) & 3; | |
| 2668 | + SRC_EA(val, OS_LONG, 0, NULL); | |
| 2669 | + if (s->env->macsr & MACSR_FI) { | |
| 2670 | + gen_op_set_macf(val, acc); | |
| 2671 | + } else if (s->env->macsr & MACSR_SU) { | |
| 2672 | + gen_op_set_macs(val, acc); | |
| 2673 | + } else { | |
| 2674 | + gen_op_set_macu(val, acc); | |
| 2675 | + } | |
| 2676 | + gen_op_mac_clear_flags(); | |
| 2677 | + gen_op_mac_set_flags(acc); | |
| 2678 | +} | |
| 2679 | + | |
| 2680 | +DISAS_INSN(to_macsr) | |
| 2681 | +{ | |
| 2682 | + int val; | |
| 2683 | + SRC_EA(val, OS_LONG, 0, NULL); | |
| 2684 | + gen_op_set_macsr(val); | |
| 2685 | + gen_lookup_tb(s); | |
| 2686 | +} | |
| 2687 | + | |
| 2688 | +DISAS_INSN(to_mask) | |
| 2689 | +{ | |
| 2690 | + int val; | |
| 2691 | + SRC_EA(val, OS_LONG, 0, NULL); | |
| 2692 | + gen_op_or32(QREG_MAC_MASK, val, gen_im32(0xffff0000)); | |
| 2693 | +} | |
| 2694 | + | |
| 2695 | +DISAS_INSN(to_mext) | |
| 2696 | +{ | |
| 2697 | + int val; | |
| 2698 | + int acc; | |
| 2699 | + SRC_EA(val, OS_LONG, 0, NULL); | |
| 2700 | + acc = (insn & 0x400) ? 2 : 0; | |
| 2701 | + if (s->env->macsr & MACSR_FI) | |
| 2702 | + gen_op_set_mac_extf(val, acc); | |
| 2703 | + else if (s->env->macsr & MACSR_SU) | |
| 2704 | + gen_op_set_mac_exts(val, acc); | |
| 2705 | + else | |
| 2706 | + gen_op_set_mac_extu(val, acc); | |
| 2707 | +} | |
| 2708 | + | |
| 2436 | 2709 | static disas_proc opcode_table[65536]; |
| 2437 | 2710 | |
| 2438 | 2711 | static void |
| ... | ... | @@ -2545,7 +2818,20 @@ void register_m68k_insns (CPUM68KState *env) |
| 2545 | 2818 | INSN(addsub, 9000, f000, CF_ISA_A); |
| 2546 | 2819 | INSN(subx, 9180, f1f8, CF_ISA_A); |
| 2547 | 2820 | INSN(suba, 91c0, f1c0, CF_ISA_A); |
| 2821 | + | |
| 2548 | 2822 | INSN(undef_mac, a000, f000, CF_ISA_A); |
| 2823 | + INSN(mac, a000, f100, CF_EMAC); | |
| 2824 | + INSN(from_mac, a180, f9b0, CF_EMAC); | |
| 2825 | + INSN(move_mac, a110, f9fc, CF_EMAC); | |
| 2826 | + INSN(from_macsr,a980, f9f0, CF_EMAC); | |
| 2827 | + INSN(from_mask, ad80, fff0, CF_EMAC); | |
| 2828 | + INSN(from_mext, ab80, fbf0, CF_EMAC); | |
| 2829 | + INSN(macsr_to_ccr, a9c0, ffff, CF_EMAC); | |
| 2830 | + INSN(to_mac, a100, f9c0, CF_EMAC); | |
| 2831 | + INSN(to_macsr, a900, ffc0, CF_EMAC); | |
| 2832 | + INSN(to_mext, ab00, fbc0, CF_EMAC); | |
| 2833 | + INSN(to_mask, ad00, ffc0, CF_EMAC); | |
| 2834 | + | |
| 2549 | 2835 | INSN(mov3q, a140, f1c0, CF_ISA_B); |
| 2550 | 2836 | INSN(cmp, b000, f1c0, CF_ISA_B); /* cmp.b */ |
| 2551 | 2837 | INSN(cmp, b040, f1c0, CF_ISA_B); /* cmp.w */ | ... | ... |