Commit a9d9eb8fd45279fa8455afa03331296dbe2871ff
1 parent
b33c17e1
Implement PowerPC Altivec load & stores, used by Apple firmware for memcpy.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3349 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
5 changed files
with
274 additions
and
8 deletions
target-ppc/cpu.h
... | ... | @@ -292,7 +292,7 @@ typedef struct CPUPPCState CPUPPCState; |
292 | 292 | typedef struct ppc_tb_t ppc_tb_t; |
293 | 293 | typedef struct ppc_spr_t ppc_spr_t; |
294 | 294 | typedef struct ppc_dcr_t ppc_dcr_t; |
295 | -typedef struct ppc_avr_t ppc_avr_t; | |
295 | +typedef union ppc_avr_t ppc_avr_t; | |
296 | 296 | typedef union ppc_tlb_t ppc_tlb_t; |
297 | 297 | |
298 | 298 | /* SPR access micro-ops generations callbacks */ |
... | ... | @@ -311,8 +311,11 @@ struct ppc_spr_t { |
311 | 311 | }; |
312 | 312 | |
313 | 313 | /* Altivec registers (128 bits) */ |
314 | -struct ppc_avr_t { | |
315 | - uint32_t u[4]; | |
314 | +union ppc_avr_t { | |
315 | + uint8_t u8[16]; | |
316 | + uint16_t u16[8]; | |
317 | + uint32_t u32[4]; | |
318 | + uint64_t u64[2]; | |
316 | 319 | }; |
317 | 320 | |
318 | 321 | /* Software TLB cache */ |
... | ... | @@ -454,7 +457,7 @@ struct CPUPPCState { |
454 | 457 | */ |
455 | 458 | ppc_gpr_t t0, t1, t2; |
456 | 459 | #endif |
457 | - ppc_avr_t t0_avr, t1_avr, t2_avr; | |
460 | + ppc_avr_t avr0, avr1, avr2; | |
458 | 461 | |
459 | 462 | /* general purpose registers */ |
460 | 463 | ppc_gpr_t gpr[32]; | ... | ... |
target-ppc/exec.h
... | ... | @@ -54,9 +54,9 @@ register unsigned long T2 asm(AREG3); |
54 | 54 | #define T2_64 T2 |
55 | 55 | #endif |
56 | 56 | /* Provision for Altivec */ |
57 | -#define T0_avr (env->t0_avr) | |
58 | -#define T1_avr (env->t1_avr) | |
59 | -#define T2_avr (env->t2_avr) | |
57 | +#define AVR0 (env->avr0) | |
58 | +#define AVR1 (env->avr1) | |
59 | +#define AVR2 (env->avr2) | |
60 | 60 | |
61 | 61 | #define FT0 (env->ft0) |
62 | 62 | #define FT1 (env->ft1) | ... | ... |
target-ppc/op_mem.h
... | ... | @@ -1054,6 +1054,66 @@ void OPPROTO glue(op_POWER2_stfq_le, MEMSUFFIX) (void) |
1054 | 1054 | RETURN(); |
1055 | 1055 | } |
1056 | 1056 | |
1057 | +/* Altivec vector extension */ | |
1058 | +#if defined(WORDS_BIGENDIAN) | |
1059 | +#define VR_DWORD0 0 | |
1060 | +#define VR_DWORD1 1 | |
1061 | +#else | |
1062 | +#define VR_DWORD0 1 | |
1063 | +#define VR_DWORD1 0 | |
1064 | +#endif | |
1065 | +void OPPROTO glue(op_vr_lvx, MEMSUFFIX) (void) | |
1066 | +{ | |
1067 | + AVR0.u64[VR_DWORD0] = glue(ldq, MEMSUFFIX)((uint32_t)T0); | |
1068 | + AVR0.u64[VR_DWORD1] = glue(ldq, MEMSUFFIX)((uint32_t)T0 + 8); | |
1069 | +} | |
1070 | + | |
1071 | +void OPPROTO glue(op_vr_lvx_le, MEMSUFFIX) (void) | |
1072 | +{ | |
1073 | + AVR0.u64[VR_DWORD1] = glue(ldq, MEMSUFFIX)((uint32_t)T0); | |
1074 | + AVR0.u64[VR_DWORD0] = glue(ldq, MEMSUFFIX)((uint32_t)T0 + 8); | |
1075 | +} | |
1076 | + | |
1077 | +void OPPROTO glue(op_vr_stvx, MEMSUFFIX) (void) | |
1078 | +{ | |
1079 | + glue(stq, MEMSUFFIX)((uint32_t)T0, AVR0.u64[VR_DWORD0]); | |
1080 | + glue(stq, MEMSUFFIX)((uint32_t)T0 + 8, AVR0.u64[VR_DWORD1]); | |
1081 | +} | |
1082 | + | |
1083 | +void OPPROTO glue(op_vr_stvx_le, MEMSUFFIX) (void) | |
1084 | +{ | |
1085 | + glue(stq, MEMSUFFIX)((uint32_t)T0, AVR0.u64[VR_DWORD1]); | |
1086 | + glue(stq, MEMSUFFIX)((uint32_t)T0 + 8, AVR0.u64[VR_DWORD0]); | |
1087 | +} | |
1088 | + | |
1089 | +#if defined(TARGET_PPC64) | |
1090 | +void OPPROTO glue(op_vr_lvx_64, MEMSUFFIX) (void) | |
1091 | +{ | |
1092 | + AVR0.u64[VR_DWORD0] = glue(ldq, MEMSUFFIX)((uint64_t)T0); | |
1093 | + AVR0.u64[VR_DWORD1] = glue(ldq, MEMSUFFIX)((uint64_t)T0 + 8); | |
1094 | +} | |
1095 | + | |
1096 | +void OPPROTO glue(op_vr_lvx_le_64, MEMSUFFIX) (void) | |
1097 | +{ | |
1098 | + AVR0.u64[VR_DWORD1] = glue(ldq, MEMSUFFIX)((uint64_t)T0); | |
1099 | + AVR0.u64[VR_DWORD0] = glue(ldq, MEMSUFFIX)((uint64_t)T0 + 8); | |
1100 | +} | |
1101 | + | |
1102 | +void OPPROTO glue(op_vr_stvx_64, MEMSUFFIX) (void) | |
1103 | +{ | |
1104 | + glue(stq, MEMSUFFIX)((uint64_t)T0, AVR0.u64[VR_DWORD0]); | |
1105 | + glue(stq, MEMSUFFIX)((uint64_t)T0 + 8, AVR0.u64[VR_DWORD1]); | |
1106 | +} | |
1107 | + | |
1108 | +void OPPROTO glue(op_vr_stvx_le_64, MEMSUFFIX) (void) | |
1109 | +{ | |
1110 | + glue(stq, MEMSUFFIX)((uint64_t)T0, AVR0.u64[VR_DWORD1]); | |
1111 | + glue(stq, MEMSUFFIX)((uint64_t)T0 + 8, AVR0.u64[VR_DWORD0]); | |
1112 | +} | |
1113 | +#endif | |
1114 | +#undef VR_DWORD0 | |
1115 | +#undef VR_DWORD1 | |
1116 | + | |
1057 | 1117 | #if defined(TARGET_PPCEMB) |
1058 | 1118 | /* SPE extension */ |
1059 | 1119 | #define _PPC_SPE_LD_OP(name, op) \ | ... | ... |
target-ppc/op_template.h
... | ... | @@ -57,6 +57,7 @@ void OPPROTO glue(op_store_T2_gpr_gpr, REG) (void) |
57 | 57 | } |
58 | 58 | #endif |
59 | 59 | |
60 | +/* General purpose registers containing vector operands moves */ | |
60 | 61 | #if defined(TARGET_PPCEMB) |
61 | 62 | void OPPROTO glue(op_load_gpr64_T0_gpr, REG) (void) |
62 | 63 | { |
... | ... | @@ -99,6 +100,45 @@ void OPPROTO glue(op_store_T2_gpr64_gpr, REG) (void) |
99 | 100 | #endif |
100 | 101 | #endif /* defined(TARGET_PPCEMB) */ |
101 | 102 | |
103 | +/* Altivec registers moves */ | |
104 | +void OPPROTO glue(op_load_avr_A0_avr, REG) (void) | |
105 | +{ | |
106 | + AVR0 = env->avr[REG]; | |
107 | + RETURN(); | |
108 | +} | |
109 | + | |
110 | +void OPPROTO glue(op_load_avr_A1_avr, REG) (void) | |
111 | +{ | |
112 | + AVR1 = env->avr[REG]; | |
113 | + RETURN(); | |
114 | +} | |
115 | + | |
116 | +void OPPROTO glue(op_load_avr_A2_avr, REG) (void) | |
117 | +{ | |
118 | + AVR2 = env->avr[REG]; | |
119 | + RETURN(); | |
120 | +} | |
121 | + | |
122 | +void OPPROTO glue(op_store_A0_avr_avr, REG) (void) | |
123 | +{ | |
124 | + env->avr[REG] = AVR0; | |
125 | + RETURN(); | |
126 | +} | |
127 | + | |
128 | +void OPPROTO glue(op_store_A1_avr_avr, REG) (void) | |
129 | +{ | |
130 | + env->avr[REG] = AVR1; | |
131 | + RETURN(); | |
132 | +} | |
133 | + | |
134 | +#if 0 // unused | |
135 | +void OPPROTO glue(op_store_A2_avr_avr, REG) (void) | |
136 | +{ | |
137 | + env->avr[REG] = AVR2; | |
138 | + RETURN(); | |
139 | +} | |
140 | +#endif | |
141 | + | |
102 | 142 | #if REG <= 7 |
103 | 143 | /* Condition register moves */ |
104 | 144 | void OPPROTO glue(op_load_crf_T0_crf, REG) (void) | ... | ... |
target-ppc/translate.c
... | ... | @@ -164,6 +164,7 @@ typedef struct DisasContext { |
164 | 164 | int sf_mode; |
165 | 165 | #endif |
166 | 166 | int fpu_enabled; |
167 | + int altivec_enabled; | |
167 | 168 | #if defined(TARGET_PPCEMB) |
168 | 169 | int spe_enabled; |
169 | 170 | #endif |
... | ... | @@ -235,6 +236,9 @@ GEN_EXCP(ctx, POWERPC_EXCP_FPU, 0) |
235 | 236 | #define GEN_EXCP_NO_AP(ctx) \ |
236 | 237 | GEN_EXCP(ctx, POWERPC_EXCP_APU, 0) |
237 | 238 | |
239 | +#define GEN_EXCP_NO_VR(ctx) \ | |
240 | +GEN_EXCP(ctx, POWERPC_EXCP_VPU, 0) | |
241 | + | |
238 | 242 | /* Stop translation */ |
239 | 243 | static always_inline void GEN_STOP (DisasContext *ctx) |
240 | 244 | { |
... | ... | @@ -5530,6 +5534,161 @@ GEN_HANDLER(icbt_440, 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE) |
5530 | 5534 | */ |
5531 | 5535 | } |
5532 | 5536 | |
5537 | +/*** Altivec vector extension ***/ | |
5538 | +/* Altivec registers moves */ | |
5539 | +GEN32(gen_op_load_avr_A0, gen_op_load_avr_A0_avr); | |
5540 | +GEN32(gen_op_load_avr_A1, gen_op_load_avr_A1_avr); | |
5541 | +GEN32(gen_op_load_avr_A2, gen_op_load_avr_A2_avr); | |
5542 | + | |
5543 | +GEN32(gen_op_store_A0_avr, gen_op_store_A0_avr_avr); | |
5544 | +GEN32(gen_op_store_A1_avr, gen_op_store_A1_avr_avr); | |
5545 | +#if 0 // unused | |
5546 | +GEN32(gen_op_store_A2_avr, gen_op_store_A2_avr_avr); | |
5547 | +#endif | |
5548 | + | |
5549 | +#define op_vr_ldst(name) (*gen_op_##name[ctx->mem_idx])() | |
5550 | +#if defined(CONFIG_USER_ONLY) | |
5551 | +#if defined(TARGET_PPC64) | |
5552 | +/* User-mode only - 64 bits mode */ | |
5553 | +#define OP_VR_LD_TABLE(name) \ | |
5554 | +static GenOpFunc *gen_op_vr_l##name[] = { \ | |
5555 | + &gen_op_vr_l##name##_raw, \ | |
5556 | + &gen_op_vr_l##name##_le_raw, \ | |
5557 | + &gen_op_vr_l##name##_64_raw, \ | |
5558 | + &gen_op_vr_l##name##_le_64_raw, \ | |
5559 | +}; | |
5560 | +#define OP_VR_ST_TABLE(name) \ | |
5561 | +static GenOpFunc *gen_op_vr_st##name[] = { \ | |
5562 | + &gen_op_vr_st##name##_raw, \ | |
5563 | + &gen_op_vr_st##name##_le_raw, \ | |
5564 | + &gen_op_vr_st##name##_64_raw, \ | |
5565 | + &gen_op_vr_st##name##_le_64_raw, \ | |
5566 | +}; | |
5567 | +#else /* defined(TARGET_PPC64) */ | |
5568 | +/* User-mode only - 32 bits mode */ | |
5569 | +#define OP_VR_LD_TABLE(name) \ | |
5570 | +static GenOpFunc *gen_op_vr_l##name[] = { \ | |
5571 | + &gen_op_vr_l##name##_raw, \ | |
5572 | + &gen_op_vr_l##name##_le_raw, \ | |
5573 | +}; | |
5574 | +#define OP_VR_ST_TABLE(name) \ | |
5575 | +static GenOpFunc *gen_op_vr_st##name[] = { \ | |
5576 | + &gen_op_vr_st##name##_raw, \ | |
5577 | + &gen_op_vr_st##name##_le_raw, \ | |
5578 | +}; | |
5579 | +#endif /* defined(TARGET_PPC64) */ | |
5580 | +#else /* defined(CONFIG_USER_ONLY) */ | |
5581 | +#if defined(TARGET_PPC64H) | |
5582 | +/* Full system with hypervisor mode */ | |
5583 | +#define OP_VR_LD_TABLE(name) \ | |
5584 | +static GenOpFunc *gen_op_vr_l##name[] = { \ | |
5585 | + &gen_op_vr_l##name##_user, \ | |
5586 | + &gen_op_vr_l##name##_le_user, \ | |
5587 | + &gen_op_vr_l##name##_64_user, \ | |
5588 | + &gen_op_vr_l##name##_le_64_user, \ | |
5589 | + &gen_op_vr_l##name##_kernel, \ | |
5590 | + &gen_op_vr_l##name##_le_kernel, \ | |
5591 | + &gen_op_vr_l##name##_64_kernel, \ | |
5592 | + &gen_op_vr_l##name##_le_64_kernel, \ | |
5593 | + &gen_op_vr_l##name##_hypv, \ | |
5594 | + &gen_op_vr_l##name##_le_hypv, \ | |
5595 | + &gen_op_vr_l##name##_64_hypv, \ | |
5596 | + &gen_op_vr_l##name##_le_64_hypv, \ | |
5597 | +}; | |
5598 | +#define OP_VR_ST_TABLE(name) \ | |
5599 | +static GenOpFunc *gen_op_vr_st##name[] = { \ | |
5600 | + &gen_op_vr_st##name##_user, \ | |
5601 | + &gen_op_vr_st##name##_le_user, \ | |
5602 | + &gen_op_vr_st##name##_64_user, \ | |
5603 | + &gen_op_vr_st##name##_le_64_user, \ | |
5604 | + &gen_op_vr_st##name##_kernel, \ | |
5605 | + &gen_op_vr_st##name##_le_kernel, \ | |
5606 | + &gen_op_vr_st##name##_64_kernel, \ | |
5607 | + &gen_op_vr_st##name##_le_64_kernel, \ | |
5608 | + &gen_op_vr_st##name##_hypv, \ | |
5609 | + &gen_op_vr_st##name##_le_hypv, \ | |
5610 | + &gen_op_vr_st##name##_64_hypv, \ | |
5611 | + &gen_op_vr_st##name##_le_64_hypv, \ | |
5612 | +}; | |
5613 | +#elif defined(TARGET_PPC64) | |
5614 | +/* Full system - 64 bits mode */ | |
5615 | +#define OP_VR_LD_TABLE(name) \ | |
5616 | +static GenOpFunc *gen_op_vr_l##name[] = { \ | |
5617 | + &gen_op_vr_l##name##_user, \ | |
5618 | + &gen_op_vr_l##name##_le_user, \ | |
5619 | + &gen_op_vr_l##name##_64_user, \ | |
5620 | + &gen_op_vr_l##name##_le_64_user, \ | |
5621 | + &gen_op_vr_l##name##_kernel, \ | |
5622 | + &gen_op_vr_l##name##_le_kernel, \ | |
5623 | + &gen_op_vr_l##name##_64_kernel, \ | |
5624 | + &gen_op_vr_l##name##_le_64_kernel, \ | |
5625 | +}; | |
5626 | +#define OP_VR_ST_TABLE(name) \ | |
5627 | +static GenOpFunc *gen_op_vr_st##name[] = { \ | |
5628 | + &gen_op_vr_st##name##_user, \ | |
5629 | + &gen_op_vr_st##name##_le_user, \ | |
5630 | + &gen_op_vr_st##name##_64_user, \ | |
5631 | + &gen_op_vr_st##name##_le_64_user, \ | |
5632 | + &gen_op_vr_st##name##_kernel, \ | |
5633 | + &gen_op_vr_st##name##_le_kernel, \ | |
5634 | + &gen_op_vr_st##name##_64_kernel, \ | |
5635 | + &gen_op_vr_st##name##_le_64_kernel, \ | |
5636 | +}; | |
5637 | +#else /* defined(TARGET_PPC64) */ | |
5638 | +/* Full system - 32 bits mode */ | |
5639 | +#define OP_VR_LD_TABLE(name) \ | |
5640 | +static GenOpFunc *gen_op_vr_l##name[] = { \ | |
5641 | + &gen_op_vr_l##name##_user, \ | |
5642 | + &gen_op_vr_l##name##_le_user, \ | |
5643 | + &gen_op_vr_l##name##_kernel, \ | |
5644 | + &gen_op_vr_l##name##_le_kernel, \ | |
5645 | +}; | |
5646 | +#define OP_VR_ST_TABLE(name) \ | |
5647 | +static GenOpFunc *gen_op_vr_st##name[] = { \ | |
5648 | + &gen_op_vr_st##name##_user, \ | |
5649 | + &gen_op_vr_st##name##_le_user, \ | |
5650 | + &gen_op_vr_st##name##_kernel, \ | |
5651 | + &gen_op_vr_st##name##_le_kernel, \ | |
5652 | +}; | |
5653 | +#endif /* defined(TARGET_PPC64) */ | |
5654 | +#endif /* defined(CONFIG_USER_ONLY) */ | |
5655 | + | |
5656 | +#define GEN_VR_LDX(name, opc2, opc3) \ | |
5657 | +GEN_HANDLER(l##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC) \ | |
5658 | +{ \ | |
5659 | + if (unlikely(!ctx->altivec_enabled)) { \ | |
5660 | + GEN_EXCP_NO_VR(ctx); \ | |
5661 | + return; \ | |
5662 | + } \ | |
5663 | + gen_addr_reg_index(ctx); \ | |
5664 | + op_vr_ldst(vr_l##name); \ | |
5665 | + gen_op_store_A0_avr(rD(ctx->opcode)); \ | |
5666 | +} | |
5667 | + | |
5668 | +#define GEN_VR_STX(name, opc2, opc3) \ | |
5669 | +GEN_HANDLER(st##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC) \ | |
5670 | +{ \ | |
5671 | + if (unlikely(!ctx->altivec_enabled)) { \ | |
5672 | + GEN_EXCP_NO_VR(ctx); \ | |
5673 | + return; \ | |
5674 | + } \ | |
5675 | + gen_addr_reg_index(ctx); \ | |
5676 | + gen_op_load_avr_A0(rS(ctx->opcode)); \ | |
5677 | + op_vr_ldst(vr_st##name); \ | |
5678 | +} | |
5679 | + | |
5680 | +OP_VR_LD_TABLE(vx); | |
5681 | +GEN_VR_LDX(vx, 0x07, 0x03); | |
5682 | +/* As we don't emulate the cache, lvxl is stricly equivalent to lvx */ | |
5683 | +#define gen_op_vr_lvxl gen_op_vr_lvx | |
5684 | +GEN_VR_LDX(vxl, 0x07, 0x0B); | |
5685 | + | |
5686 | +OP_VR_ST_TABLE(vx); | |
5687 | +GEN_VR_STX(vx, 0x07, 0x07); | |
5688 | +/* As we don't emulate the cache, stvxl is stricly equivalent to stvx */ | |
5689 | +#define gen_op_vr_stvxl gen_op_vr_stvx | |
5690 | +GEN_VR_STX(vxl, 0x07, 0x0F); | |
5691 | + | |
5533 | 5692 | #if defined(TARGET_PPCEMB) |
5534 | 5693 | /*** SPE extension ***/ |
5535 | 5694 | |
... | ... | @@ -6553,11 +6712,15 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, |
6553 | 6712 | ctx.dcache_line_size = env->dcache_line_size; |
6554 | 6713 | ctx.fpu_enabled = msr_fp; |
6555 | 6714 | #if defined(TARGET_PPCEMB) |
6556 | - if (env->flags & POWERPC_FLAG_SPE) | |
6715 | + if ((env->flags & POWERPC_FLAG_SPE) && msr_spe) | |
6557 | 6716 | ctx.spe_enabled = msr_spe; |
6558 | 6717 | else |
6559 | 6718 | ctx.spe_enabled = 0; |
6560 | 6719 | #endif |
6720 | + if ((env->flags & POWERPC_FLAG_VRE) && msr_vr) | |
6721 | + ctx.altivec_enabled = msr_vr; | |
6722 | + else | |
6723 | + ctx.altivec_enabled = 0; | |
6561 | 6724 | if ((env->flags & POWERPC_FLAG_SE) && msr_se) |
6562 | 6725 | single_step = 1; |
6563 | 6726 | else | ... | ... |