2 * Alpha emulation cpu micro-operations helpers for qemu.
4 * Copyright (c) 2007 Jocelyn Mayer
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "host-utils.h"
23 #include "softfloat.h"
25 #include "op_helper.h"
27 #define MEMSUFFIX _raw
28 #include "op_helper_mem.h"
30 #if !defined(CONFIG_USER_ONLY)
31 #define MEMSUFFIX _kernel
32 #include "op_helper_mem.h"
34 #define MEMSUFFIX _executive
35 #include "op_helper_mem.h"
37 #define MEMSUFFIX _supervisor
38 #include "op_helper_mem.h"
40 #define MEMSUFFIX _user
41 #include "op_helper_mem.h"
43 /* This is used for pal modes */
44 #define MEMSUFFIX _data
45 #include "op_helper_mem.h"
48 void helper_tb_flush (void)
53 void cpu_dump_EA (target_ulong EA);
54 void helper_print_mem_EA (target_ulong EA)
59 /*****************************************************************************/
60 /* Exceptions processing helpers */
61 void helper_excp (uint32_t excp, uint32_t error)
63 env->exception_index = excp;
64 env->error_code = error;
68 uint64_t helper_amask (uint64_t arg)
70 switch (env->implver) {
72 /* EV4, EV45, LCA, LCA45 & EV5 */
83 void helper_load_pcc (void)
89 void helper_load_implver (void)
94 void helper_load_fpcr (void)
97 #ifdef CONFIG_SOFTFLOAT
98 T0 |= env->fp_status.float_exception_flags << 52;
99 if (env->fp_status.float_exception_flags)
101 env->ipr[IPR_EXC_SUM] &= ~0x3E:
102 env->ipr[IPR_EXC_SUM] |= env->fp_status.float_exception_flags << 1;
104 switch (env->fp_status.float_rounding_mode) {
105 case float_round_nearest_even:
108 case float_round_down:
114 case float_round_to_zero:
119 void helper_store_fpcr (void)
121 #ifdef CONFIG_SOFTFLOAT
122 set_float_exception_flags((T0 >> 52) & 0x3F, &FP_STATUS);
124 switch ((T0 >> 58) & 3) {
126 set_float_rounding_mode(float_round_to_zero, &FP_STATUS);
129 set_float_rounding_mode(float_round_down, &FP_STATUS);
132 set_float_rounding_mode(float_round_nearest_even, &FP_STATUS);
135 set_float_rounding_mode(float_round_up, &FP_STATUS);
140 void helper_load_irf (void)
146 void helper_set_irf (void)
151 void helper_clear_irf (void)
156 void helper_addqv (void)
160 if (unlikely((T2 ^ T1 ^ (-1ULL)) & (T2 ^ T0) & (1ULL << 63))) {
161 helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
165 void helper_addlv (void)
168 T0 = (uint32_t)(T0 + T1);
169 if (unlikely((T2 ^ T1 ^ (-1UL)) & (T2 ^ T0) & (1UL << 31))) {
170 helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
174 void helper_subqv (void)
178 if (unlikely(((~T2) ^ T0 ^ (-1ULL)) & ((~T2) ^ T1) & (1ULL << 63))) {
179 helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
183 void helper_sublv (void)
186 T0 = (uint32_t)(T0 - T1);
187 if (unlikely(((~T2) ^ T0 ^ (-1UL)) & ((~T2) ^ T1) & (1UL << 31))) {
188 helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
192 void helper_mullv (void)
194 int64_t res = (int64_t)T0 * (int64_t)T1;
196 if (unlikely((int32_t)res != res)) {
197 helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
199 T0 = (int64_t)((int32_t)res);
206 muls64(&tl, &th, T0, T1);
207 /* If th != 0 && th != -1, then we had an overflow */
208 if (unlikely((th + 1) > 1)) {
209 helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
214 uint64_t helper_ctpop (uint64_t arg)
219 uint64_t helper_ctlz (uint64_t arg)
224 uint64_t helper_cttz (uint64_t arg)
229 static always_inline uint64_t byte_zap (uint64_t op, uint8_t mskb)
234 mask |= ((mskb >> 0) & 1) * 0x00000000000000FFULL;
235 mask |= ((mskb >> 1) & 1) * 0x000000000000FF00ULL;
236 mask |= ((mskb >> 2) & 1) * 0x0000000000FF0000ULL;
237 mask |= ((mskb >> 3) & 1) * 0x00000000FF000000ULL;
238 mask |= ((mskb >> 4) & 1) * 0x000000FF00000000ULL;
239 mask |= ((mskb >> 5) & 1) * 0x0000FF0000000000ULL;
240 mask |= ((mskb >> 6) & 1) * 0x00FF000000000000ULL;
241 mask |= ((mskb >> 7) & 1) * 0xFF00000000000000ULL;
246 void helper_mskbl (void)
248 T0 = byte_zap(T0, 0x01 << (T1 & 7));
251 void helper_extbl (void)
254 T0 = byte_zap(T0, 0xFE);
257 void helper_insbl (void)
260 T0 = byte_zap(T0, ~(0x01 << (T1 & 7)));
263 void helper_mskwl (void)
265 T0 = byte_zap(T0, 0x03 << (T1 & 7));
268 void helper_extwl (void)
271 T0 = byte_zap(T0, 0xFC);
274 void helper_inswl (void)
277 T0 = byte_zap(T0, ~(0x03 << (T1 & 7)));
280 void helper_mskll (void)
282 T0 = byte_zap(T0, 0x0F << (T1 & 7));
285 void helper_extll (void)
288 T0 = byte_zap(T0, 0xF0);
291 void helper_insll (void)
294 T0 = byte_zap(T0, ~(0x0F << (T1 & 7)));
297 void helper_zap (void)
299 T0 = byte_zap(T0, T1);
302 void helper_zapnot (void)
304 T0 = byte_zap(T0, ~T1);
307 void helper_mskql (void)
309 T0 = byte_zap(T0, 0xFF << (T1 & 7));
312 void helper_extql (void)
315 T0 = byte_zap(T0, 0x00);
318 void helper_insql (void)
321 T0 = byte_zap(T0, ~(0xFF << (T1 & 7)));
324 void helper_mskwh (void)
326 T0 = byte_zap(T0, (0x03 << (T1 & 7)) >> 8);
329 void helper_inswh (void)
331 T0 >>= 64 - ((T1 & 7) * 8);
332 T0 = byte_zap(T0, ~((0x03 << (T1 & 7)) >> 8));
335 void helper_extwh (void)
337 T0 <<= 64 - ((T1 & 7) * 8);
338 T0 = byte_zap(T0, ~0x07);
341 void helper_msklh (void)
343 T0 = byte_zap(T0, (0x0F << (T1 & 7)) >> 8);
346 void helper_inslh (void)
348 T0 >>= 64 - ((T1 & 7) * 8);
349 T0 = byte_zap(T0, ~((0x0F << (T1 & 7)) >> 8));
352 void helper_extlh (void)
354 T0 <<= 64 - ((T1 & 7) * 8);
355 T0 = byte_zap(T0, ~0x0F);
358 void helper_mskqh (void)
360 T0 = byte_zap(T0, (0xFF << (T1 & 7)) >> 8);
363 void helper_insqh (void)
365 T0 >>= 64 - ((T1 & 7) * 8);
366 T0 = byte_zap(T0, ~((0xFF << (T1 & 7)) >> 8));
369 void helper_extqh (void)
371 T0 <<= 64 - ((T1 & 7) * 8);
372 T0 = byte_zap(T0, 0x00);
375 void helper_cmpbge (void)
377 uint8_t opa, opb, res;
381 for (i = 0; i < 7; i++) {
390 void helper_cmov_fir (int freg)
393 env->fir[freg] = FT1;
396 void helper_sqrts (void)
398 FT0 = float32_sqrt(FT0, &FP_STATUS);
401 void helper_cpys (void)
410 r.i = p.i & 0x8000000000000000ULL;
411 r.i |= q.i & ~0x8000000000000000ULL;
415 void helper_cpysn (void)
424 r.i = (~p.i) & 0x8000000000000000ULL;
425 r.i |= q.i & ~0x8000000000000000ULL;
429 void helper_cpyse (void)
438 r.i = p.i & 0xFFF0000000000000ULL;
439 r.i |= q.i & ~0xFFF0000000000000ULL;
443 void helper_itofs (void)
451 FT0 = int64_to_float32(p.i, &FP_STATUS);
454 void helper_ftois (void)
461 p.i = float32_to_int64(FT0, &FP_STATUS);
465 void helper_sqrtt (void)
467 FT0 = float64_sqrt(FT0, &FP_STATUS);
470 void helper_cmptun (void)
478 if (float64_is_nan(FT0) || float64_is_nan(FT1))
479 p.i = 0x4000000000000000ULL;
483 void helper_cmpteq (void)
491 if (float64_eq(FT0, FT1, &FP_STATUS))
492 p.i = 0x4000000000000000ULL;
496 void helper_cmptle (void)
504 if (float64_le(FT0, FT1, &FP_STATUS))
505 p.i = 0x4000000000000000ULL;
509 void helper_cmptlt (void)
517 if (float64_lt(FT0, FT1, &FP_STATUS))
518 p.i = 0x4000000000000000ULL;
522 void helper_itoft (void)
530 FT0 = int64_to_float64(p.i, &FP_STATUS);
533 void helper_ftoit (void)
540 p.i = float64_to_int64(FT0, &FP_STATUS);
544 static always_inline int vaxf_is_valid (float ff)
553 exp = (p.i >> 23) & 0xFF;
554 mant = p.i & 0x007FFFFF;
555 if (exp == 0 && ((p.i & 0x80000000) || mant != 0)) {
556 /* Reserved operands / Dirty zero */
563 static always_inline float vaxf_to_ieee32 (float ff)
572 exp = (p.i >> 23) & 0xFF;
583 static always_inline float ieee32_to_vaxf (float fi)
592 exp = (p.i >> 23) & 0xFF;
593 mant = p.i & 0x007FFFFF;
595 /* NaN or infinity */
597 } else if (exp == 0) {
617 void helper_addf (void)
621 if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) {
624 ft0 = vaxf_to_ieee32(FT0);
625 ft1 = vaxf_to_ieee32(FT1);
626 ft2 = float32_add(ft0, ft1, &FP_STATUS);
627 FT0 = ieee32_to_vaxf(ft2);
630 void helper_subf (void)
634 if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) {
637 ft0 = vaxf_to_ieee32(FT0);
638 ft1 = vaxf_to_ieee32(FT1);
639 ft2 = float32_sub(ft0, ft1, &FP_STATUS);
640 FT0 = ieee32_to_vaxf(ft2);
643 void helper_mulf (void)
647 if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) {
650 ft0 = vaxf_to_ieee32(FT0);
651 ft1 = vaxf_to_ieee32(FT1);
652 ft2 = float32_mul(ft0, ft1, &FP_STATUS);
653 FT0 = ieee32_to_vaxf(ft2);
656 void helper_divf (void)
660 if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) {
663 ft0 = vaxf_to_ieee32(FT0);
664 ft1 = vaxf_to_ieee32(FT1);
665 ft2 = float32_div(ft0, ft1, &FP_STATUS);
666 FT0 = ieee32_to_vaxf(ft2);
669 void helper_sqrtf (void)
673 if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) {
676 ft0 = vaxf_to_ieee32(FT0);
677 ft1 = float32_sqrt(ft0, &FP_STATUS);
678 FT0 = ieee32_to_vaxf(ft1);
681 void helper_itoff (void)
686 static always_inline int vaxg_is_valid (double ff)
695 exp = (p.i >> 52) & 0x7FF;
696 mant = p.i & 0x000FFFFFFFFFFFFFULL;
697 if (exp == 0 && ((p.i & 0x8000000000000000ULL) || mant != 0)) {
698 /* Reserved operands / Dirty zero */
705 static always_inline double vaxg_to_ieee64 (double fg)
714 exp = (p.i >> 52) & 0x7FF;
725 static always_inline double ieee64_to_vaxg (double fi)
735 exp = (p.i >> 52) & 0x7FF;
736 mant = p.i & 0x000FFFFFFFFFFFFFULL;
738 /* NaN or infinity */
739 p.i = 1; /* VAX dirty zero */
740 } else if (exp == 0) {
751 p.i = 1; /* VAX dirty zero */
760 void helper_addg (void)
762 double ft0, ft1, ft2;
764 if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) {
767 ft0 = vaxg_to_ieee64(FT0);
768 ft1 = vaxg_to_ieee64(FT1);
769 ft2 = float64_add(ft0, ft1, &FP_STATUS);
770 FT0 = ieee64_to_vaxg(ft2);
773 void helper_subg (void)
775 double ft0, ft1, ft2;
777 if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) {
780 ft0 = vaxg_to_ieee64(FT0);
781 ft1 = vaxg_to_ieee64(FT1);
782 ft2 = float64_sub(ft0, ft1, &FP_STATUS);
783 FT0 = ieee64_to_vaxg(ft2);
786 void helper_mulg (void)
788 double ft0, ft1, ft2;
790 if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) {
793 ft0 = vaxg_to_ieee64(FT0);
794 ft1 = vaxg_to_ieee64(FT1);
795 ft2 = float64_mul(ft0, ft1, &FP_STATUS);
796 FT0 = ieee64_to_vaxg(ft2);
799 void helper_divg (void)
801 double ft0, ft1, ft2;
803 if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) {
806 ft0 = vaxg_to_ieee64(FT0);
807 ft1 = vaxg_to_ieee64(FT1);
808 ft2 = float64_div(ft0, ft1, &FP_STATUS);
809 FT0 = ieee64_to_vaxg(ft2);
812 void helper_sqrtg (void)
816 if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) {
819 ft0 = vaxg_to_ieee64(FT0);
820 ft1 = float64_sqrt(ft0, &FP_STATUS);
821 FT0 = ieee64_to_vaxg(ft1);
824 void helper_cmpgeq (void)
832 if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) {
835 ft0 = vaxg_to_ieee64(FT0);
836 ft1 = vaxg_to_ieee64(FT1);
838 if (float64_eq(ft0, ft1, &FP_STATUS))
839 p.u = 0x4000000000000000ULL;
843 void helper_cmpglt (void)
851 if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) {
854 ft0 = vaxg_to_ieee64(FT0);
855 ft1 = vaxg_to_ieee64(FT1);
857 if (float64_lt(ft0, ft1, &FP_STATUS))
858 p.u = 0x4000000000000000ULL;
862 void helper_cmpgle (void)
870 if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) {
873 ft0 = vaxg_to_ieee64(FT0);
874 ft1 = vaxg_to_ieee64(FT1);
876 if (float64_le(ft0, ft1, &FP_STATUS))
877 p.u = 0x4000000000000000ULL;
881 void helper_cvtqs (void)
892 void helper_cvttq (void)
903 void helper_cvtqt (void)
914 void helper_cvtqf (void)
922 FT0 = ieee32_to_vaxf(p.u);
925 void helper_cvtgf (void)
929 ft0 = vaxg_to_ieee64(FT0);
930 FT0 = ieee32_to_vaxf(ft0);
933 void helper_cvtgd (void)
938 void helper_cvtgq (void)
945 p.u = vaxg_to_ieee64(FT0);
949 void helper_cvtqg (void)
957 FT0 = ieee64_to_vaxg(p.u);
960 void helper_cvtdg (void)
965 void helper_cvtlq (void)
973 q.u = (p.u >> 29) & 0x3FFFFFFF;
975 q.u = (int64_t)((int32_t)q.u);
979 static always_inline void __helper_cvtql (int s, int v)
987 q.u = ((uint64_t)(p.u & 0xC0000000)) << 32;
988 q.u |= ((uint64_t)(p.u & 0x7FFFFFFF)) << 29;
990 if (v && (int64_t)((int32_t)p.u) != (int64_t)p.u) {
991 helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
998 void helper_cvtql (void)
1000 __helper_cvtql(0, 0);
1003 void helper_cvtqlv (void)
1005 __helper_cvtql(0, 1);
1008 void helper_cvtqlsv (void)
1010 __helper_cvtql(1, 1);
1013 void helper_cmpfeq (void)
1015 if (float64_eq(FT0, FT1, &FP_STATUS))
1021 void helper_cmpfne (void)
1023 if (float64_eq(FT0, FT1, &FP_STATUS))
1029 void helper_cmpflt (void)
1031 if (float64_lt(FT0, FT1, &FP_STATUS))
1037 void helper_cmpfle (void)
1039 if (float64_lt(FT0, FT1, &FP_STATUS))
1045 void helper_cmpfgt (void)
1047 if (float64_le(FT0, FT1, &FP_STATUS))
1053 void helper_cmpfge (void)
1055 if (float64_lt(FT0, FT1, &FP_STATUS))
1061 #if !defined (CONFIG_USER_ONLY)
1062 void helper_mfpr (int iprn)
1066 if (cpu_alpha_mfpr(env, iprn, &val) == 0)
1070 void helper_mtpr (int iprn)
1072 cpu_alpha_mtpr(env, iprn, T0, NULL);
1076 #if defined(HOST_SPARC) || defined(HOST_SPARC64)
1077 void helper_reset_FT0 (void)
1082 void helper_reset_FT1 (void)
1087 void helper_reset_FT2 (void)
1093 /*****************************************************************************/
1094 /* Softmmu support */
1095 #if !defined (CONFIG_USER_ONLY)
1097 /* XXX: the two following helpers are pure hacks.
1098 * Hopefully, we emulate the PALcode, then we should never see
1099 * HW_LD / HW_ST instructions.
1101 void helper_ld_phys_to_virt (void)
1103 uint64_t tlb_addr, physaddr;
1107 mmu_idx = cpu_mmu_index(env);
1108 index = (T0 >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1110 tlb_addr = env->tlb_table[mmu_idx][index].addr_read;
1111 if ((T0 & TARGET_PAGE_MASK) ==
1112 (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
1113 physaddr = T0 + env->tlb_table[mmu_idx][index].addend;
1115 /* the page is not in the TLB : fill it */
1117 tlb_fill(T0, 0, mmu_idx, retaddr);
1123 void helper_st_phys_to_virt (void)
1125 uint64_t tlb_addr, physaddr;
1129 mmu_idx = cpu_mmu_index(env);
1130 index = (T0 >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1132 tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
1133 if ((T0 & TARGET_PAGE_MASK) ==
1134 (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
1135 physaddr = T0 + env->tlb_table[mmu_idx][index].addend;
1137 /* the page is not in the TLB : fill it */
1139 tlb_fill(T0, 1, mmu_idx, retaddr);
1145 #define MMUSUFFIX _mmu
1148 #include "softmmu_template.h"
1151 #include "softmmu_template.h"
1154 #include "softmmu_template.h"
1157 #include "softmmu_template.h"
1159 /* try to fill the TLB and return an exception if error. If retaddr is
1160 NULL, it means that the function was called in C code (i.e. not
1161 from generated code or from helper.c) */
1162 /* XXX: fix it to restore all registers */
1163 void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
1165 TranslationBlock *tb;
1166 CPUState *saved_env;
1170 /* XXX: hack to restore env in all cases, even if not called from
1173 env = cpu_single_env;
1174 ret = cpu_alpha_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
1175 if (!likely(ret == 0)) {
1176 if (likely(retaddr)) {
1177 /* now we have a real cpu fault */
1178 pc = (unsigned long)retaddr;
1179 tb = tb_find_pc(pc);
1181 /* the PC is inside the translated code. It means that we have
1182 a virtual CPU fault */
1183 cpu_restore_state(tb, env, pc, NULL);
1186 /* Exception index and error code are already set */