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 */ | ... | ... |