From 8a269ca4167b43cbf1acaf51929f3f5919edcd1e Mon Sep 17 00:00:00 2001 From: Andreas Färber Date: Wed, 22 Aug 2012 05:48:44 +0000 Subject: MAINTAINERS: Document sPAPR (pSeries) machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreas Färber Acked-by: David Gibson Signed-off-by: Alexander Graf --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 29aac4fce..af7c7db81 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -374,6 +374,13 @@ S: Odd Fixes F: hw/ppc_prep.c F: hw/prep_pci.[hc] +sPAPR +M: David Gibson +M: Alexander Graf +L: qemu-ppc@nongnu.org +S: Supported +F: hw/spapr* + SH4 Machines ------------ R2D -- cgit v1.2.3 From 98cded3a05de6a3295e89cc149ff267f1619bdc4 Mon Sep 17 00:00:00 2001 From: Andreas Färber Date: Wed, 22 Aug 2012 05:48:45 +0000 Subject: MAINTAINERS: Document e500 machines and devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreas Färber Cc: Alexander Graf Cc: Scott Wood Signed-off-by: Alexander Graf --- MAINTAINERS | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index af7c7db81..cfb73944c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -352,6 +352,22 @@ L: qemu-ppc@nongnu.org S: Maintained F: hw/ppc405_boards.c +e500 +M: Alexander Graf +M: Scott Wood +L: qemu-ppc@nongnu.org +S: Supported +F: hw/ppc/e500.[hc] +F: hw/ppc/e500plat.c + +mpc8544ds +M: Alexander Graf +M: Scott Wood +L: qemu-ppc@nongnu.org +S: Supported +F: hw/ppc/mpc8544ds.c +F: hw/mpc8544_guts.c + New World M: Alexander Graf L: qemu-ppc@nongnu.org @@ -464,6 +480,13 @@ S: Supported F: hw/pci* F: hw/piix* +ppce500 +M: Alexander Graf +M: Scott Wood +L: qemu-ppc@nongnu.org +S: Supported +F: hw/ppce500_* + SCSI M: Paolo Bonzini S: Supported -- cgit v1.2.3 From 9b9fe13540d2375a109c1d17b53d240a592e442d Mon Sep 17 00:00:00 2001 From: Andreas Färber Date: Wed, 22 Aug 2012 05:48:46 +0000 Subject: MAINTAINERS: Downgrade ppc405 to Odd Fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As requested by Alex. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index cfb73944c..9d4ccfce7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -349,7 +349,7 @@ PowerPC Machines 405 M: Alexander Graf L: qemu-ppc@nongnu.org -S: Maintained +S: Odd Fixes F: hw/ppc405_boards.c e500 -- cgit v1.2.3 From aaade8d7d4d2a3d9b7fb99b198369b1b35a75450 Mon Sep 17 00:00:00 2001 From: Andreas Färber Date: Wed, 22 Aug 2012 05:48:47 +0000 Subject: MAINTAINERS: Document Bamboo machine and ppc4xx devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Place it in alphabetical order and add new Devices section ppc4xx to share file rules with 405 and virtex_ml507. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- MAINTAINERS | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 9d4ccfce7..dca8753ee 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -352,6 +352,12 @@ L: qemu-ppc@nongnu.org S: Odd Fixes F: hw/ppc405_boards.c +Bamboo +M: Alexander Graf +L: qemu-ppc@nongnu.org +S: Odd Fixes +F: hw/ppc440_bamboo.c + e500 M: Alexander Graf M: Scott Wood @@ -480,6 +486,12 @@ S: Supported F: hw/pci* F: hw/piix* +ppc4xx +M: Alexander Graf +L: qemu-ppc@nongnu.org +S: Odd Fixes +F: hw/ppc4xx*.[hc] + ppce500 M: Alexander Graf M: Scott Wood -- cgit v1.2.3 From 794d00bfc7c38cfc559fbec137ecd0117b40e77b Mon Sep 17 00:00:00 2001 From: Andreas Färber Date: Wed, 22 Aug 2012 05:48:48 +0000 Subject: MAINTAINERS: Document virtex_ml507 machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Place it in alphabetical order, there is a separate section for sharing ppc4xx devices now. Signed-off-by: Andreas Färber Acked-by: Edgar E. Iglesias Signed-off-by: Alexander Graf --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index dca8753ee..78d4ff227 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -403,6 +403,12 @@ L: qemu-ppc@nongnu.org S: Supported F: hw/spapr* +virtex_ml507 +M: Edgar E. Iglesias +L: qemu-ppc@nongnu.org +S: Odd Fixes +F: hw/virtex_ml507.c + SH4 Machines ------------ R2D -- cgit v1.2.3 From ef9bd1507b60edba0619e16f1179b158eac2c3ac Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 11 Sep 2012 08:47:10 +0000 Subject: target-ppc: simplify NaN propagation for vector functions Commit e024e881bb1a8b5085026589360d26ed97acdd64 provided a pickNaN() function for PowerPC, implementing the correct NaN propagation rules. Therefore there is no need to test the operands manually, we can rely on the softfloat code to do that. Signed-off-by: Aurelien Jarno Signed-off-by: Alexander Graf --- target-ppc/int_helper.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index f638b2a07..5b2a3c879 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -409,9 +409,7 @@ VARITH(uwm, u32) int i; \ \ for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ - HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \ - r->f[i] = func(a->f[i], b->f[i], &env->vec_status); \ - } \ + r->f[i] = func(a->f[i], b->f[i], &env->vec_status); \ } \ } VARITHFP(addfp, float32_add) @@ -1039,9 +1037,7 @@ void helper_vrefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b) int i; for (i = 0; i < ARRAY_SIZE(r->f); i++) { - HANDLE_NAN1(r->f[i], b->f[i]) { - r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status); - } + r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status); } } @@ -1054,9 +1050,7 @@ void helper_vrefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b) \ set_float_rounding_mode(rounding, &s); \ for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ - HANDLE_NAN1(r->f[i], b->f[i]) { \ - r->f[i] = float32_round_to_int (b->f[i], &s); \ - } \ + r->f[i] = float32_round_to_int (b->f[i], &s); \ } \ } VRFI(n, float_round_nearest_even) @@ -1089,11 +1083,9 @@ void helper_vrsqrtefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b) int i; for (i = 0; i < ARRAY_SIZE(r->f); i++) { - HANDLE_NAN1(r->f[i], b->f[i]) { - float32 t = float32_sqrt(b->f[i], &env->vec_status); + float32 t = float32_sqrt(b->f[i], &env->vec_status); - r->f[i] = float32_div(float32_one, t, &env->vec_status); - } + r->f[i] = float32_div(float32_one, t, &env->vec_status); } } @@ -1109,9 +1101,7 @@ void helper_vexptefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b) int i; for (i = 0; i < ARRAY_SIZE(r->f); i++) { - HANDLE_NAN1(r->f[i], b->f[i]) { - r->f[i] = float32_exp2(b->f[i], &env->vec_status); - } + r->f[i] = float32_exp2(b->f[i], &env->vec_status); } } @@ -1120,9 +1110,7 @@ void helper_vlogefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b) int i; for (i = 0; i < ARRAY_SIZE(r->f); i++) { - HANDLE_NAN1(r->f[i], b->f[i]) { - r->f[i] = float32_log2(b->f[i], &env->vec_status); - } + r->f[i] = float32_log2(b->f[i], &env->vec_status); } } -- cgit v1.2.3 From db1babb8dbb6d18433a51f1b4c3d186ea7057a6f Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 11 Sep 2012 08:47:11 +0000 Subject: target-ppc: use the softfloat min/max functions Use the new softfloat float32_min() and float32_max() to implement the vminfp and vmaxfp instructions. As a bonus we can get rid of the call to the HANDLE_NAN2 macro, as the NaN handling is directly done at the softfloat level. Signed-off-by: Aurelien Jarno Signed-off-by: Alexander Graf --- target-ppc/int_helper.c | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 5b2a3c879..61412433d 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -414,6 +414,8 @@ VARITH(uwm, u32) } VARITHFP(addfp, float32_add) VARITHFP(subfp, float32_sub) +VARITHFP(minfp, float32_min) +VARITHFP(maxfp, float32_max) #undef VARITHFP #define VARITHSAT_CASE(type, op, cvt, element) \ @@ -728,27 +730,6 @@ VMINMAX(uw, u32) #undef VMINMAX_DO #undef VMINMAX -#define VMINMAXFP(suffix, rT, rF) \ - void helper_v##suffix(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \ - ppc_avr_t *b) \ - { \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ - HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \ - if (float32_lt_quiet(a->f[i], b->f[i], \ - &env->vec_status)) { \ - r->f[i] = rT->f[i]; \ - } else { \ - r->f[i] = rF->f[i]; \ - } \ - } \ - } \ - } -VMINMAXFP(minfp, a, b) -VMINMAXFP(maxfp, b, a) -#undef VMINMAXFP - void helper_vmladduhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { int i; -- cgit v1.2.3 From 2f93c23fe71420e5095f2fae1877fe747ad9f876 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 11 Sep 2012 08:47:12 +0000 Subject: target-ppc: use the softfloat float32_muladd function Use the new softfloat float32_muladd() function to implement the vmaddfp and vnmsubfp instructions. As a bonus we can get rid of the call to the HANDLE_NAN3 macro, as the NaN handling is directly done at the softfloat level. Signed-off-by: Aurelien Jarno Signed-off-by: Alexander Graf --- target-ppc/int_helper.c | 57 ++++++++++++------------------------------------- 1 file changed, 14 insertions(+), 43 deletions(-) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 61412433d..6f9beffb2 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -418,6 +418,20 @@ VARITHFP(minfp, float32_min) VARITHFP(maxfp, float32_max) #undef VARITHFP +#define VARITHFPFMA(suffix, type) \ + void helper_v##suffix(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \ + ppc_avr_t *b, ppc_avr_t *c) \ + { \ + int i; \ + for (i = 0; i < ARRAY_SIZE(r->f); i++) { \ + r->f[i] = float32_muladd(a->f[i], c->f[i], b->f[i], \ + type, &env->vec_status); \ + } \ + } +VARITHFPFMA(maddfp, 0); +VARITHFPFMA(nmsubfp, float_muladd_negate_result | float_muladd_negate_c); +#undef VARITHFPFMA + #define VARITHSAT_CASE(type, op, cvt, element) \ { \ type result = (type)a->element[i] op (type)b->element[i]; \ @@ -649,27 +663,6 @@ VCT(uxs, cvtsduw, u32) VCT(sxs, cvtsdsw, s32) #undef VCT -void helper_vmaddfp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, - ppc_avr_t *c) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(r->f); i++) { - HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) { - /* Need to do the computation in higher precision and round - * once at the end. */ - float64 af, bf, cf, t; - - af = float32_to_float64(a->f[i], &env->vec_status); - bf = float32_to_float64(b->f[i], &env->vec_status); - cf = float32_to_float64(c->f[i], &env->vec_status); - t = float64_mul(af, cf, &env->vec_status); - t = float64_add(t, bf, &env->vec_status); - r->f[i] = float64_to_float32(t, &env->vec_status); - } - } -} - void helper_vmhaddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { @@ -909,28 +902,6 @@ VMUL(uh, u16, u32) #undef VMUL_DO #undef VMUL -void helper_vnmsubfp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, - ppc_avr_t *b, ppc_avr_t *c) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(r->f); i++) { - HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) { - /* Need to do the computation is higher precision and round - * once at the end. */ - float64 af, bf, cf, t; - - af = float32_to_float64(a->f[i], &env->vec_status); - bf = float32_to_float64(b->f[i], &env->vec_status); - cf = float32_to_float64(c->f[i], &env->vec_status); - t = float64_mul(af, cf, &env->vec_status); - t = float64_sub(t, bf, &env->vec_status); - t = float64_chs(t); - r->f[i] = float64_to_float32(t, &env->vec_status); - } - } -} - void helper_vperm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { -- cgit v1.2.3 From 89243b3b0183471a373d1457e7f93811773b64a7 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 11 Sep 2012 08:47:13 +0000 Subject: target-ppc: get rid of the HANDLE_NAN{1, 2, 3} macros We can finally get rid of the ugly HANDLE_NAN{1,2,3} macros. Signed-off-by: Aurelien Jarno Signed-off-by: Alexander Graf --- target-ppc/int_helper.c | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 6f9beffb2..f39b4f682 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -287,23 +287,6 @@ target_ulong helper_602_mfrom(target_ulong arg) for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--) #endif -/* If X is a NaN, store the corresponding QNaN into RESULT. Otherwise, - * execute the following block. */ -#define DO_HANDLE_NAN(result, x) \ - if (float32_is_any_nan(x)) { \ - CPU_FloatU __f; \ - __f.f = x; \ - __f.l = __f.l | (1 << 22); /* Set QNaN bit. */ \ - result = __f.f; \ - } else - -#define HANDLE_NAN1(result, x) \ - DO_HANDLE_NAN(result, x) -#define HANDLE_NAN2(result, x, y) \ - DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) -#define HANDLE_NAN3(result, x, y, z) \ - DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) DO_HANDLE_NAN(result, z) - /* Saturating arithmetic helpers. */ #define SATCVT(from, to, from_type, to_type, min, max) \ static inline to_type cvt##from##to(from_type x, int *sat) \ @@ -1413,10 +1396,6 @@ VUPK(lsh, s32, s16, UPKLO) #undef UPKHI #undef UPKLO -#undef DO_HANDLE_NAN -#undef HANDLE_NAN1 -#undef HANDLE_NAN2 -#undef HANDLE_NAN3 #undef VECTOR_FOR_INORDER_I #undef HI_IDX #undef LO_IDX -- cgit v1.2.3 From f1af19d767073a0926ce12c19b1f06c4933bca35 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Sep 2012 16:57:09 +0000 Subject: ppc: Make kvm_arch_put_registers() put *all* the registers At least when invoked with high enough 'level' arguments, kvm_arch_put_registers() is supposed to copy essentially all the cpu state as encoded in qemu's internal structures into the kvm state. Currently the ppc version does not do this - it never calls KVM_SET_SREGS, for example, and therefore never sets the SDR1 and various other important though rarely changed registers. Instead, the code paths which need to set these registers need to explicitly make (conditional) kvm calls which transfer the changes to kvm. This breaks the usual model of handling state updates in qemu, where code just changes the internal model and has it flushed out to kvm automatically at some later point. This patch fixes this for Book S ppc CPUs by adding a suitable call to KVM_SET_SREGS and als to KVM_SET_ONE_REG to set the HIOR (the only register that is set with that call so far). This lets us remove the hacks to explicitly set these registers from the kvmppc_set_papr() function. The problem still exists for Book E CPUs (which use a different version of the kvm_sregs structure). But fixing that has some complications of its own so can be left to another day. Lkewise, there is still some ugly code for setting the PVR through special calls to SET_SREGS which is left in for now. The PVR needs to be set especially early because it can affect what other features are available on the CPU, so I need to do more thinking to see if it can be integrated into the normal paths or not. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/kvm.c | 89 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 50 insertions(+), 39 deletions(-) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index a31d278a5..1a7489bac 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -60,6 +60,7 @@ static int cap_booke_sregs; static int cap_ppc_smt; static int cap_ppc_rma; static int cap_spapr_tce; +static int cap_hior; /* XXX We have a race condition where we actually have a level triggered * interrupt, but the infrastructure can't expose that yet, so the guest @@ -86,6 +87,7 @@ int kvm_arch_init(KVMState *s) cap_ppc_smt = kvm_check_extension(s, KVM_CAP_PPC_SMT); cap_ppc_rma = kvm_check_extension(s, KVM_CAP_PPC_RMA); cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE); + cap_hior = kvm_check_extension(s, KVM_CAP_PPC_HIOR); if (!cap_interrupt_level) { fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the " @@ -469,6 +471,53 @@ int kvm_arch_put_registers(CPUPPCState *env, int level) env->tlb_dirty = false; } + if (cap_segstate && (level >= KVM_PUT_RESET_STATE)) { + struct kvm_sregs sregs; + + sregs.pvr = env->spr[SPR_PVR]; + + sregs.u.s.sdr1 = env->spr[SPR_SDR1]; + + /* Sync SLB */ +#ifdef TARGET_PPC64 + for (i = 0; i < 64; i++) { + sregs.u.s.ppc64.slb[i].slbe = env->slb[i].esid; + sregs.u.s.ppc64.slb[i].slbv = env->slb[i].vsid; + } +#endif + + /* Sync SRs */ + for (i = 0; i < 16; i++) { + sregs.u.s.ppc32.sr[i] = env->sr[i]; + } + + /* Sync BATs */ + for (i = 0; i < 8; i++) { + sregs.u.s.ppc32.dbat[i] = ((uint64_t)env->DBAT[1][i] << 32) + | env->DBAT[0][i]; + sregs.u.s.ppc32.ibat[i] = ((uint64_t)env->IBAT[1][i] << 32) + | env->IBAT[0][i]; + } + + ret = kvm_vcpu_ioctl(env, KVM_SET_SREGS, &sregs); + if (ret) { + return ret; + } + } + + if (cap_hior && (level >= KVM_PUT_RESET_STATE)) { + uint64_t hior = env->spr[SPR_HIOR]; + struct kvm_one_reg reg = { + .id = KVM_REG_PPC_HIOR, + .addr = (uintptr_t) &hior, + }; + + ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, ®); + if (ret) { + return ret; + } + } + return ret; } @@ -946,52 +995,14 @@ int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len) void kvmppc_set_papr(CPUPPCState *env) { struct kvm_enable_cap cap = {}; - struct kvm_one_reg reg = {}; - struct kvm_sregs sregs = {}; int ret; - uint64_t hior = env->spr[SPR_HIOR]; cap.cap = KVM_CAP_PPC_PAPR; ret = kvm_vcpu_ioctl(env, KVM_ENABLE_CAP, &cap); if (ret) { - goto fail; - } - - /* - * XXX We set HIOR here. It really should be a qdev property of - * the CPU node, but we don't have CPUs converted to qdev yet. - * - * Once we have qdev CPUs, move HIOR to a qdev property and - * remove this chunk. - */ - reg.id = KVM_REG_PPC_HIOR; - reg.addr = (uintptr_t)&hior; - ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, ®); - if (ret) { - fprintf(stderr, "Couldn't set HIOR. Maybe you're running an old \n" - "kernel with support for HV KVM but no PAPR PR \n" - "KVM in which case things will work. If they don't \n" - "please update your host kernel!\n"); - } - - /* Set SDR1 so kernel space finds the HTAB */ - ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs); - if (ret) { - goto fail; - } - - sregs.u.s.sdr1 = env->spr[SPR_SDR1]; - - ret = kvm_vcpu_ioctl(env, KVM_SET_SREGS, &sregs); - if (ret) { - goto fail; + cpu_abort(env, "This KVM version does not support PAPR\n"); } - - return; - -fail: - cpu_abort(env, "This KVM version does not support PAPR\n"); } int kvmppc_smt_threads(void) -- cgit v1.2.3 From 048706d971c1830d7813052ca027ae00c519e894 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Sep 2012 16:57:10 +0000 Subject: pseries: Fix and cleanup CPU initialization and reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current pseries machine init function iterates over the CPUs at several points, doing various bits of initialization. This is messy; these can and should be merged into a single iteration doing all the necessary per cpu initialization. Worse, some of these initializations were setting up state which should be set on every reset, not just at machine init time. A few of the initializations simply weren't necessary at all. This patch, therefore, moves those things that need to be to the per-cpu reset handler, and combines the remainder into two loops over the cpus (which also creates them). The second loop is for setting up hash table information, and will be removed in a subsequent patch also making other fixes to the hash table setup. This exposes a bug in our start-cpu RTAS routine (called by the guest to start up CPUs other than CPU0) under kvm. Previously, this function did not make a call to ensure that it's changes to the new cpu's state were pushed into KVM in-kernel state. We sort-of got away with this because some of the initializations had already placed the secondary CPUs into the right starting state for the sorts of Linux guests we've been running. Nonetheless the start-cpu RTAS call's behaviour was not correct and could easily have been broken by guest changes. This patch also fixes it. Signed-off-by: David Gibson Reviewed-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/spapr.c | 34 ++++++++++++++++++++-------------- hw/spapr_rtas.c | 5 +++++ 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/hw/spapr.c b/hw/spapr.c index c34b767c6..d88525aad 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -581,8 +581,16 @@ static void spapr_reset(void *opaque) static void spapr_cpu_reset(void *opaque) { PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; cpu_reset(CPU(cpu)); + + /* All CPUs start halted. CPU0 is unhalted from the machine level + * reset code and the rest are explicitly started up by the guest + * using an RTAS call */ + env->halted = 1; + + env->spr[SPR_HIOR] = 0; } /* Returns whether we want to use VGA or not */ @@ -665,11 +673,16 @@ static void ppc_spapr_init(ram_addr_t ram_size, /* Set time-base frequency to 512 MHz */ cpu_ppc_tb_init(env, TIMEBASE_FREQ); - qemu_register_reset(spapr_cpu_reset, cpu); - env->hreset_vector = 0x60; + /* PAPR always has exception vectors in RAM not ROM */ env->hreset_excp_prefix = 0; - env->gpr[3] = env->cpu_index; + + /* Tell KVM that we're in PAPR mode */ + if (kvm_enabled()) { + kvmppc_set_papr(env); + } + + qemu_register_reset(spapr_cpu_reset, cpu); } /* allocate RAM */ @@ -685,7 +698,10 @@ static void ppc_spapr_init(ram_addr_t ram_size, /* allocate hash page table. For now we always make this 16mb, * later we should probably make it scale to the size of guest - * RAM */ + * RAM. FIXME: setting the htab information in the CPU env really + * belongs at CPU reset time, but we can get away with it for now + * because the PAPR guest is not permitted to write SDR1 so in + * fact these settings will never change during the run */ spapr->htab_size = 1ULL << (pteg_shift + 7); spapr->htab = qemu_memalign(spapr->htab_size, spapr->htab_size); @@ -697,11 +713,6 @@ static void ppc_spapr_init(ram_addr_t ram_size, /* Tell KVM that we're in PAPR mode */ env->spr[SPR_SDR1] = (unsigned long)spapr->htab | ((pteg_shift + 7) - 18); - env->spr[SPR_HIOR] = 0; - - if (kvm_enabled()) { - kvmppc_set_papr(env); - } } filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin"); @@ -827,11 +838,6 @@ static void ppc_spapr_init(ram_addr_t ram_size, spapr->entry_point = 0x100; - /* SLOF will startup the secondary CPUs using RTAS */ - for (env = first_cpu; env != NULL; env = env->next_cpu) { - env->halted = 1; - } - /* Prepare the device tree */ spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, rma_size, initrd_base, initrd_size, diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c index ae1859515..b808f8001 100644 --- a/hw/spapr_rtas.c +++ b/hw/spapr_rtas.c @@ -184,6 +184,11 @@ static void rtas_start_cpu(sPAPREnvironment *spapr, return; } + /* This will make sure qemu state is up to date with kvm, and + * mark it dirty so our changes get flushed back before the + * new cpu enters */ + kvm_cpu_synchronize_state(env); + env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME); env->nip = start; env->gpr[3] = r3; -- cgit v1.2.3 From c8787ad477f3be5a971b877dcb1bae5752c5796a Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Sep 2012 16:57:11 +0000 Subject: pseries: Use new method to correct reset sequence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A number of things need to occur during reset of the PAPR paravirtualized platform in a specific order. For example, the hash table needs to be cleared before the CPUs are reset, so that they initialize their register state correctly, and the CPUs need to have their main reset called before we set up the entry point state on the boot cpu. We also need to have the main qdev reset happen before the creation and installation of the device tree for the new boot, because we need the state of the devices settled to correctly construct the device tree. We currently do the pseries once-per-reset initializations done from a reset handler. However we can't adequately control when this handler is called during the reset - in particular we can't guarantee it happens after all the qdev resets (since qdevs might be registered after the machine init function has executed). This patch uses the new QEMUMachine reset method to to fix this problem, ensuring the various order dependent reset steps happen in the correct order. Signed-off-by: David Gibson Reviewed-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/spapr.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/hw/spapr.c b/hw/spapr.c index d88525aad..68542e89b 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -559,13 +559,13 @@ static void emulate_spapr_hypercall(CPUPPCState *env) env->gpr[3] = spapr_hypercall(env, env->gpr[3], &env->gpr[4]); } -static void spapr_reset(void *opaque) +static void ppc_spapr_reset(void) { - sPAPREnvironment *spapr = (sPAPREnvironment *)opaque; - /* flush out the hash table */ memset(spapr->htab, 0, spapr->htab_size); + qemu_devices_reset(); + /* Load the fdt */ spapr_finalize_fdt(spapr, spapr->fdt_addr, spapr->rtas_addr, spapr->rtas_size); @@ -845,14 +845,13 @@ static void ppc_spapr_init(ram_addr_t ram_size, boot_device, kernel_cmdline, pteg_shift + 7); assert(spapr->fdt_skel != NULL); - - qemu_register_reset(spapr_reset, spapr); } static QEMUMachine spapr_machine = { .name = "pseries", .desc = "pSeries Logical Partition (PAPR compliant)", .init = ppc_spapr_init, + .reset = ppc_spapr_reset, .max_cpus = MAX_CPUS, .no_parallel = 1, .use_scsi = 1, -- cgit v1.2.3 From 7f763a5d994bbddb50705d2e50decdf52937521f Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Sep 2012 16:57:12 +0000 Subject: pseries: Add support for new KVM hash table control call This adds support for then new "reset htab" ioctl which allows qemu to properly cleanup the MMU hash table when the guest is reset. With the corresponding kernel support, reset of a guest now works properly. This also paves the way for indicating a different size hash table to the kernel and for the kernel to be able to impose limits on the requested size. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr.c | 274 ++++++++++++++++++++++++++++++--------------------- hw/spapr.h | 4 +- target-ppc/kvm.c | 29 ++++++ target-ppc/kvm_ppc.h | 19 ++++ 4 files changed, 213 insertions(+), 113 deletions(-) diff --git a/hw/spapr.c b/hw/spapr.c index 68542e89b..0a0e9cddc 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -85,6 +85,8 @@ #define PHANDLE_XICP 0x00001111 +#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift)) + sPAPREnvironment *spapr; int spapr_allocate_irq(int hint, enum xics_irq_type type) @@ -134,12 +136,13 @@ int spapr_allocate_irq_block(int num, enum xics_irq_type type) return first; } -static int spapr_set_associativity(void *fdt, sPAPREnvironment *spapr) +static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr) { int ret = 0, offset; CPUPPCState *env; char cpu_model[32]; int smt = kvmppc_smt_threads(); + uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)}; assert(spapr->cpu_model); @@ -163,8 +166,16 @@ static int spapr_set_associativity(void *fdt, sPAPREnvironment *spapr) return offset; } - ret = fdt_setprop(fdt, offset, "ibm,associativity", associativity, - sizeof(associativity)); + if (nb_numa_nodes > 1) { + ret = fdt_setprop(fdt, offset, "ibm,associativity", associativity, + sizeof(associativity)); + if (ret < 0) { + return ret; + } + } + + ret = fdt_setprop(fdt, offset, "ibm,pft-size", + pft_size_prop, sizeof(pft_size_prop)); if (ret < 0) { return ret; } @@ -206,45 +217,36 @@ static size_t create_page_sizes_prop(CPUPPCState *env, uint32_t *prop, return (p - prop) * sizeof(uint32_t); } +#define _FDT(exp) \ + do { \ + int ret = (exp); \ + if (ret < 0) { \ + fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \ + #exp, fdt_strerror(ret)); \ + exit(1); \ + } \ + } while (0) + + static void *spapr_create_fdt_skel(const char *cpu_model, - target_phys_addr_t rma_size, target_phys_addr_t initrd_base, target_phys_addr_t initrd_size, target_phys_addr_t kernel_size, const char *boot_device, - const char *kernel_cmdline, - long hash_shift) + const char *kernel_cmdline) { void *fdt; CPUPPCState *env; - uint64_t mem_reg_property[2]; uint32_t start_prop = cpu_to_be32(initrd_base); uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size); - uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)}; char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt" "\0hcall-tce\0hcall-vio\0hcall-splpar\0hcall-bulk"; char qemu_hypertas_prop[] = "hcall-memop1"; + uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)}; uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)}; - int i; char *modelname; - int smt = kvmppc_smt_threads(); + int i, smt = kvmppc_smt_threads(); unsigned char vec5[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x80}; - uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)}; - uint32_t associativity[] = {cpu_to_be32(0x4), cpu_to_be32(0x0), - cpu_to_be32(0x0), cpu_to_be32(0x0), - cpu_to_be32(0x0)}; - char mem_name[32]; - target_phys_addr_t node0_size, mem_start; - -#define _FDT(exp) \ - do { \ - int ret = (exp); \ - if (ret < 0) { \ - fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \ - #exp, fdt_strerror(ret)); \ - exit(1); \ - } \ - } while (0) fdt = g_malloc0(FDT_MAX_SIZE); _FDT((fdt_create(fdt, FDT_MAX_SIZE))); @@ -289,55 +291,6 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_end_node(fdt))); - /* memory node(s) */ - node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size; - if (rma_size > node0_size) { - rma_size = node0_size; - } - - /* RMA */ - mem_reg_property[0] = 0; - mem_reg_property[1] = cpu_to_be64(rma_size); - _FDT((fdt_begin_node(fdt, "memory@0"))); - _FDT((fdt_property_string(fdt, "device_type", "memory"))); - _FDT((fdt_property(fdt, "reg", mem_reg_property, - sizeof(mem_reg_property)))); - _FDT((fdt_property(fdt, "ibm,associativity", associativity, - sizeof(associativity)))); - _FDT((fdt_end_node(fdt))); - - /* RAM: Node 0 */ - if (node0_size > rma_size) { - mem_reg_property[0] = cpu_to_be64(rma_size); - mem_reg_property[1] = cpu_to_be64(node0_size - rma_size); - - sprintf(mem_name, "memory@" TARGET_FMT_lx, rma_size); - _FDT((fdt_begin_node(fdt, mem_name))); - _FDT((fdt_property_string(fdt, "device_type", "memory"))); - _FDT((fdt_property(fdt, "reg", mem_reg_property, - sizeof(mem_reg_property)))); - _FDT((fdt_property(fdt, "ibm,associativity", associativity, - sizeof(associativity)))); - _FDT((fdt_end_node(fdt))); - } - - /* RAM: Node 1 and beyond */ - mem_start = node0_size; - for (i = 1; i < nb_numa_nodes; i++) { - mem_reg_property[0] = cpu_to_be64(mem_start); - mem_reg_property[1] = cpu_to_be64(node_mem[i]); - associativity[3] = associativity[4] = cpu_to_be32(i); - sprintf(mem_name, "memory@" TARGET_FMT_lx, mem_start); - _FDT((fdt_begin_node(fdt, mem_name))); - _FDT((fdt_property_string(fdt, "device_type", "memory"))); - _FDT((fdt_property(fdt, "reg", mem_reg_property, - sizeof(mem_reg_property)))); - _FDT((fdt_property(fdt, "ibm,associativity", associativity, - sizeof(associativity)))); - _FDT((fdt_end_node(fdt))); - mem_start += node_mem[i]; - } - /* cpus */ _FDT((fdt_begin_node(fdt, "cpus"))); @@ -389,8 +342,6 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_property_cell(fdt, "timebase-frequency", tbfreq))); _FDT((fdt_property_cell(fdt, "clock-frequency", cpufreq))); _FDT((fdt_property_cell(fdt, "ibm,slb-size", env->slb_nr))); - _FDT((fdt_property(fdt, "ibm,pft-size", - pft_size_prop, sizeof(pft_size_prop)))); _FDT((fdt_property_string(fdt, "status", "okay"))); _FDT((fdt_property(fdt, "64-bit", NULL, 0))); @@ -489,6 +440,68 @@ static void *spapr_create_fdt_skel(const char *cpu_model, return fdt; } +static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt) +{ + uint32_t associativity[] = {cpu_to_be32(0x4), cpu_to_be32(0x0), + cpu_to_be32(0x0), cpu_to_be32(0x0), + cpu_to_be32(0x0)}; + char mem_name[32]; + target_phys_addr_t node0_size, mem_start; + uint64_t mem_reg_property[2]; + int i, off; + + /* memory node(s) */ + node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size; + if (spapr->rma_size > node0_size) { + spapr->rma_size = node0_size; + } + + /* RMA */ + mem_reg_property[0] = 0; + mem_reg_property[1] = cpu_to_be64(spapr->rma_size); + off = fdt_add_subnode(fdt, 0, "memory@0"); + _FDT(off); + _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); + _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property, + sizeof(mem_reg_property)))); + _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity, + sizeof(associativity)))); + + /* RAM: Node 0 */ + if (node0_size > spapr->rma_size) { + mem_reg_property[0] = cpu_to_be64(spapr->rma_size); + mem_reg_property[1] = cpu_to_be64(node0_size - spapr->rma_size); + + sprintf(mem_name, "memory@" TARGET_FMT_lx, spapr->rma_size); + off = fdt_add_subnode(fdt, 0, mem_name); + _FDT(off); + _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); + _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property, + sizeof(mem_reg_property)))); + _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity, + sizeof(associativity)))); + } + + /* RAM: Node 1 and beyond */ + mem_start = node0_size; + for (i = 1; i < nb_numa_nodes; i++) { + mem_reg_property[0] = cpu_to_be64(mem_start); + mem_reg_property[1] = cpu_to_be64(node_mem[i]); + associativity[3] = associativity[4] = cpu_to_be32(i); + sprintf(mem_name, "memory@" TARGET_FMT_lx, mem_start); + off = fdt_add_subnode(fdt, 0, mem_name); + _FDT(off); + _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); + _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property, + sizeof(mem_reg_property)))); + _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity, + sizeof(associativity)))); + mem_start += node_mem[i]; + } + + return 0; +} + static void spapr_finalize_fdt(sPAPREnvironment *spapr, target_phys_addr_t fdt_addr, target_phys_addr_t rtas_addr, @@ -503,6 +516,12 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr, /* open out the base tree into a temp buffer for the final tweaks */ _FDT((fdt_open_into(spapr->fdt_skel, fdt, FDT_MAX_SIZE))); + ret = spapr_populate_memory(spapr, fdt); + if (ret < 0) { + fprintf(stderr, "couldn't setup memory nodes in fdt\n"); + exit(1); + } + ret = spapr_populate_vdevice(spapr->vio_bus, fdt); if (ret < 0) { fprintf(stderr, "couldn't setup vio devices in fdt\n"); @@ -525,11 +544,9 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr, } /* Advertise NUMA via ibm,associativity */ - if (nb_numa_nodes > 1) { - ret = spapr_set_associativity(fdt, spapr); - if (ret < 0) { - fprintf(stderr, "Couldn't set up NUMA device tree properties\n"); - } + ret = spapr_fixup_cpu_dt(fdt, spapr); + if (ret < 0) { + fprintf(stderr, "Couldn't finalize CPU device tree properties\n"); } if (!spapr->has_graphics) { @@ -559,10 +576,39 @@ static void emulate_spapr_hypercall(CPUPPCState *env) env->gpr[3] = spapr_hypercall(env, env->gpr[3], &env->gpr[4]); } +static void spapr_reset_htab(sPAPREnvironment *spapr) +{ + long shift; + + /* allocate hash page table. For now we always make this 16mb, + * later we should probably make it scale to the size of guest + * RAM */ + + shift = kvmppc_reset_htab(spapr->htab_shift); + + if (shift > 0) { + /* Kernel handles htab, we don't need to allocate one */ + spapr->htab_shift = shift; + } else { + if (!spapr->htab) { + /* Allocate an htab if we don't yet have one */ + spapr->htab = qemu_memalign(HTAB_SIZE(spapr), HTAB_SIZE(spapr)); + } + + /* And clear it */ + memset(spapr->htab, 0, HTAB_SIZE(spapr)); + } + + /* Update the RMA size if necessary */ + if (spapr->vrma_adjust) { + spapr->rma_size = kvmppc_rma_size(ram_size, spapr->htab_shift); + } +} + static void ppc_spapr_reset(void) { - /* flush out the hash table */ - memset(spapr->htab, 0, spapr->htab_size); + /* Reset the hash table & recalc the RMA */ + spapr_reset_htab(spapr); qemu_devices_reset(); @@ -591,6 +637,12 @@ static void spapr_cpu_reset(void *opaque) env->halted = 1; env->spr[SPR_HIOR] = 0; + + env->external_htab = spapr->htab; + env->htab_base = -1; + env->htab_mask = HTAB_SIZE(spapr) - 1; + env->spr[SPR_SDR1] = (unsigned long)spapr->htab | + (spapr->htab_shift - 18); } /* Returns whether we want to use VGA or not */ @@ -624,11 +676,10 @@ static void ppc_spapr_init(ram_addr_t ram_size, int i; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); - target_phys_addr_t rma_alloc_size, rma_size; + target_phys_addr_t rma_alloc_size; uint32_t initrd_base = 0; long kernel_size = 0, initrd_size = 0; long load_limit, rtas_limit, fw_size; - long pteg_shift = 17; char *filename; msi_supported = true; @@ -645,20 +696,39 @@ static void ppc_spapr_init(ram_addr_t ram_size, hw_error("qemu: Unable to create RMA\n"); exit(1); } + if (rma_alloc_size && (rma_alloc_size < ram_size)) { - rma_size = rma_alloc_size; + spapr->rma_size = rma_alloc_size; } else { - rma_size = ram_size; + spapr->rma_size = ram_size; + + /* With KVM, we don't actually know whether KVM supports an + * unbounded RMA (PR KVM) or is limited by the hash table size + * (HV KVM using VRMA), so we always assume the latter + * + * In that case, we also limit the initial allocations for RTAS + * etc... to 256M since we have no way to know what the VRMA size + * is going to be as it depends on the size of the hash table + * isn't determined yet. + */ + if (kvm_enabled()) { + spapr->vrma_adjust = 1; + spapr->rma_size = MIN(spapr->rma_size, 0x10000000); + } } /* We place the device tree and RTAS just below either the top of the RMA, * or just below 2GB, whichever is lowere, so that it can be * processed with 32-bit real mode code if necessary */ - rtas_limit = MIN(rma_size, 0x80000000); + rtas_limit = MIN(spapr->rma_size, 0x80000000); spapr->rtas_addr = rtas_limit - RTAS_MAX_SIZE; spapr->fdt_addr = spapr->rtas_addr - FDT_MAX_SIZE; load_limit = spapr->fdt_addr - FW_OVERHEAD; + /* For now, always aim for a 16MB hash table */ + /* FIXME: we should change this default based on RAM size */ + spapr->htab_shift = 24; + /* init CPUs */ if (cpu_model == NULL) { cpu_model = kvm_enabled() ? "host" : "POWER7"; @@ -696,25 +766,6 @@ static void ppc_spapr_init(ram_addr_t ram_size, memory_region_add_subregion(sysmem, nonrma_base, ram); } - /* allocate hash page table. For now we always make this 16mb, - * later we should probably make it scale to the size of guest - * RAM. FIXME: setting the htab information in the CPU env really - * belongs at CPU reset time, but we can get away with it for now - * because the PAPR guest is not permitted to write SDR1 so in - * fact these settings will never change during the run */ - spapr->htab_size = 1ULL << (pteg_shift + 7); - spapr->htab = qemu_memalign(spapr->htab_size, spapr->htab_size); - - for (env = first_cpu; env != NULL; env = env->next_cpu) { - env->external_htab = spapr->htab; - env->htab_base = -1; - env->htab_mask = spapr->htab_size - 1; - - /* Tell KVM that we're in PAPR mode */ - env->spr[SPR_SDR1] = (unsigned long)spapr->htab | - ((pteg_shift + 7) - 18); - } - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin"); spapr->rtas_size = load_image_targphys(filename, spapr->rtas_addr, rtas_limit - spapr->rtas_addr); @@ -787,7 +838,7 @@ static void ppc_spapr_init(ram_addr_t ram_size, } } - if (rma_size < (MIN_RMA_SLOF << 20)) { + if (spapr->rma_size < (MIN_RMA_SLOF << 20)) { fprintf(stderr, "qemu: pSeries SLOF firmware requires >= " "%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF); exit(1); @@ -839,11 +890,10 @@ static void ppc_spapr_init(ram_addr_t ram_size, spapr->entry_point = 0x100; /* Prepare the device tree */ - spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, rma_size, + spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, initrd_base, initrd_size, kernel_size, - boot_device, kernel_cmdline, - pteg_shift + 7); + boot_device, kernel_cmdline); assert(spapr->fdt_skel != NULL); } diff --git a/hw/spapr.h b/hw/spapr.h index ac34a171e..f1fb646a5 100644 --- a/hw/spapr.h +++ b/hw/spapr.h @@ -15,7 +15,9 @@ typedef struct sPAPREnvironment { target_phys_addr_t ram_limit; void *htab; - long htab_size; + long htab_shift; + target_phys_addr_t rma_size; + int vrma_adjust; target_phys_addr_t fdt_addr, rtas_addr; long rtas_size; void *fdt_skel; diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 1a7489bac..546c11604 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -1010,6 +1010,7 @@ int kvmppc_smt_threads(void) return cap_ppc_smt ? cap_ppc_smt : 1; } +#ifdef TARGET_PPC64 off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem) { void *rma; @@ -1053,6 +1054,16 @@ off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem) return size; } +uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift) +{ + if (cap_ppc_rma >= 2) { + return current_size; + } + return MIN(current_size, + getrampagesize() << (hash_shift - 7)); +} +#endif + void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd) { struct kvm_create_spapr_tce args = { @@ -1112,6 +1123,24 @@ int kvmppc_remove_spapr_tce(void *table, int fd, uint32_t window_size) return 0; } +int kvmppc_reset_htab(int shift_hint) +{ + uint32_t shift = shift_hint; + + if (kvm_enabled() && + kvm_check_extension(kvm_state, KVM_CAP_PPC_ALLOC_HTAB)) { + int ret; + ret = kvm_vm_ioctl(kvm_state, KVM_PPC_ALLOCATE_HTAB, &shift); + if (ret < 0) { + return ret; + } + return shift; + } + + /* For now.. */ + return 0; +} + static inline uint32_t mfpvr(void) { uint32_t pvr; diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index e2f870385..baad6eb75 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -27,6 +27,8 @@ int kvmppc_smt_threads(void); off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem); void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd); int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size); +int kvmppc_reset_htab(int shift_hint); +uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift); #endif /* !CONFIG_USER_ONLY */ const ppc_def_t *kvmppc_host_cpu_def(void); int kvmppc_fixup_cpu(CPUPPCState *env); @@ -94,6 +96,23 @@ static inline int kvmppc_remove_spapr_tce(void *table, int pfd, { return -1; } + +static inline int kvmppc_reset_htab(int shift_hint) +{ + return -1; +} + +static inline uint64_t kvmppc_rma_size(uint64_t current_size, + unsigned int hash_shift) +{ + return ram_size; +} + +static inline int kvmppc_update_sdr1(CPUPPCState *env) +{ + return 0; +} + #endif /* !CONFIG_USER_ONLY */ static inline const ppc_def_t *kvmppc_host_cpu_def(void) -- cgit v1.2.3 From 4dd96f244f62d5e4b493c1f4071c0d4a4a57474d Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Sep 2012 16:57:13 +0000 Subject: pseries: Clear TCE and signal state when resetting PAPR VIO devices When we reset the system, the reset method for VIO bus devices resets the state of their request queue (if present) as it should. However it was not resetting the state of their TCE table (DMA translation) if present. It was also not resetting the state of the per-device signal mask set with H_VIO_SIGNAL. This patch corrects both bugs, and also removes some small code duplication in the reset paths. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr_vio.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index 7ca445216..752836e76 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -324,9 +324,7 @@ static void spapr_vio_quiesce_one(VIOsPAPRDevice *dev) } dev->dma = spapr_tce_new_dma_context(liobn, pc->rtce_window_size); - dev->crq.qladdr = 0; - dev->crq.qsize = 0; - dev->crq.qnext = 0; + free_crq(dev); } static void rtas_set_tce_bypass(sPAPREnvironment *spapr, uint32_t token, @@ -409,9 +407,10 @@ static void spapr_vio_busdev_reset(DeviceState *qdev) VIOsPAPRDevice *dev = DO_UPCAST(VIOsPAPRDevice, qdev, qdev); VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); - if (dev->crq.qsize) { - free_crq(dev); - } + /* Shut down the request queue and TCEs if necessary */ + spapr_vio_quiesce_one(dev); + + dev->signal_state = 0; if (pc->reset) { pc->reset(dev); -- cgit v1.2.3 From eddeed26ac83392053aef823a341f643ea8e3d2f Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Sep 2012 16:57:14 +0000 Subject: pseries: Reset emulated PCI TCE tables on system reset The emulated PCI host bridge on the pseries machine incorporates an IOMMU (PAPR TCE table). Currently the mappings in this IOMMU are not cleared when we reset the system. This patch fixes this bug. To do this it adds a new reset function to the IOMMU emulation code. The VIO devices already reset their TCE tables, but they do so by destroying and re-creating their DMA context. This doesn't work for the PCI host bridge, because the infrastructure for PCI IOMMUs has already copied/cached the DMA pointer context into the subordinate PCI device structures. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr.h | 1 + hw/spapr_iommu.c | 11 +++++++++++ hw/spapr_pci.c | 10 ++++++++++ 3 files changed, 22 insertions(+) diff --git a/hw/spapr.h b/hw/spapr.h index f1fb646a5..f9a7b0fa3 100644 --- a/hw/spapr.h +++ b/hw/spapr.h @@ -338,6 +338,7 @@ typedef struct sPAPRTCE { void spapr_iommu_init(void); DMAContext *spapr_tce_new_dma_context(uint32_t liobn, size_t window_size); void spapr_tce_free(DMAContext *dma); +void spapr_tce_reset(DMAContext *dma); int spapr_dma_dt(void *fdt, int node_off, const char *propname, uint32_t liobn, uint64_t window, uint32_t size); int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname, diff --git a/hw/spapr_iommu.c b/hw/spapr_iommu.c index 53b731773..216aa0680 100644 --- a/hw/spapr_iommu.c +++ b/hw/spapr_iommu.c @@ -162,6 +162,17 @@ void spapr_tce_free(DMAContext *dma) } } +void spapr_tce_reset(DMAContext *dma) +{ + if (dma) { + sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma); + size_t table_size = (tcet->window_size >> SPAPR_TCE_PAGE_SHIFT) + * sizeof(sPAPRTCE); + + memset(tcet->table, 0, table_size); + } +} + static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba, target_ulong tce) { diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index 661c05bc3..203155e32 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -595,6 +595,15 @@ static int spapr_phb_init(SysBusDevice *s) return 0; } +static void spapr_phb_reset(DeviceState *qdev) +{ + SysBusDevice *s = sysbus_from_qdev(qdev); + sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s); + + /* Reset the IOMMU state */ + spapr_tce_reset(sphb->dma); +} + static Property spapr_phb_properties[] = { DEFINE_PROP_HEX64("buid", sPAPRPHBState, buid, 0), DEFINE_PROP_STRING("busname", sPAPRPHBState, busname), @@ -613,6 +622,7 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data) sdc->init = spapr_phb_init; dc->props = spapr_phb_properties; + dc->reset = spapr_phb_reset; } static const TypeInfo spapr_phb_info = { -- cgit v1.2.3 From 256b408abea2cfe18d8c0278e5b46213509db271 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Sep 2012 16:57:15 +0000 Subject: pseries: Fix XICS reset The XICS interrupt controller used on the pseries machine currently has no reset handler. We can get away with this under some circumstances, but it's not correct, and can cause failures if the XICS happens to be in the wrong state at the time of reset. This patch adds a hook to properly reset the XICS state. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/xics.c | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/hw/xics.c b/hw/xics.c index b674771dc..a8a08ce02 100644 --- a/hw/xics.c +++ b/hw/xics.c @@ -489,11 +489,36 @@ static void rtas_int_on(sPAPREnvironment *spapr, uint32_t token, rtas_st(rets, 0, 0); /* Success */ } +static void xics_reset(void *opaque) +{ + struct icp_state *icp = (struct icp_state *)opaque; + struct ics_state *ics = icp->ics; + int i; + + for (i = 0; i < icp->nr_servers; i++) { + icp->ss[i].xirr = 0; + icp->ss[i].pending_priority = 0; + icp->ss[i].mfrr = 0xff; + /* Make all outputs are deasserted */ + qemu_set_irq(icp->ss[i].output, 0); + } + + for (i = 0; i < ics->nr_irqs; i++) { + /* Reset everything *except* the type */ + ics->irqs[i].server = 0; + ics->irqs[i].asserted = 0; + ics->irqs[i].sent = 0; + ics->irqs[i].rejected = 0; + ics->irqs[i].masked_pending = 0; + ics->irqs[i].priority = 0xff; + ics->irqs[i].saved_priority = 0xff; + } +} + struct icp_state *xics_system_init(int nr_irqs) { CPUPPCState *env; int max_server_num; - int i; struct icp_state *icp; struct ics_state *ics; @@ -508,10 +533,6 @@ struct icp_state *xics_system_init(int nr_irqs) icp->nr_servers = max_server_num + 1; icp->ss = g_malloc0(icp->nr_servers*sizeof(struct icp_server_state)); - for (i = 0; i < icp->nr_servers; i++) { - icp->ss[i].mfrr = 0xff; - } - for (env = first_cpu; env != NULL; env = env->next_cpu) { struct icp_server_state *ss = &icp->ss[env->cpu_index]; @@ -539,11 +560,6 @@ struct icp_state *xics_system_init(int nr_irqs) icp->ics = ics; ics->icp = icp; - for (i = 0; i < nr_irqs; i++) { - ics->irqs[i].priority = 0xff; - ics->irqs[i].saved_priority = 0xff; - } - ics->qirqs = qemu_allocate_irqs(ics_set_irq, ics, nr_irqs); spapr_register_hypercall(H_CPPR, h_cppr); @@ -556,5 +572,7 @@ struct icp_state *xics_system_init(int nr_irqs) spapr_rtas_register("ibm,int-off", rtas_int_off); spapr_rtas_register("ibm,int-on", rtas_int_on); + qemu_register_reset(xics_reset, icp); + return icp; } -- cgit v1.2.3 From 1dd088946cf464a994bc93945a360aef049493af Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Sep 2012 16:57:16 +0000 Subject: pseries: Small cleanup to H_CEDE implementation The H_CEDE hypercall implementation for the pseries machine doesn't trigger quite the right path in the main cpu exec loop. We should set exit_request to pop up one extra level and recheck state, and we should set the exception_index to EXCP_HLT (H_CEDE is roughly equivalent to the hlt instruction on x86). In practice, this doesn't really matter except for KVM, and KVM implements H_CEDE internally so we never hit this code path. But we might as well get it right, just in case it matters some day. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr_hcall.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c index abd847f96..2df94d197 100644 --- a/hw/spapr_hcall.c +++ b/hw/spapr_hcall.c @@ -544,6 +544,8 @@ static target_ulong h_cede(CPUPPCState *env, sPAPREnvironment *spapr, hreg_compute_hflags(env); if (!cpu_has_work(env)) { env->halted = 1; + env->exception_index = EXCP_HLT; + env->exit_request = 1; } return H_SUCCESS; } -- cgit v1.2.3 From 98ca8c023825fc6dd99e6cea1956d84ed8cadb3a Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Sep 2012 16:57:17 +0000 Subject: pseries: Remove C bitfields from xics code The XICS interrupt controller emulation uses some C bitfield variables in its internal state structure. This makes like awkward for saving the state because we don't have easy VMSTATE helpers for bitfields. This patch removes the bitfields, instead using explicit bit masking in a single status variable. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/xics.c | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/hw/xics.c b/hw/xics.c index a8a08ce02..648af2538 100644 --- a/hw/xics.c +++ b/hw/xics.c @@ -165,11 +165,12 @@ struct ics_irq_state { int server; uint8_t priority; uint8_t saved_priority; +#define XICS_STATUS_ASSERTED 0x1 +#define XICS_STATUS_SENT 0x2 +#define XICS_STATUS_REJECTED 0x4 +#define XICS_STATUS_MASKED_PENDING 0x8 + uint8_t status; enum xics_irq_type type; - int asserted:1; - int sent:1; - int rejected:1; - int masked_pending:1; }; struct ics_state { @@ -191,8 +192,8 @@ static void resend_msi(struct ics_state *ics, int srcno) struct ics_irq_state *irq = ics->irqs + srcno; /* FIXME: filter by server#? */ - if (irq->rejected) { - irq->rejected = 0; + if (irq->status & XICS_STATUS_REJECTED) { + irq->status &= ~XICS_STATUS_REJECTED; if (irq->priority != 0xff) { icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); @@ -204,8 +205,10 @@ static void resend_lsi(struct ics_state *ics, int srcno) { struct ics_irq_state *irq = ics->irqs + srcno; - if ((irq->priority != 0xff) && irq->asserted && !irq->sent) { - irq->sent = 1; + if ((irq->priority != 0xff) + && (irq->status & XICS_STATUS_ASSERTED) + && !(irq->status & XICS_STATUS_SENT)) { + irq->status |= XICS_STATUS_SENT; icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); } } @@ -216,7 +219,7 @@ static void set_irq_msi(struct ics_state *ics, int srcno, int val) if (val) { if (irq->priority == 0xff) { - irq->masked_pending = 1; + irq->status |= XICS_STATUS_MASKED_PENDING; /* masked pending */ ; } else { icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); @@ -228,7 +231,11 @@ static void set_irq_lsi(struct ics_state *ics, int srcno, int val) { struct ics_irq_state *irq = ics->irqs + srcno; - irq->asserted = val; + if (val) { + irq->status |= XICS_STATUS_ASSERTED; + } else { + irq->status &= ~XICS_STATUS_ASSERTED; + } resend_lsi(ics, srcno); } @@ -248,11 +255,12 @@ static void write_xive_msi(struct ics_state *ics, int srcno) { struct ics_irq_state *irq = ics->irqs + srcno; - if (!irq->masked_pending || (irq->priority == 0xff)) { + if (!(irq->status & XICS_STATUS_MASKED_PENDING) + || (irq->priority == 0xff)) { return; } - irq->masked_pending = 0; + irq->status &= ~XICS_STATUS_MASKED_PENDING; icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); } @@ -281,8 +289,8 @@ static void ics_reject(struct ics_state *ics, int nr) { struct ics_irq_state *irq = ics->irqs + nr - ics->offset; - irq->rejected = 1; /* Irrelevant but harmless for LSI */ - irq->sent = 0; /* Irrelevant but harmless for MSI */ + irq->status |= XICS_STATUS_REJECTED; /* Irrelevant but harmless for LSI */ + irq->status &= ~XICS_STATUS_SENT; /* Irrelevant but harmless for MSI */ } static void ics_resend(struct ics_state *ics) @@ -307,7 +315,7 @@ static void ics_eoi(struct ics_state *ics, int nr) struct ics_irq_state *irq = ics->irqs + srcno; if (irq->type == XICS_LSI) { - irq->sent = 0; + irq->status &= ~XICS_STATUS_SENT; } } @@ -506,10 +514,7 @@ static void xics_reset(void *opaque) for (i = 0; i < ics->nr_irqs; i++) { /* Reset everything *except* the type */ ics->irqs[i].server = 0; - ics->irqs[i].asserted = 0; - ics->irqs[i].sent = 0; - ics->irqs[i].rejected = 0; - ics->irqs[i].masked_pending = 0; + ics->irqs[i].status = 0; ics->irqs[i].priority = 0xff; ics->irqs[i].saved_priority = 0xff; } -- cgit v1.2.3 From ff9d2afa618acd81d926c9c213b4ff5f7163db1d Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Sep 2012 16:57:18 +0000 Subject: pseries: Remove XICS irq type enum type Currently the XICS interrupt controller emulation uses a custom enum to specify whether a given interrupt is level-sensitive or message-triggered. This enum makes life awkward for saving the state, and isn't particularly useful since there are only two possibilities. This patch replaces the enum with a simple bool. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr.c | 8 ++++---- hw/spapr.h | 8 ++++---- hw/spapr_pci.c | 2 +- hw/xics.c | 16 +++++++--------- hw/xics.h | 8 +------- 5 files changed, 17 insertions(+), 25 deletions(-) diff --git a/hw/spapr.c b/hw/spapr.c index 0a0e9cddc..1177efaa9 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -89,7 +89,7 @@ sPAPREnvironment *spapr; -int spapr_allocate_irq(int hint, enum xics_irq_type type) +int spapr_allocate_irq(int hint, bool lsi) { int irq; @@ -105,13 +105,13 @@ int spapr_allocate_irq(int hint, enum xics_irq_type type) return 0; } - xics_set_irq_type(spapr->icp, irq, type); + xics_set_irq_type(spapr->icp, irq, lsi); return irq; } /* Allocate block of consequtive IRQs, returns a number of the first */ -int spapr_allocate_irq_block(int num, enum xics_irq_type type) +int spapr_allocate_irq_block(int num, bool lsi) { int first = -1; int i; @@ -119,7 +119,7 @@ int spapr_allocate_irq_block(int num, enum xics_irq_type type) for (i = 0; i < num; ++i) { int irq; - irq = spapr_allocate_irq(0, type); + irq = spapr_allocate_irq(0, lsi); if (!irq) { return -1; } diff --git a/hw/spapr.h b/hw/spapr.h index f9a7b0fa3..51a966b1e 100644 --- a/hw/spapr.h +++ b/hw/spapr.h @@ -291,17 +291,17 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn); target_ulong spapr_hypercall(CPUPPCState *env, target_ulong opcode, target_ulong *args); -int spapr_allocate_irq(int hint, enum xics_irq_type type); -int spapr_allocate_irq_block(int num, enum xics_irq_type type); +int spapr_allocate_irq(int hint, bool lsi); +int spapr_allocate_irq_block(int num, bool lsi); static inline int spapr_allocate_msi(int hint) { - return spapr_allocate_irq(hint, XICS_MSI); + return spapr_allocate_irq(hint, false); } static inline int spapr_allocate_lsi(int hint) { - return spapr_allocate_irq(hint, XICS_LSI); + return spapr_allocate_irq(hint, true); } static inline uint32_t rtas_ld(target_ulong phys, int n) diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index 203155e32..b628f89a0 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -351,7 +351,7 @@ static void rtas_ibm_change_msi(sPAPREnvironment *spapr, /* There is no cached config, allocate MSIs */ if (!phb->msi_table[ndev].nvec) { - irq = spapr_allocate_irq_block(req_num, XICS_MSI); + irq = spapr_allocate_irq_block(req_num, true); if (irq < 0) { fprintf(stderr, "Cannot allocate MSIs for device#%d", ndev); rtas_st(rets, 0, -1); /* Hardware error */ diff --git a/hw/xics.c b/hw/xics.c index 648af2538..75c8cca41 100644 --- a/hw/xics.c +++ b/hw/xics.c @@ -170,7 +170,7 @@ struct ics_irq_state { #define XICS_STATUS_REJECTED 0x4 #define XICS_STATUS_MASKED_PENDING 0x8 uint8_t status; - enum xics_irq_type type; + bool lsi; }; struct ics_state { @@ -244,7 +244,7 @@ static void ics_set_irq(void *opaque, int srcno, int val) struct ics_state *ics = (struct ics_state *)opaque; struct ics_irq_state *irq = ics->irqs + srcno; - if (irq->type == XICS_LSI) { + if (irq->lsi) { set_irq_lsi(ics, srcno, val); } else { set_irq_msi(ics, srcno, val); @@ -278,7 +278,7 @@ static void ics_write_xive(struct ics_state *ics, int nr, int server, irq->server = server; irq->priority = priority; - if (irq->type == XICS_LSI) { + if (irq->lsi) { write_xive_lsi(ics, srcno); } else { write_xive_msi(ics, srcno); @@ -301,7 +301,7 @@ static void ics_resend(struct ics_state *ics) struct ics_irq_state *irq = ics->irqs + i; /* FIXME: filter by server#? */ - if (irq->type == XICS_LSI) { + if (irq->lsi) { resend_lsi(ics, i); } else { resend_msi(ics, i); @@ -314,7 +314,7 @@ static void ics_eoi(struct ics_state *ics, int nr) int srcno = nr - ics->offset; struct ics_irq_state *irq = ics->irqs + srcno; - if (irq->type == XICS_LSI) { + if (irq->lsi) { irq->status &= ~XICS_STATUS_SENT; } } @@ -333,14 +333,12 @@ qemu_irq xics_get_qirq(struct icp_state *icp, int irq) return icp->ics->qirqs[irq - icp->ics->offset]; } -void xics_set_irq_type(struct icp_state *icp, int irq, - enum xics_irq_type type) +void xics_set_irq_type(struct icp_state *icp, int irq, bool lsi) { assert((irq >= icp->ics->offset) && (irq < (icp->ics->offset + icp->ics->nr_irqs))); - assert((type == XICS_MSI) || (type == XICS_LSI)); - icp->ics->irqs[irq - icp->ics->offset].type = type; + icp->ics->irqs[irq - icp->ics->offset].lsi = lsi; } static target_ulong h_cppr(CPUPPCState *env, sPAPREnvironment *spapr, diff --git a/hw/xics.h b/hw/xics.h index 99b96ac85..681726869 100644 --- a/hw/xics.h +++ b/hw/xics.h @@ -31,14 +31,8 @@ struct icp_state; -enum xics_irq_type { - XICS_MSI, /* Message-signalled (edge) interrupt */ - XICS_LSI, /* Level-signalled interrupt */ -}; - qemu_irq xics_get_qirq(struct icp_state *icp, int irq); -void xics_set_irq_type(struct icp_state *icp, int irq, - enum xics_irq_type type); +void xics_set_irq_type(struct icp_state *icp, int irq, bool lsi); struct icp_state *xics_system_init(int nr_irqs); -- cgit v1.2.3 From 490d4a2b6edafb27cd688ded7fdb1290453d71b0 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Sep 2012 16:57:19 +0000 Subject: pseries: Remove never used flags field from spapr vio devices The general device state structure for PAPR VIO emulated devices includes a 'flags' field which was never used. This patch removes it. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr_vio.h | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h index ea6aa43e2..acef65efd 100644 --- a/hw/spapr_vio.h +++ b/hw/spapr_vio.h @@ -60,7 +60,6 @@ typedef struct VIOsPAPRDeviceClass { struct VIOsPAPRDevice { DeviceState qdev; uint32_t reg; - uint32_t flags; uint32_t irq; target_ulong signal_state; VIOsPAPR_CRQ crq; -- cgit v1.2.3 From 53724ee565565f69560dbe17553bede8c0169379 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Sep 2012 16:57:20 +0000 Subject: pseries: Rework implementation of TCE bypass On the pseries machine the IOMMU (aka TCE tables) is always active for all PCI and VIO devices. Mostly to simplify the SLOF firmware, we implement an extension which allows the IOMMU to be temporarily disabled for certain devices. Currently this is implemented by setting the device's DMAContext pointer to NULL (thus reverting to qemu's default no-IOMMU DMA behaviour), then replacing it when bypass mode is disabled. This approach causes a bunch of complications though. It complexifies the management of the DMAContext lifetimes, it's problematic for savevm/loadvm, and it means that while bypass is active we have nowhere to store the device's LIOBN (Logical IO Bus Number, used to identify DMA address spaces). At present we regenerate the LIOBN from other address information but this restricts how we can allocate LIOBNs. This patch gives up on this approach, replacing it with the much simpler one of having a 'bypass' boolean flag in the TCE state structure. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr.h | 1 + hw/spapr_iommu.c | 25 +++++++++++++++++++------ hw/spapr_vio.c | 26 ++++++++++---------------- hw/spapr_vio.h | 1 - 4 files changed, 30 insertions(+), 23 deletions(-) diff --git a/hw/spapr.h b/hw/spapr.h index 51a966b1e..e984e3fc3 100644 --- a/hw/spapr.h +++ b/hw/spapr.h @@ -339,6 +339,7 @@ void spapr_iommu_init(void); DMAContext *spapr_tce_new_dma_context(uint32_t liobn, size_t window_size); void spapr_tce_free(DMAContext *dma); void spapr_tce_reset(DMAContext *dma); +void spapr_tce_set_bypass(DMAContext *dma, bool bypass); int spapr_dma_dt(void *fdt, int node_off, const char *propname, uint32_t liobn, uint64_t window, uint32_t size); int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname, diff --git a/hw/spapr_iommu.c b/hw/spapr_iommu.c index 216aa0680..38034c07b 100644 --- a/hw/spapr_iommu.c +++ b/hw/spapr_iommu.c @@ -42,6 +42,7 @@ struct sPAPRTCETable { uint32_t liobn; uint32_t window_size; sPAPRTCE *table; + bool bypass; int fd; QLIST_ENTRY(sPAPRTCETable) list; }; @@ -78,6 +79,12 @@ static int spapr_tce_translate(DMAContext *dma, DMA_ADDR_FMT "\n", tcet->liobn, addr); #endif + if (tcet->bypass) { + *paddr = addr; + *len = (target_phys_addr_t)-1; + return 0; + } + /* Check if we are in bound */ if (addr >= tcet->window_size) { #ifdef DEBUG_TCE @@ -162,15 +169,21 @@ void spapr_tce_free(DMAContext *dma) } } +void spapr_tce_set_bypass(DMAContext *dma, bool bypass) +{ + sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma); + + tcet->bypass = bypass; +} + void spapr_tce_reset(DMAContext *dma) { - if (dma) { - sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma); - size_t table_size = (tcet->window_size >> SPAPR_TCE_PAGE_SHIFT) - * sizeof(sPAPRTCE); + sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma); + size_t table_size = (tcet->window_size >> SPAPR_TCE_PAGE_SHIFT) + * sizeof(sPAPRTCE); - memset(tcet->table, 0, table_size); - } + tcet->bypass = false; + memset(tcet->table, 0, table_size); } static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba, diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index 752836e76..848806d3f 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -316,14 +316,9 @@ int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq) static void spapr_vio_quiesce_one(VIOsPAPRDevice *dev) { - VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); - uint32_t liobn = SPAPR_VIO_BASE_LIOBN | dev->reg; - if (dev->dma) { - spapr_tce_free(dev->dma); + spapr_tce_reset(dev->dma); } - dev->dma = spapr_tce_new_dma_context(liobn, pc->rtce_window_size); - free_crq(dev); } @@ -346,16 +341,14 @@ static void rtas_set_tce_bypass(sPAPREnvironment *spapr, uint32_t token, rtas_st(rets, 0, -3); return; } - if (enable) { - spapr_tce_free(dev->dma); - dev->dma = NULL; - } else { - VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); - uint32_t liobn = SPAPR_VIO_BASE_LIOBN | dev->reg; - dev->dma = spapr_tce_new_dma_context(liobn, pc->rtce_window_size); + if (!dev->dma) { + rtas_st(rets, 0, -3); + return; } + spapr_tce_set_bypass(dev->dma, !!enable); + rtas_st(rets, 0, 0); } @@ -421,7 +414,6 @@ static int spapr_vio_busdev_init(DeviceState *qdev) { VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev; VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); - uint32_t liobn; char *id; if (dev->reg != -1) { @@ -463,8 +455,10 @@ static int spapr_vio_busdev_init(DeviceState *qdev) return -1; } - liobn = SPAPR_VIO_BASE_LIOBN | dev->reg; - dev->dma = spapr_tce_new_dma_context(liobn, pc->rtce_window_size); + if (pc->rtce_window_size) { + uint32_t liobn = SPAPR_VIO_BASE_LIOBN | dev->reg; + dev->dma = spapr_tce_new_dma_context(liobn, pc->rtce_window_size); + } return pc->init(dev); } diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h index acef65efd..cc85d2610 100644 --- a/hw/spapr_vio.h +++ b/hw/spapr_vio.h @@ -131,7 +131,6 @@ void spapr_vscsi_create(VIOsPAPRBus *bus); VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus); -int spapr_tce_set_bypass(uint32_t unit, uint32_t enable); void spapr_vio_quiesce(void); #endif /* _HW_SPAPR_VIO_H */ -- cgit v1.2.3 From 3fe719f467530b7c8ac0797881ff4b66d1357c18 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Sep 2012 16:57:21 +0000 Subject: pseries: Fix semantics of RTAS int-on, int-off and set-xive functions Currently the ibm,int-on and ibm,int-off RTAS functions are implemented as no-ops. This is because when implemented as specified in PAPR they caused Linux (which calls both int-on/off and set-xive) to end up with interrupts masked when they should not be. Since Linux's set-xive calls make the int-on/off calls redundant, making them nops worked around the problem. In fact, the problem was caused because there was a subtle bug in set-xive, PAPR specifies that as well as updating the current priority, it also needs to update the saved priority used by int-on/off. With this bug fixed the problem goes away. This patch implements this more correct fix. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/xics.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/hw/xics.c b/hw/xics.c index 75c8cca41..ce88aa750 100644 --- a/hw/xics.c +++ b/hw/xics.c @@ -270,13 +270,14 @@ static void write_xive_lsi(struct ics_state *ics, int srcno) } static void ics_write_xive(struct ics_state *ics, int nr, int server, - uint8_t priority) + uint8_t priority, uint8_t saved_priority) { int srcno = nr - ics->offset; struct ics_irq_state *irq = ics->irqs + srcno; irq->server = server; irq->priority = priority; + irq->saved_priority = saved_priority; if (irq->lsi) { write_xive_lsi(ics, srcno); @@ -405,7 +406,7 @@ static void rtas_set_xive(sPAPREnvironment *spapr, uint32_t token, return; } - ics_write_xive(ics, nr, server, priority); + ics_write_xive(ics, nr, server, priority, priority); rtas_st(rets, 0, 0); /* Success */ } @@ -453,14 +454,8 @@ static void rtas_int_off(sPAPREnvironment *spapr, uint32_t token, return; } - /* This is a NOP for now, since the described PAPR semantics don't - * seem to gel with what Linux does */ -#if 0 - struct ics_irq_state *irq = xics->irqs + (nr - xics->offset); - - irq->saved_priority = irq->priority; - ics_write_xive_msi(xics, nr, irq->server, 0xff); -#endif + ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 0xff, + ics->irqs[nr - ics->offset].priority); rtas_st(rets, 0, 0); /* Success */ } @@ -484,13 +479,9 @@ static void rtas_int_on(sPAPREnvironment *spapr, uint32_t token, return; } - /* This is a NOP for now, since the described PAPR semantics don't - * seem to gel with what Linux does */ -#if 0 - struct ics_irq_state *irq = xics->irqs + (nr - xics->offset); - - ics_write_xive_msi(xics, nr, irq->server, irq->saved_priority); -#endif + ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, + ics->irqs[nr - ics->offset].saved_priority, + ics->irqs[nr - ics->offset].saved_priority); rtas_st(rets, 0, 0); /* Success */ } -- cgit v1.2.3 From ace9a2cbac9b2949aadc176ffa83a1d2a0873e2c Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 19 Sep 2012 21:08:42 +0000 Subject: target-ppc: KVM: Fix some kernel version edge cases for kvmppc_reset_htab() The kvmppc_reset_htab() function invokes the KVM_PPC_ALLOCATE_HTAB vm ioctl to request KVM to allocate and reset a hash page table for the guest - it returns the size of hash table allocated, or 0 to indicate that qemu needs to allocate the hash table itself. In practice qemu needs to allocate the htab for full emulation and with Book3sPR KVM, but the kernel has to allocate it for Book3sHV KVM (the hash table needs to be physically contiguous in that case). Unfortunately, the logic in this function is incorrect for some existing kernels. Specifically: * at least some PR KVM versions advertise the relevant capability but don't actually implement the ioctl(), returning ENOTTY. * For old kernels which don't have the capability, we currently return 0. This is correct for PV KVM, where we need to allocate the htab, but not for HV KVM - kernels of this era always allocate a 16MB hash table per guest. This patch corrects both of these edge cases. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/kvm.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 546c11604..1975323eb 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -1127,18 +1127,38 @@ int kvmppc_reset_htab(int shift_hint) { uint32_t shift = shift_hint; - if (kvm_enabled() && - kvm_check_extension(kvm_state, KVM_CAP_PPC_ALLOC_HTAB)) { + if (!kvm_enabled()) { + /* Full emulation, tell caller to allocate htab itself */ + return 0; + } + if (kvm_check_extension(kvm_state, KVM_CAP_PPC_ALLOC_HTAB)) { int ret; ret = kvm_vm_ioctl(kvm_state, KVM_PPC_ALLOCATE_HTAB, &shift); - if (ret < 0) { + if (ret == -ENOTTY) { + /* At least some versions of PR KVM advertise the + * capability, but don't implement the ioctl(). Oops. + * Return 0 so that we allocate the htab in qemu, as is + * correct for PR. */ + return 0; + } else if (ret < 0) { return ret; } return shift; } - /* For now.. */ - return 0; + /* We have a kernel that predates the htab reset calls. For PR + * KVM, we need to allocate the htab ourselves, for an HV KVM of + * this era, it has allocated a 16MB fixed size hash table + * already. Kernels of this era have the GET_PVINFO capability + * only on PR, so we use this hack to determine the right + * answer */ + if (kvm_check_extension(kvm_state, KVM_CAP_PPC_GET_PVINFO)) { + /* PR - tell caller to allocate htab */ + return 0; + } else { + /* HV - assume 16MB kernel allocated htab */ + return 24; + } } static inline uint32_t mfpvr(void) -- cgit v1.2.3 From 5a1972c8472fafd519a68b689fdcaf33ec857945 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Fri, 31 Aug 2012 22:21:21 +0200 Subject: ppc405_uc: Fix buffer overflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Report from smatch: ppc405_uc.c:209 dcr_read_pob(12) error: buffer overflow 'pob->besr' 2 <= 2 ppc405_uc.c:232 dcr_write_pob(12) error: buffer overflow 'pob->besr' 2 <= 2 The old code reads and writes besr[POB0_BESR1 - POB0_BESR0] or besr[2] which is one too much. Signed-off-by: Stefan Weil Reviewed-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/ppc405_uc.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index 89e5013b5..b52ab2f17 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -191,7 +191,8 @@ enum { typedef struct ppc4xx_pob_t ppc4xx_pob_t; struct ppc4xx_pob_t { uint32_t bear; - uint32_t besr[2]; + uint32_t besr0; + uint32_t besr1; }; static uint32_t dcr_read_pob (void *opaque, int dcrn) @@ -205,8 +206,10 @@ static uint32_t dcr_read_pob (void *opaque, int dcrn) ret = pob->bear; break; case POB0_BESR0: + ret = pob->besr0; + break; case POB0_BESR1: - ret = pob->besr[dcrn - POB0_BESR0]; + ret = pob->besr1; break; default: /* Avoid gcc warning */ @@ -227,9 +230,12 @@ static void dcr_write_pob (void *opaque, int dcrn, uint32_t val) /* Read only */ break; case POB0_BESR0: + /* Write-clear */ + pob->besr0 &= ~val; + break; case POB0_BESR1: /* Write-clear */ - pob->besr[dcrn - POB0_BESR0] &= ~val; + pob->besr1 &= ~val; break; } } @@ -241,8 +247,8 @@ static void ppc4xx_pob_reset (void *opaque) pob = opaque; /* No error */ pob->bear = 0x00000000; - pob->besr[0] = 0x0000000; - pob->besr[1] = 0x0000000; + pob->besr0 = 0x0000000; + pob->besr1 = 0x0000000; } static void ppc4xx_pob_init(CPUPPCState *env) -- cgit v1.2.3 From 35f9304d925a5423c51bd2c83a81fa3cc2b6e680 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 20 Sep 2012 17:42:30 +0000 Subject: pseries: Remove unnecessary locking from PAPR hash table hcalls In the paravirtualized environment provided by PAPR, there is a standard locking scheme so that hypercalls updating the hash page table from different guest threads don't corrupt the haah table state. We implement this HVLOCK bit in out page table hypercalls. However, it is not necessary in our case, since the hypercalls all run in the qemu environment under the big qemu lock. Therefore, this patch removes the locking code. This has the additional advantage of freeing up a hash PTE bit which will be useful for migration support. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr_hcall.c | 42 ++++-------------------------------------- 1 file changed, 4 insertions(+), 38 deletions(-) diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c index 2df94d197..826ca673f 100644 --- a/hw/spapr_hcall.c +++ b/hw/spapr_hcall.c @@ -39,22 +39,6 @@ #define HPTE_V_1TB_SEG 0x4000000000000000ULL #define HPTE_V_VRMA_MASK 0x4001ffffff000000ULL -#define HPTE_V_HVLOCK 0x40ULL - -static inline int lock_hpte(void *hpte, target_ulong bits) -{ - uint64_t pteh; - - pteh = ldq_p(hpte); - - /* We're protected by qemu's global lock here */ - if (pteh & bits) { - return 0; - } - stq_p(hpte, pteh | HPTE_V_HVLOCK); - return 1; -} - static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r, target_ulong pte_index) { @@ -151,8 +135,7 @@ static target_ulong h_enter(CPUPPCState *env, sPAPREnvironment *spapr, if (i == 8) { return H_PTEG_FULL; } - if (((ldq_p(hpte) & HPTE_V_VALID) == 0) && - lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID)) { + if ((ldq_p(hpte) & HPTE_V_VALID) == 0) { break; } hpte += HASH_PTE_SIZE_64; @@ -160,7 +143,7 @@ static target_ulong h_enter(CPUPPCState *env, sPAPREnvironment *spapr, } else { i = 0; hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64); - if (!lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID)) { + if (ldq_p(hpte) & HPTE_V_VALID) { return H_PTEG_FULL; } } @@ -168,7 +151,6 @@ static target_ulong h_enter(CPUPPCState *env, sPAPREnvironment *spapr, /* eieio(); FIXME: need some sort of barrier for smp? */ stq_p(hpte, pteh); - assert(!(ldq_p(hpte) & HPTE_V_HVLOCK)); args[0] = pte_index + i; return H_SUCCESS; } @@ -193,11 +175,6 @@ static target_ulong remove_hpte(CPUPPCState *env, target_ulong ptex, } hpte = env->external_htab + (ptex * HASH_PTE_SIZE_64); - while (!lock_hpte(hpte, HPTE_V_HVLOCK)) { - /* We have no real concurrency in qemu soft-emulation, so we - * will never actually have a contested lock */ - assert(0); - } v = ldq_p(hpte); r = ldq_p(hpte + (HASH_PTE_SIZE_64/2)); @@ -205,16 +182,13 @@ static target_ulong remove_hpte(CPUPPCState *env, target_ulong ptex, if ((v & HPTE_V_VALID) == 0 || ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) || ((flags & H_ANDCOND) && (v & avpn) != 0)) { - stq_p(hpte, v & ~HPTE_V_HVLOCK); - assert(!(ldq_p(hpte) & HPTE_V_HVLOCK)); return REMOVE_NOT_FOUND; } - *vp = v & ~HPTE_V_HVLOCK; + *vp = v; *rp = r; stq_p(hpte, 0); rb = compute_tlbie_rb(v, r, ptex); ppc_tlb_invalidate_one(env, rb); - assert(!(ldq_p(hpte) & HPTE_V_HVLOCK)); return REMOVE_SUCCESS; } @@ -324,19 +298,12 @@ static target_ulong h_protect(CPUPPCState *env, sPAPREnvironment *spapr, } hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64); - while (!lock_hpte(hpte, HPTE_V_HVLOCK)) { - /* We have no real concurrency in qemu soft-emulation, so we - * will never actually have a contested lock */ - assert(0); - } v = ldq_p(hpte); r = ldq_p(hpte + (HASH_PTE_SIZE_64/2)); if ((v & HPTE_V_VALID) == 0 || ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) { - stq_p(hpte, v & ~HPTE_V_HVLOCK); - assert(!(ldq_p(hpte) & HPTE_V_HVLOCK)); return H_NOT_FOUND; } @@ -350,8 +317,7 @@ static target_ulong h_protect(CPUPPCState *env, sPAPREnvironment *spapr, ppc_tlb_invalidate_one(env, rb); stq_p(hpte + (HASH_PTE_SIZE_64/2), r); /* Don't need a memory barrier, due to qemu's global lock */ - stq_p(hpte, v & ~HPTE_V_HVLOCK); - assert(!(ldq_p(hpte) & HPTE_V_HVLOCK)); + stq_p(hpte, v); return H_SUCCESS; } -- cgit v1.2.3 From 382be75df77142cf6bdc7f5852738029eeb9e23a Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 20 Sep 2012 17:42:27 +0000 Subject: pseries: Set hash table size based on RAM size Currently the pseries machine code always attempts to set the size of the guests's hash page table to 16MB. However, because of the way the POWER MMU works, a suitable hash page table size should really depend on memory size. 16MB will be excessive for guests with <1GB and RAM, and may not be enough for guests with >2GB of RAM (depending on guest page size and other factors). The usual given rule of thumb is that the hash table should be 1/64 of the size of memory, but in fact the Linux guests we are aiming at don't really need that much. This patch, therefore, changes the hash table allocation code to aim for 1/128 of the size of RAM (rounding up). When using KVM, this size may still be adjusted by the host kernel if it is unable to allocate a suitable (contiguous) table. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/hw/spapr.c b/hw/spapr.c index 1177efaa9..a8bd3c1ae 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -725,9 +725,16 @@ static void ppc_spapr_init(ram_addr_t ram_size, spapr->fdt_addr = spapr->rtas_addr - FDT_MAX_SIZE; load_limit = spapr->fdt_addr - FW_OVERHEAD; - /* For now, always aim for a 16MB hash table */ - /* FIXME: we should change this default based on RAM size */ - spapr->htab_shift = 24; + /* We aim for a hash table of size 1/128 the size of RAM. The + * normal rule of thumb is 1/64 the size of RAM, but that's much + * more than needed for the Linux guests we support. */ + spapr->htab_shift = 18; /* Minimum architected size */ + while (spapr->htab_shift <= 46) { + if ((1ULL << (spapr->htab_shift + 7)) >= ram_size) { + break; + } + spapr->htab_shift++; + } /* init CPUs */ if (cpu_model == NULL) { -- cgit v1.2.3 From 011aba24ed73000e126dd1bb90a6bea2afd91649 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 20 Sep 2012 17:42:28 +0000 Subject: target-ppc: Remove unused power_mode field from cpu state CPUPPCState includes a variable 'power_mode' which is used nowhere. This patch removes it. This includes saving a dummy zero in its place during vmsave, to avoid breaking the save format. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/cpu.h | 1 - target-ppc/machine.c | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index ca2fc2198..faf440407 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1079,7 +1079,6 @@ struct CPUPPCState { int mmu_idx; /* precomputed MMU index to speed up mem accesses */ /* Power management */ - int power_mode; int (*check_pow)(CPUPPCState *env); #if !defined(CONFIG_USER_ONLY) diff --git a/target-ppc/machine.c b/target-ppc/machine.c index d6c2ee41b..21ce7575e 100644 --- a/target-ppc/machine.c +++ b/target-ppc/machine.c @@ -82,7 +82,7 @@ void cpu_save(QEMUFile *f, void *opaque) qemu_put_betls(f, &env->hflags); qemu_put_betls(f, &env->hflags_nmsr); qemu_put_sbe32s(f, &env->mmu_idx); - qemu_put_sbe32s(f, &env->power_mode); + qemu_put_sbe32(f, 0); } int cpu_load(QEMUFile *f, void *opaque, int version_id) @@ -167,7 +167,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) qemu_get_betls(f, &env->hflags); qemu_get_betls(f, &env->hflags_nmsr); qemu_get_sbe32s(f, &env->mmu_idx); - qemu_get_sbe32s(f, &env->power_mode); + qemu_get_sbe32(f); /* Discard unused power_mode */ return 0; } -- cgit v1.2.3 From 711934334eb3895a89c555c1f57eb3d84ddb2906 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Sun, 23 Sep 2012 08:37:59 +0200 Subject: fdt: move dumpdtb interpretation code to device_tree.c The dumpdtb code can be useful in more places than just for e500. Move it to a generic place. Signed-off-by: Alexander Graf --- device_tree.c | 22 ++++++++++++++++++++++ device_tree.h | 2 ++ hw/ppc/e500.c | 15 +-------------- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/device_tree.c b/device_tree.c index d7a9b6bb8..69ca953b4 100644 --- a/device_tree.c +++ b/device_tree.c @@ -304,3 +304,25 @@ int qemu_devtree_add_subnode(void *fdt, const char *name) g_free(dupname); return retval; } + +void qemu_devtree_dumpdtb(void *fdt, int size) +{ + QemuOpts *machine_opts; + + machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); + if (machine_opts) { + const char *dumpdtb = qemu_opt_get(machine_opts, "dumpdtb"); + if (dumpdtb) { + /* Dump the dtb to a file and quit */ + FILE *f = fopen(dumpdtb, "wb"); + size_t len; + len = fwrite(fdt, size, 1, f); + fclose(f); + if (len != size) { + exit(1); + } + exit(0); + } + } + +} diff --git a/device_tree.h b/device_tree.h index f7a3e6cfc..f0b3f35e0 100644 --- a/device_tree.h +++ b/device_tree.h @@ -49,4 +49,6 @@ int qemu_devtree_add_subnode(void *fdt, const char *name); sizeof(qdt_tmp)); \ } while (0) +void qemu_devtree_dumpdtb(void *fdt, int size); + #endif /* __DEVICE_TREE_H__ */ diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 6f0de6d95..5bab34047 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -139,12 +139,10 @@ static int ppce500_load_device_tree(CPUPPCState *env, 0x0, 0x10000, }; QemuOpts *machine_opts; - const char *dumpdtb = NULL; const char *dtb_file = NULL; machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); if (machine_opts) { - dumpdtb = qemu_opt_get(machine_opts, "dumpdtb"); dtb_file = qemu_opt_get(machine_opts, "dtb"); toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible"); } @@ -334,18 +332,7 @@ static int ppce500_load_device_tree(CPUPPCState *env, } done: - if (dumpdtb) { - /* Dump the dtb to a file and quit */ - FILE *f = fopen(dumpdtb, "wb"); - size_t len; - len = fwrite(fdt, fdt_size, 1, f); - fclose(f); - if (len != fdt_size) { - exit(1); - } - exit(0); - } - + qemu_devtree_dumpdtb(fdt, fdt_size); ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); if (ret < 0) { goto out; -- cgit v1.2.3 From 6641b77254d3c191ecee5a87947425f623ac9ca0 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Sun, 23 Sep 2012 23:27:37 +0200 Subject: device tree: simplify dumpdtb code As per Peter's suggestion, we can use glib to write out a buffer in whole to a file, simplifying the code dramatically. Signed-off-by: Alexander Graf --- device_tree.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/device_tree.c b/device_tree.c index 69ca953b4..a9236133c 100644 --- a/device_tree.c +++ b/device_tree.c @@ -314,14 +314,7 @@ void qemu_devtree_dumpdtb(void *fdt, int size) const char *dumpdtb = qemu_opt_get(machine_opts, "dumpdtb"); if (dumpdtb) { /* Dump the dtb to a file and quit */ - FILE *f = fopen(dumpdtb, "wb"); - size_t len; - len = fwrite(fdt, size, 1, f); - fclose(f); - if (len != size) { - exit(1); - } - exit(0); + exit(g_file_set_contents(dumpdtb, fdt, size, NULL) ? 0 : 1); } } -- cgit v1.2.3 From 9dd5eba1bc69bccbd83885d157d84e2514799a22 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Wed, 22 Aug 2012 14:55:40 +0000 Subject: PPC: e500: increase DTC_LOAD_PAD An allowance of 5 MiB for BSS is not enough for Linux kernels with certain debug options enabled (not sure exactly which one caused it, but I'd guess lockdep). The kernel I ran into this with had a BSS of around 6.4 MB. Unfortunately, uImage does not give us enough information to determine the actual BSS size. Increase the allowance to 18 MiB to give us plenty of room. Eventually this should be more intelligent, possibly packing initrd+dtb at the end of guest RAM. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/ppc/e500.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 5bab34047..fc3fde0b6 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -36,7 +36,7 @@ #define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb" #define UIMAGE_LOAD_BASE 0 -#define DTC_LOAD_PAD 0x500000 +#define DTC_LOAD_PAD 0x1800000 #define DTC_PAD_MASK 0xFFFFF #define INITRD_LOAD_PAD 0x2000000 #define INITRD_PAD_MASK 0xFFFFFF -- cgit v1.2.3 From 7e7ec2d290ca5b1bdd555da9852dc5ee60232fe5 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Wed, 22 Aug 2012 14:55:41 +0000 Subject: PPC: e500: calculate initrd_base like dt_base While investigating dtb pad issues, I noticed that initrd_base wasn't taking loadaddr into account the way dt_base was. This seems wrong. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/ppc/e500.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index fc3fde0b6..feb712e5a 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -540,7 +540,8 @@ void ppce500_init(PPCE500Params *params) /* Load initrd. */ if (params->initrd_filename) { - initrd_base = (kernel_size + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK; + initrd_base = (loadaddr + kernel_size + INITRD_LOAD_PAD) & + ~INITRD_PAD_MASK; initrd_size = load_image_targphys(params->initrd_filename, initrd_base, ram_size - initrd_base); -- cgit v1.2.3 From efcb9383b974114e5f682e531346006f8f2466c0 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 25 Sep 2012 17:12:20 +0000 Subject: pseries: Don't test for MSR_PR for hypercalls under KVM PAPR hypercalls should only be invoked from the guest kernel, not guest user programs, that is, with MSR[PR]=0. Currently we check this in spapr_hypercall, returning H_PRIVILEGE if MSR[PR]=1. However, under KVM the state of MSR[PR] is already checked by the host kernel before passing the hypercall to qemu, making this check redundant. Worse, however, we don't generally synchronize KVM and qemu state on the hypercall path, meaning that qemu could incorrectly reject a hypercall because it has a stale MSR value. This patch fixes the problem by moving the privilege test exclusively to the TCG hypercall path. Signed-off-by: David Gibson CC: qemu-stable@nongnu.org Signed-off-by: Alexander Graf --- hw/spapr.c | 7 ++++++- hw/spapr_hcall.c | 5 ----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/spapr.c b/hw/spapr.c index a8bd3c1ae..ab227a009 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -573,7 +573,12 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr) static void emulate_spapr_hypercall(CPUPPCState *env) { - env->gpr[3] = spapr_hypercall(env, env->gpr[3], &env->gpr[4]); + if (msr_pr) { + hcall_dprintf("Hypercall made with MSR[PR]=1\n"); + env->gpr[3] = H_PRIVILEGE; + } else { + env->gpr[3] = spapr_hypercall(env, env->gpr[3], &env->gpr[4]); + } } static void spapr_reset_htab(sPAPREnvironment *spapr) diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c index 826ca673f..194d9c24b 100644 --- a/hw/spapr_hcall.c +++ b/hw/spapr_hcall.c @@ -681,11 +681,6 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn) target_ulong spapr_hypercall(CPUPPCState *env, target_ulong opcode, target_ulong *args) { - if (msr_pr) { - hcall_dprintf("Hypercall made with MSR[PR]=1\n"); - return H_PRIVILEGE; - } - if ((opcode <= MAX_HCALL_OPCODE) && ((opcode & 0x3) == 0)) { spapr_hcall_fn fn = papr_hypercall_table[opcode / 4]; -- cgit v1.2.3 From 2b15811c8cd4dbe8dcde32320936fe74e51e4279 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 25 Sep 2012 17:12:21 +0000 Subject: ppc/pseries: Reset VPA registration on CPU reset The ppc specific CPU state contains several variables which track the VPA, SLB shadow and dispatch trace log. These are structures shared between OS and hypervisor that are used on the pseries machine to track various per-CPU quantities. The address of these structures needs to be registered by the guest on each boot, however currently this registration is not cleared when we reset the cpu. This patch corrects this bug. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index fba2b4242..a97228703 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -10423,6 +10423,14 @@ static void ppc_cpu_reset(CPUState *s) env->pending_interrupts = 0; env->exception_index = POWERPC_EXCP_NONE; env->error_code = 0; + +#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) + env->vpa = 0; + env->slb_shadow = 0; + env->dispatch_trace_log = 0; + env->dtl_size = 0; +#endif /* TARGET_PPC64 */ + /* Flush all TLBs */ tlb_flush(env, 1); } -- cgit v1.2.3 From fb37c3029c5a695e367baaacc6baf17640cc63cc Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 4 Oct 2012 18:52:21 +0200 Subject: PPC: e500: Only expose even TLB sizes in initial TLB When booting our e500 machine, we automatically generate a big TLB entry in TLB1 that covers all of the code we need to run in there until the guest can handle its TLB on its own. However, e500v2 can only handle MAS1.0 sizes. However, we keep our TLB information in MAS2.0 layout, which means we have twice as many TLB sizes to choose from. That also means we can run into a situation where we try to add a TLB size that could not fit into the MAS1.0 size bits. Fix it by making sure we always have the lower bit set to 0. That way we are always guaranteed to have MAS1.0 compatible TLB size information. Signed-off-by: Alexander Graf --- hw/ppc/e500.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index feb712e5a..d23f9b2f6 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -362,6 +362,10 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env) the device tree top */ dt_end = bi->dt_base + bi->dt_size; ps = booke206_page_size_to_tlb(dt_end) + 1; + if (ps & 1) { + /* e500v2 can only do even TLB size bits */ + ps++; + } size = (ps << MAS1_TSIZE_SHIFT); tlb->mas1 = MAS1_VALID | size; tlb->mas2 = 0; -- cgit v1.2.3 From ef8beb0e94c75984e016e855164361c36e15396c Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 5 Oct 2012 04:34:40 +0200 Subject: PPC: KVM: Fix BAT put In the sregs API, upper and lower 32bit segments of the BAT registers are swapped when doing a set. Since we need to support old kernels out there, don't bother to fix it in the kernel, but instead work around the problem in QEMU by swapping on put. Signed-off-by: Alexander Graf --- target-ppc/kvm.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 1975323eb..93c5bb75e 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -493,10 +493,11 @@ int kvm_arch_put_registers(CPUPPCState *env, int level) /* Sync BATs */ for (i = 0; i < 8; i++) { - sregs.u.s.ppc32.dbat[i] = ((uint64_t)env->DBAT[1][i] << 32) - | env->DBAT[0][i]; - sregs.u.s.ppc32.ibat[i] = ((uint64_t)env->IBAT[1][i] << 32) - | env->IBAT[0][i]; + /* Beware. We have to swap upper and lower bits here */ + sregs.u.s.ppc32.dbat[i] = ((uint64_t)env->DBAT[0][i] << 32) + | env->DBAT[1][i]; + sregs.u.s.ppc32.ibat[i] = ((uint64_t)env->IBAT[0][i] << 32) + | env->IBAT[1][i]; } ret = kvm_vcpu_ioctl(env, KVM_SET_SREGS, &sregs); -- cgit v1.2.3 From b2532d88c9eb4f4734f62d5075585ee8c1516605 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Thu, 27 Sep 2012 07:41:42 +0200 Subject: cpu: Add missing 'static' attribute to qemu_global_mutex Contrary to its name, 'qemu_global_mutex' is only used locally in cpus.c. Signed-off-by: Stefan Weil Signed-off-by: Stefan Hajnoczi --- cpus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpus.c b/cpus.c index 4b726ef4e..1d5d4904c 100644 --- a/cpus.c +++ b/cpus.c @@ -613,7 +613,7 @@ static void qemu_tcg_init_cpu_signals(void) } #endif /* _WIN32 */ -QemuMutex qemu_global_mutex; +static QemuMutex qemu_global_mutex; static QemuCond qemu_io_proceeded_cond; static bool iothread_requesting_mutex; -- cgit v1.2.3 From f97713ff191ab855ca5c03458f8dab0c9bf58443 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 27 Sep 2012 14:55:43 +0100 Subject: tcg/arm: Use tcg_out_mov_reg rather than inline equivalent code Use the recently introduced tcg_out_mov_reg() function rather than the equivalent inline code. Signed-off-by: Peter Maydell Reviewed-by: Aurelien Jarno Signed-off-by: Stefan Hajnoczi --- tcg/arm/tcg-target.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c index 2bad0a2b1..5e8dbdd88 100644 --- a/tcg/arm/tcg-target.c +++ b/tcg/arm/tcg-target.c @@ -1197,20 +1197,11 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) case 1: case 2: default: - if (data_reg != TCG_REG_R0) { - tcg_out_dat_reg(s, COND_AL, ARITH_MOV, - data_reg, 0, TCG_REG_R0, SHIFT_IMM_LSL(0)); - } + tcg_out_mov_reg(s, COND_AL, data_reg, TCG_REG_R0); break; case 3: - if (data_reg != TCG_REG_R0) { - tcg_out_dat_reg(s, COND_AL, ARITH_MOV, - data_reg, 0, TCG_REG_R0, SHIFT_IMM_LSL(0)); - } - if (data_reg2 != TCG_REG_R1) { - tcg_out_dat_reg(s, COND_AL, ARITH_MOV, - data_reg2, 0, TCG_REG_R1, SHIFT_IMM_LSL(0)); - } + tcg_out_mov_reg(s, COND_AL, data_reg, TCG_REG_R0); + tcg_out_mov_reg(s, COND_AL, data_reg2, TCG_REG_R1); break; } -- cgit v1.2.3 From 30daca5f77588a75bf9bcd604e21c5506402fabb Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Thu, 27 Sep 2012 20:57:38 +0200 Subject: slirp: Fix spelling in comment (enought -> enough, insure -> ensure) Signed-off-by: Stefan Weil Signed-off-by: Stefan Hajnoczi --- slirp/ip_icmp.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/slirp/ip_icmp.h b/slirp/ip_icmp.h index 1a1af91e1..be4426b8e 100644 --- a/slirp/ip_icmp.h +++ b/slirp/ip_icmp.h @@ -92,8 +92,8 @@ struct icmp { /* * Lower bounds on packet lengths for various types. - * For the error advice packets must first insure that the - * packet is large enought to contain the returned ip header. + * For the error advice packets must first ensure that the + * packet is large enough to contain the returned ip header. * Only then can we do the check to see if 64 bits of packet * data have been returned, since we need to check the returned * ip header length. -- cgit v1.2.3 From d69eba24269c0d3d376b7de4095dcca376a3beea Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Fri, 28 Sep 2012 18:11:49 +0200 Subject: vnc: Fix spelling (hellmen -> hellman) in comment The algorithm was named after Martin E. Hellman. Signed-off-by: Stefan Weil Signed-off-by: Stefan Hajnoczi --- ui/vnc-tls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/vnc-tls.c b/ui/vnc-tls.c index 3aaa93928..a7f7d07ac 100644 --- a/ui/vnc-tls.c +++ b/ui/vnc-tls.c @@ -49,7 +49,7 @@ static int vnc_tls_initialize(void) if (gnutls_global_init () < 0) return 0; - /* XXX ought to re-generate diffie-hellmen params periodically */ + /* XXX ought to re-generate diffie-hellman params periodically */ if (gnutls_dh_params_init (&dh_params) < 0) return 0; if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0) -- cgit v1.2.3 From 58455eb9f2865d54c8bf208805f7a4c217b5c00d Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Fri, 28 Sep 2012 19:07:39 +0200 Subject: qemu-sockets: Fix compiler warning (regression for MinGW) setsockopt needs a type cast for MinGW. That type cast is missing in a recent commit which results in a compiler warning. Like for other socket related functions which have the same problem, we add a 'qemu_setsockopt' macro which provides that type cast where needed and use the new macro to avoid the warning. A 'qemu_getsockopt' is also added and can be used for future modifications. Signed-off-by: Stefan Weil Signed-off-by: Stefan Hajnoczi --- qemu-common.h | 10 +++++++++- qemu-sockets.c | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/qemu-common.h b/qemu-common.h index 15d9e4ed7..b54612b1a 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -223,11 +223,19 @@ int qemu_pipe(int pipefd[2]); #endif #ifdef _WIN32 -/* MinGW needs a type cast for the 'buf' argument. */ +/* MinGW needs type casts for the 'buf' and 'optval' arguments. */ +#define qemu_getsockopt(sockfd, level, optname, optval, optlen) \ + getsockopt(sockfd, level, optname, (void *)optval, optlen) +#define qemu_setsockopt(sockfd, level, optname, optval, optlen) \ + setsockopt(sockfd, level, optname, (const void *)optval, optlen) #define qemu_recv(sockfd, buf, len, flags) recv(sockfd, (void *)buf, len, flags) #define qemu_sendto(sockfd, buf, len, flags, destaddr, addrlen) \ sendto(sockfd, (const void *)buf, len, flags, destaddr, addrlen) #else +#define qemu_getsockopt(sockfd, level, optname, optval, optlen) \ + getsockopt(sockfd, level, optname, optval, optlen) +#define qemu_setsockopt(sockfd, level, optname, optval, optlen) \ + setsockopt(sockfd, level, optname, optval, optlen) #define qemu_recv(sockfd, buf, len, flags) recv(sockfd, buf, len, flags) #define qemu_sendto(sockfd, buf, len, flags, destaddr, addrlen) \ sendto(sockfd, buf, len, flags, destaddr, addrlen) diff --git a/qemu-sockets.c b/qemu-sockets.c index 1f14e8bc6..0f5949085 100644 --- a/qemu-sockets.c +++ b/qemu-sockets.c @@ -282,7 +282,7 @@ static int inet_connect_addr(struct addrinfo *addr, bool *in_progress, inet_strfamily(addr->ai_family), strerror(errno)); return -1; } - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + qemu_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (connect_state != NULL) { socket_set_nonblock(sock); } -- cgit v1.2.3 From 4d5b97da35ecbfdad6fe1cbe7fdd7d71ef735602 Mon Sep 17 00:00:00 2001 From: Amos Kong Date: Sat, 29 Sep 2012 13:36:21 +0800 Subject: cleanup useless return sentence This patch cleans up return sentences in the end of void functions. Reported-by: Paolo Bonzini Signed-off-by: Amos Kong Signed-off-by: Stefan Hajnoczi --- block/qed-table.c | 1 - blockdev.c | 1 - hw/9pfs/virtio-9p.c | 5 ----- hw/blizzard.c | 2 -- hw/bt-hci.c | 1 - hw/device-hotplug.c | 1 - hw/exynos4210_combiner.c | 4 ---- hw/exynos4210_gic.c | 4 ---- hw/exynos4210_mct.c | 2 -- hw/fdc.c | 2 -- hw/framebuffer.c | 1 - hw/ide/macio.c | 1 - hw/ivshmem.c | 4 ---- hw/megasas.c | 1 - hw/msix.c | 1 - hw/pflash_cfi01.c | 1 - hw/pflash_cfi02.c | 1 - hw/pxa2xx_keypad.c | 1 - hw/sb16.c | 1 - hw/scsi-disk.c | 2 -- hw/tcx.c | 1 - hw/usb/dev-uas.c | 2 -- hw/usb/hcd-ohci.c | 2 -- hw/usb/hcd-xhci.c | 1 - hw/xen_domainbuild.c | 1 - libcacard/vcard.c | 1 - libcacard/vcard_emul_nss.c | 3 --- libcacard/vreader.c | 1 - linux-user/signal.c | 2 -- os-posix.c | 1 - qemu-sockets.c | 1 - qga/commands-posix.c | 2 -- qga/commands-win32.c | 2 -- savevm.c | 1 - slirp/ip_input.c | 1 - slirp/tcp_input.c | 2 -- slirp/udp.c | 1 - target-unicore32/translate.c | 2 -- ui/vnc-auth-sasl.c | 1 - vl.c | 1 - xen-all.c | 1 - 41 files changed, 67 deletions(-) diff --git a/block/qed-table.c b/block/qed-table.c index ce07b0554..de845ec3d 100644 --- a/block/qed-table.c +++ b/block/qed-table.c @@ -103,7 +103,6 @@ static void qed_write_table_cb(void *opaque, int ret) out: qemu_vfree(write_table_cb->table); gencb_complete(&write_table_cb->gencb, ret); - return; } /** diff --git a/blockdev.c b/blockdev.c index 5f18dfa97..99828ad2b 100644 --- a/blockdev.c +++ b/blockdev.c @@ -830,7 +830,6 @@ exit: QSIMPLEQ_FOREACH_SAFE(states, &snap_bdrv_states, entry, next) { g_free(states); } - return; } diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c index 4b5254011..8b9cdc96e 100644 --- a/hw/9pfs/virtio-9p.c +++ b/hw/9pfs/virtio-9p.c @@ -505,7 +505,6 @@ static void virtfs_reset(V9fsPDU *pdu) error_report("9pfs:%s: One or more uncluncked fids " "found during reset", __func__); } - return; } #define P9_QID_TYPE_DIR 0x80 @@ -934,7 +933,6 @@ static void v9fs_version(void *opaque) out: complete_pdu(s, pdu, offset); v9fs_string_free(&version); - return; } static void v9fs_attach(void *opaque) @@ -1314,7 +1312,6 @@ out_nofid: g_free(wnames); g_free(qids); } - return; } static int32_t get_iounit(V9fsPDU *pdu, V9fsPath *path) @@ -2257,7 +2254,6 @@ static void v9fs_flush(void *opaque) free_pdu(pdu->s, cancel_pdu); } complete_pdu(s, pdu, 7); - return; } static void v9fs_link(void *opaque) @@ -2763,7 +2759,6 @@ out: put_fid(pdu, fidp); out_nofid: complete_pdu(s, pdu, retval); - return; } static void v9fs_mknod(void *opaque) diff --git a/hw/blizzard.c b/hw/blizzard.c index d1c9d8151..06e19b364 100644 --- a/hw/blizzard.c +++ b/hw/blizzard.c @@ -878,8 +878,6 @@ void s1d13745_write_block(void *opaque, int dc, len -= 2; buf += 2; } - - return; } static void blizzard_update_display(void *opaque) diff --git a/hw/bt-hci.c b/hw/bt-hci.c index a3a7fb49e..f19299a77 100644 --- a/hw/bt-hci.c +++ b/hw/bt-hci.c @@ -786,7 +786,6 @@ static void bt_hci_lmp_connection_request(struct bt_link_s *link) memcpy(¶ms.dev_class, &link->host->class, sizeof(params.dev_class)); params.link_type = ACL_LINK; bt_hci_event(hci, EVT_CONN_REQUEST, ¶ms, EVT_CONN_REQUEST_SIZE); - return; } static void bt_hci_conn_accept_timeout(void *opaque) diff --git a/hw/device-hotplug.c b/hw/device-hotplug.c index 2bdc615b4..eec0fe314 100644 --- a/hw/device-hotplug.c +++ b/hw/device-hotplug.c @@ -89,5 +89,4 @@ err: if (dinfo) { drive_put_ref(dinfo); } - return; } diff --git a/hw/exynos4210_combiner.c b/hw/exynos4210_combiner.c index 80af22cc3..60b33c788 100644 --- a/hw/exynos4210_combiner.c +++ b/hw/exynos4210_combiner.c @@ -347,8 +347,6 @@ static void exynos4210_combiner_write(void *opaque, target_phys_addr_t offset, TARGET_FMT_plx "\n", offset); break; } - - return; } /* Get combiner group and bit from irq number */ @@ -380,8 +378,6 @@ static void exynos4210_combiner_handler(void *opaque, int irq, int level) } exynos4210_combiner_update(s, group_n); - - return; } static void exynos4210_combiner_reset(DeviceState *d) diff --git a/hw/exynos4210_gic.c b/hw/exynos4210_gic.c index 7d03dd9ae..4fea09873 100644 --- a/hw/exynos4210_gic.c +++ b/hw/exynos4210_gic.c @@ -193,8 +193,6 @@ static void exynos4210_irq_handler(void *opaque, int irq, int level) /* Bypass */ qemu_set_irq(s->board_irqs[irq], level); - - return; } /* @@ -410,8 +408,6 @@ static void exynos4210_irq_gate_handler(void *opaque, int irq, int level) } qemu_irq_lower(s->out); - - return; } static void exynos4210_irq_gate_reset(DeviceState *d) diff --git a/hw/exynos4210_mct.c b/hw/exynos4210_mct.c index 7a22b1f90..6f94ce230 100644 --- a/hw/exynos4210_mct.c +++ b/hw/exynos4210_mct.c @@ -574,8 +574,6 @@ static void exynos4210_gfrc_event(void *opaque) exynos4210_gfrc_set_count(&s->g_timer, distance); exynos4210_gfrc_start(&s->g_timer); - - return; } /* diff --git a/hw/fdc.c b/hw/fdc.c index 43b0f2050..25a49e350 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -1286,8 +1286,6 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction) fdctrl->msr |= FD_MSR_DIO; /* IO based transfer: calculate len */ fdctrl_raise_irq(fdctrl, FD_SR0_SEEK); - - return; } /* Prepare a transfer of deleted data */ diff --git a/hw/framebuffer.c b/hw/framebuffer.c index 85a00a579..27fa6f51f 100644 --- a/hw/framebuffer.c +++ b/hw/framebuffer.c @@ -107,5 +107,4 @@ void framebuffer_update_display( DIRTY_MEMORY_VGA); *first_row = first; *last_row = last; - return; } diff --git a/hw/ide/macio.c b/hw/ide/macio.c index 848cb3142..f22872514 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -89,7 +89,6 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) done: bdrv_acct_done(s->bs, &s->acct); io->dma_end(opaque); - return; } static void pmac_ide_transfer_cb(void *opaque, int ret) diff --git a/hw/ivshmem.c b/hw/ivshmem.c index 59f1aa426..5c4ccb85f 100644 --- a/hw/ivshmem.c +++ b/hw/ivshmem.c @@ -149,7 +149,6 @@ static void ivshmem_IntrStatus_write(IVShmemState *s, uint32_t val) s->intrstatus = val; ivshmem_update_irq(s, val); - return; } static uint32_t ivshmem_IntrStatus_read(IVShmemState *s) @@ -510,8 +509,6 @@ static void ivshmem_read(void *opaque, const uint8_t * buf, int flags) if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) { ivshmem_add_eventfd(s, incoming_posn, guest_max_eventfd); } - - return; } /* Select the MSI-X vectors used by device. @@ -536,7 +533,6 @@ static void ivshmem_reset(DeviceState *d) s->intrstatus = 0; ivshmem_use_msix(s); - return; } static uint64_t ivshmem_get_size(IVShmemState * s) { diff --git a/hw/megasas.c b/hw/megasas.c index c728aea69..0e57740fd 100644 --- a/hw/megasas.c +++ b/hw/megasas.c @@ -652,7 +652,6 @@ static void megasas_finish_dcmd(MegasasCmd *cmd, uint32_t iov_size) } } cmd->iov_size = 0; - return; } static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd) diff --git a/hw/msix.c b/hw/msix.c index d81209413..b623cb597 100644 --- a/hw/msix.c +++ b/hw/msix.c @@ -366,7 +366,6 @@ void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar, MemoryRegion *pba_bar) g_free(dev->msix_entry_used); dev->msix_entry_used = NULL; dev->cap_present &= ~QEMU_PCI_CAP_MSIX; - return; } void msix_uninit_exclusive_bar(PCIDevice *dev) diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c index 855890d1f..3b437da9c 100644 --- a/hw/pflash_cfi01.c +++ b/hw/pflash_cfi01.c @@ -442,7 +442,6 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset, pfl->bypass = 0; pfl->wcycle = 0; pfl->cmd = 0; - return; } diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index 8cb154958..39337ec30 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -474,7 +474,6 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t offset, do_bypass: pfl->wcycle = 2; pfl->cmd = 0; - return; } diff --git a/hw/pxa2xx_keypad.c b/hw/pxa2xx_keypad.c index 59db02584..1a997c9c8 100644 --- a/hw/pxa2xx_keypad.c +++ b/hw/pxa2xx_keypad.c @@ -172,7 +172,6 @@ static void pxa27x_keyboard_event (PXA2xxKeyPadState *kp, int keycode) kp->kpc |= KPC_MI; qemu_irq_raise(kp->irq); } - return; } static uint64_t pxa2xx_keypad_read(void *opaque, target_phys_addr_t offset, diff --git a/hw/sb16.c b/hw/sb16.c index c81455d7f..523ab0d5f 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -822,7 +822,6 @@ static void complete (SB16State *s) ldebug ("\n"); s->cmd = -1; - return; } static void legacy_reset (SB16State *s) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 99bb02ebf..1b0afa635 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -1437,7 +1437,6 @@ invalid_param_len: invalid_field: scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); - return; } static inline bool check_lba_range(SCSIDiskState *s, @@ -1535,7 +1534,6 @@ static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf) invalid_param_len: scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN)); - return; } static void scsi_disk_emulate_write_data(SCSIRequest *req) diff --git a/hw/tcx.c b/hw/tcx.c index 93994d644..2db2db123 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -472,7 +472,6 @@ static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint64_t val, default: break; } - return; } static const MemoryRegionOps tcx_dac_ops = { diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c index 5a0057a36..4389380e9 100644 --- a/hw/usb/dev-uas.c +++ b/hw/usb/dev-uas.c @@ -576,7 +576,6 @@ bad_target: */ usb_uas_queue_response(uas, req->tag, UAS_RC_INVALID_INFO_UNIT, 0); g_free(req); - return; } static void usb_uas_task(UASDevice *uas, uas_ui *ui) @@ -640,7 +639,6 @@ bad_target: incorrect_lun: usb_uas_queue_response(uas, tag, UAS_RC_INCORRECT_LUN, 0); - return; } static int usb_uas_handle_data(USBDevice *dev, USBPacket *p) diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index c36184ae4..59c7055cb 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -1470,8 +1470,6 @@ static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val) if (old_state != port->ctrl) ohci_set_interrupt(ohci, OHCI_INTR_RHSC); - - return; } static uint64_t ohci_mem_read(void *opaque, diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index e79a8724c..3a41b067c 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -807,7 +807,6 @@ static void xhci_events_update(XHCIState *xhci, int v) DPRINTF("xhci_events_update(): event ring no longer full\n"); intr->er_full = 0; } - return; } static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v) diff --git a/hw/xen_domainbuild.c b/hw/xen_domainbuild.c index a6a12e593..db1497469 100644 --- a/hw/xen_domainbuild.c +++ b/hw/xen_domainbuild.c @@ -153,7 +153,6 @@ static void xen_domain_poll(void *opaque) quit: qemu_system_shutdown_request(); - return; } static int xen_domain_watcher(void) diff --git a/libcacard/vcard.c b/libcacard/vcard.c index b02556ee0..539177bb4 100644 --- a/libcacard/vcard.c +++ b/libcacard/vcard.c @@ -200,7 +200,6 @@ vcard_free(VCard *vcard) } vcard_buffer_response_delete(vcard->vcard_buffer_response); g_free(vcard); - return; } void diff --git a/libcacard/vcard_emul_nss.c b/libcacard/vcard_emul_nss.c index 802cae3a2..b861c5afc 100644 --- a/libcacard/vcard_emul_nss.c +++ b/libcacard/vcard_emul_nss.c @@ -168,7 +168,6 @@ vcard_emul_delete_key(VCardKey *key) if (key->slot) { PK11_FreeSlot(key->slot); } - return; } /* @@ -418,7 +417,6 @@ vcard_emul_reset(VCard *card, VCardPower power) /* TODO: we may also need to send insertion/removal events? */ slot = vcard_emul_card_get_slot(card); PK11_Logout(slot); /* NOTE: ignoring SECStatus return value */ - return; } @@ -535,7 +533,6 @@ vcard_emul_get_atr(VCard *card, unsigned char *atr, int *atr_len) memcpy(atr, nss_atr, len); *atr_len = len; - return; } /* diff --git a/libcacard/vreader.c b/libcacard/vreader.c index ec126dfa4..96d2407e7 100644 --- a/libcacard/vreader.c +++ b/libcacard/vreader.c @@ -93,7 +93,6 @@ vreader_free(VReader *reader) reader->reader_private_free(reader->reader_private); } g_free(reader); - return; } static VCard * diff --git a/linux-user/signal.c b/linux-user/signal.c index 78691473f..15bc4e8f6 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -2762,7 +2762,6 @@ static void setup_frame(int sig, struct target_sigaction * ka, give_sigsegv: unlock_user_struct(frame, frame_addr, 1); force_sig(TARGET_SIGSEGV/*, current*/); - return; } long do_sigreturn(CPUMIPSState *regs) @@ -2871,7 +2870,6 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, give_sigsegv: unlock_user_struct(frame, frame_addr, 1); force_sig(TARGET_SIGSEGV/*, current*/); - return; } long do_rt_sigreturn(CPUMIPSState *env) diff --git a/os-posix.c b/os-posix.c index eabccb8fe..178e7caa4 100644 --- a/os-posix.c +++ b/os-posix.c @@ -194,7 +194,6 @@ void os_parse_cmd_args(int index, const char *optarg) break; #endif } - return; } static void change_process_uid(void) diff --git a/qemu-sockets.c b/qemu-sockets.c index 0f5949085..2b1ed2f0e 100644 --- a/qemu-sockets.c +++ b/qemu-sockets.c @@ -266,7 +266,6 @@ static void wait_for_connect(void *opaque) s->callback(s->fd, s->opaque); } g_free(s); - return; } static int inet_connect_addr(struct addrinfo *addr, bool *in_progress, diff --git a/qga/commands-posix.c b/qga/commands-posix.c index ce9042123..b0eec7414 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -988,8 +988,6 @@ int64_t qmp_guest_fsfreeze_thaw(Error **err) void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) { error_set(err, QERR_UNSUPPORTED); - - return; } #endif diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 54bc5462e..5bd8fb27f 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -180,8 +180,6 @@ int64_t qmp_guest_fsfreeze_thaw(Error **err) void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) { error_set(err, QERR_UNSUPPORTED); - - return; } typedef enum { diff --git a/savevm.c b/savevm.c index c7fe28314..31fd2e0ad 100644 --- a/savevm.c +++ b/savevm.c @@ -2201,7 +2201,6 @@ void qmp_xen_save_devices_state(const char *filename, Error **errp) the_end: if (saved_vm_running) vm_start(); - return; } int load_vmstate(const char *name) diff --git a/slirp/ip_input.c b/slirp/ip_input.c index ce24faf16..6f4cff8fd 100644 --- a/slirp/ip_input.c +++ b/slirp/ip_input.c @@ -213,7 +213,6 @@ ip_input(struct mbuf *m) return; bad: m_free(m); - return; } #define iptofrag(P) ((struct ipasfrag *)(((char*)(P)) - sizeof(struct qlink))) diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c index 942aaf44f..6440eae7f 100644 --- a/slirp/tcp_input.c +++ b/slirp/tcp_input.c @@ -1281,8 +1281,6 @@ drop: * Drop space held by incoming segment and return. */ m_free(m); - - return; } static void diff --git a/slirp/udp.c b/slirp/udp.c index ced509656..9286cb7d3 100644 --- a/slirp/udp.c +++ b/slirp/udp.c @@ -231,7 +231,6 @@ udp_input(register struct mbuf *m, int iphlen) return; bad: m_free(m); - return; } int udp_output2(struct socket *so, struct mbuf *m, diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c index 36f4f2f96..c3cdafa18 100644 --- a/target-unicore32/translate.c +++ b/target-unicore32/translate.c @@ -1932,8 +1932,6 @@ static void disas_uc32_insn(CPUUniCore32State *env, DisasContext *s) } ILLEGAL; } - - return; } /* generate intermediate code in gen_opc_buf and gen_opparam_buf for diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c index 8fba7702c..9a0ad30a9 100644 --- a/ui/vnc-auth-sasl.c +++ b/ui/vnc-auth-sasl.c @@ -619,7 +619,6 @@ void start_auth_sasl(VncState *vs) authabort: vnc_client_error(vs); - return; } diff --git a/vl.c b/vl.c index 8d305ca59..29e05a303 100644 --- a/vl.c +++ b/vl.c @@ -1023,7 +1023,6 @@ static void numa_add(const char *optarg) } nb_numa_nodes++; } - return; } static void smp_parse(const char *optarg) diff --git a/xen-all.c b/xen-all.c index e6308be23..bcb7ef7c8 100644 --- a/xen-all.c +++ b/xen-all.c @@ -1092,7 +1092,6 @@ static void xen_read_physmap(XenIOState *state) QLIST_INSERT_HEAD(&state->physmap, physmap, list); } free(entries); - return; } int xen_hvm_init(void) -- cgit v1.2.3 From da665c99f1b5d3247f7f9f8a24f3eb1fda94e1e4 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Wed, 3 Oct 2012 11:19:39 +0200 Subject: hw: Add missing 'static' attribute for QEMUMachine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was missing for leon3 and mips_fulong2e. Signed-off-by: Stefan Weil Reviewed-by: Andreas Färber Signed-off-by: Stefan Hajnoczi --- hw/leon3.c | 2 +- hw/mips_fulong2e.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/leon3.c b/hw/leon3.c index 878d3aa55..7a9729dc2 100644 --- a/hw/leon3.c +++ b/hw/leon3.c @@ -210,7 +210,7 @@ static void leon3_generic_hw_init(ram_addr_t ram_size, } } -QEMUMachine leon3_generic_machine = { +static QEMUMachine leon3_generic_machine = { .name = "leon3_generic", .desc = "Leon-3 generic", .init = leon3_generic_hw_init, diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c index 38e4b8615..d4a8672f2 100644 --- a/hw/mips_fulong2e.c +++ b/hw/mips_fulong2e.c @@ -392,7 +392,7 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device, network_init(); } -QEMUMachine mips_fulong2e_machine = { +static QEMUMachine mips_fulong2e_machine = { .name = "fulong2e", .desc = "Fulong 2e mini pc", .init = mips_fulong2e_init, -- cgit v1.2.3 From 8e7e2b14e7c86cdceb337cf7f5c4c351ab350775 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Wed, 3 Oct 2012 23:11:02 +0200 Subject: qemu-barrier: Fix compiler version check for future gcc versions The current check will give a wrong result for gcc-5.x with x < 4. Using QEMU_GNUC_PREREQ is simpler and fixes that issue. Signed-off-by: Stefan Weil Signed-off-by: Stefan Hajnoczi --- qemu-barrier.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-barrier.h b/qemu-barrier.h index 7e1119781..16f09429c 100644 --- a/qemu-barrier.h +++ b/qemu-barrier.h @@ -19,7 +19,7 @@ * mfence on 32 bit as well, e.g. if built with -march=pentium-m. * However, on i386, there seem to be known bugs as recently as 4.3. * */ -#if defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 4 +#if QEMU_GNUC_PREREQ(4, 4) #define smp_mb() __sync_synchronize() #else #define smp_mb() asm volatile("lock; addl $0,0(%%esp) " ::: "memory") -- cgit v1.2.3 From c36b7de64dfb106ee0384d2634fd4037218ffbca Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 4 Oct 2012 16:15:21 -0300 Subject: qdev: kill bogus comment When the DeviceInfo code was removed, the comment describing qdev_subclass_init() was left in the code by mistake. Remove it. Cc: qemu-trivial@nongnu.org Signed-off-by: Eduardo Habkost Signed-off-by: Stefan Hajnoczi --- hw/qdev.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/qdev.c b/hw/qdev.c index b5a52ac50..a7270a5cb 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -34,7 +34,6 @@ int qdev_hotplug = 0; static bool qdev_hot_added = false; static bool qdev_hot_removed = false; -/* Register a new device type. */ const VMStateDescription *qdev_get_vmsd(DeviceState *dev) { DeviceClass *dc = DEVICE_GET_CLASS(dev); -- cgit v1.2.3 From 02cd521f6e207bd8843a7c1309f6d065cf01c6ee Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Thu, 4 Oct 2012 22:49:43 +0200 Subject: versatilepb: Use symbolic indices for ARM PIC It is more readable, and all other code does it like that, too. Signed-off-by: Stefan Weil Reviewed-by: Peter Maydell Signed-off-by: Stefan Hajnoczi --- hw/versatilepb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 7a9203471..b3f807714 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -211,7 +211,8 @@ static void versatile_init(ram_addr_t ram_size, cpu_pic = arm_pic_init_cpu(cpu); dev = sysbus_create_varargs("pl190", 0x10140000, - cpu_pic[0], cpu_pic[1], NULL); + cpu_pic[ARM_PIC_CPU_IRQ], + cpu_pic[ARM_PIC_CPU_FIQ], NULL); for (n = 0; n < 32; n++) { pic[n] = qdev_get_gpio_in(dev, n); } -- cgit v1.2.3 From 6fd2a026fbf46ed5927a57e3e043a2039a0651d0 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 5 Oct 2012 15:04:43 +0100 Subject: cpu_dump_state: move DUMP_FPU and DUMP_CCOP flags from x86-only to generic Move the DUMP_FPU and DUMP_CCOP flags for cpu_dump_state() from being x86-specific flags to being generic ones. This allows us to drop some TARGET_I386 ifdefs in various places, and means that we can (potentially) be more consistent across architectures about which monitor commands or debug abort printouts include FPU register contents and info about QEMU's condition-code optimisations. Signed-off-by: Peter Maydell --- cpu-all.h | 3 +++ cpu-exec.c | 2 +- cpus.c | 6 +----- exec.c | 12 ++---------- monitor.c | 8 +------- target-i386/cpu.c | 2 +- target-i386/cpu.h | 4 ---- target-i386/helper.c | 4 ++-- target-i386/seg_helper.c | 4 ++-- target-i386/smm_helper.c | 4 ++-- 10 files changed, 15 insertions(+), 34 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 74d3681c2..2b9968267 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -356,6 +356,9 @@ CPUArchState *cpu_copy(CPUArchState *env); CPUArchState *qemu_get_cpu(int cpu); #define CPU_DUMP_CODE 0x00010000 +#define CPU_DUMP_FPU 0x00020000 /* dump FPU register state, not just integer */ +/* dump info about TCG QEMU's condition code optimization state */ +#define CPU_DUMP_CCOP 0x00040000 void cpu_dump_state(CPUArchState *env, FILE *f, fprintf_function cpu_fprintf, int flags); diff --git a/cpu-exec.c b/cpu-exec.c index 134b3c4fc..252da8688 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -552,7 +552,7 @@ int cpu_exec(CPUArchState *env) #if defined(TARGET_I386) env->eflags = env->eflags | cpu_cc_compute_all(env, CC_OP) | (DF & DF_MASK); - log_cpu_state(env, X86_DUMP_CCOP); + log_cpu_state(env, CPU_DUMP_CCOP); env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); #elif defined(TARGET_M68K) cpu_m68k_flush_flags(env, env->cc_op); diff --git a/cpus.c b/cpus.c index 4b726ef4e..5ba87fe0c 100644 --- a/cpus.c +++ b/cpus.c @@ -395,11 +395,7 @@ void hw_error(const char *fmt, ...) fprintf(stderr, "\n"); for(env = first_cpu; env != NULL; env = env->next_cpu) { fprintf(stderr, "CPU #%d:\n", env->cpu_index); -#ifdef TARGET_I386 - cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU); -#else - cpu_dump_state(env, stderr, fprintf, 0); -#endif + cpu_dump_state(env, stderr, fprintf, CPU_DUMP_FPU); } va_end(ap); abort(); diff --git a/exec.c b/exec.c index 1114a0932..7899042ce 100644 --- a/exec.c +++ b/exec.c @@ -1742,20 +1742,12 @@ void cpu_abort(CPUArchState *env, const char *fmt, ...) fprintf(stderr, "qemu: fatal: "); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); -#ifdef TARGET_I386 - cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP); -#else - cpu_dump_state(env, stderr, fprintf, 0); -#endif + cpu_dump_state(env, stderr, fprintf, CPU_DUMP_FPU | CPU_DUMP_CCOP); if (qemu_log_enabled()) { qemu_log("qemu: fatal: "); qemu_log_vprintf(fmt, ap2); qemu_log("\n"); -#ifdef TARGET_I386 - log_cpu_state(env, X86_DUMP_FPU | X86_DUMP_CCOP); -#else - log_cpu_state(env, 0); -#endif + log_cpu_state(env, CPU_DUMP_FPU | CPU_DUMP_CCOP); qemu_log_flush(); qemu_log_close(); } diff --git a/monitor.c b/monitor.c index a0e3ffb92..131b325f1 100644 --- a/monitor.c +++ b/monitor.c @@ -898,13 +898,7 @@ static void do_info_registers(Monitor *mon) { CPUArchState *env; env = mon_get_cpu(); -#ifdef TARGET_I386 - cpu_dump_state(env, (FILE *)mon, monitor_fprintf, - X86_DUMP_FPU); -#else - cpu_dump_state(env, (FILE *)mon, monitor_fprintf, - 0); -#endif + cpu_dump_state(env, (FILE *)mon, monitor_fprintf, CPU_DUMP_FPU); } static void do_info_jit(Monitor *mon) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index bb1e44eb0..f3708e63b 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1759,7 +1759,7 @@ static void x86_cpu_reset(CPUState *s) if (qemu_loglevel_mask(CPU_LOG_RESET)) { qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); - log_cpu_state(env, X86_DUMP_FPU | X86_DUMP_CCOP); + log_cpu_state(env, CPU_DUMP_FPU | CPU_DUMP_CCOP); } xcc->parent_reset(s); diff --git a/target-i386/cpu.h b/target-i386/cpu.h index e4a7d5b6e..871c27011 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -995,10 +995,6 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4); void cpu_smm_update(CPUX86State *env); uint64_t cpu_get_tsc(CPUX86State *env); -/* used to debug */ -#define X86_DUMP_FPU 0x0001 /* dump FPU state too */ -#define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */ - #define TARGET_PAGE_BITS 12 #ifdef TARGET_X86_64 diff --git a/target-i386/helper.c b/target-i386/helper.c index c635667d6..2ee7c6d1b 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -284,7 +284,7 @@ void cpu_dump_state(CPUX86State *env, FILE *f, fprintf_function cpu_fprintf, cpu_fprintf(f, "\nDR6=" TARGET_FMT_lx " DR7=" TARGET_FMT_lx "\n", env->dr[6], env->dr[7]); } - if (flags & X86_DUMP_CCOP) { + if (flags & CPU_DUMP_CCOP) { if ((unsigned)env->cc_op < CC_OP_NB) snprintf(cc_op_name, sizeof(cc_op_name), "%s", cc_op_str[env->cc_op]); else @@ -303,7 +303,7 @@ void cpu_dump_state(CPUX86State *env, FILE *f, fprintf_function cpu_fprintf, } } cpu_fprintf(f, "EFER=%016" PRIx64 "\n", env->efer); - if (flags & X86_DUMP_FPU) { + if (flags & CPU_DUMP_FPU) { int fptag; fptag = 0; for(i = 0; i < 8; i++) { diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c index 5fff8d59c..ff9337441 100644 --- a/target-i386/seg_helper.c +++ b/target-i386/seg_helper.c @@ -31,7 +31,7 @@ #ifdef DEBUG_PCALL # define LOG_PCALL(...) qemu_log_mask(CPU_LOG_PCALL, ## __VA_ARGS__) # define LOG_PCALL_STATE(env) \ - log_cpu_state_mask(CPU_LOG_PCALL, (env), X86_DUMP_CCOP) + log_cpu_state_mask(CPU_LOG_PCALL, (env), CPU_DUMP_CCOP) #else # define LOG_PCALL(...) do { } while (0) # define LOG_PCALL_STATE(env) do { } while (0) @@ -1177,7 +1177,7 @@ static void do_interrupt_all(CPUX86State *env, int intno, int is_int, qemu_log(" EAX=" TARGET_FMT_lx, EAX); } qemu_log("\n"); - log_cpu_state(env, X86_DUMP_CCOP); + log_cpu_state(env, CPU_DUMP_CCOP); #if 0 { int i; diff --git a/target-i386/smm_helper.c b/target-i386/smm_helper.c index 8b04eb2e0..eea2fe978 100644 --- a/target-i386/smm_helper.c +++ b/target-i386/smm_helper.c @@ -47,7 +47,7 @@ void do_smm_enter(CPUX86State *env) int i, offset; qemu_log_mask(CPU_LOG_INT, "SMM: enter\n"); - log_cpu_state_mask(CPU_LOG_INT, env, X86_DUMP_CCOP); + log_cpu_state_mask(CPU_LOG_INT, env, CPU_DUMP_CCOP); env->hflags |= HF_SMM_MASK; cpu_smm_update(env); @@ -295,7 +295,7 @@ void helper_rsm(CPUX86State *env) cpu_smm_update(env); qemu_log_mask(CPU_LOG_INT, "SMM: after RSM\n"); - log_cpu_state_mask(CPU_LOG_INT, env, X86_DUMP_CCOP); + log_cpu_state_mask(CPU_LOG_INT, env, CPU_DUMP_CCOP); } #endif /* !CONFIG_USER_ONLY */ -- cgit v1.2.3 From f2617cfc237a7f7e72bd3791ed1f3d35f496bb22 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 5 Oct 2012 15:04:44 +0100 Subject: target-arm: Reinstate display of VFP registers in cpu_dump_state Reinstate the display of VFP registers in cpu_dump_state(), if the CPU has them (this code had been #if 0'd out a for a long time). We drop the attempt ot display the values as floating point, since this makes assumptions about the host 'float' and 'double' formats and is not done by eg the i386 cpu_dump_state(). This display is gated on the CPU_DUMP_FPU flag, as for x86. Signed-off-by: Peter Maydell --- target-arm/translate.c | 42 ++++++++++++++++-------------------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 5fded491e..bb53e35db 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -9970,19 +9970,6 @@ void cpu_dump_state(CPUARMState *env, FILE *f, fprintf_function cpu_fprintf, int flags) { int i; -#if 0 - union { - uint32_t i; - float s; - } s0, s1; - CPU_DoubleU d; - /* ??? This assumes float64 and double have the same layout. - Oh well, it's only debug dumps. */ - union { - float64 f64; - double d; - } d0; -#endif uint32_t psr; for(i=0;i<16;i++) { @@ -10002,20 +9989,23 @@ void cpu_dump_state(CPUARMState *env, FILE *f, fprintf_function cpu_fprintf, psr & CPSR_T ? 'T' : 'A', cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26); -#if 0 - for (i = 0; i < 16; i++) { - d.d = env->vfp.regs[i]; - s0.i = d.l.lower; - s1.i = d.l.upper; - d0.f64 = d.d; - cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g) d%02d=%08x%08x(%8g)\n", - i * 2, (int)s0.i, s0.s, - i * 2 + 1, (int)s1.i, s1.s, - i, (int)(uint32_t)d.l.upper, (int)(uint32_t)d.l.lower, - d0.d); + if (flags & CPU_DUMP_FPU) { + int numvfpregs = 0; + if (arm_feature(env, ARM_FEATURE_VFP)) { + numvfpregs += 16; + } + if (arm_feature(env, ARM_FEATURE_VFP3)) { + numvfpregs += 16; + } + for (i = 0; i < numvfpregs; i++) { + uint64_t v = float64_val(env->vfp.regs[i]); + cpu_fprintf(f, "s%02d=%08x s%02d=%08x d%02d=%016" PRIx64 "\n", + i * 2, (uint32_t)v, + i * 2 + 1, (uint32_t)(v >> 32), + i, v); + } + cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]); } - cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]); -#endif } void restore_state_to_opc(CPUARMState *env, TranslationBlock *tb, int pc_pos) -- cgit v1.2.3 From 66c374de8a949062bfb1792f7e685a168c61c416 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Fri, 5 Oct 2012 15:04:44 +0100 Subject: target-arm: use globals for CC flags Use globals for CC flags instead of loading/storing them each they are accessed. This allows some optimizations to be performed by the TCG optimization passes. Signed-off-by: Aurelien Jarno Signed-off-by: Peter Maydell --- target-arm/translate.c | 127 ++++++++++++++++++------------------------------- 1 file changed, 46 insertions(+), 81 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index bb53e35db..105593165 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -85,6 +85,7 @@ static TCGv_ptr cpu_env; /* We reuse the same 64-bit temporaries for efficiency. */ static TCGv_i64 cpu_V0, cpu_V1, cpu_M0; static TCGv_i32 cpu_R[16]; +static TCGv_i32 cpu_CF, cpu_NF, cpu_VF, cpu_ZF; static TCGv_i32 cpu_exclusive_addr; static TCGv_i32 cpu_exclusive_val; static TCGv_i32 cpu_exclusive_high; @@ -115,6 +116,11 @@ void arm_translate_init(void) offsetof(CPUARMState, regs[i]), regnames[i]); } + cpu_CF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, CF), "CF"); + cpu_NF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, NF), "NF"); + cpu_VF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, VF), "VF"); + cpu_ZF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, ZF), "ZF"); + cpu_exclusive_addr = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, exclusive_addr), "exclusive_addr"); cpu_exclusive_val = tcg_global_mem_new_i32(TCG_AREG0, @@ -369,53 +375,39 @@ static void gen_add16(TCGv t0, TCGv t1) tcg_temp_free_i32(t1); } -#define gen_set_CF(var) tcg_gen_st_i32(var, cpu_env, offsetof(CPUARMState, CF)) - /* Set CF to the top bit of var. */ static void gen_set_CF_bit31(TCGv var) { - TCGv tmp = tcg_temp_new_i32(); - tcg_gen_shri_i32(tmp, var, 31); - gen_set_CF(tmp); - tcg_temp_free_i32(tmp); + tcg_gen_shri_i32(cpu_CF, var, 31); } /* Set N and Z flags from var. */ static inline void gen_logic_CC(TCGv var) { - tcg_gen_st_i32(var, cpu_env, offsetof(CPUARMState, NF)); - tcg_gen_st_i32(var, cpu_env, offsetof(CPUARMState, ZF)); + tcg_gen_mov_i32(cpu_NF, var); + tcg_gen_mov_i32(cpu_ZF, var); } /* T0 += T1 + CF. */ static void gen_adc(TCGv t0, TCGv t1) { - TCGv tmp; tcg_gen_add_i32(t0, t0, t1); - tmp = load_cpu_field(CF); - tcg_gen_add_i32(t0, t0, tmp); - tcg_temp_free_i32(tmp); + tcg_gen_add_i32(t0, t0, cpu_CF); } /* dest = T0 + T1 + CF. */ static void gen_add_carry(TCGv dest, TCGv t0, TCGv t1) { - TCGv tmp; tcg_gen_add_i32(dest, t0, t1); - tmp = load_cpu_field(CF); - tcg_gen_add_i32(dest, dest, tmp); - tcg_temp_free_i32(tmp); + tcg_gen_add_i32(dest, dest, cpu_CF); } /* dest = T0 - T1 + CF - 1. */ static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1) { - TCGv tmp; tcg_gen_sub_i32(dest, t0, t1); - tmp = load_cpu_field(CF); - tcg_gen_add_i32(dest, dest, tmp); + tcg_gen_add_i32(dest, dest, cpu_CF); tcg_gen_subi_i32(dest, dest, 1); - tcg_temp_free_i32(tmp); } /* FIXME: Implement this natively. */ @@ -423,16 +415,14 @@ static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1) static void shifter_out_im(TCGv var, int shift) { - TCGv tmp = tcg_temp_new_i32(); if (shift == 0) { - tcg_gen_andi_i32(tmp, var, 1); + tcg_gen_andi_i32(cpu_CF, var, 1); } else { - tcg_gen_shri_i32(tmp, var, shift); - if (shift != 31) - tcg_gen_andi_i32(tmp, tmp, 1); + tcg_gen_shri_i32(cpu_CF, var, shift); + if (shift != 31) { + tcg_gen_andi_i32(cpu_CF, cpu_CF, 1); + } } - gen_set_CF(tmp); - tcg_temp_free_i32(tmp); } /* Shift by immediate. Includes special handling for shift == 0. */ @@ -449,8 +439,7 @@ static inline void gen_arm_shift_im(TCGv var, int shiftop, int shift, int flags) case 1: /* LSR */ if (shift == 0) { if (flags) { - tcg_gen_shri_i32(var, var, 31); - gen_set_CF(var); + tcg_gen_shri_i32(cpu_CF, var, 31); } tcg_gen_movi_i32(var, 0); } else { @@ -474,11 +463,11 @@ static inline void gen_arm_shift_im(TCGv var, int shiftop, int shift, int flags) shifter_out_im(var, shift - 1); tcg_gen_rotri_i32(var, var, shift); break; } else { - TCGv tmp = load_cpu_field(CF); + TCGv tmp = tcg_temp_new_i32(); if (flags) shifter_out_im(var, 0); tcg_gen_shri_i32(var, var, 1); - tcg_gen_shli_i32(tmp, tmp, 31); + tcg_gen_shli_i32(tmp, cpu_CF, 31); tcg_gen_or_i32(var, var, tmp); tcg_temp_free_i32(tmp); } @@ -603,99 +592,75 @@ static void gen_thumb2_parallel_addsub(int op1, int op2, TCGv a, TCGv b) static void gen_test_cc(int cc, int label) { TCGv tmp; - TCGv tmp2; int inv; switch (cc) { case 0: /* eq: Z */ - tmp = load_cpu_field(ZF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ZF, 0, label); break; case 1: /* ne: !Z */ - tmp = load_cpu_field(ZF); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label); + tcg_gen_brcondi_i32(TCG_COND_NE, cpu_ZF, 0, label); break; case 2: /* cs: C */ - tmp = load_cpu_field(CF); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label); + tcg_gen_brcondi_i32(TCG_COND_NE, cpu_CF, 0, label); break; case 3: /* cc: !C */ - tmp = load_cpu_field(CF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_CF, 0, label); break; case 4: /* mi: N */ - tmp = load_cpu_field(NF); - tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + tcg_gen_brcondi_i32(TCG_COND_LT, cpu_NF, 0, label); break; case 5: /* pl: !N */ - tmp = load_cpu_field(NF); - tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + tcg_gen_brcondi_i32(TCG_COND_GE, cpu_NF, 0, label); break; case 6: /* vs: V */ - tmp = load_cpu_field(VF); - tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + tcg_gen_brcondi_i32(TCG_COND_LT, cpu_VF, 0, label); break; case 7: /* vc: !V */ - tmp = load_cpu_field(VF); - tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + tcg_gen_brcondi_i32(TCG_COND_GE, cpu_VF, 0, label); break; case 8: /* hi: C && !Z */ inv = gen_new_label(); - tmp = load_cpu_field(CF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv); - tcg_temp_free_i32(tmp); - tmp = load_cpu_field(ZF); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label); + tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_CF, 0, inv); + tcg_gen_brcondi_i32(TCG_COND_NE, cpu_ZF, 0, label); gen_set_label(inv); break; case 9: /* ls: !C || Z */ - tmp = load_cpu_field(CF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); - tcg_temp_free_i32(tmp); - tmp = load_cpu_field(ZF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); + tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_CF, 0, label); + tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ZF, 0, label); break; case 10: /* ge: N == V -> N ^ V == 0 */ - tmp = load_cpu_field(VF); - tmp2 = load_cpu_field(NF); - tcg_gen_xor_i32(tmp, tmp, tmp2); - tcg_temp_free_i32(tmp2); + tmp = tcg_temp_new_i32(); + tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF); tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + tcg_temp_free_i32(tmp); break; case 11: /* lt: N != V -> N ^ V != 0 */ - tmp = load_cpu_field(VF); - tmp2 = load_cpu_field(NF); - tcg_gen_xor_i32(tmp, tmp, tmp2); - tcg_temp_free_i32(tmp2); + tmp = tcg_temp_new_i32(); + tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF); tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + tcg_temp_free_i32(tmp); break; case 12: /* gt: !Z && N == V */ inv = gen_new_label(); - tmp = load_cpu_field(ZF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv); - tcg_temp_free_i32(tmp); - tmp = load_cpu_field(VF); - tmp2 = load_cpu_field(NF); - tcg_gen_xor_i32(tmp, tmp, tmp2); - tcg_temp_free_i32(tmp2); + tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ZF, 0, inv); + tmp = tcg_temp_new_i32(); + tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF); tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); + tcg_temp_free_i32(tmp); gen_set_label(inv); break; case 13: /* le: Z || N != V */ - tmp = load_cpu_field(ZF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); - tcg_temp_free_i32(tmp); - tmp = load_cpu_field(VF); - tmp2 = load_cpu_field(NF); - tcg_gen_xor_i32(tmp, tmp, tmp2); - tcg_temp_free_i32(tmp2); + tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ZF, 0, label); + tmp = tcg_temp_new_i32(); + tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF); tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); + tcg_temp_free_i32(tmp); break; default: fprintf(stderr, "Bad condition code 0x%x\n", cc); abort(); } - tcg_temp_free_i32(tmp); } static const uint8_t table_logic_cc[16] = { -- cgit v1.2.3 From 72485ec4f63d86c428f9223fc966bd7d2cc8100c Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Fri, 5 Oct 2012 15:04:44 +0100 Subject: target-arm: convert add_cc and sub_cc helpers to TCG Now that the setcond TCG op is available, it's possible to replace add_cc and sub_cc helpers by TCG code. The code generated by TCG is actually very close to the one generated by GCC for the helper, and this avoid all the consequences of using an helper: globals saved back to memory, no possible optimization, call overhead, etc. Signed-off-by: Aurelien Jarno Signed-off-by: Peter Maydell --- target-arm/helper.h | 2 -- target-arm/op_helper.c | 20 --------------- target-arm/translate.c | 66 ++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 48 insertions(+), 40 deletions(-) diff --git a/target-arm/helper.h b/target-arm/helper.h index afdb2b5b1..7151e28d4 100644 --- a/target-arm/helper.h +++ b/target-arm/helper.h @@ -142,9 +142,7 @@ DEF_HELPER_2(recpe_u32, i32, i32, env) DEF_HELPER_2(rsqrte_u32, i32, i32, env) DEF_HELPER_5(neon_tbl, i32, env, i32, i32, i32, i32) -DEF_HELPER_3(add_cc, i32, env, i32, i32) DEF_HELPER_3(adc_cc, i32, env, i32, i32) -DEF_HELPER_3(sub_cc, i32, env, i32, i32) DEF_HELPER_3(sbc_cc, i32, env, i32, i32) DEF_HELPER_3(shl, i32, env, i32, i32) diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index f13fc3ae5..6095f2435 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -323,16 +323,6 @@ uint64_t HELPER(get_cp_reg64)(CPUARMState *env, void *rip) The only way to do that in TCG is a conditional branch, which clobbers all our temporaries. For now implement these as helper functions. */ -uint32_t HELPER (add_cc)(CPUARMState *env, uint32_t a, uint32_t b) -{ - uint32_t result; - result = a + b; - env->NF = env->ZF = result; - env->CF = result < a; - env->VF = (a ^ b ^ -1) & (a ^ result); - return result; -} - uint32_t HELPER(adc_cc)(CPUARMState *env, uint32_t a, uint32_t b) { uint32_t result; @@ -348,16 +338,6 @@ uint32_t HELPER(adc_cc)(CPUARMState *env, uint32_t a, uint32_t b) return result; } -uint32_t HELPER(sub_cc)(CPUARMState *env, uint32_t a, uint32_t b) -{ - uint32_t result; - result = a - b; - env->NF = env->ZF = result; - env->CF = a >= b; - env->VF = (a ^ b) & (a ^ result); - return result; -} - uint32_t HELPER(sbc_cc)(CPUARMState *env, uint32_t a, uint32_t b) { uint32_t result; diff --git a/target-arm/translate.c b/target-arm/translate.c index 105593165..da3246a95 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -410,6 +410,36 @@ static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1) tcg_gen_subi_i32(dest, dest, 1); } +/* dest = T0 + T1. Compute C, N, V and Z flags */ +static void gen_add_CC(TCGv dest, TCGv t0, TCGv t1) +{ + TCGv tmp; + tcg_gen_add_i32(cpu_NF, t0, t1); + tcg_gen_mov_i32(cpu_ZF, cpu_NF); + tcg_gen_setcond_i32(TCG_COND_LTU, cpu_CF, cpu_NF, t0); + tcg_gen_xor_i32(cpu_VF, cpu_NF, t0); + tmp = tcg_temp_new_i32(); + tcg_gen_xor_i32(tmp, t0, t1); + tcg_gen_andc_i32(cpu_VF, cpu_VF, tmp); + tcg_temp_free_i32(tmp); + tcg_gen_mov_i32(dest, cpu_NF); +} + +/* dest = T0 - T1. Compute C, N, V and Z flags */ +static void gen_sub_CC(TCGv dest, TCGv t0, TCGv t1) +{ + TCGv tmp; + tcg_gen_sub_i32(cpu_NF, t0, t1); + tcg_gen_mov_i32(cpu_ZF, cpu_NF); + tcg_gen_setcond_i32(TCG_COND_GEU, cpu_CF, t0, t1); + tcg_gen_xor_i32(cpu_VF, cpu_NF, t0); + tmp = tcg_temp_new_i32(); + tcg_gen_xor_i32(tmp, t0, t1); + tcg_gen_and_i32(cpu_VF, cpu_VF, tmp); + tcg_temp_free_i32(tmp); + tcg_gen_mov_i32(dest, cpu_NF); +} + /* FIXME: Implement this natively. */ #define tcg_gen_abs_i32(t0, t1) gen_helper_abs(t0, t1) @@ -6970,11 +7000,11 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) if (IS_USER(s)) { goto illegal_op; } - gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + gen_sub_CC(tmp, tmp, tmp2); gen_exception_return(s, tmp); } else { if (set_cc) { - gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + gen_sub_CC(tmp, tmp, tmp2); } else { tcg_gen_sub_i32(tmp, tmp, tmp2); } @@ -6983,7 +7013,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) break; case 0x03: if (set_cc) { - gen_helper_sub_cc(tmp, cpu_env, tmp2, tmp); + gen_sub_CC(tmp, tmp2, tmp); } else { tcg_gen_sub_i32(tmp, tmp2, tmp); } @@ -6991,7 +7021,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) break; case 0x04: if (set_cc) { - gen_helper_add_cc(tmp, cpu_env, tmp, tmp2); + gen_add_CC(tmp, tmp, tmp2); } else { tcg_gen_add_i32(tmp, tmp, tmp2); } @@ -7037,13 +7067,13 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) break; case 0x0a: if (set_cc) { - gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + gen_sub_CC(tmp, tmp, tmp2); } tcg_temp_free_i32(tmp); break; case 0x0b: if (set_cc) { - gen_helper_add_cc(tmp, cpu_env, tmp, tmp2); + gen_add_CC(tmp, tmp, tmp2); } tcg_temp_free_i32(tmp); break; @@ -7830,7 +7860,7 @@ gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out, TCG break; case 8: /* add */ if (conds) - gen_helper_add_cc(t0, cpu_env, t0, t1); + gen_add_CC(t0, t0, t1); else tcg_gen_add_i32(t0, t0, t1); break; @@ -7848,13 +7878,13 @@ gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out, TCG break; case 13: /* sub */ if (conds) - gen_helper_sub_cc(t0, cpu_env, t0, t1); + gen_sub_CC(t0, t0, t1); else tcg_gen_sub_i32(t0, t0, t1); break; case 14: /* rsb */ if (conds) - gen_helper_sub_cc(t0, cpu_env, t1, t0); + gen_sub_CC(t0, t1, t0); else tcg_gen_sub_i32(t0, t1, t0); break; @@ -8982,12 +9012,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) if (s->condexec_mask) tcg_gen_sub_i32(tmp, tmp, tmp2); else - gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + gen_sub_CC(tmp, tmp, tmp2); } else { if (s->condexec_mask) tcg_gen_add_i32(tmp, tmp, tmp2); else - gen_helper_add_cc(tmp, cpu_env, tmp, tmp2); + gen_add_CC(tmp, tmp, tmp2); } tcg_temp_free_i32(tmp2); store_reg(s, rd, tmp); @@ -9018,7 +9048,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) tcg_gen_movi_i32(tmp2, insn & 0xff); switch (op) { case 1: /* cmp */ - gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + gen_sub_CC(tmp, tmp, tmp2); tcg_temp_free_i32(tmp); tcg_temp_free_i32(tmp2); break; @@ -9026,7 +9056,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) if (s->condexec_mask) tcg_gen_add_i32(tmp, tmp, tmp2); else - gen_helper_add_cc(tmp, cpu_env, tmp, tmp2); + gen_add_CC(tmp, tmp, tmp2); tcg_temp_free_i32(tmp2); store_reg(s, rd, tmp); break; @@ -9034,7 +9064,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) if (s->condexec_mask) tcg_gen_sub_i32(tmp, tmp, tmp2); else - gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + gen_sub_CC(tmp, tmp, tmp2); tcg_temp_free_i32(tmp2); store_reg(s, rd, tmp); break; @@ -9070,7 +9100,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) case 1: /* cmp */ tmp = load_reg(s, rd); tmp2 = load_reg(s, rm); - gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + gen_sub_CC(tmp, tmp, tmp2); tcg_temp_free_i32(tmp2); tcg_temp_free_i32(tmp); break; @@ -9183,14 +9213,14 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) if (s->condexec_mask) tcg_gen_neg_i32(tmp, tmp2); else - gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + gen_sub_CC(tmp, tmp, tmp2); break; case 0xa: /* cmp */ - gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + gen_sub_CC(tmp, tmp, tmp2); rd = 16; break; case 0xb: /* cmn */ - gen_helper_add_cc(tmp, cpu_env, tmp, tmp2); + gen_add_CC(tmp, tmp, tmp2); rd = 16; break; case 0xc: /* orr */ -- cgit v1.2.3 From 365af80e47bf150506345cdfbcbf32120f18cdf6 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Fri, 5 Oct 2012 15:04:44 +0100 Subject: target-arm: convert sar, shl and shr helpers to TCG Now that the movcond TCG op is available, it's possible to replace shl and shr helpers by TCG code. The code generated by TCG is slightly longer than the code generated by GCC for the helper but is still worth it as this avoid all the consequences of using an helper: globals saved back to memory, no possible optimization, call overhead, etc. Signed-off-by: Aurelien Jarno Signed-off-by: Peter Maydell --- target-arm/helper.h | 3 --- target-arm/op_helper.c | 24 ------------------------ target-arm/translate.c | 49 +++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 43 insertions(+), 33 deletions(-) diff --git a/target-arm/helper.h b/target-arm/helper.h index 7151e28d4..794e2b186 100644 --- a/target-arm/helper.h +++ b/target-arm/helper.h @@ -145,9 +145,6 @@ DEF_HELPER_5(neon_tbl, i32, env, i32, i32, i32, i32) DEF_HELPER_3(adc_cc, i32, env, i32, i32) DEF_HELPER_3(sbc_cc, i32, env, i32, i32) -DEF_HELPER_3(shl, i32, env, i32, i32) -DEF_HELPER_3(shr, i32, env, i32, i32) -DEF_HELPER_3(sar, i32, env, i32, i32) DEF_HELPER_3(shl_cc, i32, env, i32, i32) DEF_HELPER_3(shr_cc, i32, env, i32, i32) DEF_HELPER_3(sar_cc, i32, env, i32, i32) diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index 6095f2435..aef592ab8 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -355,30 +355,6 @@ uint32_t HELPER(sbc_cc)(CPUARMState *env, uint32_t a, uint32_t b) /* Similarly for variable shift instructions. */ -uint32_t HELPER(shl)(CPUARMState *env, uint32_t x, uint32_t i) -{ - int shift = i & 0xff; - if (shift >= 32) - return 0; - return x << shift; -} - -uint32_t HELPER(shr)(CPUARMState *env, uint32_t x, uint32_t i) -{ - int shift = i & 0xff; - if (shift >= 32) - return 0; - return (uint32_t)x >> shift; -} - -uint32_t HELPER(sar)(CPUARMState *env, uint32_t x, uint32_t i) -{ - int shift = i & 0xff; - if (shift >= 32) - shift = 31; - return (int32_t)x >> shift; -} - uint32_t HELPER(shl_cc)(CPUARMState *env, uint32_t x, uint32_t i) { int shift = i & 0xff; diff --git a/target-arm/translate.c b/target-arm/translate.c index da3246a95..92ceacd87 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -440,6 +440,37 @@ static void gen_sub_CC(TCGv dest, TCGv t0, TCGv t1) tcg_gen_mov_i32(dest, cpu_NF); } +#define GEN_SHIFT(name) \ +static void gen_##name(TCGv dest, TCGv t0, TCGv t1) \ +{ \ + TCGv tmp1, tmp2, tmp3; \ + tmp1 = tcg_temp_new_i32(); \ + tcg_gen_andi_i32(tmp1, t1, 0xff); \ + tmp2 = tcg_const_i32(0); \ + tmp3 = tcg_const_i32(0x1f); \ + tcg_gen_movcond_i32(TCG_COND_GTU, tmp2, tmp1, tmp3, tmp2, t0); \ + tcg_temp_free_i32(tmp3); \ + tcg_gen_andi_i32(tmp1, tmp1, 0x1f); \ + tcg_gen_##name##_i32(dest, tmp2, tmp1); \ + tcg_temp_free_i32(tmp2); \ + tcg_temp_free_i32(tmp1); \ +} +GEN_SHIFT(shl) +GEN_SHIFT(shr) +#undef GEN_SHIFT + +static void gen_sar(TCGv dest, TCGv t0, TCGv t1) +{ + TCGv tmp1, tmp2; + tmp1 = tcg_temp_new_i32(); + tcg_gen_andi_i32(tmp1, t1, 0xff); + tmp2 = tcg_const_i32(0x1f); + tcg_gen_movcond_i32(TCG_COND_GTU, tmp1, tmp1, tmp2, tmp2, tmp1); + tcg_temp_free_i32(tmp2); + tcg_gen_sar_i32(dest, t0, tmp1); + tcg_temp_free_i32(tmp1); +} + /* FIXME: Implement this natively. */ #define tcg_gen_abs_i32(t0, t1) gen_helper_abs(t0, t1) @@ -516,9 +547,15 @@ static inline void gen_arm_shift_reg(TCGv var, int shiftop, } } else { switch (shiftop) { - case 0: gen_helper_shl(var, cpu_env, var, shift); break; - case 1: gen_helper_shr(var, cpu_env, var, shift); break; - case 2: gen_helper_sar(var, cpu_env, var, shift); break; + case 0: + gen_shl(var, var, shift); + break; + case 1: + gen_shr(var, var, shift); + break; + case 2: + gen_sar(var, var, shift); + break; case 3: tcg_gen_andi_i32(shift, shift, 0x1f); tcg_gen_rotr_i32(var, var, shift); break; } @@ -9161,7 +9198,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) break; case 0x2: /* lsl */ if (s->condexec_mask) { - gen_helper_shl(tmp2, cpu_env, tmp2, tmp); + gen_shl(tmp2, tmp2, tmp); } else { gen_helper_shl_cc(tmp2, cpu_env, tmp2, tmp); gen_logic_CC(tmp2); @@ -9169,7 +9206,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) break; case 0x3: /* lsr */ if (s->condexec_mask) { - gen_helper_shr(tmp2, cpu_env, tmp2, tmp); + gen_shr(tmp2, tmp2, tmp); } else { gen_helper_shr_cc(tmp2, cpu_env, tmp2, tmp); gen_logic_CC(tmp2); @@ -9177,7 +9214,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) break; case 0x4: /* asr */ if (s->condexec_mask) { - gen_helper_sar(tmp2, cpu_env, tmp2, tmp); + gen_sar(tmp2, tmp2, tmp); } else { gen_helper_sar_cc(tmp2, cpu_env, tmp2, tmp); gen_logic_CC(tmp2); -- cgit v1.2.3 From 00e3ab2db059d243e210052937fc4f4169aa839c Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Fri, 5 Oct 2012 15:04:45 +0100 Subject: target-arm: mark a few integer helpers const and pure Signed-off-by: Aurelien Jarno Signed-off-by: Peter Maydell --- target-arm/helper.h | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/target-arm/helper.h b/target-arm/helper.h index 794e2b186..8b9adf131 100644 --- a/target-arm/helper.h +++ b/target-arm/helper.h @@ -1,8 +1,8 @@ #include "def-helper.h" -DEF_HELPER_1(clz, i32, i32) -DEF_HELPER_1(sxtb16, i32, i32) -DEF_HELPER_1(uxtb16, i32, i32) +DEF_HELPER_FLAGS_1(clz, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32) +DEF_HELPER_FLAGS_1(sxtb16, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32) +DEF_HELPER_FLAGS_1(uxtb16, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32) DEF_HELPER_3(add_setq, i32, env, i32, i32) DEF_HELPER_3(add_saturate, i32, env, i32, i32) @@ -10,10 +10,10 @@ DEF_HELPER_3(sub_saturate, i32, env, i32, i32) DEF_HELPER_3(add_usaturate, i32, env, i32, i32) DEF_HELPER_3(sub_usaturate, i32, env, i32, i32) DEF_HELPER_2(double_saturate, i32, env, s32) -DEF_HELPER_2(sdiv, s32, s32, s32) -DEF_HELPER_2(udiv, i32, i32, i32) -DEF_HELPER_1(rbit, i32, i32) -DEF_HELPER_1(abs, i32, i32) +DEF_HELPER_FLAGS_2(sdiv, TCG_CALL_CONST | TCG_CALL_PURE, s32, s32, s32) +DEF_HELPER_FLAGS_2(udiv, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32, i32) +DEF_HELPER_FLAGS_1(rbit, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32) +DEF_HELPER_FLAGS_1(abs, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32) #define PAS_OP(pfx) \ DEF_HELPER_3(pfx ## add8, i32, i32, i32, ptr) \ @@ -45,11 +45,12 @@ DEF_HELPER_3(usat, i32, env, i32, i32) DEF_HELPER_3(ssat16, i32, env, i32, i32) DEF_HELPER_3(usat16, i32, env, i32, i32) -DEF_HELPER_2(usad8, i32, i32, i32) +DEF_HELPER_FLAGS_2(usad8, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32, i32) DEF_HELPER_1(logicq_cc, i32, i64) -DEF_HELPER_3(sel_flags, i32, i32, i32, i32) +DEF_HELPER_FLAGS_3(sel_flags, TCG_CALL_CONST | TCG_CALL_PURE, + i32, i32, i32, i32) DEF_HELPER_2(exception, void, env, i32) DEF_HELPER_1(wfi, void, env) -- cgit v1.2.3 From d593c48ef91b6fee609d9c87958fe76dd2b36852 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Fri, 5 Oct 2012 15:04:45 +0100 Subject: target-arm: use deposit instead of hardcoded version Use the deposit op instead of and hardcoded bit field insertion. It allows the host to emit the corresponding instruction if available. Signed-off-by: Aurelien Jarno Signed-off-by: Peter Maydell --- target-arm/translate.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 92ceacd87..c6840b783 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -277,15 +277,6 @@ static void gen_sbfx(TCGv var, int shift, int width) } } -/* Bitfield insertion. Insert val into base. Clobbers base and val. */ -static void gen_bfi(TCGv dest, TCGv base, TCGv val, int shift, uint32_t mask) -{ - tcg_gen_andi_i32(val, val, mask); - tcg_gen_shli_i32(val, val, shift); - tcg_gen_andi_i32(base, base, ~(mask << shift)); - tcg_gen_or_i32(dest, base, val); -} - /* Return (b << 32) + a. Mark inputs as dead */ static TCGv_i64 gen_addq_msw(TCGv_i64 a, TCGv b) { @@ -2660,12 +2651,12 @@ static int disas_vfp_insn(CPUARMState * env, DisasContext *s, uint32_t insn) switch (size) { case 0: tmp2 = neon_load_reg(rn, pass); - gen_bfi(tmp, tmp2, tmp, offset, 0xff); + tcg_gen_deposit_i32(tmp, tmp2, tmp, offset, 8); tcg_temp_free_i32(tmp2); break; case 1: tmp2 = neon_load_reg(rn, pass); - gen_bfi(tmp, tmp2, tmp, offset, 0xffff); + tcg_gen_deposit_i32(tmp, tmp2, tmp, offset, 16); tcg_temp_free_i32(tmp2); break; case 2: @@ -4021,7 +4012,8 @@ static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn) } if (size != 2) { tmp2 = neon_load_reg(rd, pass); - gen_bfi(tmp, tmp2, tmp, shift, size ? 0xffff : 0xff); + tcg_gen_deposit_i32(tmp, tmp2, tmp, + shift, size ? 16 : 8); tcg_temp_free_i32(tmp2); } neon_store_reg(rd, pass, tmp); @@ -7625,7 +7617,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) } if (i != 32) { tmp2 = load_reg(s, rd); - gen_bfi(tmp, tmp2, tmp, shift, (1u << i) - 1); + tcg_gen_deposit_i32(tmp, tmp2, tmp, shift, i); tcg_temp_free_i32(tmp2); } store_reg(s, rd, tmp); @@ -8736,7 +8728,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw imm = imm + 1 - shift; if (imm != 32) { tmp2 = load_reg(s, rd); - gen_bfi(tmp, tmp2, tmp, shift, (1u << imm) - 1); + tcg_gen_deposit_i32(tmp, tmp2, tmp, shift, imm); tcg_temp_free_i32(tmp2); } break; -- cgit v1.2.3 From 1273d9ca09e91bb290d10f704055f6abec363dd6 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 5 Oct 2012 15:04:45 +0100 Subject: target-arm: Drop unused DECODE_CPREG_CRN macro This macro snuck through code review despite being unused; drop it. Signed-off-by: Peter Maydell --- target-arm/cpu.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 7fac94f81..ff4de10f1 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -423,8 +423,6 @@ void armv7m_nvic_complete_irq(void *opaque, int irq); (((cp) << 16) | ((is64) << 15) | ((crn) << 11) | \ ((crm) << 7) | ((opc1) << 3) | (opc2)) -#define DECODE_CPREG_CRN(enc) (((enc) >> 7) & 0xf) - /* ARMCPRegInfo type field bits. If the SPECIAL bit is set this is a * special-behaviour cp reg and bits [15..8] indicate what behaviour * it has. Otherwise it is a simple cp reg, where CONST indicates that -- cgit v1.2.3 From f783cb22409c6537b3cab7e78e527f62b4237d1e Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 1 Oct 2012 21:00:42 +0200 Subject: target-xtensa: de-optimize EXTUI Now that "and" with 0xff, 0xffff and 0xffffffff and "shr" with 0 shift are optimized in tcg/tcg-op.h there is no need to do it in target-xtensa/translate.c. Acked-by: Max Filippov Signed-off-by: Aurelien Jarno --- target-xtensa/translate.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c index b9acd706c..82e8cccad 100644 --- a/target-xtensa/translate.c +++ b/target-xtensa/translate.c @@ -1829,26 +1829,8 @@ static void disas_xtensa_insn(DisasContext *dc) int maskimm = (1 << (OP2 + 1)) - 1; TCGv_i32 tmp = tcg_temp_new_i32(); - - if (shiftimm) { - tcg_gen_shri_i32(tmp, cpu_R[RRR_T], shiftimm); - } else { - tcg_gen_mov_i32(tmp, cpu_R[RRR_T]); - } - - switch (maskimm) { - case 0xff: - tcg_gen_ext8u_i32(cpu_R[RRR_R], tmp); - break; - - case 0xffff: - tcg_gen_ext16u_i32(cpu_R[RRR_R], tmp); - break; - - default: - tcg_gen_andi_i32(cpu_R[RRR_R], tmp, maskimm); - break; - } + tcg_gen_shri_i32(tmp, cpu_R[RRR_T], shiftimm); + tcg_gen_andi_i32(cpu_R[RRR_R], tmp, maskimm); tcg_temp_free(tmp); } break; -- cgit v1.2.3 From 626cd050e2c9094c1b005bc39cab637f8cbe3755 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 1 Oct 2012 21:00:43 +0200 Subject: tcg: remove obsolete jmp op The TCG jmp operation doesn't really make sense in the QEMU context, it is unused, it is not implemented by some targets, and it is wrongly implemented by some others. This patch simply removes it. Reviewed-by: Richard Henderson Acked-by: Blue Swirl Acked-by: Stefan Weil Signed-off-by: Aurelien Jarno --- tcg/README | 7 +------ tcg/arm/tcg-target.c | 7 ------- tcg/hppa/tcg-target.c | 6 ------ tcg/i386/tcg-target.c | 9 --------- tcg/ia64/tcg-target.c | 4 ---- tcg/mips/tcg-target.c | 5 ----- tcg/ppc/tcg-target.c | 10 ---------- tcg/ppc64/tcg-target.c | 10 ---------- tcg/s390/tcg-target.c | 6 ------ tcg/sparc/tcg-target.c | 2 -- tcg/tcg-opc.h | 1 - tcg/tci/tcg-target.c | 4 ---- tci.c | 1 - 13 files changed, 1 insertion(+), 71 deletions(-) diff --git a/tcg/README b/tcg/README index 27846f1ea..aa86992bc 100644 --- a/tcg/README +++ b/tcg/README @@ -88,8 +88,7 @@ supported. * Branches: -Use the instruction 'br' to jump to a label. Use 'jmp' to jump to an -explicit address. Conditional branches can only jump to labels. +Use the instruction 'br' to jump to a label. 3.3) Code Optimizations @@ -129,10 +128,6 @@ call function 'ptr' (pointer type) ********* Jumps/Labels -* jmp t0 - -Absolute jump to address t0 (pointer type). - * set_label $label Define label 'label' at the current program point. diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c index 2bad0a2b1..1e61864d4 100644 --- a/tcg/arm/tcg-target.c +++ b/tcg/arm/tcg-target.c @@ -1530,12 +1530,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, else tcg_out_callr(s, COND_AL, args[0]); break; - case INDEX_op_jmp: - if (const_args[0]) - tcg_out_goto(s, COND_AL, args[0]); - else - tcg_out_bx(s, COND_AL, args[0]); - break; case INDEX_op_br: tcg_out_goto_label(s, COND_AL, args[0]); break; @@ -1769,7 +1763,6 @@ static const TCGTargetOpDef arm_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, { INDEX_op_call, { "ri" } }, - { INDEX_op_jmp, { "ri" } }, { INDEX_op_br, { } }, { INDEX_op_mov_i32, { "r", "r" } }, diff --git a/tcg/hppa/tcg-target.c b/tcg/hppa/tcg-target.c index 2c79c1081..44974c4e8 100644 --- a/tcg/hppa/tcg-target.c +++ b/tcg/hppa/tcg-target.c @@ -1353,11 +1353,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, } break; - case INDEX_op_jmp: - fprintf(stderr, "unimplemented jmp\n"); - tcg_abort(); - break; - case INDEX_op_br: tcg_out_branch(s, args[0], 1); break; @@ -1592,7 +1587,6 @@ static const TCGTargetOpDef hppa_op_defs[] = { { INDEX_op_goto_tb, { } }, { INDEX_op_call, { "ri" } }, - { INDEX_op_jmp, { "r" } }, { INDEX_op_br, { } }, { INDEX_op_mov_i32, { "r", "r" } }, diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c index 0e218c861..bb2306df8 100644 --- a/tcg/i386/tcg-target.c +++ b/tcg/i386/tcg-target.c @@ -1513,14 +1513,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_modrm(s, OPC_GRP5, EXT5_CALLN_Ev, args[0]); } break; - case INDEX_op_jmp: - if (const_args[0]) { - tcg_out_jmp(s, args[0]); - } else { - /* jmp *reg */ - tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, args[0]); - } - break; case INDEX_op_br: tcg_out_jxx(s, JCC_JMP, args[0], 0); break; @@ -1848,7 +1840,6 @@ static const TCGTargetOpDef x86_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, { INDEX_op_call, { "ri" } }, - { INDEX_op_jmp, { "ri" } }, { INDEX_op_br, { } }, { INDEX_op_mov_i32, { "r", "r" } }, { INDEX_op_movi_i32, { "r" } }, diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c index dc9c12cf1..705712f77 100644 --- a/tcg/ia64/tcg-target.c +++ b/tcg/ia64/tcg-target.c @@ -1916,9 +1916,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, case INDEX_op_goto_tb: tcg_out_goto_tb(s, args[0]); break; - case INDEX_op_jmp: - tcg_out_jmp(s, args[0]); - break; case INDEX_op_movi_i32: tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]); @@ -2156,7 +2153,6 @@ static const TCGTargetOpDef ia64_op_defs[] = { { INDEX_op_call, { "r" } }, { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, - { INDEX_op_jmp, { "r" } }, { INDEX_op_mov_i32, { "r", "r" } }, { INDEX_op_movi_i32, { "r" } }, diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c index 34e3e7f82..7e4013e1e 100644 --- a/tcg/mips/tcg-target.c +++ b/tcg/mips/tcg-target.c @@ -1322,10 +1322,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, args[0], 0); tcg_out_nop(s); break; - case INDEX_op_jmp: - tcg_out_opc_reg(s, OPC_JR, 0, args[0], 0); - tcg_out_nop(s); - break; case INDEX_op_br: tcg_out_brcond(s, TCG_COND_EQ, TCG_REG_ZERO, TCG_REG_ZERO, args[0]); break; @@ -1577,7 +1573,6 @@ static const TCGTargetOpDef mips_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, { INDEX_op_call, { "C" } }, - { INDEX_op_jmp, { "r" } }, { INDEX_op_br, { } }, { INDEX_op_mov_i32, { "r", "r" } }, diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c index 90c275d69..56baedda5 100644 --- a/tcg/ppc/tcg-target.c +++ b/tcg/ppc/tcg-target.c @@ -1417,15 +1417,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, case INDEX_op_call: tcg_out_call (s, args[0], const_args[0]); break; - case INDEX_op_jmp: - if (const_args[0]) { - tcg_out_b (s, 0, args[0]); - } - else { - tcg_out32 (s, MTSPR | RS (args[0]) | CTR); - tcg_out32 (s, BCCTR | BO_ALWAYS); - } - break; case INDEX_op_movi_i32: tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]); break; @@ -1904,7 +1895,6 @@ static const TCGTargetOpDef ppc_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, { INDEX_op_call, { "ri" } }, - { INDEX_op_jmp, { "ri" } }, { INDEX_op_br, { } }, { INDEX_op_mov_i32, { "r", "r" } }, diff --git a/tcg/ppc64/tcg-target.c b/tcg/ppc64/tcg-target.c index 19944bc42..6e9b363a1 100644 --- a/tcg/ppc64/tcg-target.c +++ b/tcg/ppc64/tcg-target.c @@ -1245,15 +1245,6 @@ static void tcg_out_op (TCGContext *s, TCGOpcode opc, const TCGArg *args, case INDEX_op_call: tcg_out_call (s, args[0], const_args[0]); break; - case INDEX_op_jmp: - if (const_args[0]) { - tcg_out_b (s, 0, args[0]); - } - else { - tcg_out32 (s, MTSPR | RS (args[0]) | CTR); - tcg_out32 (s, BCCTR | BO_ALWAYS); - } - break; case INDEX_op_movi_i32: tcg_out_movi (s, TCG_TYPE_I32, args[0], args[1]); break; @@ -1588,7 +1579,6 @@ static const TCGTargetOpDef ppc_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, { INDEX_op_call, { "ri" } }, - { INDEX_op_jmp, { "ri" } }, { INDEX_op_br, { } }, { INDEX_op_mov_i32, { "r", "r" } }, diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c index 3b90605fb..4b4305952 100644 --- a/tcg/s390/tcg-target.c +++ b/tcg/s390/tcg-target.c @@ -2037,11 +2037,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, break; #endif /* TCG_TARGET_REG_BITS == 64 */ - case INDEX_op_jmp: - /* This one is obsolete and never emitted. */ - tcg_abort(); - break; - default: fprintf(stderr,"unimplemented opc 0x%x\n",opc); tcg_abort(); @@ -2052,7 +2047,6 @@ static const TCGTargetOpDef s390_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, { INDEX_op_call, { "ri" } }, - { INDEX_op_jmp, { "ri" } }, { INDEX_op_br, { } }, { INDEX_op_mov_i32, { "r", "r" } }, diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c index 8fd7f86de..e82fab262 100644 --- a/tcg/sparc/tcg-target.c +++ b/tcg/sparc/tcg-target.c @@ -1097,7 +1097,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, /* delay slot */ tcg_out_nop(s); break; - case INDEX_op_jmp: case INDEX_op_br: tcg_out_branch_i32(s, COND_A, args[0]); tcg_out_nop(s); @@ -1367,7 +1366,6 @@ static const TCGTargetOpDef sparc_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, { INDEX_op_call, { "ri" } }, - { INDEX_op_jmp, { "ri" } }, { INDEX_op_br, { } }, { INDEX_op_mov_i32, { "r", "r" } }, diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h index dbb0e3916..04cb7ca03 100644 --- a/tcg/tcg-opc.h +++ b/tcg/tcg-opc.h @@ -38,7 +38,6 @@ DEF(discard, 1, 0, 0, 0) DEF(set_label, 0, 0, 1, TCG_OPF_BB_END) DEF(call, 0, 1, 2, TCG_OPF_SIDE_EFFECTS) /* variable number of parameters */ -DEF(jmp, 0, 1, 0, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) DEF(br, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) #define IMPL(X) (X ? 0 : TCG_OPF_NOT_PRESENT) diff --git a/tcg/tci/tcg-target.c b/tcg/tci/tcg-target.c index d272a906e..e93074083 100644 --- a/tcg/tci/tcg-target.c +++ b/tcg/tci/tcg-target.c @@ -69,7 +69,6 @@ static const TCGTargetOpDef tcg_target_op_defs[] = { { INDEX_op_exit_tb, { NULL } }, { INDEX_op_goto_tb, { NULL } }, { INDEX_op_call, { RI } }, - { INDEX_op_jmp, { RI } }, { INDEX_op_br, { NULL } }, { INDEX_op_mov_i32, { R, R } }, @@ -583,9 +582,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, case INDEX_op_call: tcg_out_ri(s, const_args[0], args[0]); break; - case INDEX_op_jmp: - TODO(); - break; case INDEX_op_setcond_i32: tcg_out_r(s, args[0]); tcg_out_r(s, args[1]); diff --git a/tci.c b/tci.c index a4f7b7841..98f5f713e 100644 --- a/tci.c +++ b/tci.c @@ -505,7 +505,6 @@ tcg_target_ulong tcg_qemu_tb_exec(CPUArchState *cpustate, uint8_t *tb_ptr) tci_write_reg(TCG_REG_R0, tmp64); #endif break; - case INDEX_op_jmp: case INDEX_op_br: label = tci_read_label(&tb_ptr); assert(tb_ptr == old_code_ptr + op_size); -- cgit v1.2.3 From a1e472119aa2efa88a2a24b1aa50e45ea8cc8f31 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sat, 8 Sep 2012 11:38:41 +0200 Subject: vga: rename pci_vga_init() into pci_std_vga_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This better explains what is this function about. Adjust all callers. Cc: Alexander Graf Cc: Andreas Färber Cc: David Gibson Cc: Anthony Liguori Acked-by: Richard Henderson Acked-by: Blue Swirl Acked-by: Andreas Färber Signed-off-by: Aurelien Jarno --- hw/alpha_pci.c | 2 +- hw/mips_malta.c | 2 +- hw/pc.c | 2 +- hw/ppc_newworld.c | 2 +- hw/ppc_oldworld.c | 2 +- hw/ppc_prep.c | 2 +- hw/spapr.c | 2 +- hw/sun4u.c | 2 +- hw/vga-pci.c | 6 +++--- hw/vga-pci.h | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/hw/alpha_pci.c b/hw/alpha_pci.c index ea546f83f..0352e72d5 100644 --- a/hw/alpha_pci.c +++ b/hw/alpha_pci.c @@ -128,6 +128,6 @@ void alpha_pci_vga_setup(PCIBus *pci_bus) /* If VGA is enabled at all, and one of the above didn't work, then fallback to Standard VGA. */ if (vga_interface_type != VGA_NONE) { - pci_vga_init(pci_bus); + pci_std_vga_init(pci_bus); } } diff --git a/hw/mips_malta.c b/hw/mips_malta.c index ad23f26e5..c39dee583 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -992,7 +992,7 @@ void mips_malta_init (ram_addr_t ram_size, } else if (vmsvga_enabled) { pci_vmsvga_init(pci_bus); } else if (std_vga_enabled) { - pci_vga_init(pci_bus); + pci_std_vga_init(pci_bus); } } diff --git a/hw/pc.c b/hw/pc.c index 7e7e0e223..33fee622d 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -1014,7 +1014,7 @@ DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus) #endif } else if (std_vga_enabled) { if (pci_bus) { - dev = pci_vga_init(pci_bus); + dev = pci_std_vga_init(pci_bus); } else { dev = isa_vga_init(isa_bus); } diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c index e95cfe831..84af948f5 100644 --- a/hw/ppc_newworld.c +++ b/hw/ppc_newworld.c @@ -330,7 +330,7 @@ static void ppc_core99_init (ram_addr_t ram_size, machine_arch = ARCH_MAC99; } /* init basic PC hardware */ - pci_vga_init(pci_bus); + pci_std_vga_init(pci_bus); escc_mem = escc_init(0, pic[0x25], pic[0x24], serial_hds[0], serial_hds[1], ESCC_CLOCK, 4); diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index 1dcd8a6c3..8267eb43b 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -250,7 +250,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size, pci_bus = pci_grackle_init(0xfec00000, pic, get_system_memory(), get_system_io()); - pci_vga_init(pci_bus); + pci_std_vga_init(pci_bus); escc_mem = escc_init(0, pic[0x0f], pic[0x10], serial_hds[0], serial_hds[1], ESCC_CLOCK, 4); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 592b7b255..1fa760970 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -611,7 +611,7 @@ static void ppc_prep_init (ram_addr_t ram_size, memory_region_add_subregion(sysmem, 0x80000000, PPC_io_memory); /* init basic PC hardware */ - pci_vga_init(pci_bus); + pci_std_vga_init(pci_bus); if (serial_hds[0]) serial_isa_init(isa_bus, 0, serial_hds[0]); diff --git a/hw/spapr.c b/hw/spapr.c index c34b767c6..80735d6ab 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -590,7 +590,7 @@ static int spapr_vga_init(PCIBus *pci_bus) { switch (vga_interface_type) { case VGA_STD: - pci_vga_init(pci_bus); + pci_std_vga_init(pci_bus); return 1; case VGA_NONE: return 0; diff --git a/hw/sun4u.c b/hw/sun4u.c index 07cd04273..cca090f87 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -821,7 +821,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, ivec_irqs = qemu_allocate_irqs(cpu_set_ivec_irq, env, IVEC_MAX); pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, ivec_irqs, &pci_bus2, &pci_bus3, &pbm_irqs); - pci_vga_init(pci_bus); + pci_std_vga_init(pci_bus); // XXX Should be pci_bus3 isa_bus = pci_ebus_init(pci_bus, -1, pbm_irqs); diff --git a/hw/vga-pci.c b/hw/vga-pci.c index 9abbada8f..992ffd98b 100644 --- a/hw/vga-pci.c +++ b/hw/vga-pci.c @@ -47,7 +47,7 @@ static const VMStateDescription vmstate_vga_pci = { } }; -static int pci_vga_initfn(PCIDevice *dev) +static int pci_std_vga_initfn(PCIDevice *dev) { PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, dev); VGACommonState *s = &d->vga; @@ -70,7 +70,7 @@ static int pci_vga_initfn(PCIDevice *dev) return 0; } -DeviceState *pci_vga_init(PCIBus *bus) +DeviceState *pci_std_vga_init(PCIBus *bus) { return &pci_create_simple(bus, -1, "VGA")->qdev; } @@ -86,7 +86,7 @@ static void vga_class_init(ObjectClass *klass, void *data) PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); k->no_hotplug = 1; - k->init = pci_vga_initfn; + k->init = pci_std_vga_initfn; k->romfile = "vgabios-stdvga.bin"; k->vendor_id = PCI_VENDOR_ID_QEMU; k->device_id = PCI_DEVICE_ID_QEMU_VGA; diff --git a/hw/vga-pci.h b/hw/vga-pci.h index 49abf1309..d111cdc01 100644 --- a/hw/vga-pci.h +++ b/hw/vga-pci.h @@ -4,7 +4,7 @@ #include "qemu-common.h" /* vga-pci.c */ -DeviceState *pci_vga_init(PCIBus *bus); +DeviceState *pci_std_vga_init(PCIBus *bus); /* cirrus_vga.c */ DeviceState *pci_cirrus_vga_init(PCIBus *bus); -- cgit v1.2.3 From 6405c86412719a0ccd1a09b81baf0b78e8a4ae6b Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sat, 8 Sep 2012 16:40:56 +0200 Subject: vga: rename isa_vga_init() to isa_std_vga_init() This better explains what is this function about. Adjust all callers. Cc: Anthony Liguori Signed-off-by: Aurelien Jarno --- hw/mips_r4k.c | 2 +- hw/pc.c | 2 +- hw/pc.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 967a76e53..2115f7f3d 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -281,7 +281,7 @@ void mips_r4k_init (ram_addr_t ram_size, } } - isa_vga_init(isa_bus); + isa_std_vga_init(isa_bus); if (nd_table[0].used) isa_ne2000_init(isa_bus, 0x300, 9, &nd_table[0]); diff --git a/hw/pc.c b/hw/pc.c index 33fee622d..78805f625 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -1016,7 +1016,7 @@ DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus) if (pci_bus) { dev = pci_std_vga_init(pci_bus); } else { - dev = isa_vga_init(isa_bus); + dev = isa_std_vga_init(isa_bus); } } diff --git a/hw/pc.h b/hw/pc.h index e4db0715b..77c38d609 100644 --- a/hw/pc.h +++ b/hw/pc.h @@ -176,7 +176,7 @@ enum vga_retrace_method { extern enum vga_retrace_method vga_retrace_method; -static inline DeviceState *isa_vga_init(ISABus *bus) +static inline DeviceState *isa_std_vga_init(ISABus *bus) { ISADevice *dev; -- cgit v1.2.3 From 36b7f27d2195a09dbfb7f08b2323d807c1ad90b0 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sat, 8 Sep 2012 16:01:20 +0200 Subject: vl.c: convert *vga_enabled functions to QOM And get rid of qdev_exists(). Signed-off-by: Aurelien Jarno --- hw/qdev.c | 5 ----- hw/qdev.h | 1 - vl.c | 7 ++++--- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/hw/qdev.c b/hw/qdev.c index 3b5ce3312..adfc4a7ea 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -52,11 +52,6 @@ const char *qdev_fw_name(DeviceState *dev) return object_get_typename(OBJECT(dev)); } -bool qdev_exists(const char *name) -{ - return !!object_class_by_name(name); -} - static void qdev_property_add_legacy(DeviceState *dev, Property *prop, Error **errp); diff --git a/hw/qdev.h b/hw/qdev.h index d69919441..c6ac63620 100644 --- a/hw/qdev.h +++ b/hw/qdev.h @@ -153,7 +153,6 @@ typedef struct GlobalProperty { DeviceState *qdev_create(BusState *bus, const char *name); DeviceState *qdev_try_create(BusState *bus, const char *name); -bool qdev_exists(const char *name); int qdev_device_help(QemuOpts *opts); DeviceState *qdev_device_add(QemuOpts *opts); int qdev_init(DeviceState *dev) QEMU_WARN_UNUSED_RESULT; diff --git a/vl.c b/vl.c index 8d305ca59..bf9cdf8eb 100644 --- a/vl.c +++ b/vl.c @@ -1700,17 +1700,18 @@ static const QEMUOption qemu_options[] = { static bool vga_available(void) { - return qdev_exists("VGA") || qdev_exists("isa-vga"); + return object_class_by_name("VGA") || object_class_by_name("isa-vga"); } static bool cirrus_vga_available(void) { - return qdev_exists("cirrus-vga") || qdev_exists("isa-cirrus-vga"); + return object_class_by_name("cirrus-vga") + || object_class_by_name("isa-cirrus-vga"); } static bool vmware_vga_available(void) { - return qdev_exists("vmware-svga"); + return object_class_by_name("vmware-svga"); } static void select_vgahw (const char *p) -- cgit v1.2.3 From 879049a39724f91224f10c8d80b3cf70c9dc1c5e Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sat, 8 Sep 2012 12:01:06 +0200 Subject: vl.c: check for qxl availability Check for qxl availability in vl.c. This will allow to remove #ifdef CONFIG_SPICE .. #endif later in this series Cc: Anthony Liguori Cc: Gerd Hoffmann Signed-off-by: Aurelien Jarno --- vl.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index bf9cdf8eb..17a33a096 100644 --- a/vl.c +++ b/vl.c @@ -1714,6 +1714,11 @@ static bool vmware_vga_available(void) return object_class_by_name("vmware-svga"); } +static bool qxl_vga_available(void) +{ + return object_class_by_name("qxl-vga"); +} + static void select_vgahw (const char *p) { const char *opts; @@ -1743,7 +1748,12 @@ static void select_vgahw (const char *p) } else if (strstart(p, "xenfb", &opts)) { vga_interface_type = VGA_XENFB; } else if (strstart(p, "qxl", &opts)) { - vga_interface_type = VGA_QXL; + if (qxl_vga_available()) { + vga_interface_type = VGA_QXL; + } else { + fprintf(stderr, "Error: QXL VGA not available\n"); + exit(0); + } } else if (!strstart(p, "none", &opts)) { invalid_vga: fprintf(stderr, "Unknown vga type: %s\n", p); -- cgit v1.2.3 From 3605ded557eb2a6d06a942b952c8fac4c676b125 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 10 Sep 2012 01:01:44 +0200 Subject: vl.c: default to std if cirrus is not available Signed-off-by: Aurelien Jarno --- vl.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/vl.c b/vl.c index 17a33a096..02dade19f 100644 --- a/vl.c +++ b/vl.c @@ -3617,8 +3617,12 @@ int main(int argc, char **argv, char **envp) exit(1); /* If no default VGA is requested, the default is "none". */ - if (default_vga && cirrus_vga_available()) { - vga_model = "cirrus"; + if (default_vga) { + if (cirrus_vga_available()) { + vga_model = "cirrus"; + } else if (vga_available()) { + vga_model = "std"; + } } select_vgahw(vga_model); -- cgit v1.2.3 From 129d42fb8496de5c1896160fddab949784d4dea4 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sat, 8 Sep 2012 11:49:24 +0200 Subject: pci: add a pci_vga_init() function This function create a PCI VGA device according to the value of vga_interface_type. It returns a PCIDevice (and not a DeviceState). Cc: Anthony Liguori Signed-off-by: Aurelien Jarno --- hw/pci.c | 18 ++++++++++++++++++ hw/pci.h | 3 +++ 2 files changed, 21 insertions(+) diff --git a/hw/pci.c b/hw/pci.c index de4b4485e..2ca6ff6fe 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -1474,6 +1474,24 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model, return res; } +PCIDevice *pci_vga_init(PCIBus *bus) +{ + switch (vga_interface_type) { + case VGA_CIRRUS: + return pci_create_simple(bus, -1, "cirrus-vga"); + case VGA_QXL: + return pci_create_simple(bus, -1, "qxl-vga"); + case VGA_STD: + return pci_create_simple(bus, -1, "VGA"); + case VGA_VMWARE: + return pci_create_simple(bus, -1, "vmware-svga"); + case VGA_NONE: + default: /* Other non-PCI types. Checking for unsupported types is already + done in vl.c. */ + return NULL; + } +} + /* Whether a given bus number is in range of the secondary * bus of the given bridge device. */ static bool pci_secondary_bus_in_range(PCIDevice *dev, int bus_num) diff --git a/hw/pci.h b/hw/pci.h index 4b6ab3d19..d50d26c8a 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -334,6 +334,9 @@ PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model, const char *default_devaddr); PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model, const char *default_devaddr); + +PCIDevice *pci_vga_init(PCIBus *bus); + int pci_bus_num(PCIBus *s); void pci_for_each_device(PCIBus *bus, int bus_num, void (*fn)(PCIBus *bus, PCIDevice *d, void *opaque), -- cgit v1.2.3 From 14e7a6456e1dba2c6499b3b05637fee9f553e6ce Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sat, 8 Sep 2012 16:58:57 +0200 Subject: isa: add a isa_vga_init() function This function create a ISA VGA device according to the value of vga_interface_type. It returns a ISADevice (and not a DeviceState). Signed-off-by: Aurelien Jarno --- hw/isa-bus.c | 20 ++++++++++++++++++++ hw/isa.h | 2 ++ 2 files changed, 22 insertions(+) diff --git a/hw/isa-bus.c b/hw/isa-bus.c index 47c93d37b..214f19457 100644 --- a/hw/isa-bus.c +++ b/hw/isa-bus.c @@ -19,6 +19,7 @@ #include "hw.h" #include "monitor.h" #include "sysbus.h" +#include "sysemu.h" #include "isa.h" #include "exec-memory.h" @@ -166,6 +167,25 @@ ISADevice *isa_create_simple(ISABus *bus, const char *name) return dev; } +ISADevice *isa_vga_init(ISABus *bus) +{ + switch (vga_interface_type) { + case VGA_CIRRUS: + return isa_create_simple(bus, "isa-cirrus-vga"); + case VGA_QXL: + fprintf(stderr, "%s: qxl: no PCI bus\n", __func__); + return NULL; + case VGA_STD: + return isa_create_simple(bus, "isa-vga"); + case VGA_VMWARE: + fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __func__); + return NULL; + case VGA_NONE: + default: + return NULL; + } +} + static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent) { ISADevice *d = ISA_DEVICE(dev); diff --git a/hw/isa.h b/hw/isa.h index dc970527a..8fb498aa8 100644 --- a/hw/isa.h +++ b/hw/isa.h @@ -47,6 +47,8 @@ ISADevice *isa_create(ISABus *bus, const char *name); ISADevice *isa_try_create(ISABus *bus, const char *name); ISADevice *isa_create_simple(ISABus *bus, const char *name); +ISADevice *isa_vga_init(ISABus *bus); + /** * isa_register_ioport: Install an I/O port region on the ISA bus. * -- cgit v1.2.3 From 9c59864d16d720184e723c0c29c505c34e94fed5 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sat, 8 Sep 2012 11:53:12 +0200 Subject: mips/malta: use the new pci_vga_init() function Signed-off-by: Aurelien Jarno --- hw/mips_malta.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index c39dee583..632b466e3 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -33,7 +33,6 @@ #include "mips.h" #include "mips_cpudevs.h" #include "pci.h" -#include "vmware_vga.h" #include "qemu-char.h" #include "sysemu.h" #include "arch_init.h" @@ -48,7 +47,6 @@ #include "blockdev.h" #include "exec-memory.h" #include "sysbus.h" /* SysBusDevice */ -#include "vga-pci.h" //#define DEBUG_BOARD_INIT @@ -987,13 +985,7 @@ void mips_malta_init (ram_addr_t ram_size, network_init(); /* Optional PCI video card */ - if (cirrus_vga_enabled) { - pci_cirrus_vga_init(pci_bus); - } else if (vmsvga_enabled) { - pci_vmsvga_init(pci_bus); - } else if (std_vga_enabled) { - pci_std_vga_init(pci_bus); - } + pci_vga_init(pci_bus); } static int mips_malta_sysbus_device_init(SysBusDevice *sysbusdev) -- cgit v1.2.3 From 606f90cc22094bab743c84d40a11f6ded603ad34 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sat, 8 Sep 2012 12:16:28 +0200 Subject: alpha: use the new pci_vga_init() function This remove the fallback to std-vga in case, as availability of the requested vga device is now tested in vl.c, and returns an error message to the user. Acked-by: Richard Henderson Signed-off-by: Aurelien Jarno --- hw/alpha_dp264.c | 2 +- hw/alpha_pci.c | 24 ------------------------ hw/alpha_sys.h | 2 -- 3 files changed, 1 insertion(+), 27 deletions(-) diff --git a/hw/alpha_dp264.c b/hw/alpha_dp264.c index 9eb939f38..5ea04c75a 100644 --- a/hw/alpha_dp264.c +++ b/hw/alpha_dp264.c @@ -77,7 +77,7 @@ static void clipper_init(ram_addr_t ram_size, isa_create_simple(isa_bus, "i8042"); /* VGA setup. Don't bother loading the bios. */ - alpha_pci_vga_setup(pci_bus); + pci_vga_init(pci_bus); /* Serial code setup. */ for (i = 0; i < MAX_SERIAL_PORTS; ++i) { diff --git a/hw/alpha_pci.c b/hw/alpha_pci.c index 0352e72d5..8079a46ae 100644 --- a/hw/alpha_pci.c +++ b/hw/alpha_pci.c @@ -10,8 +10,6 @@ #include "alpha_sys.h" #include "qemu-log.h" #include "sysemu.h" -#include "vmware_vga.h" -#include "vga-pci.h" /* PCI IO reads/writes, to byte-word addressable memory. */ @@ -109,25 +107,3 @@ const MemoryRegionOps alpha_pci_iack_ops = { .max_access_size = 4, }, }; - -void alpha_pci_vga_setup(PCIBus *pci_bus) -{ - switch (vga_interface_type) { -#ifdef CONFIG_SPICE - case VGA_QXL: - pci_create_simple(pci_bus, -1, "qxl-vga"); - return; -#endif - case VGA_CIRRUS: - pci_cirrus_vga_init(pci_bus); - return; - case VGA_VMWARE: - pci_vmsvga_init(pci_bus); - return; - } - /* If VGA is enabled at all, and one of the above didn't work, then - fallback to Standard VGA. */ - if (vga_interface_type != VGA_NONE) { - pci_std_vga_init(pci_bus); - } -} diff --git a/hw/alpha_sys.h b/hw/alpha_sys.h index de40f8b61..7604d09c8 100644 --- a/hw/alpha_sys.h +++ b/hw/alpha_sys.h @@ -19,6 +19,4 @@ extern const MemoryRegionOps alpha_pci_bw_io_ops; extern const MemoryRegionOps alpha_pci_conf1_ops; extern const MemoryRegionOps alpha_pci_iack_ops; -void alpha_pci_vga_setup(PCIBus *pci_bus); - #endif -- cgit v1.2.3 From e7a2e96df0692e19f253476027a565dc7c11da76 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sat, 8 Sep 2012 12:19:38 +0200 Subject: ppc/newworld: use the new pci_vga_init() function As a bonus it allows new vga card types (including none). Cc: Alexander Graf Signed-off-by: Aurelien Jarno --- hw/ppc_newworld.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c index 84af948f5..b8d3c9c98 100644 --- a/hw/ppc_newworld.c +++ b/hw/ppc_newworld.c @@ -67,7 +67,6 @@ #include "hw/usb.h" #include "blockdev.h" #include "exec-memory.h" -#include "vga-pci.h" #define MAX_IDE_BUS 2 #define CFG_ADDR 0xf0000510 @@ -330,7 +329,7 @@ static void ppc_core99_init (ram_addr_t ram_size, machine_arch = ARCH_MAC99; } /* init basic PC hardware */ - pci_std_vga_init(pci_bus); + pci_vga_init(pci_bus); escc_mem = escc_init(0, pic[0x25], pic[0x24], serial_hds[0], serial_hds[1], ESCC_CLOCK, 4); -- cgit v1.2.3 From 3e20ad3a9b674abc3464504d59bba46304316136 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sat, 8 Sep 2012 12:21:20 +0200 Subject: ppc/oldworld: use the new pci_vga_init() function As a bonus it allows new vga card types (including none). Cc: Alexander Graf Signed-off-by: Aurelien Jarno --- hw/ppc_oldworld.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index 8267eb43b..2c4a47813 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -43,7 +43,6 @@ #include "kvm_ppc.h" #include "blockdev.h" #include "exec-memory.h" -#include "vga-pci.h" #define MAX_IDE_BUS 2 #define CFG_ADDR 0xf0000510 @@ -250,7 +249,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size, pci_bus = pci_grackle_init(0xfec00000, pic, get_system_memory(), get_system_io()); - pci_std_vga_init(pci_bus); + pci_vga_init(pci_bus); escc_mem = escc_init(0, pic[0x0f], pic[0x10], serial_hds[0], serial_hds[1], ESCC_CLOCK, 4); -- cgit v1.2.3 From 95fa01fab0082483c1849f1439303db4183c8dd4 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sat, 8 Sep 2012 12:22:44 +0200 Subject: ppc/prep: use the new pci_vga_init() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As a bonus it allows new vga card types (including none). Acked-by: Andreas Färber Signed-off-by: Aurelien Jarno --- hw/ppc_prep.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 1fa760970..15444303e 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -39,7 +39,6 @@ #include "blockdev.h" #include "arch_init.h" #include "exec-memory.h" -#include "vga-pci.h" //#define HARD_DEBUG_PPC_IO //#define DEBUG_PPC_IO @@ -611,7 +610,7 @@ static void ppc_prep_init (ram_addr_t ram_size, memory_region_add_subregion(sysmem, 0x80000000, PPC_io_memory); /* init basic PC hardware */ - pci_std_vga_init(pci_bus); + pci_vga_init(pci_bus); if (serial_hds[0]) serial_isa_init(isa_bus, 0, serial_hds[0]); -- cgit v1.2.3 From 1ddcae82a2509668b94a13e84921bdcafddcdfff Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sat, 8 Sep 2012 12:40:45 +0200 Subject: ppc/pSeries: use the new pci_vga_init() function Keep the case to prevent some vga card to be selected. Cc: Alexander Graf Cc: David Gibson Signed-off-by: Aurelien Jarno --- hw/spapr.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/hw/spapr.c b/hw/spapr.c index 80735d6ab..8b0c39026 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -46,7 +46,6 @@ #include "kvm.h" #include "kvm_ppc.h" #include "pci.h" -#include "vga-pci.h" #include "exec-memory.h" #include "hw/usb.h" @@ -589,11 +588,9 @@ static void spapr_cpu_reset(void *opaque) static int spapr_vga_init(PCIBus *pci_bus) { switch (vga_interface_type) { - case VGA_STD: - pci_std_vga_init(pci_bus); - return 1; case VGA_NONE: - return 0; + case VGA_STD: + return pci_vga_init(pci_bus) != NULL; default: fprintf(stderr, "This vga model is not supported," "currently it only supports -vga std\n"); -- cgit v1.2.3 From f2898771435701df33145cacabeb42c6aa3a9a16 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sat, 8 Sep 2012 12:23:54 +0200 Subject: sun/sun4u: use the new pci_vga_init() function As a bonus it allows new vga card types (including none). Acked-by: Blue Swirl Signed-off-by: Aurelien Jarno --- hw/sun4u.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/sun4u.c b/hw/sun4u.c index cca090f87..137a7c666 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -39,7 +39,6 @@ #include "elf.h" #include "blockdev.h" #include "exec-memory.h" -#include "vga-pci.h" //#define DEBUG_IRQ //#define DEBUG_EBUS @@ -821,7 +820,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, ivec_irqs = qemu_allocate_irqs(cpu_set_ivec_irq, env, IVEC_MAX); pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, ivec_irqs, &pci_bus2, &pci_bus3, &pbm_irqs); - pci_std_vga_init(pci_bus); + pci_vga_init(pci_bus); // XXX Should be pci_bus3 isa_bus = pci_ebus_init(pci_bus, -1, pbm_irqs); -- cgit v1.2.3 From 16094b75b38dcb5582810bd4149fa8336a939dc8 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sat, 8 Sep 2012 12:47:45 +0200 Subject: pc: use the new pci_vga_init() and isa_vga_init() functions The CONFIG_SPICE is now tested in vl.c and thus not needed anymore. Cc: Anthony Liguori Signed-off-by: Aurelien Jarno --- hw/pc.c | 35 ++++++----------------------------- 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 78805f625..6c0722db5 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -27,7 +27,6 @@ #include "fdc.h" #include "ide.h" #include "pci.h" -#include "vmware_vga.h" #include "monitor.h" #include "fw_cfg.h" #include "hpet_emul.h" @@ -51,7 +50,6 @@ #include "exec-memory.h" #include "arch_init.h" #include "bitmap.h" -#include "vga-pci.h" /* debug PC/ISA interrupts */ //#define DEBUG_IRQ @@ -992,34 +990,13 @@ DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus) { DeviceState *dev = NULL; - if (cirrus_vga_enabled) { - if (pci_bus) { - dev = pci_cirrus_vga_init(pci_bus); - } else { - dev = &isa_create_simple(isa_bus, "isa-cirrus-vga")->qdev; - } - } else if (vmsvga_enabled) { - if (pci_bus) { - dev = pci_vmsvga_init(pci_bus); - } else { - fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__); - } -#ifdef CONFIG_SPICE - } else if (qxl_enabled) { - if (pci_bus) { - dev = &pci_create_simple(pci_bus, -1, "qxl-vga")->qdev; - } else { - fprintf(stderr, "%s: qxl: no PCI bus\n", __FUNCTION__); - } -#endif - } else if (std_vga_enabled) { - if (pci_bus) { - dev = pci_std_vga_init(pci_bus); - } else { - dev = isa_std_vga_init(isa_bus); - } + if (pci_bus) { + PCIDevice *pcidev = pci_vga_init(pci_bus); + dev = pcidev ? &pcidev->qdev : NULL; + } else if (isa_bus) { + ISADevice *isadev = isa_vga_init(isa_bus); + dev = isadev ? &isadev->qdev : NULL; } - return dev; } -- cgit v1.2.3 From f642dfce199eecda5a558ce94c17a34707d63ccd Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sat, 8 Sep 2012 17:02:29 +0200 Subject: mips/r4k: use the new is_vga_init() function Signed-off-by: Aurelien Jarno --- hw/mips_r4k.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 2115f7f3d..967a76e53 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -281,7 +281,7 @@ void mips_r4k_init (ram_addr_t ram_size, } } - isa_std_vga_init(isa_bus); + isa_vga_init(isa_bus); if (nd_table[0].used) isa_ne2000_init(isa_bus, 0x300, 9, &nd_table[0]); -- cgit v1.2.3 From 457ebdcd91aa7f0df094e12a8c46235f0c7d4f9b Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sat, 8 Sep 2012 12:58:09 +0200 Subject: vga: cleanup after isa_vga_init() and pci_vga_init() conversion Now that all machines call isa_vga_init() or pci_vga_init(), some unused code can be removed. Cc: Anthony Liguori Signed-off-by: Aurelien Jarno --- hw/cirrus_vga.c | 6 ------ hw/pc.h | 13 ------------- hw/vga-pci.c | 6 ------ hw/vga-pci.h | 12 ------------ hw/vmware_vga.c | 1 - hw/vmware_vga.h | 15 --------------- sysemu.h | 3 --- 7 files changed, 56 deletions(-) delete mode 100644 hw/vga-pci.h delete mode 100644 hw/vmware_vga.h diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 9a0a56572..a10132953 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -28,7 +28,6 @@ */ #include "hw.h" #include "pci.h" -#include "vga-pci.h" #include "console.h" #include "vga_int.h" #include "loader.h" @@ -2970,11 +2969,6 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev) return 0; } -DeviceState *pci_cirrus_vga_init(PCIBus *bus) -{ - return &pci_create_simple(bus, -1, "cirrus-vga")->qdev; -} - static void cirrus_vga_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/pc.h b/hw/pc.h index 77c38d609..9923d9602 100644 --- a/hw/pc.h +++ b/hw/pc.h @@ -176,19 +176,6 @@ enum vga_retrace_method { extern enum vga_retrace_method vga_retrace_method; -static inline DeviceState *isa_std_vga_init(ISABus *bus) -{ - ISADevice *dev; - - dev = isa_try_create(bus, "isa-vga"); - if (!dev) { - fprintf(stderr, "Warning: isa-vga not available\n"); - return NULL; - } - qdev_init_nofail(&dev->qdev); - return &dev->qdev; -} - int isa_vga_mm_init(target_phys_addr_t vram_base, target_phys_addr_t ctrl_base, int it_shift, MemoryRegion *address_space); diff --git a/hw/vga-pci.c b/hw/vga-pci.c index 992ffd98b..996d47f23 100644 --- a/hw/vga-pci.c +++ b/hw/vga-pci.c @@ -24,7 +24,6 @@ #include "hw.h" #include "console.h" #include "pci.h" -#include "vga-pci.h" #include "vga_int.h" #include "pixel_ops.h" #include "qemu-timer.h" @@ -70,11 +69,6 @@ static int pci_std_vga_initfn(PCIDevice *dev) return 0; } -DeviceState *pci_std_vga_init(PCIBus *bus) -{ - return &pci_create_simple(bus, -1, "VGA")->qdev; -} - static Property vga_pci_properties[] = { DEFINE_PROP_UINT32("vgamem_mb", PCIVGAState, vga.vram_size_mb, 16), DEFINE_PROP_END_OF_LIST(), diff --git a/hw/vga-pci.h b/hw/vga-pci.h deleted file mode 100644 index d111cdc01..000000000 --- a/hw/vga-pci.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef VGA_PCI_H -#define VGA_PCI_H - -#include "qemu-common.h" - -/* vga-pci.c */ -DeviceState *pci_std_vga_init(PCIBus *bus); - -/* cirrus_vga.c */ -DeviceState *pci_cirrus_vga_init(PCIBus *bus); - -#endif diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index e815a04e9..6f7074e55 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -25,7 +25,6 @@ #include "loader.h" #include "console.h" #include "pci.h" -#include "vmware_vga.h" #undef VERBOSE #define HW_RECT_ACCEL diff --git a/hw/vmware_vga.h b/hw/vmware_vga.h deleted file mode 100644 index 000fbddc0..000000000 --- a/hw/vmware_vga.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef QEMU_VMWARE_VGA_H -#define QEMU_VMWARE_VGA_H - -#include "qemu-common.h" - -/* vmware_vga.c */ -static inline DeviceState *pci_vmsvga_init(PCIBus *bus) -{ - PCIDevice *dev; - - dev = pci_create_simple(bus, -1, "vmware-svga"); - return &dev->qdev; -} - -#endif diff --git a/sysemu.h b/sysemu.h index 109304672..0c39a3ac1 100644 --- a/sysemu.h +++ b/sysemu.h @@ -105,10 +105,7 @@ typedef enum { } VGAInterfaceType; extern int vga_interface_type; -#define cirrus_vga_enabled (vga_interface_type == VGA_CIRRUS) -#define std_vga_enabled (vga_interface_type == VGA_STD) #define xenfb_enabled (vga_interface_type == VGA_XENFB) -#define vmsvga_enabled (vga_interface_type == VGA_VMWARE) #define qxl_enabled (vga_interface_type == VGA_QXL) extern int graphic_width; -- cgit v1.2.3 From bcc66562ad185e9c2a667b00426f625e2489bda9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 24 Sep 2012 14:21:39 -0700 Subject: tcg: Add is_unsigned_cond Before we rearrange the TCG_COND enumeration, add a predicate for the (single) use of comparisons vs TCGCond. Signed-off-by: Richard Henderson Signed-off-by: Aurelien Jarno --- tcg/s390/tcg-target.c | 2 +- tcg/tcg.h | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c index 4b4305952..c0ef6ba9a 100644 --- a/tcg/s390/tcg-target.c +++ b/tcg/s390/tcg-target.c @@ -1113,7 +1113,7 @@ static void tgen64_xori(TCGContext *s, TCGReg dest, tcg_target_ulong val) static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1, TCGArg c2, int c2const) { - bool is_unsigned = (c > TCG_COND_GT); + bool is_unsigned = is_unsigned_cond(c); if (c2const) { if (c2 == 0) { if (type == TCG_TYPE_I32) { diff --git a/tcg/tcg.h b/tcg/tcg.h index af7464a65..6ff2ab55b 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -298,6 +298,11 @@ static inline TCGCond tcg_unsigned_cond(TCGCond c) return (c >= TCG_COND_LT && c <= TCG_COND_GT ? c + 4 : c); } +static inline bool is_unsigned_cond(TCGCond c) +{ + return c >= TCG_COND_LTU; +} + #define TEMP_VAL_DEAD 0 #define TEMP_VAL_REG 1 #define TEMP_VAL_MEM 2 -- cgit v1.2.3 From 0aed257f08444feb6269d0c302b35a8fb10fcb3f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 24 Sep 2012 14:21:40 -0700 Subject: tcg: Add TCG_COND_NEVER, TCG_COND_ALWAYS There are several cases that can be handled easier inside both translators and code generators if we have out-of-band values for conditions. It's easy enough to handle ALWAYS and NEVER in the natural way inside the tcg middle-end. Signed-off-by: Richard Henderson Signed-off-by: Aurelien Jarno --- tcg/arm/tcg-target.c | 2 +- tcg/hppa/tcg-target.c | 2 +- tcg/i386/tcg-target.c | 2 +- tcg/optimize.c | 6 ++++ tcg/ppc/tcg-target.c | 2 +- tcg/ppc64/tcg-target.c | 2 +- tcg/s390/tcg-target.c | 4 +-- tcg/sparc/tcg-target.c | 2 +- tcg/tcg-op.h | 82 ++++++++++++++++++++++++++++++++++++++------------ tcg/tcg.c | 2 ++ tcg/tcg.h | 37 ++++++++++++++--------- 11 files changed, 102 insertions(+), 41 deletions(-) diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c index 1e61864d4..fbbbefe98 100644 --- a/tcg/arm/tcg-target.c +++ b/tcg/arm/tcg-target.c @@ -335,7 +335,7 @@ enum arm_cond_code_e { COND_AL = 0xe, }; -static const uint8_t tcg_cond_to_arm_cond[10] = { +static const uint8_t tcg_cond_to_arm_cond[] = { [TCG_COND_EQ] = COND_EQ, [TCG_COND_NE] = COND_NE, [TCG_COND_LT] = COND_LT, diff --git a/tcg/hppa/tcg-target.c b/tcg/hppa/tcg-target.c index 44974c4e8..b93343015 100644 --- a/tcg/hppa/tcg-target.c +++ b/tcg/hppa/tcg-target.c @@ -732,7 +732,7 @@ static void tcg_out_branch(TCGContext *s, int label_index, int nul) } } -static const uint8_t tcg_cond_to_cmp_cond[10] = +static const uint8_t tcg_cond_to_cmp_cond[] = { [TCG_COND_EQ] = COND_EQ, [TCG_COND_NE] = COND_EQ | COND_FALSE, diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c index bb2306df8..4952c057b 100644 --- a/tcg/i386/tcg-target.c +++ b/tcg/i386/tcg-target.c @@ -338,7 +338,7 @@ static inline int tcg_target_const_match(tcg_target_long val, #define JCC_JLE 0xe #define JCC_JG 0xf -static const uint8_t tcg_cond_to_jcc[10] = { +static const uint8_t tcg_cond_to_jcc[] = { [TCG_COND_EQ] = JCC_JE, [TCG_COND_NE] = JCC_JNE, [TCG_COND_LT] = JCC_JL, diff --git a/tcg/optimize.c b/tcg/optimize.c index 35532a1e0..edb2b0ea9 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -321,6 +321,8 @@ static TCGArg do_constant_folding_cond(TCGOpcode op, TCGArg x, return (uint32_t)temps[x].val <= (uint32_t)temps[y].val; case TCG_COND_GTU: return (uint32_t)temps[x].val > (uint32_t)temps[y].val; + default: + break; } break; case 64: @@ -345,6 +347,8 @@ static TCGArg do_constant_folding_cond(TCGOpcode op, TCGArg x, return (uint64_t)temps[x].val <= (uint64_t)temps[y].val; case TCG_COND_GTU: return (uint64_t)temps[x].val > (uint64_t)temps[y].val; + default: + break; } break; } @@ -362,6 +366,8 @@ static TCGArg do_constant_folding_cond(TCGOpcode op, TCGArg x, case TCG_COND_LEU: case TCG_COND_EQ: return 1; + default: + break; } } else if (temps[y].state == TCG_TEMP_CONST && temps[y].val == 0) { switch (c) { diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c index 56baedda5..60b7b9262 100644 --- a/tcg/ppc/tcg-target.c +++ b/tcg/ppc/tcg-target.c @@ -437,7 +437,7 @@ enum { CR_SO }; -static const uint32_t tcg_to_bc[10] = { +static const uint32_t tcg_to_bc[] = { [TCG_COND_EQ] = BC | BI (7, CR_EQ) | BO_COND_TRUE, [TCG_COND_NE] = BC | BI (7, CR_EQ) | BO_COND_FALSE, [TCG_COND_LT] = BC | BI (7, CR_LT) | BO_COND_TRUE, diff --git a/tcg/ppc64/tcg-target.c b/tcg/ppc64/tcg-target.c index 6e9b363a1..5403fc1f9 100644 --- a/tcg/ppc64/tcg-target.c +++ b/tcg/ppc64/tcg-target.c @@ -418,7 +418,7 @@ enum { CR_SO }; -static const uint32_t tcg_to_bc[10] = { +static const uint32_t tcg_to_bc[] = { [TCG_COND_EQ] = BC | BI (7, CR_EQ) | BO_COND_TRUE, [TCG_COND_NE] = BC | BI (7, CR_EQ) | BO_COND_FALSE, [TCG_COND_LT] = BC | BI (7, CR_LT) | BO_COND_TRUE, diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c index c0ef6ba9a..fd9286f52 100644 --- a/tcg/s390/tcg-target.c +++ b/tcg/s390/tcg-target.c @@ -268,7 +268,7 @@ static const int tcg_target_call_oarg_regs[] = { #define S390_CC_ALWAYS 15 /* Condition codes that result from a COMPARE and COMPARE LOGICAL. */ -static const uint8_t tcg_cond_to_s390_cond[10] = { +static const uint8_t tcg_cond_to_s390_cond[] = { [TCG_COND_EQ] = S390_CC_EQ, [TCG_COND_NE] = S390_CC_NE, [TCG_COND_LT] = S390_CC_LT, @@ -284,7 +284,7 @@ static const uint8_t tcg_cond_to_s390_cond[10] = { /* Condition codes that result from a LOAD AND TEST. Here, we have no unsigned instruction variation, however since the test is vs zero we can re-map the outcomes appropriately. */ -static const uint8_t tcg_cond_to_ltr_cond[10] = { +static const uint8_t tcg_cond_to_ltr_cond[] = { [TCG_COND_EQ] = S390_CC_EQ, [TCG_COND_NE] = S390_CC_NE, [TCG_COND_LT] = S390_CC_LT, diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c index e82fab262..0c32baa50 100644 --- a/tcg/sparc/tcg-target.c +++ b/tcg/sparc/tcg-target.c @@ -512,7 +512,7 @@ static void tcg_out_branch_i64(TCGContext *s, int opc, int label_index) } #endif -static const uint8_t tcg_cond_to_bcond[10] = { +static const uint8_t tcg_cond_to_bcond[] = { [TCG_COND_EQ] = COND_E, [TCG_COND_NE] = COND_NE, [TCG_COND_LT] = COND_L, diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index bd93fe4f0..551845801 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -646,29 +646,49 @@ static inline void tcg_gen_sari_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) static inline void tcg_gen_brcond_i32(TCGCond cond, TCGv_i32 arg1, TCGv_i32 arg2, int label_index) { - tcg_gen_op4ii_i32(INDEX_op_brcond_i32, arg1, arg2, cond, label_index); + if (cond == TCG_COND_ALWAYS) { + tcg_gen_br(label_index); + } else if (cond != TCG_COND_NEVER) { + tcg_gen_op4ii_i32(INDEX_op_brcond_i32, arg1, arg2, cond, label_index); + } } static inline void tcg_gen_brcondi_i32(TCGCond cond, TCGv_i32 arg1, int32_t arg2, int label_index) { - TCGv_i32 t0 = tcg_const_i32(arg2); - tcg_gen_brcond_i32(cond, arg1, t0, label_index); - tcg_temp_free_i32(t0); + if (cond == TCG_COND_ALWAYS) { + tcg_gen_br(label_index); + } else if (cond != TCG_COND_NEVER) { + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_brcond_i32(cond, arg1, t0, label_index); + tcg_temp_free_i32(t0); + } } static inline void tcg_gen_setcond_i32(TCGCond cond, TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - tcg_gen_op4i_i32(INDEX_op_setcond_i32, ret, arg1, arg2, cond); + if (cond == TCG_COND_ALWAYS) { + tcg_gen_movi_i32(ret, 1); + } else if (cond == TCG_COND_NEVER) { + tcg_gen_movi_i32(ret, 0); + } else { + tcg_gen_op4i_i32(INDEX_op_setcond_i32, ret, arg1, arg2, cond); + } } static inline void tcg_gen_setcondi_i32(TCGCond cond, TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) { - TCGv_i32 t0 = tcg_const_i32(arg2); - tcg_gen_setcond_i32(cond, ret, arg1, t0); - tcg_temp_free_i32(t0); + if (cond == TCG_COND_ALWAYS) { + tcg_gen_movi_i32(ret, 1); + } else if (cond == TCG_COND_NEVER) { + tcg_gen_movi_i32(ret, 0); + } else { + TCGv_i32 t0 = tcg_const_i32(arg2); + tcg_gen_setcond_i32(cond, ret, arg1, t0); + tcg_temp_free_i32(t0); + } } static inline void tcg_gen_mul_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) @@ -964,17 +984,27 @@ static inline void tcg_gen_sari_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) static inline void tcg_gen_brcond_i64(TCGCond cond, TCGv_i64 arg1, TCGv_i64 arg2, int label_index) { - tcg_gen_op6ii_i32(INDEX_op_brcond2_i32, - TCGV_LOW(arg1), TCGV_HIGH(arg1), TCGV_LOW(arg2), - TCGV_HIGH(arg2), cond, label_index); + if (cond == TCG_COND_ALWAYS) { + tcg_gen_br(label_index); + } else if (cond != TCG_COND_NEVER) { + tcg_gen_op6ii_i32(INDEX_op_brcond2_i32, + TCGV_LOW(arg1), TCGV_HIGH(arg1), TCGV_LOW(arg2), + TCGV_HIGH(arg2), cond, label_index); + } } static inline void tcg_gen_setcond_i64(TCGCond cond, TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { - tcg_gen_op6i_i32(INDEX_op_setcond2_i32, TCGV_LOW(ret), - TCGV_LOW(arg1), TCGV_HIGH(arg1), - TCGV_LOW(arg2), TCGV_HIGH(arg2), cond); + if (cond == TCG_COND_ALWAYS) { + tcg_gen_movi_i32(TCGV_LOW(ret), 1); + } else if (cond == TCG_COND_NEVER) { + tcg_gen_movi_i32(TCGV_LOW(ret), 0); + } else { + tcg_gen_op6i_i32(INDEX_op_setcond2_i32, TCGV_LOW(ret), + TCGV_LOW(arg1), TCGV_HIGH(arg1), + TCGV_LOW(arg2), TCGV_HIGH(arg2), cond); + } tcg_gen_movi_i32(TCGV_HIGH(ret), 0); } @@ -1273,13 +1303,23 @@ static inline void tcg_gen_sari_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) static inline void tcg_gen_brcond_i64(TCGCond cond, TCGv_i64 arg1, TCGv_i64 arg2, int label_index) { - tcg_gen_op4ii_i64(INDEX_op_brcond_i64, arg1, arg2, cond, label_index); + if (cond == TCG_COND_ALWAYS) { + tcg_gen_br(label_index); + } else if (cond != TCG_COND_NEVER) { + tcg_gen_op4ii_i64(INDEX_op_brcond_i64, arg1, arg2, cond, label_index); + } } static inline void tcg_gen_setcond_i64(TCGCond cond, TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { - tcg_gen_op4i_i64(INDEX_op_setcond_i64, ret, arg1, arg2, cond); + if (cond == TCG_COND_ALWAYS) { + tcg_gen_movi_i64(ret, 1); + } else if (cond == TCG_COND_NEVER) { + tcg_gen_movi_i64(ret, 0); + } else { + tcg_gen_op4i_i64(INDEX_op_setcond_i64, ret, arg1, arg2, cond); + } } static inline void tcg_gen_mul_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) @@ -1397,9 +1437,13 @@ static inline void tcg_gen_subi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) static inline void tcg_gen_brcondi_i64(TCGCond cond, TCGv_i64 arg1, int64_t arg2, int label_index) { - TCGv_i64 t0 = tcg_const_i64(arg2); - tcg_gen_brcond_i64(cond, arg1, t0, label_index); - tcg_temp_free_i64(t0); + if (cond == TCG_COND_ALWAYS) { + tcg_gen_br(label_index); + } else if (cond != TCG_COND_NEVER) { + TCGv_i64 t0 = tcg_const_i64(arg2); + tcg_gen_brcond_i64(cond, arg1, t0, label_index); + tcg_temp_free_i64(t0); + } } static inline void tcg_gen_setcondi_i64(TCGCond cond, TCGv_i64 ret, diff --git a/tcg/tcg.c b/tcg/tcg.c index c069e44a0..78ef50b6e 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -864,6 +864,8 @@ static TCGHelperInfo *tcg_find_helper(TCGContext *s, tcg_target_ulong val) static const char * const cond_name[] = { + [TCG_COND_NEVER] = "never", + [TCG_COND_ALWAYS] = "always", [TCG_COND_EQ] = "eq", [TCG_COND_NE] = "ne", [TCG_COND_LT] = "lt", diff --git a/tcg/tcg.h b/tcg/tcg.h index 6ff2ab55b..75f023970 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -266,18 +266,28 @@ typedef int TCGv_i64; #define TCG_CALL_DUMMY_TCGV MAKE_TCGV_I32(-1) #define TCG_CALL_DUMMY_ARG ((TCGArg)(-1)) +/* Conditions. Note that these are layed out for easy manipulation by + the the functions below: + bit 0 is used for inverting; + bit 1 is signed, + bit 2 is unsigned, + bit 3 is used with bit 0 for swapping signed/unsigned. */ typedef enum { - TCG_COND_EQ, - TCG_COND_NE, - TCG_COND_LT, - TCG_COND_GE, - TCG_COND_LE, - TCG_COND_GT, + /* non-signed */ + TCG_COND_NEVER = 0 | 0 | 0 | 0, + TCG_COND_ALWAYS = 0 | 0 | 0 | 1, + TCG_COND_EQ = 8 | 0 | 0 | 0, + TCG_COND_NE = 8 | 0 | 0 | 1, + /* signed */ + TCG_COND_LT = 0 | 0 | 2 | 0, + TCG_COND_GE = 0 | 0 | 2 | 1, + TCG_COND_LE = 8 | 0 | 2 | 0, + TCG_COND_GT = 8 | 0 | 2 | 1, /* unsigned */ - TCG_COND_LTU, - TCG_COND_GEU, - TCG_COND_LEU, - TCG_COND_GTU, + TCG_COND_LTU = 0 | 4 | 0 | 0, + TCG_COND_GEU = 0 | 4 | 0 | 1, + TCG_COND_LEU = 8 | 4 | 0 | 0, + TCG_COND_GTU = 8 | 4 | 0 | 1, } TCGCond; /* Invert the sense of the comparison. */ @@ -289,18 +299,17 @@ static inline TCGCond tcg_invert_cond(TCGCond c) /* Swap the operands in a comparison. */ static inline TCGCond tcg_swap_cond(TCGCond c) { - int mask = (c < TCG_COND_LT ? 0 : c < TCG_COND_LTU ? 7 : 15); - return (TCGCond)(c ^ mask); + return c & 6 ? (TCGCond)(c ^ 9) : c; } static inline TCGCond tcg_unsigned_cond(TCGCond c) { - return (c >= TCG_COND_LT && c <= TCG_COND_GT ? c + 4 : c); + return c & 2 ? (TCGCond)(c ^ 6) : c; } static inline bool is_unsigned_cond(TCGCond c) { - return c >= TCG_COND_LTU; + return (c & 4) != 0; } #define TEMP_VAL_DEAD 0 -- cgit v1.2.3 From d1e321b82a021c2e86d204af870356bc72b22546 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 24 Sep 2012 14:21:41 -0700 Subject: tcg: Add tcg_high_cond The table that was recently added for hppa is generally usable. And with the renumbering of the TCG_COND constants it's not too difficult to compute rather than have a table. Signed-off-by: Richard Henderson Signed-off-by: Aurelien Jarno --- tcg/hppa/tcg-target.c | 17 ++--------------- tcg/tcg.h | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/tcg/hppa/tcg-target.c b/tcg/hppa/tcg-target.c index b93343015..de500ae18 100644 --- a/tcg/hppa/tcg-target.c +++ b/tcg/hppa/tcg-target.c @@ -814,19 +814,6 @@ static void tcg_out_comclr(TCGContext *s, int cond, TCGArg ret, tcg_out32(s, op); } -static TCGCond const tcg_high_cond[] = { - [TCG_COND_EQ] = TCG_COND_EQ, - [TCG_COND_NE] = TCG_COND_NE, - [TCG_COND_LT] = TCG_COND_LT, - [TCG_COND_LE] = TCG_COND_LT, - [TCG_COND_GT] = TCG_COND_GT, - [TCG_COND_GE] = TCG_COND_GT, - [TCG_COND_LTU] = TCG_COND_LTU, - [TCG_COND_LEU] = TCG_COND_LTU, - [TCG_COND_GTU] = TCG_COND_GTU, - [TCG_COND_GEU] = TCG_COND_GTU -}; - static void tcg_out_brcond2(TCGContext *s, int cond, TCGArg al, TCGArg ah, TCGArg bl, int blconst, TCGArg bh, int bhconst, int label_index) @@ -841,7 +828,7 @@ static void tcg_out_brcond2(TCGContext *s, int cond, TCGArg al, TCGArg ah, tcg_out_brcond(s, TCG_COND_NE, ah, bh, bhconst, label_index); break; default: - tcg_out_brcond(s, tcg_high_cond[cond], ah, bh, bhconst, label_index); + tcg_out_brcond(s, tcg_high_cond(cond), ah, bh, bhconst, label_index); tcg_out_comclr(s, TCG_COND_NE, TCG_REG_R0, ah, bh, bhconst); tcg_out_brcond(s, tcg_unsigned_cond(cond), al, bl, blconst, label_index); @@ -894,7 +881,7 @@ static void tcg_out_setcond2(TCGContext *s, int cond, TCGArg ret, tcg_out_setcond(s, tcg_unsigned_cond(cond), scratch, al, bl, blconst); tcg_out_comclr(s, TCG_COND_EQ, TCG_REG_R0, ah, bh, bhconst); tcg_out_movi(s, TCG_TYPE_I32, scratch, 0); - tcg_out_comclr(s, tcg_invert_cond(tcg_high_cond[cond]), + tcg_out_comclr(s, tcg_invert_cond(tcg_high_cond(cond)), TCG_REG_R0, ah, bh, bhconst); tcg_out_movi(s, TCG_TYPE_I32, scratch, 1); break; diff --git a/tcg/tcg.h b/tcg/tcg.h index 75f023970..562f0adcd 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -302,16 +302,33 @@ static inline TCGCond tcg_swap_cond(TCGCond c) return c & 6 ? (TCGCond)(c ^ 9) : c; } +/* Create an "unsigned" version of a "signed" comparison. */ static inline TCGCond tcg_unsigned_cond(TCGCond c) { return c & 2 ? (TCGCond)(c ^ 6) : c; } +/* Must a comparison be considered unsigned? */ static inline bool is_unsigned_cond(TCGCond c) { return (c & 4) != 0; } +/* Create a "high" version of a double-word comparison. + This removes equality from a LTE or GTE comparison. */ +static inline TCGCond tcg_high_cond(TCGCond c) +{ + switch (c) { + case TCG_COND_GE: + case TCG_COND_LE: + case TCG_COND_GEU: + case TCG_COND_LEU: + return (TCGCond)(c ^ 8); + default: + return c; + } +} + #define TEMP_VAL_DEAD 0 #define TEMP_VAL_REG 1 #define TEMP_VAL_MEM 2 -- cgit v1.2.3 From 1d31fca470648ec66afd8743491bfb5846306341 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Sat, 6 Oct 2012 12:46:15 +0200 Subject: qemu-barrier: Fix compilation on i386 hosts Commit 610b823ef66b993660f1ab1447a769f190e4f3b3 uses QEMU_GNUC_PREREQ on i386 hosts. That macro is defined in qemu-common.h which is not always included before qemu-barrier.h, so compilation on i386 hosts was broken. Signed-off-by: Stefan Weil Signed-off-by: Aurelien Jarno --- qemu-barrier.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qemu-barrier.h b/qemu-barrier.h index 16f09429c..1de914e88 100644 --- a/qemu-barrier.h +++ b/qemu-barrier.h @@ -6,6 +6,8 @@ #if defined(__i386__) +#include "qemu-common.h" /* QEMU_GNUC_PREREQ */ + /* * Because of the strongly ordered x86 storage model, wmb() and rmb() are nops * on x86(well, a compiler barrier only). Well, at least as long as -- cgit v1.2.3 From d838201111894b17ca9123d5d2a74ab4cf6376d6 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Thu, 4 Oct 2012 20:29:02 +0200 Subject: tcg: Remove redundant pointer from TCGContext The pointer entry 'temps' always refers to the array entry 'static_temps'. Removing the pointer and renaming 'static_temps' to 'temps' reduces the size of TCGContext (4 or 8 byte) and allows better code generation. Signed-off-by: Stefan Weil Reviewed-by: Richard Henderson Signed-off-by: Blue Swirl --- tcg/tcg.c | 1 - tcg/tcg.h | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/tcg/tcg.c b/tcg/tcg.c index 78ef50b6e..32cd0c6b6 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -242,7 +242,6 @@ void tcg_context_init(TCGContext *s) int *sorted_args; memset(s, 0, sizeof(*s)); - s->temps = s->static_temps; s->nb_globals = 0; /* Count total number of arguments and allocate the corresponding diff --git a/tcg/tcg.h b/tcg/tcg.h index 562f0adcd..7bafe0eeb 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -367,7 +367,6 @@ struct TCGContext { TCGPool *pool_first, *pool_current, *pool_first_large; TCGLabel *labels; int nb_labels; - TCGTemp *temps; /* globals first, temps after */ int nb_globals; int nb_temps; /* index of free temps, -1 if none */ @@ -393,7 +392,7 @@ struct TCGContext { int frame_reg; uint8_t *code_ptr; - TCGTemp static_temps[TCG_MAX_TEMPS]; + TCGTemp temps[TCG_MAX_TEMPS]; /* globals first, temps after */ TCGHelperInfo *helpers; int nb_helpers; -- cgit v1.2.3 From 76a23ca099084ce72f5c30a3c5dc18e331384c59 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 5 Oct 2012 16:54:48 -0700 Subject: target-sparc: Tidy cpu_dump_state We don't really need to be told that %g are general register, etc. Issue a trailing newline to separate blocks. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/cpu.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c index eb9f0e725..882d30642 100644 --- a/target-sparc/cpu.c +++ b/target-sparc/cpu.c @@ -792,7 +792,6 @@ void cpu_dump_state(CPUSPARCState *env, FILE *f, fprintf_function cpu_fprintf, cpu_fprintf(f, "pc: " TARGET_FMT_lx " npc: " TARGET_FMT_lx "\n", env->pc, env->npc); - cpu_fprintf(f, "General Registers:\n"); for (i = 0; i < 8; i++) { if (i % REGS_PER_LINE == 0) { @@ -803,7 +802,6 @@ void cpu_dump_state(CPUSPARCState *env, FILE *f, fprintf_function cpu_fprintf, cpu_fprintf(f, "\n"); } } - cpu_fprintf(f, "\nCurrent Register Window:\n"); for (x = 0; x < 3; x++) { for (i = 0; i < 8; i++) { if (i % REGS_PER_LINE == 0) { @@ -817,10 +815,10 @@ void cpu_dump_state(CPUSPARCState *env, FILE *f, fprintf_function cpu_fprintf, } } } - cpu_fprintf(f, "\nFloating Point Registers:\n"); + for (i = 0; i < TARGET_DPREGS; i++) { if ((i & 3) == 0) { - cpu_fprintf(f, "%%f%02d:", i * 2); + cpu_fprintf(f, "%%f%02d: ", i * 2); } cpu_fprintf(f, " %016" PRIx64, env->fpr[i].ll); if ((i & 3) == 3) { @@ -850,6 +848,7 @@ void cpu_dump_state(CPUSPARCState *env, FILE *f, fprintf_function cpu_fprintf, cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n", env->fsr, env->y); #endif + cpu_fprintf(f, "\n"); } static void sparc_cpu_initfn(Object *obj) -- cgit v1.2.3 From b884fc5ecaacd241829f225282356d59eb186645 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 5 Oct 2012 16:54:49 -0700 Subject: target-sparc: Make CPU_LOG_INT useful by default No need for ifdefs when the log mask does just as well. No need to print pc/npc when we're dumping the whole cpu state. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/int32_helper.c | 7 ++----- target-sparc/int64_helper.c | 8 ++------ 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/target-sparc/int32_helper.c b/target-sparc/int32_helper.c index 5e33d50e2..9ac5aac33 100644 --- a/target-sparc/int32_helper.c +++ b/target-sparc/int32_helper.c @@ -21,7 +21,7 @@ #include "trace.h" #include "sysemu.h" -//#define DEBUG_PCALL +#define DEBUG_PCALL #ifdef DEBUG_PCALL static const char * const excp_names[0x80] = { @@ -78,10 +78,7 @@ void do_interrupt(CPUSPARCState *env) } } - qemu_log("%6d: %s (v=%02x) pc=%08x npc=%08x SP=%08x\n", - count, name, intno, - env->pc, - env->npc, env->regwptr[6]); + qemu_log("%6d: %s (v=%02x)\n", count, name, intno); log_cpu_state(env, 0); #if 0 { diff --git a/target-sparc/int64_helper.c b/target-sparc/int64_helper.c index 5e3eff76d..5d0bc6c6d 100644 --- a/target-sparc/int64_helper.c +++ b/target-sparc/int64_helper.c @@ -21,7 +21,7 @@ #include "helper.h" #include "trace.h" -//#define DEBUG_PCALL +#define DEBUG_PCALL #ifdef DEBUG_PCALL static const char * const excp_names[0x80] = { @@ -84,11 +84,7 @@ void do_interrupt(CPUSPARCState *env) } } - qemu_log("%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64 - " SP=%016" PRIx64 "\n", - count, name, intno, - env->pc, - env->npc, env->regwptr[6]); + qemu_log("%6d: %s (v=%04x)\n", count, name, intno); log_cpu_state(env, 0); #if 0 { -- cgit v1.2.3 From d4a288ef9c2b432307961429bdcacb2416ad8a99 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 5 Oct 2012 16:54:50 -0700 Subject: target-sparc: Tidy do_branch interfaces We always pass cpu_cond to the r_cond parameter. Use that global register directly instead of passing it down. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index e5ebedfa2..079a04044 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1337,8 +1337,7 @@ static inline void gen_cond_reg(TCGv r_dst, int cond, TCGv r_src) } #endif -static void do_branch(DisasContext *dc, int32_t offset, uint32_t insn, int cc, - TCGv r_cond) +static void do_branch(DisasContext *dc, int32_t offset, uint32_t insn, int cc) { unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29)); target_ulong target = dc->pc + offset; @@ -1368,10 +1367,10 @@ static void do_branch(DisasContext *dc, int32_t offset, uint32_t insn, int cc, tcg_gen_mov_tl(cpu_pc, cpu_npc); } } else { - flush_cond(dc, r_cond); - gen_cond(r_cond, cc, cond, dc); + flush_cond(dc, cpu_cond); + gen_cond(cpu_cond, cc, cond, dc); if (a) { - gen_branch_a(dc, target, dc->npc, r_cond); + gen_branch_a(dc, target, dc->npc, cpu_cond); dc->is_br = 1; } else { dc->pc = dc->npc; @@ -1387,8 +1386,7 @@ static void do_branch(DisasContext *dc, int32_t offset, uint32_t insn, int cc, } } -static void do_fbranch(DisasContext *dc, int32_t offset, uint32_t insn, int cc, - TCGv r_cond) +static void do_fbranch(DisasContext *dc, int32_t offset, uint32_t insn, int cc) { unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29)); target_ulong target = dc->pc + offset; @@ -1418,10 +1416,10 @@ static void do_fbranch(DisasContext *dc, int32_t offset, uint32_t insn, int cc, tcg_gen_mov_tl(cpu_pc, cpu_npc); } } else { - flush_cond(dc, r_cond); - gen_fcond(r_cond, cc, cond); + flush_cond(dc, cpu_cond); + gen_fcond(cpu_cond, cc, cond); if (a) { - gen_branch_a(dc, target, dc->npc, r_cond); + gen_branch_a(dc, target, dc->npc, cpu_cond); dc->is_br = 1; } else { dc->pc = dc->npc; @@ -1439,7 +1437,7 @@ static void do_fbranch(DisasContext *dc, int32_t offset, uint32_t insn, int cc, #ifdef TARGET_SPARC64 static void do_branch_reg(DisasContext *dc, int32_t offset, uint32_t insn, - TCGv r_cond, TCGv r_reg) + TCGv r_reg) { unsigned int cond = GET_FIELD_SP(insn, 25, 27), a = (insn & (1 << 29)); target_ulong target = dc->pc + offset; @@ -1447,10 +1445,10 @@ static void do_branch_reg(DisasContext *dc, int32_t offset, uint32_t insn, if (unlikely(AM_CHECK(dc))) { target &= 0xffffffffULL; } - flush_cond(dc, r_cond); - gen_cond_reg(r_cond, cond, r_reg); + flush_cond(dc, cpu_cond); + gen_cond_reg(cpu_cond, cond, r_reg); if (a) { - gen_branch_a(dc, target, dc->npc, r_cond); + gen_branch_a(dc, target, dc->npc, cpu_cond); dc->is_br = 1; } else { dc->pc = dc->npc; @@ -2421,9 +2419,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) target <<= 2; cc = GET_FIELD_SP(insn, 20, 21); if (cc == 0) - do_branch(dc, target, insn, 0, cpu_cond); + do_branch(dc, target, insn, 0); else if (cc == 2) - do_branch(dc, target, insn, 1, cpu_cond); + do_branch(dc, target, insn, 1); else goto illegal_insn; goto jmp_insn; @@ -2435,7 +2433,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) target = sign_extend(target, 16); target <<= 2; cpu_src1 = get_src1(insn, cpu_src1); - do_branch_reg(dc, target, insn, cpu_cond, cpu_src1); + do_branch_reg(dc, target, insn, cpu_src1); goto jmp_insn; } case 0x5: /* V9 FBPcc */ @@ -2446,7 +2444,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) target = GET_FIELD_SP(insn, 0, 18); target = sign_extend(target, 19); target <<= 2; - do_fbranch(dc, target, insn, cc, cpu_cond); + do_fbranch(dc, target, insn, cc); goto jmp_insn; } #else @@ -2460,7 +2458,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) target = GET_FIELD(insn, 10, 31); target = sign_extend(target, 22); target <<= 2; - do_branch(dc, target, insn, 0, cpu_cond); + do_branch(dc, target, insn, 0); goto jmp_insn; } case 0x6: /* FBN+x */ @@ -2470,7 +2468,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) target = GET_FIELD(insn, 10, 31); target = sign_extend(target, 22); target <<= 2; - do_fbranch(dc, target, insn, 0, cpu_cond); + do_fbranch(dc, target, insn, 0); goto jmp_insn; } case 0x4: /* SETHI */ -- cgit v1.2.3 From dee8913cbf82a03fed661ac6c461491045dac7f5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 5 Oct 2012 16:54:51 -0700 Subject: target-sparc: Tidy flush_cond interface We always pass cpu_cond to the cond parameter. Use that global register directly instead of passing it down. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 079a04044..5b2d5ea71 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1118,10 +1118,10 @@ static inline void gen_generic_branch(target_ulong npc1, target_ulong npc2, /* call this function before using the condition register as it may have been set for a jump */ -static inline void flush_cond(DisasContext *dc, TCGv cond) +static inline void flush_cond(DisasContext *dc) { if (dc->npc == JUMP_PC) { - gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1], cond); + gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1], cpu_cond); dc->npc = DYNAMIC_PC; } } @@ -1367,7 +1367,7 @@ static void do_branch(DisasContext *dc, int32_t offset, uint32_t insn, int cc) tcg_gen_mov_tl(cpu_pc, cpu_npc); } } else { - flush_cond(dc, cpu_cond); + flush_cond(dc); gen_cond(cpu_cond, cc, cond, dc); if (a) { gen_branch_a(dc, target, dc->npc, cpu_cond); @@ -1416,7 +1416,7 @@ static void do_fbranch(DisasContext *dc, int32_t offset, uint32_t insn, int cc) tcg_gen_mov_tl(cpu_pc, cpu_npc); } } else { - flush_cond(dc, cpu_cond); + flush_cond(dc); gen_fcond(cpu_cond, cc, cond); if (a) { gen_branch_a(dc, target, dc->npc, cpu_cond); @@ -1445,7 +1445,7 @@ static void do_branch_reg(DisasContext *dc, int32_t offset, uint32_t insn, if (unlikely(AM_CHECK(dc))) { target &= 0xffffffffULL; } - flush_cond(dc, cpu_cond); + flush_cond(dc); gen_cond_reg(cpu_cond, cond, r_reg); if (a) { gen_branch_a(dc, target, dc->npc, cpu_cond); -- cgit v1.2.3 From 5b12f1e8a1aad8030c3ec5790cb5f8f370a1df1f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 5 Oct 2012 16:54:52 -0700 Subject: target-sparc: Tidy gen_trap_ifnofpu interface We always pass cpu_cond to the cond parameter. Use that global register directly instead of passing it down. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 5b2d5ea71..9787664a2 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1615,13 +1615,13 @@ static inline void gen_op_fpexception_im(int fsr_flags) tcg_temp_free_i32(r_const); } -static int gen_trap_ifnofpu(DisasContext *dc, TCGv r_cond) +static int gen_trap_ifnofpu(DisasContext *dc) { #if !defined(CONFIG_USER_ONLY) if (!dc->fpu_enabled) { TCGv_i32 r_const; - save_state(dc, r_cond); + save_state(dc, cpu_cond); r_const = tcg_const_i32(TT_NFPU_INSN); gen_helper_raise_exception(cpu_env, r_const); tcg_temp_free_i32(r_const); @@ -2439,8 +2439,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) case 0x5: /* V9 FBPcc */ { int cc = GET_FIELD_SP(insn, 20, 21); - if (gen_trap_ifnofpu(dc, cpu_cond)) + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; + } target = GET_FIELD_SP(insn, 0, 18); target = sign_extend(target, 19); target <<= 2; @@ -2463,8 +2464,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } case 0x6: /* FBN+x */ { - if (gen_trap_ifnofpu(dc, cpu_cond)) + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; + } target = GET_FIELD(insn, 10, 31); target = sign_extend(target, 22); target <<= 2; @@ -2643,8 +2645,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) case 0xf: /* V9 membar */ break; /* no effect */ case 0x13: /* Graphics Status */ - if (gen_trap_ifnofpu(dc, cpu_cond)) + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; + } gen_movl_TN_reg(rd, cpu_gsr); break; case 0x16: /* Softint */ @@ -2861,8 +2864,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) break; #endif } else if (xop == 0x34) { /* FPU Operations */ - if (gen_trap_ifnofpu(dc, cpu_cond)) + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; + } gen_op_clear_ieee_excp_and_FTT(); rs1 = GET_FIELD(insn, 13, 17); rs2 = GET_FIELD(insn, 27, 31); @@ -3035,8 +3039,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) #ifdef TARGET_SPARC64 int cond; #endif - if (gen_trap_ifnofpu(dc, cpu_cond)) + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; + } gen_op_clear_ieee_excp_and_FTT(); rs1 = GET_FIELD(insn, 13, 17); rs2 = GET_FIELD(insn, 27, 31); @@ -3699,8 +3704,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) #endif break; case 0x13: /* Graphics Status */ - if (gen_trap_ifnofpu(dc, cpu_cond)) + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; + } tcg_gen_xor_tl(cpu_gsr, cpu_src1, cpu_src2); break; case 0x14: /* Softint set */ @@ -4105,8 +4111,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) int opf = GET_FIELD_SP(insn, 5, 13); rs1 = GET_FIELD(insn, 13, 17); rs2 = GET_FIELD(insn, 27, 31); - if (gen_trap_ifnofpu(dc, cpu_cond)) + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; + } switch (opf) { case 0x000: /* VIS I edge8cc */ @@ -4873,7 +4880,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) case 0x2d: /* V9 prefetch, no effect */ goto skip_move; case 0x30: /* V9 ldfa */ - if (gen_trap_ifnofpu(dc, cpu_cond)) { + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; } save_state(dc, cpu_cond); @@ -4881,7 +4888,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) gen_update_fprs_dirty(rd); goto skip_move; case 0x33: /* V9 lddfa */ - if (gen_trap_ifnofpu(dc, cpu_cond)) { + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; } save_state(dc, cpu_cond); @@ -4892,7 +4899,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) goto skip_move; case 0x32: /* V9 ldqfa */ CHECK_FPU_FEATURE(dc, FLOAT128); - if (gen_trap_ifnofpu(dc, cpu_cond)) { + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; } save_state(dc, cpu_cond); @@ -4908,8 +4915,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) skip_move: ; #endif } else if (xop >= 0x20 && xop < 0x24) { - if (gen_trap_ifnofpu(dc, cpu_cond)) + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; + } save_state(dc, cpu_cond); switch (xop) { case 0x20: /* ldf, load fpreg */ @@ -5056,8 +5064,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) goto illegal_insn; } } else if (xop > 0x23 && xop < 0x28) { - if (gen_trap_ifnofpu(dc, cpu_cond)) + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; + } save_state(dc, cpu_cond); switch (xop) { case 0x24: /* stf, store fpreg */ @@ -5100,8 +5109,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) #else if (!supervisor(dc)) goto priv_insn; - if (gen_trap_ifnofpu(dc, cpu_cond)) + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; + } goto nfq_insn; #endif #endif @@ -5118,7 +5128,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) switch (xop) { #ifdef TARGET_SPARC64 case 0x34: /* V9 stfa */ - if (gen_trap_ifnofpu(dc, cpu_cond)) { + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; } gen_stf_asi(cpu_addr, insn, 4, rd); @@ -5128,7 +5138,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) TCGv_i32 r_const; CHECK_FPU_FEATURE(dc, FLOAT128); - if (gen_trap_ifnofpu(dc, cpu_cond)) { + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; } r_const = tcg_const_i32(7); @@ -5138,7 +5148,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } break; case 0x37: /* V9 stdfa */ - if (gen_trap_ifnofpu(dc, cpu_cond)) { + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; } gen_stf_asi(cpu_addr, insn, 8, DFPREG(rd)); -- cgit v1.2.3 From 66442b07ae37a23c727ecd8c30a25054a7f21886 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 5 Oct 2012 16:54:53 -0700 Subject: target-sparc: Tidy save_state interface Use the cpu_cond global register directly instead of passing it down. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 98 ++++++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 9787664a2..eb952608d 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1136,7 +1136,7 @@ static inline void save_npc(DisasContext *dc, TCGv cond) } } -static inline void save_state(DisasContext *dc, TCGv cond) +static inline void save_state(DisasContext *dc) { tcg_gen_movi_tl(cpu_pc, dc->pc); /* flush pending conditional evaluations before exposing cpu state */ @@ -1144,7 +1144,7 @@ static inline void save_state(DisasContext *dc, TCGv cond) dc->cc_op = CC_OP_FLAGS; gen_helper_compute_psr(cpu_env); } - save_npc(dc, cond); + save_npc(dc, cpu_cond); } static inline void gen_mov_pc_npc(DisasContext *dc, TCGv cond) @@ -1621,7 +1621,7 @@ static int gen_trap_ifnofpu(DisasContext *dc) if (!dc->fpu_enabled) { TCGv_i32 r_const; - save_state(dc, cpu_cond); + save_state(dc); r_const = tcg_const_i32(TT_NFPU_INSN); gen_helper_raise_exception(cpu_env, r_const); tcg_temp_free_i32(r_const); @@ -2529,7 +2529,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) cond = GET_FIELD(insn, 3, 6); if (cond == 0x8) { /* Trap Always */ - save_state(dc, cpu_cond); + save_state(dc); if ((dc->def->features & CPU_FEATURE_HYPV) && supervisor(dc)) tcg_gen_andi_tl(cpu_dst, cpu_dst, UA2005_HTRAP_MASK); @@ -2546,7 +2546,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) /* V9 icc/xcc */ int cc = GET_FIELD_SP(insn, 11, 12); - save_state(dc, cpu_cond); + save_state(dc); if (cc == 0) gen_cond(r_cond, 0, cond, dc); else if (cc == 2) @@ -2554,7 +2554,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) else goto illegal_insn; #else - save_state(dc, cpu_cond); + save_state(dc); gen_cond(r_cond, 0, cond, dc); #endif l1 = gen_new_label(); @@ -2854,7 +2854,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) break; } else if (xop == 0x2b) { /* rdtbr / V9 flushw */ #ifdef TARGET_SPARC64 - save_state(dc, cpu_cond); + save_state(dc); gen_helper_flushw(cpu_env); #else if (!supervisor(dc)) @@ -2871,7 +2871,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) rs1 = GET_FIELD(insn, 13, 17); rs2 = GET_FIELD(insn, 27, 31); xop = GET_FIELD(insn, 18, 26); - save_state(dc, cpu_cond); + save_state(dc); switch (xop) { case 0x1: /* fmovs */ cpu_src1_32 = gen_load_fpr_F(dc, rs2); @@ -3046,7 +3046,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) rs1 = GET_FIELD(insn, 13, 17); rs2 = GET_FIELD(insn, 27, 31); xop = GET_FIELD(insn, 18, 26); - save_state(dc, cpu_cond); + save_state(dc); #ifdef TARGET_SPARC64 if ((xop & 0x11f) == 0x005) { // V9 fmovsr int l1; @@ -3607,14 +3607,14 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) dc->cc_op = CC_OP_TSUB; break; case 0x22: /* taddcctv */ - save_state(dc, cpu_cond); + save_state(dc); gen_op_tadd_ccTV(cpu_dst, cpu_src1, cpu_src2); gen_movl_TN_reg(rd, cpu_dst); tcg_gen_movi_i32(cpu_cc_op, CC_OP_TADDTV); dc->cc_op = CC_OP_TADDTV; break; case 0x23: /* tsubcctv */ - save_state(dc, cpu_cond); + save_state(dc); gen_op_tsub_ccTV(cpu_dst, cpu_src1, cpu_src2); gen_movl_TN_reg(rd, cpu_dst); tcg_gen_movi_i32(cpu_cc_op, CC_OP_TSUBTV); @@ -3691,7 +3691,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) case 0x6: /* V9 wrfprs */ tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2); tcg_gen_trunc_tl_i32(cpu_fprs, cpu_dst); - save_state(dc, cpu_cond); + save_state(dc); gen_op_next_insn(); tcg_gen_exit_tb(0); dc->is_br = 1; @@ -3818,7 +3818,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) gen_helper_wrpsr(cpu_env, cpu_dst); tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS); dc->cc_op = CC_OP_FLAGS; - save_state(dc, cpu_cond); + save_state(dc); gen_op_next_insn(); tcg_gen_exit_tb(0); dc->is_br = 1; @@ -3898,7 +3898,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) TCGv r_tmp = tcg_temp_local_new(); tcg_gen_mov_tl(r_tmp, cpu_tmp0); - save_state(dc, cpu_cond); + save_state(dc); gen_helper_wrpstate(cpu_env, r_tmp); tcg_temp_free(r_tmp); dc->npc = DYNAMIC_PC; @@ -3909,7 +3909,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) TCGv r_tmp = tcg_temp_local_new(); tcg_gen_mov_tl(r_tmp, cpu_tmp0); - save_state(dc, cpu_cond); + save_state(dc); tcg_gen_trunc_tl_i32(cpu_tmp32, r_tmp); tcg_temp_free(r_tmp); tcg_gen_st_i32(cpu_tmp32, cpu_env, @@ -3991,7 +3991,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) switch (rd) { case 0: // hpstate // XXX gen_op_wrhpstate(); - save_state(dc, cpu_cond); + save_state(dc); gen_op_next_insn(); tcg_gen_exit_tb(0); dc->is_br = 1; @@ -4559,7 +4559,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } else if (xop == 0x39) { /* V9 return */ TCGv_i32 r_const; - save_state(dc, cpu_cond); + save_state(dc); cpu_src1 = get_src1(insn, cpu_src1); if (IS_IMM) { /* immediate */ simm = GET_FIELDs(insn, 19, 31); @@ -4635,12 +4635,12 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) /* nop */ break; case 0x3c: /* save */ - save_state(dc, cpu_cond); + save_state(dc); gen_helper_save(cpu_env); gen_movl_TN_reg(rd, cpu_dst); break; case 0x3d: /* restore */ - save_state(dc, cpu_cond); + save_state(dc); gen_helper_restore(cpu_env); gen_movl_TN_reg(rd, cpu_dst); break; @@ -4723,7 +4723,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) else { TCGv_i32 r_const; - save_state(dc, cpu_cond); + save_state(dc); r_const = tcg_const_i32(7); /* XXX remove alignment check */ gen_helper_check_align(cpu_env, cpu_addr, r_const); @@ -4774,7 +4774,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (!supervisor(dc)) goto priv_insn; #endif - save_state(dc, cpu_cond); + save_state(dc); gen_ld_asi(cpu_val, cpu_addr, insn, 4, 0); break; case 0x11: /* lduba, load unsigned byte alternate */ @@ -4784,7 +4784,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (!supervisor(dc)) goto priv_insn; #endif - save_state(dc, cpu_cond); + save_state(dc); gen_ld_asi(cpu_val, cpu_addr, insn, 1, 0); break; case 0x12: /* lduha, load unsigned halfword alternate */ @@ -4794,7 +4794,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (!supervisor(dc)) goto priv_insn; #endif - save_state(dc, cpu_cond); + save_state(dc); gen_ld_asi(cpu_val, cpu_addr, insn, 2, 0); break; case 0x13: /* ldda, load double word alternate */ @@ -4806,7 +4806,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) #endif if (rd & 1) goto illegal_insn; - save_state(dc, cpu_cond); + save_state(dc); gen_ldda_asi(cpu_val, cpu_addr, insn, rd); goto skip_move; case 0x19: /* ldsba, load signed byte alternate */ @@ -4816,7 +4816,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (!supervisor(dc)) goto priv_insn; #endif - save_state(dc, cpu_cond); + save_state(dc); gen_ld_asi(cpu_val, cpu_addr, insn, 1, 1); break; case 0x1a: /* ldsha, load signed halfword alternate */ @@ -4826,7 +4826,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (!supervisor(dc)) goto priv_insn; #endif - save_state(dc, cpu_cond); + save_state(dc); gen_ld_asi(cpu_val, cpu_addr, insn, 2, 1); break; case 0x1d: /* ldstuba -- XXX: should be atomically */ @@ -4836,7 +4836,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (!supervisor(dc)) goto priv_insn; #endif - save_state(dc, cpu_cond); + save_state(dc); gen_ldstub_asi(cpu_val, cpu_addr, insn); break; case 0x1f: /* swapa, swap reg with alt. memory. Also @@ -4848,7 +4848,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (!supervisor(dc)) goto priv_insn; #endif - save_state(dc, cpu_cond); + save_state(dc); gen_movl_reg_TN(rd, cpu_val); gen_swap_asi(cpu_val, cpu_addr, insn); break; @@ -4870,11 +4870,11 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) tcg_gen_qemu_ld64(cpu_val, cpu_addr, dc->mem_idx); break; case 0x18: /* V9 ldswa */ - save_state(dc, cpu_cond); + save_state(dc); gen_ld_asi(cpu_val, cpu_addr, insn, 4, 1); break; case 0x1b: /* V9 ldxa */ - save_state(dc, cpu_cond); + save_state(dc); gen_ld_asi(cpu_val, cpu_addr, insn, 8, 0); break; case 0x2d: /* V9 prefetch, no effect */ @@ -4883,7 +4883,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (gen_trap_ifnofpu(dc)) { goto jmp_insn; } - save_state(dc, cpu_cond); + save_state(dc); gen_ldf_asi(cpu_addr, insn, 4, rd); gen_update_fprs_dirty(rd); goto skip_move; @@ -4891,7 +4891,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (gen_trap_ifnofpu(dc)) { goto jmp_insn; } - save_state(dc, cpu_cond); + save_state(dc); gen_ldf_asi(cpu_addr, insn, 8, DFPREG(rd)); gen_update_fprs_dirty(DFPREG(rd)); goto skip_move; @@ -4902,7 +4902,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (gen_trap_ifnofpu(dc)) { goto jmp_insn; } - save_state(dc, cpu_cond); + save_state(dc); gen_ldf_asi(cpu_addr, insn, 16, QFPREG(rd)); gen_update_fprs_dirty(QFPREG(rd)); goto skip_move; @@ -4918,7 +4918,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (gen_trap_ifnofpu(dc)) { goto jmp_insn; } - save_state(dc, cpu_cond); + save_state(dc); switch (xop) { case 0x20: /* ldf, load fpreg */ gen_address_mask(dc, cpu_addr); @@ -4989,7 +4989,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) else { TCGv_i32 r_const; - save_state(dc, cpu_cond); + save_state(dc); gen_address_mask(dc, cpu_addr); r_const = tcg_const_i32(7); /* XXX remove alignment check */ @@ -5008,7 +5008,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (!supervisor(dc)) goto priv_insn; #endif - save_state(dc, cpu_cond); + save_state(dc); gen_st_asi(cpu_val, cpu_addr, insn, 4); dc->npc = DYNAMIC_PC; break; @@ -5019,7 +5019,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (!supervisor(dc)) goto priv_insn; #endif - save_state(dc, cpu_cond); + save_state(dc); gen_st_asi(cpu_val, cpu_addr, insn, 1); dc->npc = DYNAMIC_PC; break; @@ -5030,7 +5030,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (!supervisor(dc)) goto priv_insn; #endif - save_state(dc, cpu_cond); + save_state(dc); gen_st_asi(cpu_val, cpu_addr, insn, 2); dc->npc = DYNAMIC_PC; break; @@ -5044,7 +5044,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (rd & 1) goto illegal_insn; else { - save_state(dc, cpu_cond); + save_state(dc); gen_stda_asi(cpu_val, cpu_addr, insn, rd); } break; @@ -5055,7 +5055,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) tcg_gen_qemu_st64(cpu_val, cpu_addr, dc->mem_idx); break; case 0x1e: /* V9 stxa */ - save_state(dc, cpu_cond); + save_state(dc); gen_st_asi(cpu_val, cpu_addr, insn, 8); dc->npc = DYNAMIC_PC; break; @@ -5067,7 +5067,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (gen_trap_ifnofpu(dc)) { goto jmp_insn; } - save_state(dc, cpu_cond); + save_state(dc); switch (xop) { case 0x24: /* stf, store fpreg */ gen_address_mask(dc, cpu_addr); @@ -5124,7 +5124,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) goto illegal_insn; } } else if (xop > 0x33 && xop < 0x3f) { - save_state(dc, cpu_cond); + save_state(dc); switch (xop) { #ifdef TARGET_SPARC64 case 0x34: /* V9 stfa */ @@ -5194,7 +5194,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) { TCGv_i32 r_const; - save_state(dc, cpu_cond); + save_state(dc); r_const = tcg_const_i32(TT_ILL_INSN); gen_helper_raise_exception(cpu_env, r_const); tcg_temp_free_i32(r_const); @@ -5205,7 +5205,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) { TCGv_i32 r_const; - save_state(dc, cpu_cond); + save_state(dc); r_const = tcg_const_i32(TT_UNIMP_FLUSH); gen_helper_raise_exception(cpu_env, r_const); tcg_temp_free_i32(r_const); @@ -5217,7 +5217,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) { TCGv_i32 r_const; - save_state(dc, cpu_cond); + save_state(dc); r_const = tcg_const_i32(TT_PRIV_INSN); gen_helper_raise_exception(cpu_env, r_const); tcg_temp_free_i32(r_const); @@ -5226,13 +5226,13 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) goto egress; #endif nfpu_insn: - save_state(dc, cpu_cond); + save_state(dc); gen_op_fpexception_im(FSR_FTT_UNIMPFPOP); dc->is_br = 1; goto egress; #if !defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64) nfq_insn: - save_state(dc, cpu_cond); + save_state(dc); gen_op_fpexception_im(FSR_FTT_SEQ_ERROR); dc->is_br = 1; goto egress; @@ -5242,7 +5242,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) { TCGv r_const; - save_state(dc, cpu_cond); + save_state(dc); r_const = tcg_const_i32(TT_NCP_INSN); gen_helper_raise_exception(cpu_env, r_const); tcg_temp_free(r_const); @@ -5308,7 +5308,7 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, QTAILQ_FOREACH(bp, &env->breakpoints, entry) { if (bp->pc == dc->pc) { if (dc->pc != pc_start) - save_state(dc, cpu_cond); + save_state(dc); gen_helper_debug(cpu_env); tcg_gen_exit_tb(0); dc->is_br = 1; -- cgit v1.2.3 From 13a6dd00433005831c2bc671b0e085cb5b04b424 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 5 Oct 2012 16:54:54 -0700 Subject: target-sparc: Tidy gen_mov_pc_npc interface Use the cpu_cond global register directly instead of passing it down. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index eb952608d..d9e1b0155 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1147,10 +1147,10 @@ static inline void save_state(DisasContext *dc) save_npc(dc, cpu_cond); } -static inline void gen_mov_pc_npc(DisasContext *dc, TCGv cond) +static inline void gen_mov_pc_npc(DisasContext *dc) { if (dc->npc == JUMP_PC) { - gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1], cond); + gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1], cpu_cond); tcg_gen_mov_tl(cpu_pc, cpu_npc); dc->pc = DYNAMIC_PC; } else if (dc->npc == DYNAMIC_PC) { @@ -2499,7 +2499,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) gen_movl_TN_reg(15, r_const); tcg_temp_free(r_const); target += dc->pc; - gen_mov_pc_npc(dc, cpu_cond); + gen_mov_pc_npc(dc); #ifdef TARGET_SPARC64 if (unlikely(AM_CHECK(dc))) { target &= 0xffffffffULL; @@ -4573,7 +4573,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) tcg_gen_mov_tl(cpu_dst, cpu_src1); } gen_helper_restore(cpu_env); - gen_mov_pc_npc(dc, cpu_cond); + gen_mov_pc_npc(dc); r_const = tcg_const_i32(3); gen_helper_check_align(cpu_env, cpu_dst, r_const); tcg_temp_free_i32(r_const); @@ -4603,7 +4603,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) r_pc = tcg_const_tl(dc->pc); gen_movl_TN_reg(rd, r_pc); tcg_temp_free(r_pc); - gen_mov_pc_npc(dc, cpu_cond); + gen_mov_pc_npc(dc); r_const = tcg_const_i32(3); gen_helper_check_align(cpu_env, cpu_dst, r_const); tcg_temp_free_i32(r_const); @@ -4619,7 +4619,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (!supervisor(dc)) goto priv_insn; - gen_mov_pc_npc(dc, cpu_cond); + gen_mov_pc_npc(dc); r_const = tcg_const_i32(3); gen_helper_check_align(cpu_env, cpu_dst, r_const); tcg_temp_free_i32(r_const); -- cgit v1.2.3 From 934da7ee0840f582c7720d0ce4507456d9955feb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 5 Oct 2012 16:54:55 -0700 Subject: target-sparc: Tidy save_npc interface Use the cpu_cond global register directly instead of passing it down. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index d9e1b0155..4cc78872d 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1126,10 +1126,10 @@ static inline void flush_cond(DisasContext *dc) } } -static inline void save_npc(DisasContext *dc, TCGv cond) +static inline void save_npc(DisasContext *dc) { if (dc->npc == JUMP_PC) { - gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1], cond); + gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1], cpu_cond); dc->npc = DYNAMIC_PC; } else if (dc->npc != DYNAMIC_PC) { tcg_gen_movi_tl(cpu_npc, dc->npc); @@ -1144,7 +1144,7 @@ static inline void save_state(DisasContext *dc) dc->cc_op = CC_OP_FLAGS; gen_helper_compute_psr(cpu_env); } - save_npc(dc, cpu_cond); + save_npc(dc); } static inline void gen_mov_pc_npc(DisasContext *dc) @@ -5372,7 +5372,7 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, } else { if (dc->pc != DYNAMIC_PC) tcg_gen_movi_tl(cpu_pc, dc->pc); - save_npc(dc, cpu_cond); + save_npc(dc); tcg_gen_exit_tb(0); } } -- cgit v1.2.3 From 2e655fe768d9873d07be3be264c042c35720694b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 5 Oct 2012 16:54:56 -0700 Subject: target-sparc: Tidy gen_generic_branch interface The arguments passed are always the same. Pass down just DisasContext instead. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 4cc78872d..d759da21c 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1098,21 +1098,20 @@ static inline void gen_branch_a(DisasContext *dc, target_ulong pc1, gen_goto_tb(dc, 1, pc2 + 4, pc2 + 8); } -static inline void gen_generic_branch(target_ulong npc1, target_ulong npc2, - TCGv r_cond) +static inline void gen_generic_branch(DisasContext *dc) { int l1, l2; l1 = gen_new_label(); l2 = gen_new_label(); - tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, 0, l1); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_cond, 0, l1); - tcg_gen_movi_tl(cpu_npc, npc1); + tcg_gen_movi_tl(cpu_npc, dc->jump_pc[0]); tcg_gen_br(l2); gen_set_label(l1); - tcg_gen_movi_tl(cpu_npc, npc2); + tcg_gen_movi_tl(cpu_npc, dc->jump_pc[1]); gen_set_label(l2); } @@ -1121,7 +1120,7 @@ static inline void gen_generic_branch(target_ulong npc1, target_ulong npc2, static inline void flush_cond(DisasContext *dc) { if (dc->npc == JUMP_PC) { - gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1], cpu_cond); + gen_generic_branch(dc); dc->npc = DYNAMIC_PC; } } @@ -1129,7 +1128,7 @@ static inline void flush_cond(DisasContext *dc) static inline void save_npc(DisasContext *dc) { if (dc->npc == JUMP_PC) { - gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1], cpu_cond); + gen_generic_branch(dc); dc->npc = DYNAMIC_PC; } else if (dc->npc != DYNAMIC_PC) { tcg_gen_movi_tl(cpu_npc, dc->npc); @@ -1150,7 +1149,7 @@ static inline void save_state(DisasContext *dc) static inline void gen_mov_pc_npc(DisasContext *dc) { if (dc->npc == JUMP_PC) { - gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1], cpu_cond); + gen_generic_branch(dc); tcg_gen_mov_tl(cpu_pc, cpu_npc); dc->pc = DYNAMIC_PC; } else if (dc->npc == DYNAMIC_PC) { -- cgit v1.2.3 From 416fcaea1ef7e9a71ccb0a968de594618ed7675e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 5 Oct 2012 16:54:57 -0700 Subject: target-sparc: Introduce DisasCompare and functions to generate it For the moment gen_cond et al retain their existing interface, using setcond to turn a (potential) comparison back into a boolean. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 92 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 83 insertions(+), 9 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index d759da21c..d61a9a031 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -86,6 +86,13 @@ typedef struct DisasContext { int n_t32; } DisasContext; +typedef struct { + TCGCond cond; + bool is_bool; + bool g1, g2; + TCGv c1, c2; +} DisasCompare; + // This function uses non-native bit order #define GET_FIELD(X, FROM, TO) \ ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1)) @@ -1166,10 +1173,28 @@ static inline void gen_op_next_insn(void) tcg_gen_addi_tl(cpu_npc, cpu_npc, 4); } -static inline void gen_cond(TCGv r_dst, unsigned int cc, unsigned int cond, - DisasContext *dc) +static void free_compare(DisasCompare *cmp) +{ + if (!cmp->g1) { + tcg_temp_free(cmp->c1); + } + if (!cmp->g2) { + tcg_temp_free(cmp->c2); + } +} + +static void gen_compare(DisasCompare *cmp, unsigned int cc, unsigned int cond, + DisasContext *dc) { TCGv_i32 r_src; + TCGv r_dst; + + /* For now we still generate a straight boolean result. */ + cmp->cond = TCG_COND_NE; + cmp->is_bool = true; + cmp->g1 = cmp->g2 = false; + cmp->c1 = r_dst = tcg_temp_new(); + cmp->c2 = tcg_const_tl(0); #ifdef TARGET_SPARC64 if (cc) @@ -1239,9 +1264,17 @@ static inline void gen_cond(TCGv r_dst, unsigned int cc, unsigned int cond, } } -static inline void gen_fcond(TCGv r_dst, unsigned int cc, unsigned int cond) +static void gen_fcompare(DisasCompare *cmp, unsigned int cc, unsigned int cond) { unsigned int offset; + TCGv r_dst; + + /* For now we still generate a straight boolean result. */ + cmp->cond = TCG_COND_NE; + cmp->is_bool = true; + cmp->g1 = cmp->g2 = false; + cmp->c1 = r_dst = tcg_temp_new(); + cmp->c2 = tcg_const_tl(0); switch (cc) { default: @@ -1311,6 +1344,37 @@ static inline void gen_fcond(TCGv r_dst, unsigned int cc, unsigned int cond) } } +static void gen_cond(TCGv r_dst, unsigned int cc, unsigned int cond, + DisasContext *dc) +{ + DisasCompare cmp; + gen_compare(&cmp, cc, cond, dc); + + /* The interface is to return a boolean in r_dst. */ + if (cmp.is_bool) { + tcg_gen_mov_tl(r_dst, cmp.c1); + } else { + tcg_gen_setcond_tl(cmp.cond, r_dst, cmp.c1, cmp.c2); + } + + free_compare(&cmp); +} + +static void gen_fcond(TCGv r_dst, unsigned int cc, unsigned int cond) +{ + DisasCompare cmp; + gen_fcompare(&cmp, cc, cond); + + /* The interface is to return a boolean in r_dst. */ + if (cmp.is_bool) { + tcg_gen_mov_tl(r_dst, cmp.c1); + } else { + tcg_gen_setcond_tl(cmp.cond, r_dst, cmp.c1, cmp.c2); + } + + free_compare(&cmp); +} + #ifdef TARGET_SPARC64 // Inverted logic static const int gen_tcg_cond_reg[8] = { @@ -1324,15 +1388,25 @@ static const int gen_tcg_cond_reg[8] = { TCG_COND_LT, }; +static void gen_compare_reg(DisasCompare *cmp, int cond, TCGv r_src) +{ + cmp->cond = tcg_invert_cond(gen_tcg_cond_reg[cond]); + cmp->is_bool = false; + cmp->g1 = true; + cmp->g2 = false; + cmp->c1 = r_src; + cmp->c2 = tcg_const_tl(0); +} + static inline void gen_cond_reg(TCGv r_dst, int cond, TCGv r_src) { - int l1; + DisasCompare cmp; + gen_compare_reg(&cmp, cond, r_src); - l1 = gen_new_label(); - tcg_gen_movi_tl(r_dst, 0); - tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], r_src, 0, l1); - tcg_gen_movi_tl(r_dst, 1); - gen_set_label(l1); + /* The interface is to return a boolean in r_dst. */ + tcg_gen_setcond_tl(cmp.cond, r_dst, cmp.c1, cmp.c2); + + free_compare(&cmp); } #endif -- cgit v1.2.3 From 3a49e7598b78bca019e35c42590914faab2a817a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 5 Oct 2012 16:54:58 -0700 Subject: target-sparc: Use DisasCompare in Tcc Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index d61a9a031..fa9a05799 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2613,25 +2613,28 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) gen_helper_raise_exception(cpu_env, cpu_tmp32); } else if (cond != 0) { - TCGv r_cond = tcg_temp_new(); + DisasCompare cmp; int l1; #ifdef TARGET_SPARC64 /* V9 icc/xcc */ int cc = GET_FIELD_SP(insn, 11, 12); save_state(dc); - if (cc == 0) - gen_cond(r_cond, 0, cond, dc); - else if (cc == 2) - gen_cond(r_cond, 1, cond, dc); - else + if (cc == 0) { + gen_compare(&cmp, 0, cond, dc); + } else if (cc == 2) { + gen_compare(&cmp, 1, cond, dc); + } else { goto illegal_insn; + } #else save_state(dc); - gen_cond(r_cond, 0, cond, dc); + gen_compare(&cmp, 0, cond, dc); #endif l1 = gen_new_label(); - tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, 0, l1); + tcg_gen_brcond_tl(tcg_invert_cond(cmp.cond), + cmp.c1, cmp.c2, l1); + free_compare(&cmp); if ((dc->def->features & CPU_FEATURE_HYPV) && supervisor(dc)) @@ -2643,7 +2646,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) gen_helper_raise_exception(cpu_env, cpu_tmp32); gen_set_label(l1); - tcg_temp_free(r_cond); } gen_op_next_insn(); tcg_gen_exit_tb(0); -- cgit v1.2.3 From 7e480893cc3eb9f307199517f0e1d5c8e72a030f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 5 Oct 2012 16:54:59 -0700 Subject: target-sparc: Use DisasCompare and movcond in FMOVR, FMOVCC Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 203 ++++++++++++++++++++--------------------------- 1 file changed, 86 insertions(+), 117 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index fa9a05799..a7cd67767 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2281,6 +2281,57 @@ static inline TCGv get_src2(unsigned int insn, TCGv def) } #ifdef TARGET_SPARC64 +static void gen_fmovs(DisasContext *dc, DisasCompare *cmp, int rd, int rs) +{ + TCGv_i32 c32, zero, dst, s1, s2; + + /* We have two choices here: extend the 32 bit data and use movcond_i64, + or fold the comparison down to 32 bits and use movcond_i32. Choose + the later. */ + c32 = tcg_temp_new_i32(); + if (cmp->is_bool) { + tcg_gen_trunc_i64_i32(c32, cmp->c1); + } else { + TCGv_i64 c64 = tcg_temp_new_i64(); + tcg_gen_setcond_i64(cmp->cond, c64, cmp->c1, cmp->c2); + tcg_gen_trunc_i64_i32(c32, c64); + tcg_temp_free_i64(c64); + } + + s1 = gen_load_fpr_F(dc, rs); + s2 = gen_load_fpr_F(dc, rd); + dst = gen_dest_fpr_F(); + zero = tcg_const_i32(0); + + tcg_gen_movcond_i32(TCG_COND_NE, dst, c32, zero, s1, s2); + + tcg_temp_free_i32(c32); + tcg_temp_free_i32(zero); + gen_store_fpr_F(dc, rd, dst); +} + +static void gen_fmovd(DisasContext *dc, DisasCompare *cmp, int rd, int rs) +{ + TCGv_i64 dst = gen_dest_fpr_D(); + tcg_gen_movcond_i64(cmp->cond, dst, cmp->c1, cmp->c2, + gen_load_fpr_D(dc, rs), + gen_load_fpr_D(dc, rd)); + gen_store_fpr_D(dc, rd, dst); +} + +static void gen_fmovq(DisasContext *dc, DisasCompare *cmp, int rd, int rs) +{ + int qd = QFPREG(rd); + int qs = QFPREG(rs); + + tcg_gen_movcond_i64(cmp->cond, cpu_fpr[qd / 2], cmp->c1, cmp->c2, + cpu_fpr[qs / 2], cpu_fpr[qd / 2]); + tcg_gen_movcond_i64(cmp->cond, cpu_fpr[qd / 2 + 1], cmp->c1, cmp->c2, + cpu_fpr[qs / 2 + 1], cpu_fpr[qd / 2 + 1]); + + gen_update_fprs_dirty(qd); +} + static inline void gen_load_trap_state_at_tl(TCGv_ptr r_tsptr, TCGv_ptr cpu_env) { TCGv_i32 r_tl = tcg_temp_new_i32(); @@ -3163,168 +3214,86 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) #endif switch (xop) { #ifdef TARGET_SPARC64 -#define FMOVSCC(fcc) \ - { \ - TCGv r_cond; \ - int l1; \ - \ - l1 = gen_new_label(); \ - r_cond = tcg_temp_new(); \ - cond = GET_FIELD_SP(insn, 14, 17); \ - gen_fcond(r_cond, fcc, cond); \ - tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, \ - 0, l1); \ - cpu_src1_32 = gen_load_fpr_F(dc, rs2); \ - gen_store_fpr_F(dc, rd, cpu_src1_32); \ - gen_set_label(l1); \ - tcg_temp_free(r_cond); \ - } -#define FMOVDCC(fcc) \ - { \ - TCGv r_cond; \ - int l1; \ - \ - l1 = gen_new_label(); \ - r_cond = tcg_temp_new(); \ - cond = GET_FIELD_SP(insn, 14, 17); \ - gen_fcond(r_cond, fcc, cond); \ - tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, \ - 0, l1); \ - cpu_src1_64 = gen_load_fpr_D(dc, rs2); \ - gen_store_fpr_D(dc, rd, cpu_src1_64); \ - gen_set_label(l1); \ - tcg_temp_free(r_cond); \ - } -#define FMOVQCC(fcc) \ - { \ - TCGv r_cond; \ - int l1; \ - \ - l1 = gen_new_label(); \ - r_cond = tcg_temp_new(); \ +#define FMOVCC(fcc, sz) \ + do { \ + DisasCompare cmp; \ cond = GET_FIELD_SP(insn, 14, 17); \ - gen_fcond(r_cond, fcc, cond); \ - tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, \ - 0, l1); \ - gen_move_Q(rd, rs2); \ - gen_set_label(l1); \ - tcg_temp_free(r_cond); \ - } + gen_fcompare(&cmp, fcc, cond); \ + gen_fmov##sz(dc, &cmp, rd, rs2); \ + free_compare(&cmp); \ + } while (0) + case 0x001: /* V9 fmovscc %fcc0 */ - FMOVSCC(0); + FMOVCC(0, s); break; case 0x002: /* V9 fmovdcc %fcc0 */ - FMOVDCC(0); + FMOVCC(0, d); break; case 0x003: /* V9 fmovqcc %fcc0 */ CHECK_FPU_FEATURE(dc, FLOAT128); - FMOVQCC(0); + FMOVCC(0, q); break; case 0x041: /* V9 fmovscc %fcc1 */ - FMOVSCC(1); + FMOVCC(1, s); break; case 0x042: /* V9 fmovdcc %fcc1 */ - FMOVDCC(1); + FMOVCC(1, d); break; case 0x043: /* V9 fmovqcc %fcc1 */ CHECK_FPU_FEATURE(dc, FLOAT128); - FMOVQCC(1); + FMOVCC(1, q); break; case 0x081: /* V9 fmovscc %fcc2 */ - FMOVSCC(2); + FMOVCC(2, s); break; case 0x082: /* V9 fmovdcc %fcc2 */ - FMOVDCC(2); + FMOVCC(2, d); break; case 0x083: /* V9 fmovqcc %fcc2 */ CHECK_FPU_FEATURE(dc, FLOAT128); - FMOVQCC(2); + FMOVCC(2, q); break; case 0x0c1: /* V9 fmovscc %fcc3 */ - FMOVSCC(3); + FMOVCC(3, s); break; case 0x0c2: /* V9 fmovdcc %fcc3 */ - FMOVDCC(3); + FMOVCC(3, d); break; case 0x0c3: /* V9 fmovqcc %fcc3 */ CHECK_FPU_FEATURE(dc, FLOAT128); - FMOVQCC(3); + FMOVCC(3, q); break; -#undef FMOVSCC -#undef FMOVDCC -#undef FMOVQCC -#define FMOVSCC(icc) \ - { \ - TCGv r_cond; \ - int l1; \ - \ - l1 = gen_new_label(); \ - r_cond = tcg_temp_new(); \ - cond = GET_FIELD_SP(insn, 14, 17); \ - gen_cond(r_cond, icc, cond, dc); \ - tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, \ - 0, l1); \ - cpu_src1_32 = gen_load_fpr_F(dc, rs2); \ - gen_store_fpr_F(dc, rd, cpu_src1_32); \ - gen_set_label(l1); \ - tcg_temp_free(r_cond); \ - } -#define FMOVDCC(icc) \ - { \ - TCGv r_cond; \ - int l1; \ - \ - l1 = gen_new_label(); \ - r_cond = tcg_temp_new(); \ +#undef FMOVCC +#define FMOVCC(xcc, sz) \ + do { \ + DisasCompare cmp; \ cond = GET_FIELD_SP(insn, 14, 17); \ - gen_cond(r_cond, icc, cond, dc); \ - tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, \ - 0, l1); \ - cpu_src1_64 = gen_load_fpr_D(dc, rs2); \ - gen_store_fpr_D(dc, rd, cpu_src1_64); \ - gen_update_fprs_dirty(DFPREG(rd)); \ - gen_set_label(l1); \ - tcg_temp_free(r_cond); \ - } -#define FMOVQCC(icc) \ - { \ - TCGv r_cond; \ - int l1; \ - \ - l1 = gen_new_label(); \ - r_cond = tcg_temp_new(); \ - cond = GET_FIELD_SP(insn, 14, 17); \ - gen_cond(r_cond, icc, cond, dc); \ - tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, \ - 0, l1); \ - gen_move_Q(rd, rs2); \ - gen_set_label(l1); \ - tcg_temp_free(r_cond); \ - } + gen_compare(&cmp, xcc, cond, dc); \ + gen_fmov##sz(dc, &cmp, rd, rs2); \ + free_compare(&cmp); \ + } while (0) case 0x101: /* V9 fmovscc %icc */ - FMOVSCC(0); + FMOVCC(0, s); break; case 0x102: /* V9 fmovdcc %icc */ - FMOVDCC(0); + FMOVCC(0, d); break; case 0x103: /* V9 fmovqcc %icc */ CHECK_FPU_FEATURE(dc, FLOAT128); - FMOVQCC(0); + FMOVCC(0, q); break; case 0x181: /* V9 fmovscc %xcc */ - FMOVSCC(1); + FMOVCC(1, s); break; case 0x182: /* V9 fmovdcc %xcc */ - FMOVDCC(1); + FMOVCC(1, d); break; case 0x183: /* V9 fmovqcc %xcc */ CHECK_FPU_FEATURE(dc, FLOAT128); - FMOVQCC(1); + FMOVCC(1, q); break; -#undef FMOVSCC -#undef FMOVDCC -#undef FMOVQCC +#undef FMOVCC #endif case 0x51: /* fcmps, V9 %fcc */ cpu_src1_32 = gen_load_fpr_F(dc, rs1); -- cgit v1.2.3 From f52879b4410aa511e7c2baccc6a2fe37096b471e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 5 Oct 2012 16:55:00 -0700 Subject: target-sparc: Use DisasCompare and movcond in MOVCC Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index a7cd67767..6c9be294e 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -4075,38 +4075,34 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) { int cc = GET_FIELD_SP(insn, 11, 12); int cond = GET_FIELD_SP(insn, 14, 17); - TCGv r_cond; - int l1; + DisasCompare cmp; - r_cond = tcg_temp_new(); if (insn & (1 << 18)) { - if (cc == 0) - gen_cond(r_cond, 0, cond, dc); - else if (cc == 2) - gen_cond(r_cond, 1, cond, dc); - else + if (cc == 0) { + gen_compare(&cmp, 0, cond, dc); + } else if (cc == 2) { + gen_compare(&cmp, 1, cond, dc); + } else { goto illegal_insn; + } } else { - gen_fcond(r_cond, cc, cond); + gen_fcompare(&cmp, cc, cond); } - l1 = gen_new_label(); - - tcg_gen_brcondi_tl(TCG_COND_EQ, r_cond, 0, l1); - if (IS_IMM) { /* immediate */ - TCGv r_const; - + /* The get_src2 above loaded the normal 13-bit + immediate field, not the 11-bit field we have + in movcc. But it did handle the reg case. */ + if (IS_IMM) { simm = GET_FIELD_SPs(insn, 0, 10); - r_const = tcg_const_tl(simm); - gen_movl_TN_reg(rd, r_const); - tcg_temp_free(r_const); - } else { - rs2 = GET_FIELD_SP(insn, 0, 4); - gen_movl_reg_TN(rs2, cpu_tmp0); - gen_movl_TN_reg(rd, cpu_tmp0); + tcg_gen_movi_tl(cpu_src2, simm); } - gen_set_label(l1); - tcg_temp_free(r_cond); + + gen_movl_reg_TN(rd, cpu_dst); + tcg_gen_movcond_tl(cmp.cond, cpu_dst, + cmp.c1, cmp.c2, + cpu_src2, cpu_dst); + free_compare(&cmp); + gen_movl_TN_reg(rd, cpu_dst); break; } case 0x2d: /* V9 sdivx */ -- cgit v1.2.3 From c33f80f52a4621e6ed2d021adb08c7de8bec09d8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 5 Oct 2012 16:55:01 -0700 Subject: target-sparc: Use DisasCompare and movcond in MOVR Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 6c9be294e..9aef8e58f 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -4118,27 +4118,24 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) case 0x2f: /* V9 movr */ { int cond = GET_FIELD_SP(insn, 10, 12); - int l1; - - cpu_src1 = get_src1(insn, cpu_src1); - - l1 = gen_new_label(); + DisasCompare cmp; - tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], - cpu_src1, 0, l1); - if (IS_IMM) { /* immediate */ - TCGv r_const; + gen_compare_reg(&cmp, cond, cpu_src1); + /* The get_src2 above loaded the normal 13-bit + immediate field, not the 10-bit field we have + in movr. But it did handle the reg case. */ + if (IS_IMM) { simm = GET_FIELD_SPs(insn, 0, 9); - r_const = tcg_const_tl(simm); - gen_movl_TN_reg(rd, r_const); - tcg_temp_free(r_const); - } else { - rs2 = GET_FIELD_SP(insn, 0, 4); - gen_movl_reg_TN(rs2, cpu_tmp0); - gen_movl_TN_reg(rd, cpu_tmp0); + tcg_gen_movi_tl(cpu_src2, simm); } - gen_set_label(l1); + + gen_movl_reg_TN(rd, cpu_dst); + tcg_gen_movcond_tl(cmp.cond, cpu_dst, + cmp.c1, cmp.c2, + cpu_src2, cpu_dst); + free_compare(&cmp); + gen_movl_TN_reg(rd, cpu_dst); break; } #endif -- cgit v1.2.3 From 61316742e2bc7b5b5257198f2248c42a9d238c84 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 5 Oct 2012 16:55:02 -0700 Subject: target-sparc: Use movcond in gen_generic_branch Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 9aef8e58f..c1a1dc480 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1107,19 +1107,15 @@ static inline void gen_branch_a(DisasContext *dc, target_ulong pc1, static inline void gen_generic_branch(DisasContext *dc) { - int l1, l2; - - l1 = gen_new_label(); - l2 = gen_new_label(); + TCGv npc0 = tcg_const_tl(dc->jump_pc[0]); + TCGv npc1 = tcg_const_tl(dc->jump_pc[1]); + TCGv zero = tcg_const_tl(0); - tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_cond, 0, l1); + tcg_gen_movcond_tl(TCG_COND_NE, cpu_npc, cpu_cond, zero, npc0, npc1); - tcg_gen_movi_tl(cpu_npc, dc->jump_pc[0]); - tcg_gen_br(l2); - - gen_set_label(l1); - tcg_gen_movi_tl(cpu_npc, dc->jump_pc[1]); - gen_set_label(l2); + tcg_temp_free(npc0); + tcg_temp_free(npc1); + tcg_temp_free(zero); } /* call this function before using the condition register as it may -- cgit v1.2.3 From c28ae41ecd3bec70f1db8545e0800b9023891057 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 5 Oct 2012 16:55:03 -0700 Subject: target-sparc: Move sdivx and udivx out of line The branches around the exception are maintaining an otherwise unnecessary use of local temps for the cpu destination. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/cpu.h | 1 + target-sparc/helper.c | 28 +++++++++++++++++++++++++ target-sparc/helper.h | 4 ++++ target-sparc/ldst_helper.c | 4 ++-- target-sparc/translate.c | 52 ++-------------------------------------------- 5 files changed, 37 insertions(+), 52 deletions(-) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index e16b7b351..214d01dd7 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -714,6 +714,7 @@ trap_state* cpu_tsptr(CPUSPARCState* env); void QEMU_NORETURN do_unaligned_access(CPUSPARCState *env, target_ulong addr, int is_write, int is_user, uintptr_t retaddr); +void cpu_restore_state2(CPUSPARCState *env, uintptr_t retaddr); #define TB_FLAG_FPU_ENABLED (1 << 4) #define TB_FLAG_AM_ENABLED (1 << 5) diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 65e1740e1..4555d2bfc 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -75,6 +75,7 @@ static target_ulong helper_udiv_common(CPUSPARCState *env, target_ulong a, x1 = (b & 0xffffffff); if (x1 == 0) { + cpu_restore_state2(env, GETPC()); helper_raise_exception(env, TT_DIV_ZERO); } @@ -113,6 +114,7 @@ static target_ulong helper_sdiv_common(CPUSPARCState *env, target_ulong a, x1 = (b & 0xffffffff); if (x1 == 0) { + cpu_restore_state2(env, GETPC()); helper_raise_exception(env, TT_DIV_ZERO); } @@ -139,3 +141,29 @@ target_ulong helper_sdiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b) { return helper_sdiv_common(env, a, b, 1); } + +#ifdef TARGET_SPARC64 +int64_t helper_sdivx(CPUSPARCState *env, int64_t a, int64_t b) +{ + if (b == 0) { + /* Raise divide by zero trap. */ + cpu_restore_state2(env, GETPC()); + helper_raise_exception(env, TT_DIV_ZERO); + } else if (b == -1) { + /* Avoid overflow trap with i386 divide insn. */ + return -a; + } else { + return a / b; + } +} + +uint64_t helper_udivx(CPUSPARCState *env, uint64_t a, uint64_t b) +{ + if (b == 0) { + /* Raise divide by zero trap. */ + cpu_restore_state2(env, GETPC()); + helper_raise_exception(env, TT_DIV_ZERO); + } + return a / b; +} +#endif diff --git a/target-sparc/helper.h b/target-sparc/helper.h index e3c7fddbe..827df67cc 100644 --- a/target-sparc/helper.h +++ b/target-sparc/helper.h @@ -38,6 +38,10 @@ DEF_HELPER_3(udiv, tl, env, tl, tl) DEF_HELPER_3(udiv_cc, tl, env, tl, tl) DEF_HELPER_3(sdiv, tl, env, tl, tl) DEF_HELPER_3(sdiv_cc, tl, env, tl, tl) +#ifdef TARGET_SPARC64 +DEF_HELPER_3(sdivx, s64, env, s64, s64) +DEF_HELPER_3(udivx, i64, env, i64, i64) +#endif DEF_HELPER_3(ldqf, void, env, tl, int) DEF_HELPER_3(stqf, void, env, tl, int) #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c index 9bec7a92f..2ca9a5c4a 100644 --- a/target-sparc/ldst_helper.c +++ b/target-sparc/ldst_helper.c @@ -2390,9 +2390,8 @@ void cpu_unassigned_access(CPUSPARCState *env, target_phys_addr_t addr, #endif #endif -#if !defined(CONFIG_USER_ONLY) /* XXX: make it generic ? */ -static void cpu_restore_state2(CPUSPARCState *env, uintptr_t retaddr) +void cpu_restore_state2(CPUSPARCState *env, uintptr_t retaddr) { TranslationBlock *tb; @@ -2407,6 +2406,7 @@ static void cpu_restore_state2(CPUSPARCState *env, uintptr_t retaddr) } } +#if !defined(CONFIG_USER_ONLY) void do_unaligned_access(CPUSPARCState *env, target_ulong addr, int is_write, int is_user, uintptr_t retaddr) { diff --git a/target-sparc/translate.c b/target-sparc/translate.c index c1a1dc480..1628cf355 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -768,44 +768,6 @@ static inline void gen_op_smul(TCGv dst, TCGv src1, TCGv src2) gen_op_multiply(dst, src1, src2, 1); } -#ifdef TARGET_SPARC64 -static inline void gen_trap_ifdivzero_tl(TCGv divisor) -{ - TCGv_i32 r_const; - int l1; - - l1 = gen_new_label(); - tcg_gen_brcondi_tl(TCG_COND_NE, divisor, 0, l1); - r_const = tcg_const_i32(TT_DIV_ZERO); - gen_helper_raise_exception(cpu_env, r_const); - tcg_temp_free_i32(r_const); - gen_set_label(l1); -} - -static inline void gen_op_sdivx(TCGv dst, TCGv src1, TCGv src2) -{ - int l1, l2; - TCGv r_temp1, r_temp2; - - l1 = gen_new_label(); - l2 = gen_new_label(); - r_temp1 = tcg_temp_local_new(); - r_temp2 = tcg_temp_local_new(); - tcg_gen_mov_tl(r_temp1, src1); - tcg_gen_mov_tl(r_temp2, src2); - gen_trap_ifdivzero_tl(r_temp2); - tcg_gen_brcondi_tl(TCG_COND_NE, r_temp1, INT64_MIN, l1); - tcg_gen_brcondi_tl(TCG_COND_NE, r_temp2, -1, l1); - tcg_gen_movi_i64(dst, INT64_MIN); - tcg_gen_br(l2); - gen_set_label(l1); - tcg_gen_div_i64(dst, r_temp1, r_temp2); - gen_set_label(l2); - tcg_temp_free(r_temp1); - tcg_temp_free(r_temp2); -} -#endif - // 1 static inline void gen_op_eval_ba(TCGv dst) { @@ -3591,17 +3553,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) break; #ifdef TARGET_SPARC64 case 0xd: /* V9 udivx */ - { - TCGv r_temp1, r_temp2; - r_temp1 = tcg_temp_local_new(); - r_temp2 = tcg_temp_local_new(); - tcg_gen_mov_tl(r_temp1, cpu_src1); - tcg_gen_mov_tl(r_temp2, cpu_src2); - gen_trap_ifdivzero_tl(r_temp2); - tcg_gen_divu_i64(cpu_dst, r_temp1, r_temp2); - tcg_temp_free(r_temp1); - tcg_temp_free(r_temp2); - } + gen_helper_udivx(cpu_dst, cpu_env, cpu_src1, cpu_src2); break; #endif case 0xe: /* udiv */ @@ -4102,7 +4054,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) break; } case 0x2d: /* V9 sdivx */ - gen_op_sdivx(cpu_dst, cpu_src1, cpu_src2); + gen_helper_sdivx(cpu_dst, cpu_env, cpu_src1, cpu_src2); gen_movl_TN_reg(rd, cpu_dst); break; case 0x2e: /* V9 popc */ -- cgit v1.2.3 From bd49ed41ebe518c79bd52e46ce5b9cf278f8a2af Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 5 Oct 2012 16:55:04 -0700 Subject: target-sparc: Tidy Tcc Share more code between unconditional and conditional paths. Move the computation of the trap number into the conditional BB; avoid using temporaries that have gone out of scope (cpu_tmp32) or rely on local temps (cpu_dst). Fully fold the exception number when the trap number is %g0+imm. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 91 ++++++++++++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 38 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 1628cf355..111c025dd 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2594,41 +2594,23 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) { unsigned int xop = GET_FIELD(insn, 7, 12); if (xop == 0x3a) { /* generate trap */ - int cond; + int cond = GET_FIELD(insn, 3, 6); + TCGv_i32 trap; + int l1 = -1, mask; - cpu_src1 = get_src1(insn, cpu_src1); - if (IS_IMM) { - rs2 = GET_FIELD(insn, 25, 31); - tcg_gen_addi_tl(cpu_dst, cpu_src1, rs2); - } else { - rs2 = GET_FIELD(insn, 27, 31); - if (rs2 != 0) { - gen_movl_reg_TN(rs2, cpu_src2); - tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_src2); - } else - tcg_gen_mov_tl(cpu_dst, cpu_src1); + if (cond == 0) { + /* Trap never. */ + break; } - cond = GET_FIELD(insn, 3, 6); - if (cond == 0x8) { /* Trap Always */ - save_state(dc); - if ((dc->def->features & CPU_FEATURE_HYPV) && - supervisor(dc)) - tcg_gen_andi_tl(cpu_dst, cpu_dst, UA2005_HTRAP_MASK); - else - tcg_gen_andi_tl(cpu_dst, cpu_dst, V8_TRAP_MASK); - tcg_gen_addi_tl(cpu_dst, cpu_dst, TT_TRAP); - tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_dst); - gen_helper_raise_exception(cpu_env, cpu_tmp32); + save_state(dc); - } else if (cond != 0) { + if (cond != 8) { + /* Conditional trap. */ DisasCompare cmp; - int l1; #ifdef TARGET_SPARC64 /* V9 icc/xcc */ int cc = GET_FIELD_SP(insn, 11, 12); - - save_state(dc); if (cc == 0) { gen_compare(&cmp, 0, cond, dc); } else if (cc == 2) { @@ -2637,27 +2619,60 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) goto illegal_insn; } #else - save_state(dc); gen_compare(&cmp, 0, cond, dc); #endif l1 = gen_new_label(); tcg_gen_brcond_tl(tcg_invert_cond(cmp.cond), cmp.c1, cmp.c2, l1); free_compare(&cmp); + } - if ((dc->def->features & CPU_FEATURE_HYPV) && - supervisor(dc)) - tcg_gen_andi_tl(cpu_dst, cpu_dst, UA2005_HTRAP_MASK); - else - tcg_gen_andi_tl(cpu_dst, cpu_dst, V8_TRAP_MASK); - tcg_gen_addi_tl(cpu_dst, cpu_dst, TT_TRAP); - tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_dst); - gen_helper_raise_exception(cpu_env, cpu_tmp32); + mask = ((dc->def->features & CPU_FEATURE_HYPV) && supervisor(dc) + ? UA2005_HTRAP_MASK : V8_TRAP_MASK); + + /* Don't use the normal temporaries, as they may well have + gone out of scope with the branch above. While we're + doing that we might as well pre-truncate to 32-bit. */ + trap = tcg_temp_new_i32(); + + rs1 = GET_FIELD_SP(insn, 14, 18); + if (IS_IMM) { + rs2 = GET_FIELD_SP(insn, 0, 6); + if (rs1 == 0) { + tcg_gen_movi_i32(trap, (rs2 & mask) + TT_TRAP); + /* Signal that the trap value is fully constant. */ + mask = 0; + } else { + TCGv t1 = tcg_temp_new(); + gen_movl_reg_TN(rs1, t1); + tcg_gen_trunc_tl_i32(trap, t1); + tcg_temp_free(t1); + tcg_gen_addi_i32(trap, trap, rs2); + } + } else { + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); + rs2 = GET_FIELD_SP(insn, 0, 4); + gen_movl_reg_TN(rs1, t1); + gen_movl_reg_TN(rs2, t2); + tcg_gen_add_tl(t1, t1, t2); + tcg_gen_trunc_tl_i32(trap, t1); + tcg_temp_free(t1); + tcg_temp_free(t2); + } + if (mask != 0) { + tcg_gen_andi_i32(trap, trap, mask); + tcg_gen_addi_i32(trap, trap, TT_TRAP); + } + + gen_helper_raise_exception(cpu_env, trap); + tcg_temp_free_i32(trap); + if (cond != 8) { gen_set_label(l1); + gen_op_next_insn(); + tcg_gen_exit_tb(0); } - gen_op_next_insn(); - tcg_gen_exit_tb(0); dc->is_br = 1; goto jmp_insn; } else if (xop == 0x28) { -- cgit v1.2.3 From a2ea4aa9898086c1e45e1db9b5f94d16dbf0762e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 5 Oct 2012 16:55:05 -0700 Subject: target-sparc: Move taddcctv and tsubcctv out of line The branches around the exception are maintaining an otherwise unnecessary use of local temps for the cpu destination. Note that gen_op_t{add,sub}_cc were identical to gen_op_{add,sub}_cc. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/helper.c | 58 +++++++++++++++++++++++++ target-sparc/helper.h | 2 + target-sparc/translate.c | 108 +++-------------------------------------------- 3 files changed, 66 insertions(+), 102 deletions(-) diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 4555d2bfc..556ac286e 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -167,3 +167,61 @@ uint64_t helper_udivx(CPUSPARCState *env, uint64_t a, uint64_t b) return a / b; } #endif + +target_ulong helper_taddcctv(CPUSPARCState *env, target_ulong src1, + target_ulong src2) +{ + target_ulong dst; + + /* Tag overflow occurs if either input has bits 0 or 1 set. */ + if ((src1 | src2) & 3) { + goto tag_overflow; + } + + dst = src1 + src2; + + /* Tag overflow occurs if the addition overflows. */ + if (~(src1 ^ src2) & (src1 ^ dst) & (1u << 31)) { + goto tag_overflow; + } + + /* Only modify the CC after any exceptions have been generated. */ + env->cc_op = CC_OP_TADDTV; + env->cc_src = src1; + env->cc_src2 = src2; + env->cc_dst = dst; + return dst; + + tag_overflow: + cpu_restore_state2(env, GETPC()); + helper_raise_exception(env, TT_TOVF); +} + +target_ulong helper_tsubcctv(CPUSPARCState *env, target_ulong src1, + target_ulong src2) +{ + target_ulong dst; + + /* Tag overflow occurs if either input has bits 0 or 1 set. */ + if ((src1 | src2) & 3) { + goto tag_overflow; + } + + dst = src1 - src2; + + /* Tag overflow occurs if the subtraction overflows. */ + if ((src1 ^ src2) & (src1 ^ dst) & (1u << 31)) { + goto tag_overflow; + } + + /* Only modify the CC after any exceptions have been generated. */ + env->cc_op = CC_OP_TSUBTV; + env->cc_src = src1; + env->cc_src2 = src2; + env->cc_dst = dst; + return dst; + + tag_overflow: + cpu_restore_state2(env, GETPC()); + helper_raise_exception(env, TT_TOVF); +} diff --git a/target-sparc/helper.h b/target-sparc/helper.h index 827df67cc..e1ae3c708 100644 --- a/target-sparc/helper.h +++ b/target-sparc/helper.h @@ -38,6 +38,8 @@ DEF_HELPER_3(udiv, tl, env, tl, tl) DEF_HELPER_3(udiv_cc, tl, env, tl, tl) DEF_HELPER_3(sdiv, tl, env, tl, tl) DEF_HELPER_3(sdiv_cc, tl, env, tl, tl) +DEF_HELPER_3(taddcctv, tl, env, tl, tl) +DEF_HELPER_3(tsubcctv, tl, env, tl, tl) #ifdef TARGET_SPARC64 DEF_HELPER_3(sdivx, s64, env, s64, s64) DEF_HELPER_3(udivx, i64, env, i64, i64) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 111c025dd..98efb8445 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -336,43 +336,6 @@ static inline void gen_mov_reg_C(TCGv reg, TCGv_i32 src) tcg_gen_andi_tl(reg, reg, 0x1); } -static inline void gen_add_tv(TCGv dst, TCGv src1, TCGv src2) -{ - TCGv r_temp; - TCGv_i32 r_const; - int l1; - - l1 = gen_new_label(); - - r_temp = tcg_temp_new(); - tcg_gen_xor_tl(r_temp, src1, src2); - tcg_gen_not_tl(r_temp, r_temp); - tcg_gen_xor_tl(cpu_tmp0, src1, dst); - tcg_gen_and_tl(r_temp, r_temp, cpu_tmp0); - tcg_gen_andi_tl(r_temp, r_temp, (1ULL << 31)); - tcg_gen_brcondi_tl(TCG_COND_EQ, r_temp, 0, l1); - r_const = tcg_const_i32(TT_TOVF); - gen_helper_raise_exception(cpu_env, r_const); - tcg_temp_free_i32(r_const); - gen_set_label(l1); - tcg_temp_free(r_temp); -} - -static inline void gen_tag_tv(TCGv src1, TCGv src2) -{ - int l1; - TCGv_i32 r_const; - - l1 = gen_new_label(); - tcg_gen_or_tl(cpu_tmp0, src1, src2); - tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0x3); - tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, l1); - r_const = tcg_const_i32(TT_TOVF); - gen_helper_raise_exception(cpu_env, r_const); - tcg_temp_free_i32(r_const); - gen_set_label(l1); -} - static inline void gen_op_addi_cc(TCGv dst, TCGv src1, target_long src2) { tcg_gen_mov_tl(cpu_cc_src, src1); @@ -517,45 +480,6 @@ static void gen_op_addx_int(DisasContext *dc, TCGv dst, TCGv src1, } } -static inline void gen_op_tadd_cc(TCGv dst, TCGv src1, TCGv src2) -{ - tcg_gen_mov_tl(cpu_cc_src, src1); - tcg_gen_mov_tl(cpu_cc_src2, src2); - tcg_gen_add_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); - tcg_gen_mov_tl(dst, cpu_cc_dst); -} - -static inline void gen_op_tadd_ccTV(TCGv dst, TCGv src1, TCGv src2) -{ - tcg_gen_mov_tl(cpu_cc_src, src1); - tcg_gen_mov_tl(cpu_cc_src2, src2); - gen_tag_tv(cpu_cc_src, cpu_cc_src2); - tcg_gen_add_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); - gen_add_tv(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); - tcg_gen_mov_tl(dst, cpu_cc_dst); -} - -static inline void gen_sub_tv(TCGv dst, TCGv src1, TCGv src2) -{ - TCGv r_temp; - TCGv_i32 r_const; - int l1; - - l1 = gen_new_label(); - - r_temp = tcg_temp_new(); - tcg_gen_xor_tl(r_temp, src1, src2); - tcg_gen_xor_tl(cpu_tmp0, src1, dst); - tcg_gen_and_tl(r_temp, r_temp, cpu_tmp0); - tcg_gen_andi_tl(r_temp, r_temp, (1ULL << 31)); - tcg_gen_brcondi_tl(TCG_COND_EQ, r_temp, 0, l1); - r_const = tcg_const_i32(TT_TOVF); - gen_helper_raise_exception(cpu_env, r_const); - tcg_temp_free_i32(r_const); - gen_set_label(l1); - tcg_temp_free(r_temp); -} - static inline void gen_op_subi_cc(TCGv dst, TCGv src1, target_long src2, DisasContext *dc) { tcg_gen_mov_tl(cpu_cc_src, src1); @@ -656,24 +580,6 @@ static void gen_op_subx_int(DisasContext *dc, TCGv dst, TCGv src1, } } -static inline void gen_op_tsub_cc(TCGv dst, TCGv src1, TCGv src2) -{ - tcg_gen_mov_tl(cpu_cc_src, src1); - tcg_gen_mov_tl(cpu_cc_src2, src2); - tcg_gen_sub_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); - tcg_gen_mov_tl(dst, cpu_cc_dst); -} - -static inline void gen_op_tsub_ccTV(TCGv dst, TCGv src1, TCGv src2) -{ - tcg_gen_mov_tl(cpu_cc_src, src1); - tcg_gen_mov_tl(cpu_cc_src2, src2); - gen_tag_tv(cpu_cc_src, cpu_cc_src2); - tcg_gen_sub_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); - gen_sub_tv(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); - tcg_gen_mov_tl(dst, cpu_cc_dst); -} - static inline void gen_op_mulscc(TCGv dst, TCGv src1, TCGv src2) { TCGv r_temp; @@ -3602,29 +3508,27 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) cpu_src2 = get_src2(insn, cpu_src2); switch (xop) { case 0x20: /* taddcc */ - gen_op_tadd_cc(cpu_dst, cpu_src1, cpu_src2); + gen_op_add_cc(cpu_dst, cpu_src1, cpu_src2); gen_movl_TN_reg(rd, cpu_dst); tcg_gen_movi_i32(cpu_cc_op, CC_OP_TADD); dc->cc_op = CC_OP_TADD; break; case 0x21: /* tsubcc */ - gen_op_tsub_cc(cpu_dst, cpu_src1, cpu_src2); + gen_op_sub_cc(cpu_dst, cpu_src1, cpu_src2); gen_movl_TN_reg(rd, cpu_dst); tcg_gen_movi_i32(cpu_cc_op, CC_OP_TSUB); dc->cc_op = CC_OP_TSUB; break; case 0x22: /* taddcctv */ - save_state(dc); - gen_op_tadd_ccTV(cpu_dst, cpu_src1, cpu_src2); + gen_helper_taddcctv(cpu_dst, cpu_env, + cpu_src1, cpu_src2); gen_movl_TN_reg(rd, cpu_dst); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_TADDTV); dc->cc_op = CC_OP_TADDTV; break; case 0x23: /* tsubcctv */ - save_state(dc); - gen_op_tsub_ccTV(cpu_dst, cpu_src1, cpu_src2); + gen_helper_tsubcctv(cpu_dst, cpu_env, + cpu_src1, cpu_src2); gen_movl_TN_reg(rd, cpu_dst); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_TSUBTV); dc->cc_op = CC_OP_TSUBTV; break; case 0x24: /* mulscc */ -- cgit v1.2.3 From 6cb675b0f89131dcb7bc4f9e0801ac7620374185 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 5 Oct 2012 16:55:06 -0700 Subject: target-sparc: Use movcond in mulscc Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 98efb8445..614905e1f 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -582,22 +582,21 @@ static void gen_op_subx_int(DisasContext *dc, TCGv dst, TCGv src1, static inline void gen_op_mulscc(TCGv dst, TCGv src1, TCGv src2) { - TCGv r_temp; - int l1; + TCGv r_temp, zero; - l1 = gen_new_label(); r_temp = tcg_temp_new(); /* old op: if (!(env->y & 1)) T1 = 0; */ + zero = tcg_const_tl(0); tcg_gen_andi_tl(cpu_cc_src, src1, 0xffffffff); tcg_gen_andi_tl(r_temp, cpu_y, 0x1); tcg_gen_andi_tl(cpu_cc_src2, src2, 0xffffffff); - tcg_gen_brcondi_tl(TCG_COND_NE, r_temp, 0, l1); - tcg_gen_movi_tl(cpu_cc_src2, 0); - gen_set_label(l1); + tcg_gen_movcond_tl(TCG_COND_EQ, cpu_cc_src2, r_temp, zero, + zero, cpu_cc_src2); + tcg_temp_free(zero); // b2 = T0 & 1; // env->y = (b2 << 31) | (env->y >> 1); -- cgit v1.2.3 From 690995a615ed584a4d494a7b61ede4f849d83e4a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 5 Oct 2012 16:55:07 -0700 Subject: target-sparc: Use movcond for FMOV*R Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 46 ++++++++++++++++------------------------------ 1 file changed, 16 insertions(+), 30 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 614905e1f..d594284da 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -3051,44 +3051,30 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) rs2 = GET_FIELD(insn, 27, 31); xop = GET_FIELD(insn, 18, 26); save_state(dc); -#ifdef TARGET_SPARC64 - if ((xop & 0x11f) == 0x005) { // V9 fmovsr - int l1; - l1 = gen_new_label(); - cond = GET_FIELD_SP(insn, 14, 17); - cpu_src1 = get_src1(insn, cpu_src1); - tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], cpu_src1, - 0, l1); - cpu_src1_32 = gen_load_fpr_F(dc, rs2); - gen_store_fpr_F(dc, rd, cpu_src1_32); - gen_set_label(l1); +#ifdef TARGET_SPARC64 +#define FMOVR(sz) \ + do { \ + DisasCompare cmp; \ + cond = GET_FIELD_SP(insn, 14, 17); \ + cpu_src1 = get_src1(insn, cpu_src1); \ + gen_compare_reg(&cmp, cond, cpu_src1); \ + gen_fmov##sz(dc, &cmp, rd, rs2); \ + free_compare(&cmp); \ + } while (0) + + if ((xop & 0x11f) == 0x005) { /* V9 fmovsr */ + FMOVR(s); break; } else if ((xop & 0x11f) == 0x006) { // V9 fmovdr - int l1; - - l1 = gen_new_label(); - cond = GET_FIELD_SP(insn, 14, 17); - cpu_src1 = get_src1(insn, cpu_src1); - tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], cpu_src1, - 0, l1); - cpu_src1_64 = gen_load_fpr_D(dc, rs2); - gen_store_fpr_D(dc, rd, cpu_src1_64); - gen_set_label(l1); + FMOVR(d); break; } else if ((xop & 0x11f) == 0x007) { // V9 fmovqr - int l1; - CHECK_FPU_FEATURE(dc, FLOAT128); - l1 = gen_new_label(); - cond = GET_FIELD_SP(insn, 14, 17); - cpu_src1 = get_src1(insn, cpu_src1); - tcg_gen_brcondi_tl(gen_tcg_cond_reg[cond], cpu_src1, - 0, l1); - gen_move_Q(rd, rs2); - gen_set_label(l1); + FMOVR(q); break; } +#undef FMOVR #endif switch (xop) { #ifdef TARGET_SPARC64 -- cgit v1.2.3 From b09b2fd30ce3079fbca1bbd7c1a87459378c5bd7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 5 Oct 2012 16:55:08 -0700 Subject: target-sparc: Cleanup "global" temporary allocation There are 6 temporaries that disas_sparc_insn relies on having been allocated. Now that they are no longer referenced across branches, they need not be allocated as local temps. Move the allocation/free of these temporaries to make it clear that they are local to the translation of a single insn. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index d594284da..48c245eeb 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -5177,16 +5177,6 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, dc->singlestep = (env->singlestep_enabled || singlestep); gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; - cpu_tmp0 = tcg_temp_new(); - cpu_tmp32 = tcg_temp_new_i32(); - cpu_tmp64 = tcg_temp_new_i64(); - - cpu_dst = tcg_temp_local_new(); - - // loads and stores - cpu_val = tcg_temp_local_new(); - cpu_addr = tcg_temp_local_new(); - num_insns = 0; max_insns = tb->cflags & CF_COUNT_MASK; if (max_insns == 0) @@ -5222,9 +5212,24 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, gen_io_start(); last_pc = dc->pc; insn = cpu_ldl_code(env, dc->pc); + + cpu_tmp0 = tcg_temp_new(); + cpu_tmp32 = tcg_temp_new_i32(); + cpu_tmp64 = tcg_temp_new_i64(); + cpu_dst = tcg_temp_new(); + cpu_val = tcg_temp_new(); + cpu_addr = tcg_temp_new(); + disas_sparc_insn(dc, insn); num_insns++; + tcg_temp_free(cpu_addr); + tcg_temp_free(cpu_val); + tcg_temp_free(cpu_dst); + tcg_temp_free_i64(cpu_tmp64); + tcg_temp_free_i32(cpu_tmp32); + tcg_temp_free(cpu_tmp0); + if (dc->is_br) break; /* if the next PC is different, we abort now */ @@ -5244,23 +5249,18 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, num_insns < max_insns); exit_gen_loop: - tcg_temp_free(cpu_addr); - tcg_temp_free(cpu_val); - tcg_temp_free(cpu_dst); - tcg_temp_free_i64(cpu_tmp64); - tcg_temp_free_i32(cpu_tmp32); - tcg_temp_free(cpu_tmp0); - - if (tb->cflags & CF_LAST_IO) + if (tb->cflags & CF_LAST_IO) { gen_io_end(); + } if (!dc->is_br) { if (dc->pc != DYNAMIC_PC && (dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) { /* static PC and NPC: we can use direct chaining */ gen_goto_tb(dc, 0, dc->pc, dc->npc); } else { - if (dc->pc != DYNAMIC_PC) + if (dc->pc != DYNAMIC_PC) { tcg_gen_movi_tl(cpu_pc, dc->pc); + } save_npc(dc); tcg_gen_exit_tb(0); } -- cgit v1.2.3 From fe1755cbb21c34a40234e2c380d049b9b031c4e2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 5 Oct 2012 16:55:09 -0700 Subject: target-sparc: Fall through from not-taken trap Now that we've cleaned up global temporary allocation, we can continue translating the fallthru path of a conditional trap. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 48c245eeb..a7f64074f 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2573,13 +2573,15 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) gen_helper_raise_exception(cpu_env, trap); tcg_temp_free_i32(trap); - if (cond != 8) { + if (cond == 8) { + /* An unconditional trap ends the TB. */ + dc->is_br = 1; + goto jmp_insn; + } else { + /* A conditional trap falls through to the next insn. */ gen_set_label(l1); - gen_op_next_insn(); - tcg_gen_exit_tb(0); + break; } - dc->is_br = 1; - goto jmp_insn; } else if (xop == 0x28) { rs1 = GET_FIELD(insn, 13, 17); switch(rs1) { -- cgit v1.2.3 From 2a484ecf8283814c92b5743845e285f0efc23247 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 5 Oct 2012 16:55:10 -0700 Subject: target-sparc: Optimize conditionals using SUBCC Aka "normal" comparisons. We now have the infrastructure to pass back non-boolean results from gen_compare. This will automatically get used by both branches and conditional moves. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 192 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 131 insertions(+), 61 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index a7f64074f..472eb518c 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1046,83 +1046,153 @@ static void free_compare(DisasCompare *cmp) } } -static void gen_compare(DisasCompare *cmp, unsigned int cc, unsigned int cond, +static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond, DisasContext *dc) { + static int subcc_cond[16] = { + -1, /* never */ + TCG_COND_EQ, + TCG_COND_LE, + TCG_COND_LT, + TCG_COND_LEU, + TCG_COND_LTU, + -1, /* neg */ + -1, /* overflow */ + -1, /* always */ + TCG_COND_NE, + TCG_COND_GT, + TCG_COND_GE, + TCG_COND_GTU, + TCG_COND_GEU, + -1, /* pos */ + -1, /* no overflow */ + }; + TCGv_i32 r_src; TCGv r_dst; - /* For now we still generate a straight boolean result. */ - cmp->cond = TCG_COND_NE; - cmp->is_bool = true; - cmp->g1 = cmp->g2 = false; - cmp->c1 = r_dst = tcg_temp_new(); - cmp->c2 = tcg_const_tl(0); - #ifdef TARGET_SPARC64 - if (cc) + if (xcc) { r_src = cpu_xcc; - else + } else { r_src = cpu_psr; + } #else r_src = cpu_psr; #endif + switch (dc->cc_op) { - case CC_OP_FLAGS: + case CC_OP_SUB: + switch (cond) { + case 6: /* neg */ + case 14: /* pos */ + cmp->cond = (cond == 6 ? TCG_COND_LT : TCG_COND_GE); + cmp->is_bool = false; + cmp->g2 = false; + cmp->c2 = tcg_const_tl(0); +#ifdef TARGET_SPARC64 + if (!xcc) { + cmp->g1 = false; + cmp->c1 = tcg_temp_new(); + tcg_gen_ext32s_tl(cmp->c1, cpu_cc_dst); + break; + } +#endif + cmp->g1 = true; + cmp->c1 = cpu_cc_dst; + break; + + case 0: /* never */ + case 8: /* always */ + case 7: /* overflow */ + case 15: /* !overflow */ + goto do_dynamic; + + default: + cmp->cond = subcc_cond[cond]; + cmp->is_bool = false; +#ifdef TARGET_SPARC64 + if (!xcc) { + /* Note that sign-extension works for unsigned compares as + long as both operands are sign-extended. */ + cmp->g1 = cmp->g2 = false; + cmp->c1 = tcg_temp_new(); + cmp->c2 = tcg_temp_new(); + tcg_gen_ext32s_tl(cmp->c1, cpu_cc_src); + tcg_gen_ext32s_tl(cmp->c2, cpu_cc_src2); + } +#endif + cmp->g1 = cmp->g2 = true; + cmp->c1 = cpu_cc_src; + cmp->c2 = cpu_cc_src2; + break; + } break; + default: + do_dynamic: gen_helper_compute_psr(cpu_env); dc->cc_op = CC_OP_FLAGS; - break; - } - switch (cond) { - case 0x0: - gen_op_eval_bn(r_dst); - break; - case 0x1: - gen_op_eval_be(r_dst, r_src); - break; - case 0x2: - gen_op_eval_ble(r_dst, r_src); - break; - case 0x3: - gen_op_eval_bl(r_dst, r_src); - break; - case 0x4: - gen_op_eval_bleu(r_dst, r_src); - break; - case 0x5: - gen_op_eval_bcs(r_dst, r_src); - break; - case 0x6: - gen_op_eval_bneg(r_dst, r_src); - break; - case 0x7: - gen_op_eval_bvs(r_dst, r_src); - break; - case 0x8: - gen_op_eval_ba(r_dst); - break; - case 0x9: - gen_op_eval_bne(r_dst, r_src); - break; - case 0xa: - gen_op_eval_bg(r_dst, r_src); - break; - case 0xb: - gen_op_eval_bge(r_dst, r_src); - break; - case 0xc: - gen_op_eval_bgu(r_dst, r_src); - break; - case 0xd: - gen_op_eval_bcc(r_dst, r_src); - break; - case 0xe: - gen_op_eval_bpos(r_dst, r_src); - break; - case 0xf: - gen_op_eval_bvc(r_dst, r_src); + /* FALLTHRU */ + + case CC_OP_FLAGS: + /* We're going to generate a boolean result. */ + cmp->cond = TCG_COND_NE; + cmp->is_bool = true; + cmp->g1 = cmp->g2 = false; + cmp->c1 = r_dst = tcg_temp_new(); + cmp->c2 = tcg_const_tl(0); + + switch (cond) { + case 0x0: + gen_op_eval_bn(r_dst); + break; + case 0x1: + gen_op_eval_be(r_dst, r_src); + break; + case 0x2: + gen_op_eval_ble(r_dst, r_src); + break; + case 0x3: + gen_op_eval_bl(r_dst, r_src); + break; + case 0x4: + gen_op_eval_bleu(r_dst, r_src); + break; + case 0x5: + gen_op_eval_bcs(r_dst, r_src); + break; + case 0x6: + gen_op_eval_bneg(r_dst, r_src); + break; + case 0x7: + gen_op_eval_bvs(r_dst, r_src); + break; + case 0x8: + gen_op_eval_ba(r_dst); + break; + case 0x9: + gen_op_eval_bne(r_dst, r_src); + break; + case 0xa: + gen_op_eval_bg(r_dst, r_src); + break; + case 0xb: + gen_op_eval_bge(r_dst, r_src); + break; + case 0xc: + gen_op_eval_bgu(r_dst, r_src); + break; + case 0xd: + gen_op_eval_bcc(r_dst, r_src); + break; + case 0xe: + gen_op_eval_bpos(r_dst, r_src); + break; + case 0xf: + gen_op_eval_bvc(r_dst, r_src); + break; + } break; } } -- cgit v1.2.3 From f1829782d6cb931973d71649f8ad1dad66188c34 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sun, 7 Oct 2012 20:07:11 +0200 Subject: qemu-barrier: Fix compilation on i386 hosts Commit 1d31fca470648ec66afd8743491bfb5846306341 tried to fix bug introduced by 610b823ef66b993660f1ab1447a769f190e4f3b3 by including qemu-common.h, which breaks the build further. Include compiler.h instead, as suggested by Blue Swirl. Signed-off-by: Aurelien Jarno --- qemu-barrier.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-barrier.h b/qemu-barrier.h index 1de914e88..faa83d265 100644 --- a/qemu-barrier.h +++ b/qemu-barrier.h @@ -6,7 +6,7 @@ #if defined(__i386__) -#include "qemu-common.h" /* QEMU_GNUC_PREREQ */ +#include "compiler.h" /* QEMU_GNUC_PREREQ */ /* * Because of the strongly ordered x86 storage model, wmb() and rmb() are nops -- cgit v1.2.3 From b4a76e84f4997392c9d2eb6f4373dc376d2ffd82 Mon Sep 17 00:00:00 2001 From: "Peter A. G. Crosthwaite" Date: Tue, 24 Jul 2012 10:55:15 +1000 Subject: ssi: Support for multiple attached devices Removed assertion that only one device is attached to the SSI bus. When multiple devices are attached, all slaves have their transfer function called for transfers. Each device is responsible for knowing whether or not its CS is active, and if not returning 0. The returned data is the logical or of all responses from the (mulitple) devices. Signed-off-by: Peter A. G. Crosthwaite Acked-by: Peter Maydell --- hw/ssi.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/hw/ssi.c b/hw/ssi.c index e5f14a0ce..35d0a04a0 100644 --- a/hw/ssi.c +++ b/hw/ssi.c @@ -2,6 +2,8 @@ * QEMU Synchronous Serial Interface support * * Copyright (c) 2009 CodeSourcery. + * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com) + * Copyright (c) 2012 PetaLogix Pty Ltd. * Written by Paul Brook * * This code is licensed under the GNU GPL v2. @@ -29,14 +31,6 @@ static int ssi_slave_init(DeviceState *dev) { SSISlave *s = SSI_SLAVE(dev); SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s); - SSIBus *bus; - BusChild *kid; - - bus = FROM_QBUS(SSIBus, qdev_get_parent_bus(dev)); - kid = QTAILQ_FIRST(&bus->qbus.children); - if (kid->child != dev || QTAILQ_NEXT(kid, sibling) != NULL) { - hw_error("Too many devices on SSI bus"); - } return ssc->init(s); } @@ -74,16 +68,16 @@ SSIBus *ssi_create_bus(DeviceState *parent, const char *name) uint32_t ssi_transfer(SSIBus *bus, uint32_t val) { BusChild *kid; - SSISlave *slave; SSISlaveClass *ssc; + uint32_t r = 0; - kid = QTAILQ_FIRST(&bus->qbus.children); - if (!kid) { - return 0; + QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) { + SSISlave *slave = SSI_SLAVE(kid->child); + ssc = SSI_SLAVE_GET_CLASS(slave); + r |= ssc->transfer(slave, val); } - slave = SSI_SLAVE(kid->child); - ssc = SSI_SLAVE_GET_CLASS(slave); - return ssc->transfer(slave, val); + + return r; } static void ssi_slave_register_types(void) -- cgit v1.2.3 From 66530953319427d7c67a723076acd68075dc7db2 Mon Sep 17 00:00:00 2001 From: "Peter A. G. Crosthwaite" Date: Tue, 24 Jul 2012 12:23:22 +1000 Subject: ssi: Implemented CS behaviour Added default CS behaviour for SSI slaves. SSI devices can set a property to enable CS behaviour which will create a GPIO on the device which is the CS. Tristating of the bus on SSI transfers is implemented. Signed-off-by: Peter A. G. Crosthwaite Acked-by: Peter Maydell --- hw/ads7846.c | 7 ++++--- hw/max111x.c | 7 ++++--- hw/spitz.c | 8 +++++--- hw/ssd0323.c | 6 ++++++ hw/ssi-sd.c | 6 ++++++ hw/ssi.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- hw/ssi.h | 37 +++++++++++++++++++++++++++++++++++++ hw/stellaris.c | 7 ++++--- hw/z2.c | 7 ++++--- 9 files changed, 118 insertions(+), 16 deletions(-) diff --git a/hw/ads7846.c b/hw/ads7846.c index 41c7f101c..2ea9e55bb 100644 --- a/hw/ads7846.c +++ b/hw/ads7846.c @@ -119,11 +119,12 @@ static int ads7856_post_load(void *opaque, int version_id) static const VMStateDescription vmstate_ads7846 = { .name = "ads7846", - .version_id = 0, - .minimum_version_id = 0, - .minimum_version_id_old = 0, + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, .post_load = ads7856_post_load, .fields = (VMStateField[]) { + VMSTATE_SSI_SLAVE(ssidev, ADS7846State), VMSTATE_INT32_ARRAY(input, ADS7846State, 8), VMSTATE_INT32(noise, ADS7846State), VMSTATE_INT32(cycle, ADS7846State), diff --git a/hw/max111x.c b/hw/max111x.c index 706d89f4f..67640f109 100644 --- a/hw/max111x.c +++ b/hw/max111x.c @@ -99,10 +99,11 @@ static uint32_t max111x_transfer(SSISlave *dev, uint32_t value) static const VMStateDescription vmstate_max111x = { .name = "max111x", - .version_id = 0, - .minimum_version_id = 0, - .minimum_version_id_old = 0, + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, .fields = (VMStateField[]) { + VMSTATE_SSI_SLAVE(ssidev, MAX111xState), VMSTATE_UINT8(tb1, MAX111xState), VMSTATE_UINT8(rb2, MAX111xState), VMSTATE_UINT8(rb3, MAX111xState), diff --git a/hw/spitz.c b/hw/spitz.c index 20e783519..24346dcd5 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -1083,10 +1083,11 @@ static TypeInfo spitz_keyboard_info = { static const VMStateDescription vmstate_corgi_ssp_regs = { .name = "corgi-ssp", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, + .version_id = 2, + .minimum_version_id = 2, + .minimum_version_id_old = 2, .fields = (VMStateField []) { + VMSTATE_SSI_SLAVE(ssidev, CorgiSSPState), VMSTATE_UINT32_ARRAY(enable, CorgiSSPState, 3), VMSTATE_END_OF_LIST(), } @@ -1115,6 +1116,7 @@ static const VMStateDescription vmstate_spitz_lcdtg_regs = { .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField []) { + VMSTATE_SSI_SLAVE(ssidev, SpitzLCDTG), VMSTATE_UINT32(bl_intensity, SpitzLCDTG), VMSTATE_UINT32(bl_power, SpitzLCDTG), VMSTATE_END_OF_LIST(), diff --git a/hw/ssd0323.c b/hw/ssd0323.c index b101c5112..5d05a35bc 100644 --- a/hw/ssd0323.c +++ b/hw/ssd0323.c @@ -279,6 +279,7 @@ static void ssd0323_cd(void *opaque, int n, int level) static void ssd0323_save(QEMUFile *f, void *opaque) { + SSISlave *ss = SSI_SLAVE(opaque); ssd0323_state *s = (ssd0323_state *)opaque; int i; @@ -296,10 +297,13 @@ static void ssd0323_save(QEMUFile *f, void *opaque) qemu_put_be32(f, s->remap); qemu_put_be32(f, s->mode); qemu_put_buffer(f, s->framebuffer, sizeof(s->framebuffer)); + + qemu_put_be32(f, ss->cs); } static int ssd0323_load(QEMUFile *f, void *opaque, int version_id) { + SSISlave *ss = SSI_SLAVE(opaque); ssd0323_state *s = (ssd0323_state *)opaque; int i; @@ -321,6 +325,8 @@ static int ssd0323_load(QEMUFile *f, void *opaque, int version_id) s->mode = qemu_get_be32(f); qemu_get_buffer(f, s->framebuffer, sizeof(s->framebuffer)); + ss->cs = qemu_get_be32(f); + return 0; } diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c index b519bdb29..cbbc64521 100644 --- a/hw/ssi-sd.c +++ b/hw/ssi-sd.c @@ -197,6 +197,7 @@ static uint32_t ssi_sd_transfer(SSISlave *dev, uint32_t val) static void ssi_sd_save(QEMUFile *f, void *opaque) { + SSISlave *ss = SSI_SLAVE(opaque); ssi_sd_state *s = (ssi_sd_state *)opaque; int i; @@ -209,10 +210,13 @@ static void ssi_sd_save(QEMUFile *f, void *opaque) qemu_put_be32(f, s->arglen); qemu_put_be32(f, s->response_pos); qemu_put_be32(f, s->stopping); + + qemu_put_be32(f, ss->cs); } static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id) { + SSISlave *ss = SSI_SLAVE(opaque); ssi_sd_state *s = (ssi_sd_state *)opaque; int i; @@ -229,6 +233,8 @@ static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id) s->response_pos = qemu_get_be32(f); s->stopping = qemu_get_be32(f); + ss->cs = qemu_get_be32(f); + return 0; } diff --git a/hw/ssi.c b/hw/ssi.c index 35d0a04a0..2e4f2fecd 100644 --- a/hw/ssi.c +++ b/hw/ssi.c @@ -27,19 +27,55 @@ static const TypeInfo ssi_bus_info = { .instance_size = sizeof(SSIBus), }; +static void ssi_cs_default(void *opaque, int n, int level) +{ + SSISlave *s = SSI_SLAVE(opaque); + bool cs = !!level; + assert(n == 0); + if (s->cs != cs) { + SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s); + if (ssc->set_cs) { + ssc->set_cs(s, cs); + } + } + s->cs = cs; +} + +static uint32_t ssi_transfer_raw_default(SSISlave *dev, uint32_t val) +{ + SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(dev); + + if ((dev->cs && ssc->cs_polarity == SSI_CS_HIGH) || + (!dev->cs && ssc->cs_polarity == SSI_CS_LOW) || + ssc->cs_polarity == SSI_CS_NONE) { + return ssc->transfer(dev, val); + } + return 0; +} + static int ssi_slave_init(DeviceState *dev) { SSISlave *s = SSI_SLAVE(dev); SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s); + if (ssc->transfer_raw == ssi_transfer_raw_default && + ssc->cs_polarity != SSI_CS_NONE) { + qdev_init_gpio_in(&s->qdev, ssi_cs_default, 1); + } + return ssc->init(s); } static void ssi_slave_class_init(ObjectClass *klass, void *data) { + SSISlaveClass *ssc = SSI_SLAVE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); + dc->init = ssi_slave_init; dc->bus_type = TYPE_SSI_BUS; + if (!ssc->transfer_raw) { + ssc->transfer_raw = ssi_transfer_raw_default; + } } static TypeInfo ssi_slave_info = { @@ -74,12 +110,23 @@ uint32_t ssi_transfer(SSIBus *bus, uint32_t val) QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) { SSISlave *slave = SSI_SLAVE(kid->child); ssc = SSI_SLAVE_GET_CLASS(slave); - r |= ssc->transfer(slave, val); + r |= ssc->transfer_raw(slave, val); } return r; } +const VMStateDescription vmstate_ssi_slave = { + .name = "SSISlave", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_BOOL(cs, SSISlave), + VMSTATE_END_OF_LIST() + } +}; + static void ssi_slave_register_types(void) { type_register_static(&ssi_bus_info); diff --git a/hw/ssi.h b/hw/ssi.h index 06657d7c1..65b159dca 100644 --- a/hw/ssi.h +++ b/hw/ssi.h @@ -23,21 +23,58 @@ typedef struct SSISlave SSISlave; #define SSI_SLAVE_GET_CLASS(obj) \ OBJECT_GET_CLASS(SSISlaveClass, (obj), TYPE_SSI_SLAVE) +typedef enum { + SSI_CS_NONE = 0, + SSI_CS_LOW, + SSI_CS_HIGH, +} SSICSMode; + /* Slave devices. */ typedef struct SSISlaveClass { DeviceClass parent_class; int (*init)(SSISlave *dev); + + /* if you have standard or no CS behaviour, just override transfer. + * This is called when the device cs is active (true by default). + */ uint32_t (*transfer)(SSISlave *dev, uint32_t val); + /* called when the CS line changes. Optional, devices only need to implement + * this if they have side effects associated with the cs line (beyond + * tristating the txrx lines). + */ + int (*set_cs)(SSISlave *dev, bool select); + /* define whether or not CS exists and is active low/high */ + SSICSMode cs_polarity; + + /* if you have non-standard CS behaviour override this to take control + * of the CS behaviour at the device level. transfer, set_cs, and + * cs_polarity are unused if this is overwritten. Transfer_raw will + * always be called for the device for every txrx access to the parent bus + */ + uint32_t (*transfer_raw)(SSISlave *dev, uint32_t val); } SSISlaveClass; struct SSISlave { DeviceState qdev; + + /* Chip select state */ + bool cs; }; #define SSI_SLAVE_FROM_QDEV(dev) DO_UPCAST(SSISlave, qdev, dev) #define FROM_SSI_SLAVE(type, dev) DO_UPCAST(type, ssidev, dev) +extern const VMStateDescription vmstate_ssi_slave; + +#define VMSTATE_SSI_SLAVE(_field, _state) { \ + .name = (stringify(_field)), \ + .size = sizeof(SSISlave), \ + .vmsd = &vmstate_ssi_slave, \ + .flags = VMS_STRUCT, \ + .offset = vmstate_offset_value(_state, _field, SSISlave), \ +} + DeviceState *ssi_create_slave(SSIBus *bus, const char *name); /* Master interface. */ diff --git a/hw/stellaris.c b/hw/stellaris.c index 562fbbf49..01050d15f 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -1184,10 +1184,11 @@ static uint32_t stellaris_ssi_bus_transfer(SSISlave *dev, uint32_t val) static const VMStateDescription vmstate_stellaris_ssi_bus = { .name = "stellaris_ssi_bus", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, + .version_id = 2, + .minimum_version_id = 2, + .minimum_version_id_old = 2, .fields = (VMStateField[]) { + VMSTATE_SSI_SLAVE(ssidev, stellaris_ssi_bus_state), VMSTATE_INT32(current_dev, stellaris_ssi_bus_state), VMSTATE_END_OF_LIST() } diff --git a/hw/z2.c b/hw/z2.c index 289cee90c..076fad20c 100644 --- a/hw/z2.c +++ b/hw/z2.c @@ -161,10 +161,11 @@ static int zipit_lcd_init(SSISlave *dev) static VMStateDescription vmstate_zipit_lcd_state = { .name = "zipit-lcd", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, + .version_id = 2, + .minimum_version_id = 2, + .minimum_version_id_old = 2, .fields = (VMStateField[]) { + VMSTATE_SSI_SLAVE(ssidev, ZipitLCD), VMSTATE_INT32(selected, ZipitLCD), VMSTATE_INT32(enabled, ZipitLCD), VMSTATE_BUFFER(buf, ZipitLCD), -- cgit v1.2.3 From 74687e40b0406a0863234ca011c3cba7720864b0 Mon Sep 17 00:00:00 2001 From: "Peter A. G. Crosthwaite" Date: Tue, 24 Jul 2012 13:56:27 +1000 Subject: ssi: Added create_slave_no_init() Slave creation function that can be used to create an SSI slave without qdev_init() being called. This give machine models a chance to set properties. Signed-off-by: Peter A. G. Crosthwaite Acked-by: Peter Maydell --- hw/ssi.c | 9 +++++++-- hw/ssi.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/ssi.c b/hw/ssi.c index 2e4f2fecd..c47419d57 100644 --- a/hw/ssi.c +++ b/hw/ssi.c @@ -86,10 +86,15 @@ static TypeInfo ssi_slave_info = { .abstract = true, }; +DeviceState *ssi_create_slave_no_init(SSIBus *bus, const char *name) +{ + return qdev_create(&bus->qbus, name); +} + DeviceState *ssi_create_slave(SSIBus *bus, const char *name) { - DeviceState *dev; - dev = qdev_create(&bus->qbus, name); + DeviceState *dev = ssi_create_slave_no_init(bus, name); + qdev_init_nofail(dev); return dev; } diff --git a/hw/ssi.h b/hw/ssi.h index 65b159dca..2bde9f5b4 100644 --- a/hw/ssi.h +++ b/hw/ssi.h @@ -76,6 +76,7 @@ extern const VMStateDescription vmstate_ssi_slave; } DeviceState *ssi_create_slave(SSIBus *bus, const char *name); +DeviceState *ssi_create_slave_no_init(SSIBus *bus, const char *name); /* Master interface. */ SSIBus *ssi_create_bus(DeviceState *parent, const char *name); -- cgit v1.2.3 From 1e5b31e6bd4fa8a9c679a18388d2219feece275a Mon Sep 17 00:00:00 2001 From: "Peter A. G. Crosthwaite" Date: Tue, 31 Jul 2012 12:24:06 +1000 Subject: qdev: allow multiple qdev_init_gpio_in() calls Allow multiple qdev_init_gpio_in() calls for the one device. The first call will define GPIOs 0-N-1, the next GPIOs N- ... . Allows different GPIOs to be handled with different handlers. Needed when two levels of the QOM class heirachy both define GPIO functionality, as a single GPIO handler with an index selecter is not possible. Signed-off-by: Peter A. G. Crosthwaite Reviewed-by: Peter Maydell --- hw/irq.c | 27 ++++++++++++++++++++------- hw/irq.h | 11 ++++++++++- hw/qdev.c | 6 +++--- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/hw/irq.c b/hw/irq.c index d413a0b23..f4e2a7804 100644 --- a/hw/irq.c +++ b/hw/irq.c @@ -38,24 +38,37 @@ void qemu_set_irq(qemu_irq irq, int level) irq->handler(irq->opaque, irq->n, level); } -qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n) +qemu_irq *qemu_extend_irqs(qemu_irq *old, int n_old, qemu_irq_handler handler, + void *opaque, int n) { qemu_irq *s; struct IRQState *p; int i; - s = (qemu_irq *)g_malloc0(sizeof(qemu_irq) * n); - p = (struct IRQState *)g_malloc0(sizeof(struct IRQState) * n); - for (i = 0; i < n; i++) { - p->handler = handler; - p->opaque = opaque; - p->n = i; + if (!old) { + n_old = 0; + } + s = old ? g_renew(qemu_irq, old, n + n_old) : g_new(qemu_irq, n); + p = old ? g_renew(struct IRQState, s[0], n + n_old) : + g_new(struct IRQState, n); + for (i = 0; i < n + n_old; i++) { + if (i >= n_old) { + p->handler = handler; + p->opaque = opaque; + p->n = i; + } s[i] = p; p++; } return s; } +qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n) +{ + return qemu_extend_irqs(NULL, 0, handler, opaque, n); +} + + void qemu_free_irqs(qemu_irq *s) { g_free(s[0]); diff --git a/hw/irq.h b/hw/irq.h index 56c55f0c4..e640c105e 100644 --- a/hw/irq.h +++ b/hw/irq.h @@ -23,8 +23,17 @@ static inline void qemu_irq_pulse(qemu_irq irq) qemu_set_irq(irq, 0); } -/* Returns an array of N IRQs. */ +/* Returns an array of N IRQs. Each IRQ is assigned the argument handler and + * opaque data. + */ qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n); + +/* Extends an Array of IRQs. Old IRQs have their handlers and opaque data + * preserved. New IRQs are assigned the argument handler and opaque data. + */ +qemu_irq *qemu_extend_irqs(qemu_irq *old, int n_old, qemu_irq_handler handler, + void *opaque, int n); + void qemu_free_irqs(qemu_irq *s); /* Returns a new IRQ with opposite polarity. */ diff --git a/hw/qdev.c b/hw/qdev.c index b6e9207ed..9b9aba376 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -285,9 +285,9 @@ BusState *qdev_get_parent_bus(DeviceState *dev) void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n) { - assert(dev->num_gpio_in == 0); - dev->num_gpio_in = n; - dev->gpio_in = qemu_allocate_irqs(handler, dev, n); + dev->gpio_in = qemu_extend_irqs(dev->gpio_in, dev->num_gpio_in, handler, + dev, n); + dev->num_gpio_in += n; } void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n) -- cgit v1.2.3 From 8120e7144b4007d26531835c7b6bc2b40a736cd2 Mon Sep 17 00:00:00 2001 From: "Peter A. G. Crosthwaite" Date: Tue, 31 Jul 2012 16:42:04 +1000 Subject: stellaris: Removed SSI mux Removed the explicit SSI mux and wired the CS line directly up to the SSI devices. Signed-off-by: Peter A. G. Crosthwaite --- hw/ssd0323.c | 1 + hw/ssi-sd.c | 1 + hw/stellaris.c | 94 ++++++++++------------------------------------------------ 3 files changed, 18 insertions(+), 78 deletions(-) diff --git a/hw/ssd0323.c b/hw/ssd0323.c index 5d05a35bc..9c42d648e 100644 --- a/hw/ssd0323.c +++ b/hw/ssd0323.c @@ -354,6 +354,7 @@ static void ssd0323_class_init(ObjectClass *klass, void *data) k->init = ssd0323_init; k->transfer = ssd0323_transfer; + k->cs_polarity = SSI_CS_HIGH; } static TypeInfo ssd0323_info = { diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c index cbbc64521..c5505ee24 100644 --- a/hw/ssi-sd.c +++ b/hw/ssi-sd.c @@ -256,6 +256,7 @@ static void ssi_sd_class_init(ObjectClass *klass, void *data) k->init = ssi_sd_init; k->transfer = ssi_sd_transfer; + k->cs_polarity = SSI_CS_LOW; } static TypeInfo ssi_sd_info = { diff --git a/hw/stellaris.c b/hw/stellaris.c index 01050d15f..353ca4c04 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -1154,58 +1154,6 @@ static int stellaris_adc_init(SysBusDevice *dev) return 0; } -/* Some boards have both an OLED controller and SD card connected to - the same SSI port, with the SD card chip select connected to a - GPIO pin. Technically the OLED chip select is connected to the SSI - Fss pin. We do not bother emulating that as both devices should - never be selected simultaneously, and our OLED controller ignores stray - 0xff commands that occur when deselecting the SD card. */ - -typedef struct { - SSISlave ssidev; - qemu_irq irq; - int current_dev; - SSIBus *bus[2]; -} stellaris_ssi_bus_state; - -static void stellaris_ssi_bus_select(void *opaque, int irq, int level) -{ - stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque; - - s->current_dev = level; -} - -static uint32_t stellaris_ssi_bus_transfer(SSISlave *dev, uint32_t val) -{ - stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev); - - return ssi_transfer(s->bus[s->current_dev], val); -} - -static const VMStateDescription vmstate_stellaris_ssi_bus = { - .name = "stellaris_ssi_bus", - .version_id = 2, - .minimum_version_id = 2, - .minimum_version_id_old = 2, - .fields = (VMStateField[]) { - VMSTATE_SSI_SLAVE(ssidev, stellaris_ssi_bus_state), - VMSTATE_INT32(current_dev, stellaris_ssi_bus_state), - VMSTATE_END_OF_LIST() - } -}; - -static int stellaris_ssi_bus_init(SSISlave *dev) -{ - stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev); - - s->bus[0] = ssi_create_bus(&dev->qdev, "ssi0"); - s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1"); - qdev_init_gpio_in(&dev->qdev, stellaris_ssi_bus_select, 1); - - vmstate_register(&dev->qdev, -1, &vmstate_stellaris_ssi_bus, s); - return 0; -} - /* Board init. */ static stellaris_board_info stellaris_boards[] = { { "LM3S811EVB", @@ -1306,19 +1254,25 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, if (board->dc2 & (1 << 4)) { dev = sysbus_create_simple("pl022", 0x40008000, pic[7]); if (board->peripherals & BP_OLED_SSI) { - DeviceState *mux; void *bus; - + DeviceState *sddev; + DeviceState *ssddev; + + /* Some boards have both an OLED controller and SD card connected to + * the same SSI port, with the SD card chip select connected to a + * GPIO pin. Technically the OLED chip select is connected to the + * SSI Fss pin. We do not bother emulating that as both devices + * should never be selected simultaneously, and our OLED controller + * ignores stray 0xff commands that occur when deselecting the SD + * card. + */ bus = qdev_get_child_bus(dev, "ssi"); - mux = ssi_create_slave(bus, "evb6965-ssi"); - gpio_out[GPIO_D][0] = qdev_get_gpio_in(mux, 0); - - bus = qdev_get_child_bus(mux, "ssi0"); - ssi_create_slave(bus, "ssi-sd"); - bus = qdev_get_child_bus(mux, "ssi1"); - dev = ssi_create_slave(bus, "ssd0323"); - gpio_out[GPIO_C][7] = qdev_get_gpio_in(dev, 0); + sddev = ssi_create_slave(bus, "ssi-sd"); + ssddev = ssi_create_slave(bus, "ssd0323"); + gpio_out[GPIO_D][0] = qemu_irq_split(qdev_get_gpio_in(sddev, 0), + qdev_get_gpio_in(ssddev, 0)); + gpio_out[GPIO_C][7] = qdev_get_gpio_in(ssddev, 1); /* Make sure the select pin is high. */ qemu_irq_raise(gpio_out[GPIO_D][0]); @@ -1395,21 +1349,6 @@ static void stellaris_machine_init(void) machine_init(stellaris_machine_init); -static void stellaris_ssi_bus_class_init(ObjectClass *klass, void *data) -{ - SSISlaveClass *k = SSI_SLAVE_CLASS(klass); - - k->init = stellaris_ssi_bus_init; - k->transfer = stellaris_ssi_bus_transfer; -} - -static TypeInfo stellaris_ssi_bus_info = { - .name = "evb6965-ssi", - .parent = TYPE_SSI_SLAVE, - .instance_size = sizeof(stellaris_ssi_bus_state), - .class_init = stellaris_ssi_bus_class_init, -}; - static void stellaris_i2c_class_init(ObjectClass *klass, void *data) { SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); @@ -1457,7 +1396,6 @@ static void stellaris_register_types(void) type_register_static(&stellaris_i2c_info); type_register_static(&stellaris_gptm_info); type_register_static(&stellaris_adc_info); - type_register_static(&stellaris_ssi_bus_info); } type_init(stellaris_register_types) -- cgit v1.2.3 From a3578d4a51250365fb7f048e8154942a2659cc4a Mon Sep 17 00:00:00 2001 From: "Peter A. G. Crosthwaite" Date: Wed, 1 Aug 2012 20:26:12 +1000 Subject: hw: Added generic FIFO API. Added a FIFO API that can be used to create and operate byte FIFOs. Signed-off-by: Peter A. G. Crosthwaite --- hw/Makefile.objs | 1 + hw/fifo.c | 78 ++++++++++++++++++++++++++++++++++++++++++++ hw/fifo.h | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 178 insertions(+) create mode 100644 hw/fifo.c create mode 100644 hw/fifo.h diff --git a/hw/Makefile.objs b/hw/Makefile.objs index b59c74953..66abbb2c7 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -35,6 +35,7 @@ common-obj-$(CONFIG_APPLESMC) += applesmc.o common-obj-$(CONFIG_SMARTCARD) += ccid-card-passthru.o common-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o common-obj-$(CONFIG_I8259) += i8259_common.o i8259.o +common-obj-y += fifo.o # PPC devices common-obj-$(CONFIG_PREP_PCI) += prep_pci.o diff --git a/hw/fifo.c b/hw/fifo.c new file mode 100644 index 000000000..68a955a77 --- /dev/null +++ b/hw/fifo.c @@ -0,0 +1,78 @@ +/* + * Generic FIFO component, implemented as a circular buffer. + * + * Copyright (c) 2012 Peter A. G. Crosthwaite + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "fifo.h" + +void fifo8_create(Fifo8 *fifo, uint32_t capacity) +{ + fifo->data = g_new(uint8_t, capacity); + fifo->capacity = capacity; + fifo->head = 0; + fifo->num = 0; +} + +void fifo8_destroy(Fifo8 *fifo) +{ + g_free(fifo->data); +} + +void fifo8_push(Fifo8 *fifo, uint8_t data) +{ + if (fifo->num == fifo->capacity) { + abort(); + } + fifo->data[(fifo->head + fifo->num) % fifo->capacity] = data; + fifo->num++; +} + +uint8_t fifo8_pop(Fifo8 *fifo) +{ + uint8_t ret; + + if (fifo->num == 0) { + abort(); + } + ret = fifo->data[fifo->head++]; + fifo->head %= fifo->capacity; + fifo->num--; + return ret; +} + +void fifo8_reset(Fifo8 *fifo) +{ + fifo->num = 0; +} + +bool fifo8_is_empty(Fifo8 *fifo) +{ + return (fifo->num == 0); +} + +bool fifo8_is_full(Fifo8 *fifo) +{ + return (fifo->num == fifo->capacity); +} + +const VMStateDescription vmstate_fifo8 = { + .name = "Fifo8", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_VBUFFER_UINT32(data, Fifo8, 1, NULL, 0, capacity), + VMSTATE_UINT32(head, Fifo8), + VMSTATE_UINT32(num, Fifo8), + VMSTATE_END_OF_LIST() + } +}; diff --git a/hw/fifo.h b/hw/fifo.h new file mode 100644 index 000000000..f23890abf --- /dev/null +++ b/hw/fifo.h @@ -0,0 +1,99 @@ +#ifndef FIFO_H +#define FIFO_H + +#include "hw.h" + +typedef struct { + /* All fields are private */ + uint8_t *data; + uint32_t capacity; + uint32_t head; + uint32_t num; +} Fifo8; + +/** + * fifo8_create: + * @fifo: struct Fifo8 to initialise with new FIFO + * @capacity: capacity of the newly created FIFO + * + * Create a FIFO of the specified size. Clients should call fifo8_destroy() + * when finished using the fifo. The FIFO is initially empty. + */ + +void fifo8_create(Fifo8 *fifo, uint32_t capacity); + +/** + * fifo8_destroy: + * @fifo: FIFO to cleanup + * + * Cleanup a FIFO created with fifo8_create(). Frees memory created for FIFO + *storage. The FIFO is no longer usable after this has been called. + */ + +void fifo8_destroy(Fifo8 *fifo); + +/** + * fifo8_push: + * @fifo: FIFO to push to + * @data: data byte to push + * + * Push a data byte to the FIFO. Behaviour is undefined if the FIFO is full. + * Clients are responsible for checking for fullness using fifo8_is_full(). + */ + +void fifo8_push(Fifo8 *fifo, uint8_t data); + +/** + * fifo8_pop: + * @fifo: fifo to pop from + * + * Pop a data byte from the FIFO. Behaviour is undefined if the FIFO is empty. + * Clients are responsible for checking for emptyness using fifo8_is_empty(). + * + * Returns: The popped data byte. + */ + +uint8_t fifo8_pop(Fifo8 *fifo); + +/** + * fifo8_reset: + * @fifo: FIFO to reset + * + * Reset a FIFO. All data is discarded and the FIFO is emptied. + */ + +void fifo8_reset(Fifo8 *fifo); + +/** + * fifo8_is_empty: + * @fifo: FIFO to check + * + * Check if a FIFO is empty. + * + * Returns: True if the fifo is empty, false otherwise. + */ + +bool fifo8_is_empty(Fifo8 *fifo); + +/** + * fifo8_is_full: + * @fifo: FIFO to check + * + * Check if a FIFO is full. + * + * Returns: True if the fifo is full, false otherwise. + */ + +bool fifo8_is_full(Fifo8 *fifo); + +extern const VMStateDescription vmstate_fifo8; + +#define VMSTATE_FIFO8(_field, _state) { \ + .name = (stringify(_field)), \ + .size = sizeof(Fifo8), \ + .vmsd = &vmstate_fifo8, \ + .flags = VMS_STRUCT, \ + .offset = vmstate_offset_value(_state, _field, Fifo8), \ +} + +#endif /* FIFO_H */ -- cgit v1.2.3 From 82a2499011a73bcafab723e1bab4127e55a64844 Mon Sep 17 00:00:00 2001 From: "Peter A. G. Crosthwaite" Date: Mon, 26 Mar 2012 22:10:59 +1000 Subject: m25p80: Initial implementation of SPI flash device Added device model for m25p80 style SPI flash family. Signed-off-by: Peter A. G. Crosthwaite --- default-configs/arm-softmmu.mak | 1 + default-configs/microblaze-softmmu.mak | 2 + default-configs/microblazeel-softmmu.mak | 2 + hw/Makefile.objs | 1 + hw/m25p80.c | 598 +++++++++++++++++++++++++++++++ 5 files changed, 604 insertions(+) create mode 100644 hw/m25p80.c diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index f335a725f..2f1a5c994 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -22,6 +22,7 @@ CONFIG_ADS7846=y CONFIG_MAX111X=y CONFIG_SSI=y CONFIG_SSI_SD=y +CONFIG_SSI_M25P80=y CONFIG_LAN9118=y CONFIG_SMC91C111=y CONFIG_DS1338=y diff --git a/default-configs/microblaze-softmmu.mak b/default-configs/microblaze-softmmu.mak index 64c9485de..2f442e5ae 100644 --- a/default-configs/microblaze-softmmu.mak +++ b/default-configs/microblaze-softmmu.mak @@ -5,3 +5,5 @@ CONFIG_PFLASH_CFI01=y CONFIG_SERIAL=y CONFIG_XILINX=y CONFIG_XILINX_AXI=y +CONFIG_SSI=y +CONFIG_SSI_M25P80=y diff --git a/default-configs/microblazeel-softmmu.mak b/default-configs/microblazeel-softmmu.mak index a9622760c..af9a3cde0 100644 --- a/default-configs/microblazeel-softmmu.mak +++ b/default-configs/microblazeel-softmmu.mak @@ -5,3 +5,5 @@ CONFIG_PFLASH_CFI01=y CONFIG_SERIAL=y CONFIG_XILINX=y CONFIG_XILINX_AXI=y +CONFIG_SSI=y +CONFIG_SSI_M25P80=y diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 66abbb2c7..854faa9b5 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -174,6 +174,7 @@ common-obj-y += scsi-disk.o cdrom.o hd-geometry.o block-common.o common-obj-y += scsi-generic.o scsi-bus.o common-obj-y += hid.o common-obj-$(CONFIG_SSI) += ssi.o +common-obj-$(CONFIG_SSI_M25P80) += m25p80.o common-obj-$(CONFIG_SSI_SD) += ssi-sd.o common-obj-$(CONFIG_SD) += sd.o common-obj-y += bt.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o diff --git a/hw/m25p80.c b/hw/m25p80.c new file mode 100644 index 000000000..9a56de802 --- /dev/null +++ b/hw/m25p80.c @@ -0,0 +1,598 @@ +/* + * ST M25P80 emulator. Emulate all SPI flash devices based on the m25p80 command + * set. Known devices table current as of Jun/2012 and taken from linux. + * See drivers/mtd/devices/m25p80.c. + * + * Copyright (C) 2011 Edgar E. Iglesias + * Copyright (C) 2012 Peter A. G. Crosthwaite + * Copyright (C) 2012 PetaLogix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) a later version of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "hw.h" +#include "blockdev.h" +#include "ssi.h" +#include "devices.h" + +#ifdef M25P80_ERR_DEBUG +#define DB_PRINT(...) do { \ + fprintf(stderr, ": %s: ", __func__); \ + fprintf(stderr, ## __VA_ARGS__); \ + } while (0); +#else + #define DB_PRINT(...) +#endif + +/* Fields for FlashPartInfo->flags */ + +/* erase capabilities */ +#define ER_4K 1 +#define ER_32K 2 +/* set to allow the page program command to write 0s back to 1. Useful for + * modelling EEPROM with SPI flash command set + */ +#define WR_1 0x100 + +typedef struct FlashPartInfo { + const char *part_name; + /* jedec code. (jedec >> 16) & 0xff is the 1st byte, >> 8 the 2nd etc */ + uint32_t jedec; + /* extended jedec code */ + uint16_t ext_jedec; + /* there is confusion between manufacturers as to what a sector is. In this + * device model, a "sector" is the size that is erased by the ERASE_SECTOR + * command (opcode 0xd8). + */ + uint32_t sector_size; + uint32_t n_sectors; + uint32_t page_size; + uint8_t flags; +} FlashPartInfo; + +/* adapted from linux */ + +#define INFO(_part_name, _jedec, _ext_jedec, _sector_size, _n_sectors, _flags)\ + .part_name = (_part_name),\ + .jedec = (_jedec),\ + .ext_jedec = (_ext_jedec),\ + .sector_size = (_sector_size),\ + .n_sectors = (_n_sectors),\ + .page_size = 256,\ + .flags = (_flags),\ + +static const FlashPartInfo known_devices[] = { + /* Atmel -- some are (confusingly) marketed as "DataFlash" */ + { INFO("at25fs010", 0x1f6601, 0, 32 << 10, 4, ER_4K) }, + { INFO("at25fs040", 0x1f6604, 0, 64 << 10, 8, ER_4K) }, + + { INFO("at25df041a", 0x1f4401, 0, 64 << 10, 8, ER_4K) }, + { INFO("at25df321a", 0x1f4701, 0, 64 << 10, 64, ER_4K) }, + { INFO("at25df641", 0x1f4800, 0, 64 << 10, 128, ER_4K) }, + + { INFO("at26f004", 0x1f0400, 0, 64 << 10, 8, ER_4K) }, + { INFO("at26df081a", 0x1f4501, 0, 64 << 10, 16, ER_4K) }, + { INFO("at26df161a", 0x1f4601, 0, 64 << 10, 32, ER_4K) }, + { INFO("at26df321", 0x1f4700, 0, 64 << 10, 64, ER_4K) }, + + /* EON -- en25xxx */ + { INFO("en25f32", 0x1c3116, 0, 64 << 10, 64, ER_4K) }, + { INFO("en25p32", 0x1c2016, 0, 64 << 10, 64, 0) }, + { INFO("en25q32b", 0x1c3016, 0, 64 << 10, 64, 0) }, + { INFO("en25p64", 0x1c2017, 0, 64 << 10, 128, 0) }, + + /* Intel/Numonyx -- xxxs33b */ + { INFO("160s33b", 0x898911, 0, 64 << 10, 32, 0) }, + { INFO("320s33b", 0x898912, 0, 64 << 10, 64, 0) }, + { INFO("640s33b", 0x898913, 0, 64 << 10, 128, 0) }, + + /* Macronix */ + { INFO("mx25l4005a", 0xc22013, 0, 64 << 10, 8, ER_4K) }, + { INFO("mx25l8005", 0xc22014, 0, 64 << 10, 16, 0) }, + { INFO("mx25l1606e", 0xc22015, 0, 64 << 10, 32, ER_4K) }, + { INFO("mx25l3205d", 0xc22016, 0, 64 << 10, 64, 0) }, + { INFO("mx25l6405d", 0xc22017, 0, 64 << 10, 128, 0) }, + { INFO("mx25l12805d", 0xc22018, 0, 64 << 10, 256, 0) }, + { INFO("mx25l12855e", 0xc22618, 0, 64 << 10, 256, 0) }, + { INFO("mx25l25635e", 0xc22019, 0, 64 << 10, 512, 0) }, + { INFO("mx25l25655e", 0xc22619, 0, 64 << 10, 512, 0) }, + + /* Spansion -- single (large) sector size only, at least + * for the chips listed here (without boot sectors). + */ + { INFO("s25sl004a", 0x010212, 0, 64 << 10, 8, 0) }, + { INFO("s25sl008a", 0x010213, 0, 64 << 10, 16, 0) }, + { INFO("s25sl016a", 0x010214, 0, 64 << 10, 32, 0) }, + { INFO("s25sl032a", 0x010215, 0, 64 << 10, 64, 0) }, + { INFO("s25sl032p", 0x010215, 0x4d00, 64 << 10, 64, ER_4K) }, + { INFO("s25sl064a", 0x010216, 0, 64 << 10, 128, 0) }, + { INFO("s25fl256s0", 0x010219, 0x4d00, 256 << 10, 128, 0) }, + { INFO("s25fl256s1", 0x010219, 0x4d01, 64 << 10, 512, 0) }, + { INFO("s25fl512s", 0x010220, 0x4d00, 256 << 10, 256, 0) }, + { INFO("s70fl01gs", 0x010221, 0x4d00, 256 << 10, 256, 0) }, + { INFO("s25sl12800", 0x012018, 0x0300, 256 << 10, 64, 0) }, + { INFO("s25sl12801", 0x012018, 0x0301, 64 << 10, 256, 0) }, + { INFO("s25fl129p0", 0x012018, 0x4d00, 256 << 10, 64, 0) }, + { INFO("s25fl129p1", 0x012018, 0x4d01, 64 << 10, 256, 0) }, + { INFO("s25fl016k", 0xef4015, 0, 64 << 10, 32, ER_4K | ER_32K) }, + { INFO("s25fl064k", 0xef4017, 0, 64 << 10, 128, ER_4K | ER_32K) }, + + /* SST -- large erase sizes are "overlays", "sectors" are 4<< 10 */ + { INFO("sst25vf040b", 0xbf258d, 0, 64 << 10, 8, ER_4K) }, + { INFO("sst25vf080b", 0xbf258e, 0, 64 << 10, 16, ER_4K) }, + { INFO("sst25vf016b", 0xbf2541, 0, 64 << 10, 32, ER_4K) }, + { INFO("sst25vf032b", 0xbf254a, 0, 64 << 10, 64, ER_4K) }, + { INFO("sst25wf512", 0xbf2501, 0, 64 << 10, 1, ER_4K) }, + { INFO("sst25wf010", 0xbf2502, 0, 64 << 10, 2, ER_4K) }, + { INFO("sst25wf020", 0xbf2503, 0, 64 << 10, 4, ER_4K) }, + { INFO("sst25wf040", 0xbf2504, 0, 64 << 10, 8, ER_4K) }, + + /* ST Microelectronics -- newer production may have feature updates */ + { INFO("m25p05", 0x202010, 0, 32 << 10, 2, 0) }, + { INFO("m25p10", 0x202011, 0, 32 << 10, 4, 0) }, + { INFO("m25p20", 0x202012, 0, 64 << 10, 4, 0) }, + { INFO("m25p40", 0x202013, 0, 64 << 10, 8, 0) }, + { INFO("m25p80", 0x202014, 0, 64 << 10, 16, 0) }, + { INFO("m25p16", 0x202015, 0, 64 << 10, 32, 0) }, + { INFO("m25p32", 0x202016, 0, 64 << 10, 64, 0) }, + { INFO("m25p64", 0x202017, 0, 64 << 10, 128, 0) }, + { INFO("m25p128", 0x202018, 0, 256 << 10, 64, 0) }, + + { INFO("m45pe10", 0x204011, 0, 64 << 10, 2, 0) }, + { INFO("m45pe80", 0x204014, 0, 64 << 10, 16, 0) }, + { INFO("m45pe16", 0x204015, 0, 64 << 10, 32, 0) }, + + { INFO("m25pe80", 0x208014, 0, 64 << 10, 16, 0) }, + { INFO("m25pe16", 0x208015, 0, 64 << 10, 32, ER_4K) }, + + { INFO("m25px32", 0x207116, 0, 64 << 10, 64, ER_4K) }, + { INFO("m25px32-s0", 0x207316, 0, 64 << 10, 64, ER_4K) }, + { INFO("m25px32-s1", 0x206316, 0, 64 << 10, 64, ER_4K) }, + { INFO("m25px64", 0x207117, 0, 64 << 10, 128, 0) }, + + /* Winbond -- w25x "blocks" are 64k, "sectors" are 4KiB */ + { INFO("w25x10", 0xef3011, 0, 64 << 10, 2, ER_4K) }, + { INFO("w25x20", 0xef3012, 0, 64 << 10, 4, ER_4K) }, + { INFO("w25x40", 0xef3013, 0, 64 << 10, 8, ER_4K) }, + { INFO("w25x80", 0xef3014, 0, 64 << 10, 16, ER_4K) }, + { INFO("w25x16", 0xef3015, 0, 64 << 10, 32, ER_4K) }, + { INFO("w25x32", 0xef3016, 0, 64 << 10, 64, ER_4K) }, + { INFO("w25q32", 0xef4016, 0, 64 << 10, 64, ER_4K) }, + { INFO("w25x64", 0xef3017, 0, 64 << 10, 128, ER_4K) }, + { INFO("w25q64", 0xef4017, 0, 64 << 10, 128, ER_4K) }, + + /* Numonyx -- n25q128 */ + { INFO("n25q128", 0x20ba18, 0, 64 << 10, 256, 0) }, + + { }, +}; + +typedef enum { + NOP = 0, + PP = 0x2, + READ = 0x3, + WRDI = 0x4, + RDSR = 0x5, + WREN = 0x6, + FAST_READ = 0xb, + ERASE_4K = 0x20, + ERASE_32K = 0x52, + ERASE_SECTOR = 0xd8, + JEDEC_READ = 0x9f, + BULK_ERASE = 0xc7, +} FlashCMD; + +typedef enum { + STATE_IDLE, + STATE_PAGE_PROGRAM, + STATE_READ, + STATE_COLLECTING_DATA, + STATE_READING_DATA, +} CMDState; + +typedef struct Flash { + SSISlave ssidev; + uint32_t r; + + BlockDriverState *bdrv; + + uint8_t *storage; + uint32_t size; + int page_size; + + uint8_t state; + uint8_t data[16]; + uint32_t len; + uint32_t pos; + uint8_t needed_bytes; + uint8_t cmd_in_progress; + uint64_t cur_addr; + bool write_enable; + + int64_t dirty_page; + + char *part_name; + const FlashPartInfo *pi; + +} Flash; + +static void bdrv_sync_complete(void *opaque, int ret) +{ + /* do nothing. Masters do not directly interact with the backing store, + * only the working copy so no mutexing required. + */ +} + +static void flash_sync_page(Flash *s, int page) +{ + if (s->bdrv) { + int bdrv_sector, nb_sectors; + QEMUIOVector iov; + + bdrv_sector = (page * s->pi->page_size) / BDRV_SECTOR_SIZE; + nb_sectors = DIV_ROUND_UP(s->pi->page_size, BDRV_SECTOR_SIZE); + qemu_iovec_init(&iov, 1); + qemu_iovec_add(&iov, s->storage + bdrv_sector * BDRV_SECTOR_SIZE, + nb_sectors * BDRV_SECTOR_SIZE); + bdrv_aio_writev(s->bdrv, bdrv_sector, &iov, nb_sectors, + bdrv_sync_complete, NULL); + } +} + +static inline void flash_sync_area(Flash *s, int64_t off, int64_t len) +{ + int64_t start, end, nb_sectors; + QEMUIOVector iov; + + if (!s->bdrv) { + return; + } + + assert(!(len % BDRV_SECTOR_SIZE)); + start = off / BDRV_SECTOR_SIZE; + end = (off + len) / BDRV_SECTOR_SIZE; + nb_sectors = end - start; + qemu_iovec_init(&iov, 1); + qemu_iovec_add(&iov, s->storage + (start * BDRV_SECTOR_SIZE), + nb_sectors * BDRV_SECTOR_SIZE); + bdrv_aio_writev(s->bdrv, start, &iov, nb_sectors, bdrv_sync_complete, NULL); +} + +static void flash_erase(Flash *s, int offset, FlashCMD cmd) +{ + uint32_t len; + uint8_t capa_to_assert = 0; + + switch (cmd) { + case ERASE_4K: + len = 4 << 10; + capa_to_assert = ER_4K; + break; + case ERASE_32K: + len = 32 << 10; + capa_to_assert = ER_32K; + break; + case ERASE_SECTOR: + len = s->pi->sector_size; + break; + case BULK_ERASE: + len = s->size; + break; + default: + abort(); + } + + DB_PRINT("offset = %#x, len = %d\n", offset, len); + if ((s->pi->flags & capa_to_assert) != capa_to_assert) { + hw_error("m25p80: %dk erase size not supported by device\n", len); + } + + if (!s->write_enable) { + DB_PRINT("erase with write protect!\n"); + return; + } + memset(s->storage + offset, 0xff, len); + flash_sync_area(s, offset, len); +} + +static inline void flash_sync_dirty(Flash *s, int64_t newpage) +{ + if (s->dirty_page >= 0 && s->dirty_page != newpage) { + flash_sync_page(s, s->dirty_page); + s->dirty_page = newpage; + } +} + +static inline +void flash_write8(Flash *s, uint64_t addr, uint8_t data) +{ + int64_t page = addr / s->pi->page_size; + uint8_t prev = s->storage[s->cur_addr]; + + if (!s->write_enable) { + DB_PRINT("write with write protect!\n"); + } + + if ((prev ^ data) & data) { + DB_PRINT("programming zero to one! addr=%lx %x -> %x\n", + addr, prev, data); + } + + if (s->pi->flags & WR_1) { + s->storage[s->cur_addr] = data; + } else { + s->storage[s->cur_addr] &= data; + } + + flash_sync_dirty(s, page); + s->dirty_page = page; +} + +static void complete_collecting_data(Flash *s) +{ + s->cur_addr = s->data[0] << 16; + s->cur_addr |= s->data[1] << 8; + s->cur_addr |= s->data[2]; + + switch (s->cmd_in_progress) { + case PP: + s->state = STATE_PAGE_PROGRAM; + break; + case READ: + case FAST_READ: + s->state = STATE_READ; + break; + case ERASE_4K: + case ERASE_32K: + case ERASE_SECTOR: + flash_erase(s, s->cur_addr, s->cmd_in_progress); + break; + default: + break; + } +} + +static void decode_new_cmd(Flash *s, uint32_t value) +{ + s->cmd_in_progress = value; + DB_PRINT("decoded new command:%x\n", value); + + switch (value) { + + case ERASE_4K: + case ERASE_32K: + case ERASE_SECTOR: + case READ: + case PP: + s->needed_bytes = 3; + s->pos = 0; + s->len = 0; + s->state = STATE_COLLECTING_DATA; + break; + + case FAST_READ: + s->needed_bytes = 4; + s->pos = 0; + s->len = 0; + s->state = STATE_COLLECTING_DATA; + break; + + case WRDI: + s->write_enable = false; + break; + case WREN: + s->write_enable = true; + break; + + case RDSR: + s->data[0] = (!!s->write_enable) << 1; + s->pos = 0; + s->len = 1; + s->state = STATE_READING_DATA; + break; + + case JEDEC_READ: + DB_PRINT("populated jedec code\n"); + s->data[0] = (s->pi->jedec >> 16) & 0xff; + s->data[1] = (s->pi->jedec >> 8) & 0xff; + s->data[2] = s->pi->jedec & 0xff; + if (s->pi->ext_jedec) { + s->data[3] = (s->pi->ext_jedec >> 8) & 0xff; + s->data[4] = s->pi->ext_jedec & 0xff; + s->len = 5; + } else { + s->len = 3; + } + s->pos = 0; + s->state = STATE_READING_DATA; + break; + + case BULK_ERASE: + if (s->write_enable) { + DB_PRINT("chip erase\n"); + flash_erase(s, 0, BULK_ERASE); + } else { + DB_PRINT("chip erase with write protect!\n"); + } + break; + case NOP: + break; + default: + DB_PRINT("Unknown cmd %x\n", value); + break; + } +} + +static int m25p80_cs(SSISlave *ss, bool select) +{ + Flash *s = FROM_SSI_SLAVE(Flash, ss); + + if (select) { + s->len = 0; + s->pos = 0; + s->state = STATE_IDLE; + flash_sync_dirty(s, -1); + } + + DB_PRINT("%sselect\n", select ? "de" : ""); + + return 0; +} + +static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx) +{ + Flash *s = FROM_SSI_SLAVE(Flash, ss); + uint32_t r = 0; + + switch (s->state) { + + case STATE_PAGE_PROGRAM: + DB_PRINT("page program cur_addr=%lx data=%x\n", s->cur_addr, + (uint8_t)tx); + flash_write8(s, s->cur_addr, (uint8_t)tx); + s->cur_addr++; + break; + + case STATE_READ: + r = s->storage[s->cur_addr]; + DB_PRINT("READ 0x%lx=%x\n", s->cur_addr, r); + s->cur_addr = (s->cur_addr + 1) % s->size; + break; + + case STATE_COLLECTING_DATA: + s->data[s->len] = (uint8_t)tx; + s->len++; + + if (s->len == s->needed_bytes) { + complete_collecting_data(s); + } + break; + + case STATE_READING_DATA: + r = s->data[s->pos]; + s->pos++; + if (s->pos == s->len) { + s->pos = 0; + s->state = STATE_IDLE; + } + break; + + default: + case STATE_IDLE: + decode_new_cmd(s, (uint8_t)tx); + break; + } + + return r; +} + +static int m25p80_init(SSISlave *ss) +{ + DriveInfo *dinfo; + Flash *s = FROM_SSI_SLAVE(Flash, ss); + const FlashPartInfo *i; + + if (!s->part_name) { /* default to actual m25p80 if no partname given */ + s->part_name = (char *)"m25p80"; + } + + i = known_devices; + for (i = known_devices;; i++) { + assert(i); + if (!i->part_name) { + fprintf(stderr, "Unknown SPI flash part: \"%s\"\n", s->part_name); + return 1; + } else if (!strcmp(i->part_name, s->part_name)) { + s->pi = i; + break; + } + } + + s->size = s->pi->sector_size * s->pi->n_sectors; + s->dirty_page = -1; + s->storage = qemu_blockalign(s->bdrv, s->size); + + dinfo = drive_get_next(IF_MTD); + + if (dinfo && dinfo->bdrv) { + DB_PRINT("Binding to IF_MTD drive\n"); + s->bdrv = dinfo->bdrv; + /* FIXME: Move to late init */ + if (bdrv_read(s->bdrv, 0, s->storage, DIV_ROUND_UP(s->size, + BDRV_SECTOR_SIZE))) { + fprintf(stderr, "Failed to initialize SPI flash!\n"); + return 1; + } + } else { + memset(s->storage, 0xFF, s->size); + } + + return 0; +} + +static void m25p80_pre_save(void *opaque) +{ + flash_sync_dirty((Flash *)opaque, -1); +} + +static const VMStateDescription vmstate_m25p80 = { + .name = "xilinx_spi", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .pre_save = m25p80_pre_save, + .fields = (VMStateField[]) { + VMSTATE_UINT8(state, Flash), + VMSTATE_UINT8_ARRAY(data, Flash, 16), + VMSTATE_UINT32(len, Flash), + VMSTATE_UINT32(pos, Flash), + VMSTATE_UINT8(needed_bytes, Flash), + VMSTATE_UINT8(cmd_in_progress, Flash), + VMSTATE_UINT64(cur_addr, Flash), + VMSTATE_BOOL(write_enable, Flash), + VMSTATE_END_OF_LIST() + } +}; + +static Property m25p80_properties[] = { + DEFINE_PROP_STRING("partname", Flash, part_name), + DEFINE_PROP_END_OF_LIST(), +}; + +static void m25p80_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SSISlaveClass *k = SSI_SLAVE_CLASS(klass); + + k->init = m25p80_init; + k->transfer = m25p80_transfer8; + k->set_cs = m25p80_cs; + k->cs_polarity = SSI_CS_LOW; + dc->props = m25p80_properties; + dc->vmsd = &vmstate_m25p80; +} + +static const TypeInfo m25p80_info = { + .name = "m25p80", + .parent = TYPE_SSI_SLAVE, + .instance_size = sizeof(Flash), + .class_init = m25p80_class_init, +}; + +static void m25p80_register_types(void) +{ + type_register_static(&m25p80_info); +} + +type_init(m25p80_register_types) -- cgit v1.2.3 From 929d1b52c43327b8a9e5a19f916ad6c9d1e6de5d Mon Sep 17 00:00:00 2001 From: "Peter A. G. Crosthwaite" Date: Mon, 26 Mar 2012 22:59:55 +1000 Subject: xilinx_spi: Initial impl. of Xilinx SPI controller Device model for xilinx XPS SPI controller (v2.0) Signed-off-by: Peter A. G. Crosthwaite --- hw/microblaze/Makefile.objs | 1 + hw/xilinx_spi.c | 383 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 384 insertions(+) create mode 100644 hw/xilinx_spi.c diff --git a/hw/microblaze/Makefile.objs b/hw/microblaze/Makefile.objs index 274d2c543..3028e651c 100644 --- a/hw/microblaze/Makefile.objs +++ b/hw/microblaze/Makefile.objs @@ -1,6 +1,7 @@ obj-y = petalogix_s3adsp1800_mmu.o obj-y += petalogix_ml605_mmu.o obj-y += microblaze_boot.o +obj-y += xilinx_spi.o obj-y += microblaze_pic_cpu.o obj-y += xilinx_ethlite.o diff --git a/hw/xilinx_spi.c b/hw/xilinx_spi.c new file mode 100644 index 000000000..7db47877e --- /dev/null +++ b/hw/xilinx_spi.c @@ -0,0 +1,383 @@ +/* + * QEMU model of the Xilinx SPI Controller + * + * Copyright (C) 2010 Edgar E. Iglesias. + * Copyright (C) 2012 Peter A. G. Crosthwaite + * Copyright (C) 2012 PetaLogix + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "sysbus.h" +#include "sysemu.h" +#include "qemu-log.h" +#include "fifo.h" + +#include "ssi.h" + +#ifdef XILINX_SPI_ERR_DEBUG +#define DB_PRINT(...) do { \ + fprintf(stderr, ": %s: ", __func__); \ + fprintf(stderr, ## __VA_ARGS__); \ + } while (0); +#else + #define DB_PRINT(...) +#endif + +#define R_DGIER (0x1c / 4) +#define R_DGIER_IE (1 << 31) + +#define R_IPISR (0x20 / 4) +#define IRQ_DRR_NOT_EMPTY (1 << (31 - 23)) +#define IRQ_DRR_OVERRUN (1 << (31 - 26)) +#define IRQ_DRR_FULL (1 << (31 - 27)) +#define IRQ_TX_FF_HALF_EMPTY (1 << 6) +#define IRQ_DTR_UNDERRUN (1 << 3) +#define IRQ_DTR_EMPTY (1 << (31 - 29)) + +#define R_IPIER (0x28 / 4) +#define R_SRR (0x40 / 4) +#define R_SPICR (0x60 / 4) +#define R_SPICR_TXFF_RST (1 << 5) +#define R_SPICR_RXFF_RST (1 << 6) +#define R_SPICR_MTI (1 << 8) + +#define R_SPISR (0x64 / 4) +#define SR_TX_FULL (1 << 3) +#define SR_TX_EMPTY (1 << 2) +#define SR_RX_FULL (1 << 1) +#define SR_RX_EMPTY (1 << 0) + +#define R_SPIDTR (0x68 / 4) +#define R_SPIDRR (0x6C / 4) +#define R_SPISSR (0x70 / 4) +#define R_TX_FF_OCY (0x74 / 4) +#define R_RX_FF_OCY (0x78 / 4) +#define R_MAX (0x7C / 4) + +#define FIFO_CAPACITY 256 + +typedef struct XilinxSPI { + SysBusDevice busdev; + MemoryRegion mmio; + + qemu_irq irq; + int irqline; + + uint8_t num_cs; + qemu_irq *cs_lines; + + SSIBus *spi; + + Fifo8 rx_fifo; + Fifo8 tx_fifo; + + uint32_t regs[R_MAX]; +} XilinxSPI; + +static void txfifo_reset(XilinxSPI *s) +{ + fifo8_reset(&s->tx_fifo); + + s->regs[R_SPISR] &= ~SR_TX_FULL; + s->regs[R_SPISR] |= SR_TX_EMPTY; +} + +static void rxfifo_reset(XilinxSPI *s) +{ + fifo8_reset(&s->rx_fifo); + + s->regs[R_SPISR] |= SR_RX_EMPTY; + s->regs[R_SPISR] &= ~SR_RX_FULL; +} + +static void xlx_spi_update_cs(XilinxSPI *s) +{ + int i; + + for (i = 0; i < s->num_cs; ++i) { + qemu_set_irq(s->cs_lines[i], !(~s->regs[R_SPISSR] & 1 << i)); + } +} + +static void xlx_spi_update_irq(XilinxSPI *s) +{ + uint32_t pending; + + s->regs[R_IPISR] |= + (!fifo8_is_empty(&s->rx_fifo) ? IRQ_DRR_NOT_EMPTY : 0) | + (fifo8_is_full(&s->rx_fifo) ? IRQ_DRR_FULL : 0); + + pending = s->regs[R_IPISR] & s->regs[R_IPIER]; + + pending = pending && (s->regs[R_DGIER] & R_DGIER_IE); + pending = !!pending; + + /* This call lies right in the data paths so don't call the + irq chain unless things really changed. */ + if (pending != s->irqline) { + s->irqline = pending; + DB_PRINT("irq_change of state %d ISR:%x IER:%X\n", + pending, s->regs[R_IPISR], s->regs[R_IPIER]); + qemu_set_irq(s->irq, pending); + } + +} + +static void xlx_spi_do_reset(XilinxSPI *s) +{ + memset(s->regs, 0, sizeof s->regs); + + rxfifo_reset(s); + txfifo_reset(s); + + s->regs[R_SPISSR] = ~0; + xlx_spi_update_irq(s); + xlx_spi_update_cs(s); +} + +static void xlx_spi_reset(DeviceState *d) +{ + xlx_spi_do_reset(DO_UPCAST(XilinxSPI, busdev.qdev, d)); +} + +static inline int spi_master_enabled(XilinxSPI *s) +{ + return !(s->regs[R_SPICR] & R_SPICR_MTI); +} + +static void spi_flush_txfifo(XilinxSPI *s) +{ + uint32_t tx; + uint32_t rx; + + while (!fifo8_is_empty(&s->tx_fifo)) { + tx = (uint32_t)fifo8_pop(&s->tx_fifo); + DB_PRINT("data tx:%x\n", tx); + rx = ssi_transfer(s->spi, tx); + DB_PRINT("data rx:%x\n", rx); + if (fifo8_is_full(&s->rx_fifo)) { + s->regs[R_IPISR] |= IRQ_DRR_OVERRUN; + } else { + fifo8_push(&s->rx_fifo, (uint8_t)rx); + if (fifo8_is_full(&s->rx_fifo)) { + s->regs[R_SPISR] |= SR_RX_FULL; + s->regs[R_IPISR] |= IRQ_DRR_FULL; + } + } + + s->regs[R_SPISR] &= ~SR_RX_EMPTY; + s->regs[R_SPISR] &= ~SR_TX_FULL; + s->regs[R_SPISR] |= SR_TX_EMPTY; + + s->regs[R_IPISR] |= IRQ_DTR_EMPTY; + s->regs[R_IPISR] |= IRQ_DRR_NOT_EMPTY; + } + +} + +static uint64_t +spi_read(void *opaque, target_phys_addr_t addr, unsigned int size) +{ + XilinxSPI *s = opaque; + uint32_t r = 0; + + addr >>= 2; + switch (addr) { + case R_SPIDRR: + if (fifo8_is_empty(&s->rx_fifo)) { + DB_PRINT("Read from empty FIFO!\n"); + return 0xdeadbeef; + } + + s->regs[R_SPISR] &= ~SR_RX_FULL; + r = fifo8_pop(&s->rx_fifo); + if (fifo8_is_empty(&s->rx_fifo)) { + s->regs[R_SPISR] |= SR_RX_EMPTY; + } + break; + + case R_SPISR: + r = s->regs[addr]; + break; + + default: + if (addr < ARRAY_SIZE(s->regs)) { + r = s->regs[addr]; + } + break; + + } + DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, r); + xlx_spi_update_irq(s); + return r; +} + +static void +spi_write(void *opaque, target_phys_addr_t addr, + uint64_t val64, unsigned int size) +{ + XilinxSPI *s = opaque; + uint32_t value = val64; + + DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr, value); + addr >>= 2; + switch (addr) { + case R_SRR: + if (value != 0xa) { + DB_PRINT("Invalid write to SRR %x\n", value); + } else { + xlx_spi_do_reset(s); + } + break; + + case R_SPIDTR: + s->regs[R_SPISR] &= ~SR_TX_EMPTY; + fifo8_push(&s->tx_fifo, (uint8_t)value); + if (fifo8_is_full(&s->tx_fifo)) { + s->regs[R_SPISR] |= SR_TX_FULL; + } + if (!spi_master_enabled(s)) { + goto done; + } else { + DB_PRINT("DTR and master enabled\n"); + } + spi_flush_txfifo(s); + break; + + case R_SPISR: + DB_PRINT("Invalid write to SPISR %x\n", value); + break; + + case R_IPISR: + /* Toggle the bits. */ + s->regs[addr] ^= value; + break; + + /* Slave Select Register. */ + case R_SPISSR: + s->regs[addr] = value; + xlx_spi_update_cs(s); + break; + + case R_SPICR: + /* FIXME: reset irq and sr state to empty queues. */ + if (value & R_SPICR_RXFF_RST) { + rxfifo_reset(s); + } + + if (value & R_SPICR_TXFF_RST) { + txfifo_reset(s); + } + value &= ~(R_SPICR_RXFF_RST | R_SPICR_TXFF_RST); + s->regs[addr] = value; + + if (!(value & R_SPICR_MTI)) { + spi_flush_txfifo(s); + } + break; + + default: + if (addr < ARRAY_SIZE(s->regs)) { + s->regs[addr] = value; + } + break; + } + +done: + xlx_spi_update_irq(s); +} + +static const MemoryRegionOps spi_ops = { + .read = spi_read, + .write = spi_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4 + } +}; + +static int xilinx_spi_init(SysBusDevice *dev) +{ + int i; + XilinxSPI *s = FROM_SYSBUS(typeof(*s), dev); + + DB_PRINT("\n"); + sysbus_init_irq(dev, &s->irq); + s->cs_lines = g_new(qemu_irq, s->num_cs); + for (i = 0; i < s->num_cs; ++i) { + sysbus_init_irq(dev, &s->cs_lines[i]); + } + + memory_region_init_io(&s->mmio, &spi_ops, s, "xilinx-spi", R_MAX * 4); + sysbus_init_mmio(dev, &s->mmio); + + s->irqline = -1; + + s->spi = ssi_create_bus(&dev->qdev, "spi"); + + fifo8_create(&s->tx_fifo, FIFO_CAPACITY); + fifo8_create(&s->rx_fifo, FIFO_CAPACITY); + + return 0; +} + +static const VMStateDescription vmstate_xilinx_spi = { + .name = "xilinx_spi", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_FIFO8(tx_fifo, XilinxSPI), + VMSTATE_FIFO8(rx_fifo, XilinxSPI), + VMSTATE_UINT32_ARRAY(regs, XilinxSPI, R_MAX), + VMSTATE_END_OF_LIST() + } +}; + +static Property xilinx_spi_properties[] = { + DEFINE_PROP_UINT8("num-ss-bits", XilinxSPI, num_cs, 1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void xilinx_spi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = xilinx_spi_init; + dc->reset = xlx_spi_reset; + dc->props = xilinx_spi_properties; + dc->vmsd = &vmstate_xilinx_spi; +} + +static TypeInfo xilinx_spi_info = { + .name = "xlnx.xps-spi", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(XilinxSPI), + .class_init = xilinx_spi_class_init, +}; + +static void xilinx_spi_register_types(void) +{ + type_register_static(&xilinx_spi_info); +} + +type_init(xilinx_spi_register_types) -- cgit v1.2.3 From acd3b6be325a66f8f10f0eed19ed5261ced411cf Mon Sep 17 00:00:00 2001 From: "Peter A. G. Crosthwaite" Date: Tue, 27 Mar 2012 17:57:47 +1000 Subject: petalogix-ml605: added SPI controller with n25q128 Added SPI controller to the reference design, with two n25q128 spi-flashes connected. Signed-off-by: Peter A. G. Crosthwaite Acked-by: Peter Maydell --- hw/petalogix_ml605_mmu.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c index dced648f4..b9bfbed4c 100644 --- a/hw/petalogix_ml605_mmu.c +++ b/hw/petalogix_ml605_mmu.c @@ -36,6 +36,7 @@ #include "blockdev.h" #include "pc.h" #include "exec-memory.h" +#include "ssi.h" #include "microblaze_boot.h" #include "microblaze_pic_cpu.h" @@ -47,6 +48,8 @@ #define BINARY_DEVICE_TREE_FILE "petalogix-ml605.dtb" +#define NUM_SPI_FLASHES 4 + #define MEMORY_BASEADDR 0x50000000 #define FLASH_BASEADDR 0x86000000 #define INTC_BASEADDR 0x81800000 @@ -79,6 +82,7 @@ petalogix_ml605_init(ram_addr_t ram_size, MemoryRegion *address_space_mem = get_system_memory(); DeviceState *dev, *dma, *eth0; MicroBlazeCPU *cpu; + SysBusDevice *busdev; CPUMBState *env; DriveInfo *dinfo; int i; @@ -139,6 +143,29 @@ petalogix_ml605_init(ram_addr_t ram_size, xilinx_axiethernetdma_init(dma, STREAM_SLAVE(eth0), 0x84600000, irq[1], irq[0], 100 * 1000000); + { + SSIBus *spi; + + dev = qdev_create(NULL, "xlnx.xps-spi"); + qdev_prop_set_uint8(dev, "num-ss-bits", NUM_SPI_FLASHES); + qdev_init_nofail(dev); + busdev = sysbus_from_qdev(dev); + sysbus_mmio_map(busdev, 0, 0x40a00000); + sysbus_connect_irq(busdev, 0, irq[4]); + + spi = (SSIBus *)qdev_get_child_bus(dev, "spi"); + + for (i = 0; i < NUM_SPI_FLASHES; i++) { + qemu_irq cs_line; + + dev = ssi_create_slave_no_init(spi, "m25p80"); + qdev_prop_set_string(dev, "partname", "n25q128"); + qdev_init_nofail(dev); + cs_line = qdev_get_gpio_in(dev, 0); + sysbus_connect_irq(busdev, i+1, cs_line); + } + } + microblaze_load_kernel(cpu, ddr_base, ram_size, BINARY_DEVICE_TREE_FILE, machine_cpu_reset); -- cgit v1.2.3 From 94befa454d430655fc863a7a855302b80f7a4812 Mon Sep 17 00:00:00 2001 From: "Peter A. G. Crosthwaite" Date: Wed, 1 Aug 2012 20:52:36 +1000 Subject: xilinx_spips: Xilinx Zynq SPI cntrlr device model Added device model for the Xilinx Zynq SPI controller (SPIPS). Signed-off-by: Peter A. G. Crosthwaite Acked-by: Peter Maydell --- hw/arm/Makefile.objs | 1 + hw/xilinx_spips.c | 352 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 353 insertions(+) create mode 100644 hw/xilinx_spips.c diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 2b39fb3c8..6d049e7de 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -1,6 +1,7 @@ obj-y = integratorcp.o versatilepb.o arm_pic.o obj-y += arm_boot.o obj-y += xilinx_zynq.o zynq_slcr.o +obj-y += xilinx_spips.o obj-y += arm_gic.o arm_gic_common.o obj-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o obj-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o diff --git a/hw/xilinx_spips.c b/hw/xilinx_spips.c new file mode 100644 index 000000000..a886c5d31 --- /dev/null +++ b/hw/xilinx_spips.c @@ -0,0 +1,352 @@ +/* + * QEMU model of the Xilinx Zynq SPI controller + * + * Copyright (c) 2012 Peter A. G. Crosthwaite + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "sysbus.h" +#include "sysemu.h" +#include "ptimer.h" +#include "qemu-log.h" +#include "fifo.h" +#include "ssi.h" + +#ifdef XILINX_SPIPS_ERR_DEBUG +#define DB_PRINT(...) do { \ + fprintf(stderr, ": %s: ", __func__); \ + fprintf(stderr, ## __VA_ARGS__); \ + } while (0); +#else + #define DB_PRINT(...) +#endif + +/* config register */ +#define R_CONFIG (0x00 / 4) +#define MODEFAIL_GEN_EN (1 << 17) +#define MAN_START_COM (1 << 16) +#define MAN_START_EN (1 << 15) +#define MANUAL_CS (1 << 14) +#define CS (0xF << 10) +#define CS_SHIFT (10) +#define PERI_SEL (1 << 9) +#define REF_CLK (1 << 8) +#define FIFO_WIDTH (3 << 6) +#define BAUD_RATE_DIV (7 << 3) +#define CLK_PH (1 << 2) +#define CLK_POL (1 << 1) +#define MODE_SEL (1 << 0) + +/* interrupt mechanism */ +#define R_INTR_STATUS (0x04 / 4) +#define R_INTR_EN (0x08 / 4) +#define R_INTR_DIS (0x0C / 4) +#define R_INTR_MASK (0x10 / 4) +#define IXR_TX_FIFO_UNDERFLOW (1 << 6) +#define IXR_RX_FIFO_FULL (1 << 5) +#define IXR_RX_FIFO_NOT_EMPTY (1 << 4) +#define IXR_TX_FIFO_FULL (1 << 3) +#define IXR_TX_FIFO_NOT_FULL (1 << 2) +#define IXR_TX_FIFO_MODE_FAIL (1 << 1) +#define IXR_RX_FIFO_OVERFLOW (1 << 0) +#define IXR_ALL ((IXR_TX_FIFO_UNDERFLOW<<1)-1) + +#define R_EN (0x14 / 4) +#define R_DELAY (0x18 / 4) +#define R_TX_DATA (0x1C / 4) +#define R_RX_DATA (0x20 / 4) +#define R_SLAVE_IDLE_COUNT (0x24 / 4) +#define R_TX_THRES (0x28 / 4) +#define R_RX_THRES (0x2C / 4) +#define R_MOD_ID (0xFC / 4) + +#define R_MAX (R_MOD_ID+1) + +/* size of TXRX FIFOs */ +#define NUM_CS_LINES 4 +#define RXFF_A 32 +#define TXFF_A 32 + +typedef struct { + SysBusDevice busdev; + MemoryRegion iomem; + qemu_irq irq; + int irqline; + + qemu_irq cs_lines[NUM_CS_LINES]; + SSIBus *spi; + + Fifo8 rx_fifo; + Fifo8 tx_fifo; + + uint32_t regs[R_MAX]; +} XilinxSPIPS; + +static void xilinx_spips_update_cs_lines(XilinxSPIPS *s) +{ + int i; + bool found = false; + int field = s->regs[R_CONFIG] >> CS_SHIFT; + + for (i = 0; i < NUM_CS_LINES; i++) { + if (~field & (1 << i) && !found) { + found = true; + DB_PRINT("selecting slave %d\n", i); + qemu_set_irq(s->cs_lines[i], 0); + } else { + qemu_set_irq(s->cs_lines[i], 1); + } + } +} + +static void xilinx_spips_update_ixr(XilinxSPIPS *s) +{ + /* These are set/cleared as they occur */ + s->regs[R_INTR_STATUS] &= (IXR_TX_FIFO_UNDERFLOW | IXR_RX_FIFO_OVERFLOW | + IXR_TX_FIFO_MODE_FAIL); + /* these are pure functions of fifo state, set them here */ + s->regs[R_INTR_STATUS] |= + (fifo8_is_full(&s->rx_fifo) ? IXR_RX_FIFO_FULL : 0) | + (s->rx_fifo.num >= s->regs[R_RX_THRES] ? IXR_RX_FIFO_NOT_EMPTY : 0) | + (fifo8_is_full(&s->tx_fifo) ? IXR_TX_FIFO_FULL : 0) | + (s->tx_fifo.num < s->regs[R_TX_THRES] ? IXR_TX_FIFO_NOT_FULL : 0); + /* drive external interrupt pin */ + int new_irqline = !!(s->regs[R_INTR_MASK] & s->regs[R_INTR_STATUS] & + IXR_ALL); + if (new_irqline != s->irqline) { + s->irqline = new_irqline; + qemu_set_irq(s->irq, s->irqline); + } +} + +static void xilinx_spips_reset(DeviceState *d) +{ + XilinxSPIPS *s = DO_UPCAST(XilinxSPIPS, busdev.qdev, d); + + int i; + for (i = 0; i < R_MAX; i++) { + s->regs[i] = 0; + } + + fifo8_reset(&s->rx_fifo); + fifo8_reset(&s->rx_fifo); + /* non zero resets */ + s->regs[R_CONFIG] |= MODEFAIL_GEN_EN; + s->regs[R_SLAVE_IDLE_COUNT] = 0xFF; + s->regs[R_TX_THRES] = 1; + s->regs[R_RX_THRES] = 1; + /* FIXME: move magic number definition somewhere sensible */ + s->regs[R_MOD_ID] = 0x01090106; + xilinx_spips_update_ixr(s); + xilinx_spips_update_cs_lines(s); +} + +static void xilinx_spips_flush_txfifo(XilinxSPIPS *s) +{ + for (;;) { + uint32_t r; + uint8_t value; + + if (fifo8_is_empty(&s->tx_fifo)) { + s->regs[R_INTR_STATUS] |= IXR_TX_FIFO_UNDERFLOW; + break; + } else { + value = fifo8_pop(&s->tx_fifo); + } + + r = ssi_transfer(s->spi, (uint32_t)value); + DB_PRINT("tx = %02x rx = %02x\n", value, r); + if (fifo8_is_full(&s->rx_fifo)) { + s->regs[R_INTR_STATUS] |= IXR_RX_FIFO_OVERFLOW; + DB_PRINT("rx FIFO overflow"); + } else { + fifo8_push(&s->rx_fifo, (uint8_t)r); + } + } + xilinx_spips_update_ixr(s); +} + +static uint64_t xilinx_spips_read(void *opaque, target_phys_addr_t addr, + unsigned size) +{ + XilinxSPIPS *s = opaque; + uint32_t mask = ~0; + uint32_t ret; + + addr >>= 2; + switch (addr) { + case R_CONFIG: + mask = 0x0002FFFF; + break; + case R_INTR_STATUS: + case R_INTR_MASK: + mask = IXR_ALL; + break; + case R_EN: + mask = 0x1; + break; + case R_SLAVE_IDLE_COUNT: + mask = 0xFF; + break; + case R_MOD_ID: + mask = 0x01FFFFFF; + break; + case R_INTR_EN: + case R_INTR_DIS: + case R_TX_DATA: + mask = 0; + break; + case R_RX_DATA: + ret = (uint32_t)fifo8_pop(&s->rx_fifo); + DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret); + xilinx_spips_update_ixr(s); + return ret; + } + DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, s->regs[addr] & mask); + return s->regs[addr] & mask; + +} + +static void xilinx_spips_write(void *opaque, target_phys_addr_t addr, + uint64_t value, unsigned size) +{ + int mask = ~0; + int man_start_com = 0; + XilinxSPIPS *s = opaque; + + DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr, (unsigned)value); + addr >>= 2; + switch (addr) { + case R_CONFIG: + mask = 0x0002FFFF; + if (value & MAN_START_COM) { + man_start_com = 1; + } + break; + case R_INTR_STATUS: + mask = IXR_ALL; + s->regs[R_INTR_STATUS] &= ~(mask & value); + goto no_reg_update; + case R_INTR_DIS: + mask = IXR_ALL; + s->regs[R_INTR_MASK] &= ~(mask & value); + goto no_reg_update; + case R_INTR_EN: + mask = IXR_ALL; + s->regs[R_INTR_MASK] |= mask & value; + goto no_reg_update; + case R_EN: + mask = 0x1; + break; + case R_SLAVE_IDLE_COUNT: + mask = 0xFF; + break; + case R_RX_DATA: + case R_INTR_MASK: + case R_MOD_ID: + mask = 0; + break; + case R_TX_DATA: + fifo8_push(&s->tx_fifo, (uint8_t)value); + goto no_reg_update; + } + s->regs[addr] = (s->regs[addr] & ~mask) | (value & mask); +no_reg_update: + if (man_start_com) { + xilinx_spips_flush_txfifo(s); + } + xilinx_spips_update_ixr(s); + xilinx_spips_update_cs_lines(s); +} + +static const MemoryRegionOps spips_ops = { + .read = xilinx_spips_read, + .write = xilinx_spips_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static int xilinx_spips_init(SysBusDevice *dev) +{ + XilinxSPIPS *s = FROM_SYSBUS(typeof(*s), dev); + int i; + + DB_PRINT("inited device model\n"); + + sysbus_init_irq(dev, &s->irq); + for (i = 0; i < NUM_CS_LINES; ++i) { + sysbus_init_irq(dev, &s->cs_lines[i]); + } + + memory_region_init_io(&s->iomem, &spips_ops, s, "spi", R_MAX*4); + sysbus_init_mmio(dev, &s->iomem); + + s->irqline = -1; + s->spi = ssi_create_bus(&dev->qdev, "spi"); + + fifo8_create(&s->rx_fifo, RXFF_A); + fifo8_create(&s->tx_fifo, TXFF_A); + + return 0; +} + +static int xilinx_spips_post_load(void *opaque, int version_id) +{ + xilinx_spips_update_ixr((XilinxSPIPS *)opaque); + xilinx_spips_update_cs_lines((XilinxSPIPS *)opaque); + return 0; +} + +static const VMStateDescription vmstate_xilinx_spips = { + .name = "xilinx_spips", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .post_load = xilinx_spips_post_load, + .fields = (VMStateField[]) { + VMSTATE_FIFO8(tx_fifo, XilinxSPIPS), + VMSTATE_FIFO8(rx_fifo, XilinxSPIPS), + VMSTATE_UINT32_ARRAY(regs, XilinxSPIPS, R_MAX), + VMSTATE_END_OF_LIST() + } +}; + +static void xilinx_spips_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = xilinx_spips_init; + dc->reset = xilinx_spips_reset; + dc->vmsd = &vmstate_xilinx_spips; +} + +static const TypeInfo xilinx_spips_info = { + .name = "xilinx,spips", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(XilinxSPIPS), + .class_init = xilinx_spips_class_init, +}; + +static void xilinx_spips_register_types(void) +{ + type_register_static(&xilinx_spips_info); +} + +type_init(xilinx_spips_register_types) -- cgit v1.2.3 From 559d489f137a696920d89ad2e3225b869c52b745 Mon Sep 17 00:00:00 2001 From: "Peter A. G. Crosthwaite" Date: Fri, 3 Aug 2012 16:08:48 +1000 Subject: xilinx_zynq: Added SPI controllers + flashes Added the two SPI controllers to the zynq machine model. Attached two SPI flash devices to each controller. Signed-off-by: Peter A. G. Crosthwaite Acked-by: Peter Maydell --- hw/xilinx_zynq.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/hw/xilinx_zynq.c b/hw/xilinx_zynq.c index 7e6c27359..fd46ba252 100644 --- a/hw/xilinx_zynq.c +++ b/hw/xilinx_zynq.c @@ -24,6 +24,9 @@ #include "flash.h" #include "blockdev.h" #include "loader.h" +#include "ssi.h" + +#define NUM_SPI_FLASHES 4 #define FLASH_SIZE (64 * 1024 * 1024) #define FLASH_SECTOR_SIZE (128 * 1024) @@ -46,6 +49,34 @@ static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq) sysbus_connect_irq(s, 0, irq); } +static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq) +{ + DeviceState *dev; + SysBusDevice *busdev; + SSIBus *spi; + int i; + + dev = qdev_create(NULL, "xilinx,spips"); + qdev_init_nofail(dev); + busdev = sysbus_from_qdev(dev); + sysbus_mmio_map(busdev, 0, base_addr); + sysbus_connect_irq(busdev, 0, irq); + + spi = (SSIBus *)qdev_get_child_bus(dev, "spi"); + + for (i = 0; i < NUM_SPI_FLASHES; ++i) { + qemu_irq cs_line; + + dev = ssi_create_slave_no_init(spi, "m25p80"); + qdev_prop_set_string(dev, "partname", "n25q128"); + qdev_init_nofail(dev); + + cs_line = qdev_get_gpio_in(dev, 0); + sysbus_connect_irq(busdev, i+1, cs_line); + } + +} + static void zynq_init(ram_addr_t ram_size, const char *boot_device, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) @@ -113,6 +144,9 @@ static void zynq_init(ram_addr_t ram_size, const char *boot_device, pic[n] = qdev_get_gpio_in(dev, n); } + zynq_init_spi_flashes(0xE0006000, pic[58-IRQ_OFFSET]); + zynq_init_spi_flashes(0xE0007000, pic[81-IRQ_OFFSET]); + sysbus_create_simple("cadence_uart", 0xE0000000, pic[59-IRQ_OFFSET]); sysbus_create_simple("cadence_uart", 0xE0001000, pic[82-IRQ_OFFSET]); -- cgit v1.2.3 From fcb5629d3eb208d84c0fe9aa1ef64a6af7de0139 Mon Sep 17 00:00:00 2001 From: "Peter A. G. Crosthwaite" Date: Mon, 6 Aug 2012 11:38:19 +1000 Subject: MAINTAINERS: Added maintainerships for SSI Added maintainership for SSI, M25P80 and the Xilinx SPI controllers. Signed-off-by: Peter A. G. Crosthwaite Acked-by: Peter Maydell --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 78d4ff227..f1f925007 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -268,6 +268,7 @@ S: Maintained F: hw/xilinx_zynq.c F: hw/zynq_slcr.c F: hw/cadence_* +F: hw/xilinx_spips.c CRIS Machines ------------- @@ -517,6 +518,12 @@ M: Paul Brook S: Odd Fixes F: hw/lsi53c895a.c +SSI +M: Peter Crosthwaite +S: Maintained +F: hw/ssi.* +F: hw/m25p80.c + USB M: Gerd Hoffmann S: Maintained @@ -565,6 +572,7 @@ F: hw/xilinx_intc.c F: hw/xilinx_ethlite.c F: hw/xilinx_timer.c F: hw/xilinx.h +F: hw/xilinx_spi.c Subsystems ---------- -- cgit v1.2.3 From b4ae3cfa57b8c1bdbbd7b7d420971e9171203ade Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Mon, 1 Oct 2012 12:34:37 +1000 Subject: ssi: Add slave autoconnect helper Added helper function to automatically connect SPI slaves based on the QOM child nodes of a device. A SSI master device can call this routine to automatically hook-up all child nodes to its SPI bus. Signed-off-by: Peter Crosthwaite Acked-by: Peter Maydell --- hw/ssi.c | 33 +++++++++++++++++++++++++++++++++ hw/ssi.h | 4 ++++ hw/xilinx_spi.c | 6 ++++-- hw/xilinx_spips.c | 4 +++- 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/hw/ssi.c b/hw/ssi.c index c47419d57..2b5635715 100644 --- a/hw/ssi.c +++ b/hw/ssi.c @@ -139,3 +139,36 @@ static void ssi_slave_register_types(void) } type_init(ssi_slave_register_types) + +typedef struct SSIAutoConnectArg { + qemu_irq **cs_linep; + SSIBus *bus; +} SSIAutoConnectArg; + +static int ssi_auto_connect_slave(Object *child, void *opaque) +{ + SSIAutoConnectArg *arg = opaque; + SSISlave *dev = (SSISlave *)object_dynamic_cast(child, TYPE_SSI_SLAVE); + qemu_irq cs_line; + + if (!dev) { + return 0; + } + + cs_line = qdev_get_gpio_in(DEVICE(dev), 0); + qdev_set_parent_bus(DEVICE(dev), &arg->bus->qbus); + **arg->cs_linep = cs_line; + (*arg->cs_linep)++; + return 0; +} + +void ssi_auto_connect_slaves(DeviceState *parent, qemu_irq *cs_line, + SSIBus *bus) +{ + SSIAutoConnectArg arg = { + .cs_linep = &cs_line, + .bus = bus + }; + + object_child_foreach(OBJECT(parent), ssi_auto_connect_slave, &arg); +} diff --git a/hw/ssi.h b/hw/ssi.h index 2bde9f5b4..a05d60beb 100644 --- a/hw/ssi.h +++ b/hw/ssi.h @@ -83,6 +83,10 @@ SSIBus *ssi_create_bus(DeviceState *parent, const char *name); uint32_t ssi_transfer(SSIBus *bus, uint32_t val); +/* Automatically connect all children nodes a spi controller as slaves */ +void ssi_auto_connect_slaves(DeviceState *parent, qemu_irq *cs_lines, + SSIBus *bus); + /* max111x.c */ void max111x_set_input(DeviceState *dev, int line, uint8_t value); diff --git a/hw/xilinx_spi.c b/hw/xilinx_spi.c index 7db47877e..5cdf967c2 100644 --- a/hw/xilinx_spi.c +++ b/hw/xilinx_spi.c @@ -320,8 +320,12 @@ static int xilinx_spi_init(SysBusDevice *dev) XilinxSPI *s = FROM_SYSBUS(typeof(*s), dev); DB_PRINT("\n"); + + s->spi = ssi_create_bus(&dev->qdev, "spi"); + sysbus_init_irq(dev, &s->irq); s->cs_lines = g_new(qemu_irq, s->num_cs); + ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi); for (i = 0; i < s->num_cs; ++i) { sysbus_init_irq(dev, &s->cs_lines[i]); } @@ -331,8 +335,6 @@ static int xilinx_spi_init(SysBusDevice *dev) s->irqline = -1; - s->spi = ssi_create_bus(&dev->qdev, "spi"); - fifo8_create(&s->tx_fifo, FIFO_CAPACITY); fifo8_create(&s->rx_fifo, FIFO_CAPACITY); diff --git a/hw/xilinx_spips.c b/hw/xilinx_spips.c index a886c5d31..f64a7828f 100644 --- a/hw/xilinx_spips.c +++ b/hw/xilinx_spips.c @@ -289,6 +289,9 @@ static int xilinx_spips_init(SysBusDevice *dev) DB_PRINT("inited device model\n"); + s->spi = ssi_create_bus(&dev->qdev, "spi"); + + ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi); sysbus_init_irq(dev, &s->irq); for (i = 0; i < NUM_CS_LINES; ++i) { sysbus_init_irq(dev, &s->cs_lines[i]); @@ -298,7 +301,6 @@ static int xilinx_spips_init(SysBusDevice *dev) sysbus_init_mmio(dev, &s->iomem); s->irqline = -1; - s->spi = ssi_create_bus(&dev->qdev, "spi"); fifo8_create(&s->rx_fifo, RXFF_A); fifo8_create(&s->tx_fifo, TXFF_A); -- cgit v1.2.3