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