summaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
Diffstat (limited to 'target')
-rw-r--r--target/ppc/internal.h3
-rw-r--r--target/ppc/translate.c96
-rw-r--r--target/riscv/cpu.c5
3 files changed, 91 insertions, 13 deletions
diff --git a/target/ppc/internal.h b/target/ppc/internal.h
index 467f3046c8..337a362205 100644
--- a/target/ppc/internal.h
+++ b/target/ppc/internal.h
@@ -165,6 +165,9 @@ EXTRACT_HELPER_SPLIT_3(DX, 10, 6, 6, 5, 16, 1, 1, 0, 0)
/* darn */
EXTRACT_HELPER(L, 16, 2);
#endif
+/* wait */
+EXTRACT_HELPER(WC, 21, 2);
+EXTRACT_HELPER(PL, 16, 2);
/*** Jump target decoding ***/
/* Immediate address */
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 5a18ee577f..388337f81b 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -4071,12 +4071,91 @@ static void gen_sync(DisasContext *ctx)
/* wait */
static void gen_wait(DisasContext *ctx)
{
- TCGv_i32 t0 = tcg_const_i32(1);
- tcg_gen_st_i32(t0, cpu_env,
- -offsetof(PowerPCCPU, env) + offsetof(CPUState, halted));
- tcg_temp_free_i32(t0);
- /* Stop translation, as the CPU is supposed to sleep from now */
- gen_exception_nip(ctx, EXCP_HLT, ctx->base.pc_next);
+ uint32_t wc;
+
+ if (ctx->insns_flags & PPC_WAIT) {
+ /* v2.03-v2.07 define an older incompatible 'wait' encoding. */
+
+ if (ctx->insns_flags2 & PPC2_PM_ISA206) {
+ /* v2.06 introduced the WC field. WC > 0 may be treated as no-op. */
+ wc = WC(ctx->opcode);
+ } else {
+ wc = 0;
+ }
+
+ } else if (ctx->insns_flags2 & PPC2_ISA300) {
+ /* v3.0 defines a new 'wait' encoding. */
+ wc = WC(ctx->opcode);
+ if (ctx->insns_flags2 & PPC2_ISA310) {
+ uint32_t pl = PL(ctx->opcode);
+
+ /* WC 1,2 may be treated as no-op. WC 3 is reserved. */
+ if (wc == 3) {
+ gen_invalid(ctx);
+ return;
+ }
+
+ /* PL 1-3 are reserved. If WC=2 then the insn is treated as noop. */
+ if (pl > 0 && wc != 2) {
+ gen_invalid(ctx);
+ return;
+ }
+
+ } else { /* ISA300 */
+ /* WC 1-3 are reserved */
+ if (wc > 0) {
+ gen_invalid(ctx);
+ return;
+ }
+ }
+
+ } else {
+ warn_report("wait instruction decoded with wrong ISA flags.");
+ gen_invalid(ctx);
+ return;
+ }
+
+ /*
+ * wait without WC field or with WC=0 waits for an exception / interrupt
+ * to occur.
+ */
+ if (wc == 0) {
+ TCGv_i32 t0 = tcg_const_i32(1);
+ tcg_gen_st_i32(t0, cpu_env,
+ -offsetof(PowerPCCPU, env) + offsetof(CPUState, halted));
+ tcg_temp_free_i32(t0);
+ /* Stop translation, as the CPU is supposed to sleep from now */
+ gen_exception_nip(ctx, EXCP_HLT, ctx->base.pc_next);
+ }
+
+ /*
+ * Other wait types must not just wait until an exception occurs because
+ * ignoring their other wake-up conditions could cause a hang.
+ *
+ * For v2.06 and 2.07, wc=1,2,3 are architected but may be implemented as
+ * no-ops.
+ *
+ * wc=1 and wc=3 explicitly allow the instruction to be treated as a no-op.
+ *
+ * wc=2 waits for an implementation-specific condition, such could be
+ * always true, so it can be implemented as a no-op.
+ *
+ * For v3.1, wc=1,2 are architected but may be implemented as no-ops.
+ *
+ * wc=1 (waitrsv) waits for an exception or a reservation to be lost.
+ * Reservation-loss may have implementation-specific conditions, so it
+ * can be implemented as a no-op.
+ *
+ * wc=2 waits for an exception or an amount of time to pass. This
+ * amount is implementation-specific so it can be implemented as a
+ * no-op.
+ *
+ * ISA v3.1 allows for execution to resume "in the rare case of
+ * an implementation-dependent event", so in any case software must
+ * not depend on the architected resumption condition to become
+ * true, so no-op implementations should be architecturally correct
+ * (if suboptimal).
+ */
}
#if defined(TARGET_PPC64)
@@ -6691,8 +6770,9 @@ GEN_HANDLER2(stdcx_, "stdcx.", 0x1F, 0x16, 0x06, 0x00000000, PPC_64B),
GEN_HANDLER_E(stqcx_, 0x1F, 0x16, 0x05, 0, PPC_NONE, PPC2_LSQ_ISA207),
#endif
GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x039FF801, PPC_MEM_SYNC),
-GEN_HANDLER(wait, 0x1F, 0x1E, 0x01, 0x03FFF801, PPC_WAIT),
-GEN_HANDLER_E(wait, 0x1F, 0x1E, 0x00, 0x039FF801, PPC_NONE, PPC2_ISA300),
+/* ISA v3.0 changed the extended opcode from 62 to 30 */
+GEN_HANDLER(wait, 0x1F, 0x1E, 0x01, 0x039FF801, PPC_WAIT),
+GEN_HANDLER_E(wait, 0x1F, 0x1E, 0x00, 0x039CF801, PPC_NONE, PPC2_ISA300),
GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW),
GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW),
GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW),
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 1bb3973806..ac6f82ebd0 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -619,11 +619,6 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
cpu->cfg.ext_ifencei = true;
}
- if (cpu->cfg.ext_m && cpu->cfg.ext_zmmul) {
- warn_report("Zmmul will override M");
- cpu->cfg.ext_m = false;
- }
-
if (cpu->cfg.ext_i && cpu->cfg.ext_e) {
error_setg(errp,
"I and E extensions are incompatible");