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,7 +196,9 @@ static inline TranslationBlock *tb_find_fast(void) | ||
| 196 | cs_base = 0; | 196 | cs_base = 0; |
| 197 | pc = env->PC; | 197 | pc = env->PC; |
| 198 | #elif defined(TARGET_M68K) | 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 | cs_base = 0; | 202 | cs_base = 0; |
| 201 | pc = env->pc; | 203 | pc = env->pc; |
| 202 | #elif defined(TARGET_SH4) | 204 | #elif defined(TARGET_SH4) |
target-m68k/cpu.h
| @@ -71,6 +71,14 @@ typedef struct CPUM68KState { | @@ -71,6 +71,14 @@ typedef struct CPUM68KState { | ||
| 71 | uint32_t fpsr; | 71 | uint32_t fpsr; |
| 72 | float_status fp_status; | 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 | /* Temporary storage for DIV helpers. */ | 82 | /* Temporary storage for DIV helpers. */ |
| 75 | uint32_t div1; | 83 | uint32_t div1; |
| 76 | uint32_t div2; | 84 | uint32_t div2; |
| @@ -143,11 +151,22 @@ enum { | @@ -143,11 +151,22 @@ enum { | ||
| 143 | #define SR_S 0x2000 | 151 | #define SR_S 0x2000 |
| 144 | #define SR_T 0x8000 | 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 | typedef struct m68k_def_t m68k_def_t; | 164 | typedef struct m68k_def_t m68k_def_t; |
| 147 | 165 | ||
| 148 | int cpu_m68k_set_model(CPUM68KState *env, const char * name); | 166 | int cpu_m68k_set_model(CPUM68KState *env, const char * name); |
| 149 | 167 | ||
| 150 | void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector); | 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 | #define M68K_FPCR_PREC (1 << 6) | 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,7 +69,6 @@ int cpu_m68k_set_model(CPUM68KState *env, const char * name) | ||
| 69 | m68k_set_feature(env, M68K_FEATURE_CF_ISA_B); | 69 | m68k_set_feature(env, M68K_FEATURE_CF_ISA_B); |
| 70 | m68k_set_feature(env, M68K_FEATURE_CF_ISA_C); | 70 | m68k_set_feature(env, M68K_FEATURE_CF_ISA_C); |
| 71 | m68k_set_feature(env, M68K_FEATURE_CF_FPU); | 71 | m68k_set_feature(env, M68K_FEATURE_CF_FPU); |
| 72 | - m68k_set_feature(env, M68K_FEATURE_CF_MAC); | ||
| 73 | m68k_set_feature(env, M68K_FEATURE_CF_EMAC); | 72 | m68k_set_feature(env, M68K_FEATURE_CF_EMAC); |
| 74 | break; | 73 | break; |
| 75 | case M68K_CPUID_ANY: | 74 | case M68K_CPUID_ANY: |
| @@ -77,7 +76,8 @@ int cpu_m68k_set_model(CPUM68KState *env, const char * name) | @@ -77,7 +76,8 @@ int cpu_m68k_set_model(CPUM68KState *env, const char * name) | ||
| 77 | m68k_set_feature(env, M68K_FEATURE_CF_ISA_B); | 76 | m68k_set_feature(env, M68K_FEATURE_CF_ISA_B); |
| 78 | m68k_set_feature(env, M68K_FEATURE_CF_ISA_C); | 77 | m68k_set_feature(env, M68K_FEATURE_CF_ISA_C); |
| 79 | m68k_set_feature(env, M68K_FEATURE_CF_FPU); | 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 | m68k_set_feature(env, M68K_FEATURE_CF_EMAC); | 81 | m68k_set_feature(env, M68K_FEATURE_CF_EMAC); |
| 82 | m68k_set_feature(env, M68K_FEATURE_EXT_FULL); | 82 | m68k_set_feature(env, M68K_FEATURE_EXT_FULL); |
| 83 | break; | 83 | break; |
| @@ -227,6 +227,40 @@ void helper_movec(CPUM68KState *env, int reg, uint32_t val) | @@ -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 | /* MMU */ | 264 | /* MMU */ |
| 231 | 265 | ||
| 232 | /* TODO: This will need fixing once the MMU is implemented. */ | 266 | /* TODO: This will need fixing once the MMU is implemented. */ |
target-m68k/op.c
| @@ -285,6 +285,16 @@ OP(shr_cc) | @@ -285,6 +285,16 @@ OP(shr_cc) | ||
| 285 | FORCE_RET(); | 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 | OP(sar_cc) | 298 | OP(sar_cc) |
| 289 | { | 299 | { |
| 290 | int32_t op1 = get_op(PARAM1); | 300 | int32_t op1 = get_op(PARAM1); |
| @@ -651,3 +661,410 @@ OP(movec) | @@ -651,3 +661,410 @@ OP(movec) | ||
| 651 | #define MEMSUFFIX _kernel | 661 | #define MEMSUFFIX _kernel |
| 652 | #include "op_mem.h" | 662 | #include "op_mem.h" |
| 653 | #endif | 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,6 +2433,279 @@ DISAS_INSN(fsave) | ||
| 2433 | qemu_assert(0, "FSAVE not implemented"); | 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 | static disas_proc opcode_table[65536]; | 2709 | static disas_proc opcode_table[65536]; |
| 2437 | 2710 | ||
| 2438 | static void | 2711 | static void |
| @@ -2545,7 +2818,20 @@ void register_m68k_insns (CPUM68KState *env) | @@ -2545,7 +2818,20 @@ void register_m68k_insns (CPUM68KState *env) | ||
| 2545 | INSN(addsub, 9000, f000, CF_ISA_A); | 2818 | INSN(addsub, 9000, f000, CF_ISA_A); |
| 2546 | INSN(subx, 9180, f1f8, CF_ISA_A); | 2819 | INSN(subx, 9180, f1f8, CF_ISA_A); |
| 2547 | INSN(suba, 91c0, f1c0, CF_ISA_A); | 2820 | INSN(suba, 91c0, f1c0, CF_ISA_A); |
| 2821 | + | ||
| 2548 | INSN(undef_mac, a000, f000, CF_ISA_A); | 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 | INSN(mov3q, a140, f1c0, CF_ISA_B); | 2835 | INSN(mov3q, a140, f1c0, CF_ISA_B); |
| 2550 | INSN(cmp, b000, f1c0, CF_ISA_B); /* cmp.b */ | 2836 | INSN(cmp, b000, f1c0, CF_ISA_B); /* cmp.b */ |
| 2551 | INSN(cmp, b040, f1c0, CF_ISA_B); /* cmp.w */ | 2837 | INSN(cmp, b040, f1c0, CF_ISA_B); /* cmp.w */ |