Implement the guest virtual instructions SPSWAP, GETIE, SETIE and RTE.
Signed-off-by: Brian Cain <[email protected]>
---
target/hexagon/hexswi.h | 1 +
target/hexagon/sys_macros.h | 33 +++++++++++++++++++++++++++------
target/hexagon/hexswi.c | 28 ++++++++++++++++++++++++++++
target/hexagon/hex_common.py | 2 +-
4 files changed, 57 insertions(+), 7 deletions(-)
diff --git a/target/hexagon/hexswi.h b/target/hexagon/hexswi.h
index 587f790414c..da11bea2b23 100644
--- a/target/hexagon/hexswi.h
+++ b/target/hexagon/hexswi.h
@@ -13,6 +13,7 @@
void hexagon_cpu_do_interrupt(CPUState *cpu);
void register_trap_exception(CPUHexagonState *env, int type, int imm,
uint32_t PC);
+void hexagon_vmrte(CPUHexagonState *env);
#define HEX_GEVB_HW_ERROR (HEX_EVENT_PRECISE << 2)
#define HEX_GEVB_HW_TRAP0 (HEX_EVENT_TRAP0 << 2)
diff --git a/target/hexagon/sys_macros.h b/target/hexagon/sys_macros.h
index b896ee1c81b..270aa0c411f 100644
--- a/target/hexagon/sys_macros.h
+++ b/target/hexagon/sys_macros.h
@@ -79,15 +79,36 @@
#define fFRAMECHECK(ADDR, EA) gen_framecheck(ctx, ADDR, EA)
#endif
-#define fVIRTINSN_SPSWAP(IMM, REG)
-#define fVIRTINSN_GETIE(IMM, REG) { REG = 0xdeafbeef; }
-#define fVIRTINSN_SETIE(IMM, REG)
-#define fVIRTINSN_RTE(IMM, REG)
+#define fVIRTINSN_SPSWAP(IMM, REG) \
+ do { \
+ if (GET_FIELD(GSR_UM, env->greg[HEX_GREG_GSR])) { \
+ uint32_t tmp = (REG); \
+ (REG) = env->greg[HEX_GREG_GOSP]; \
+ env->greg[HEX_GREG_GOSP] = tmp; \
+ } \
+ env->gpr[HEX_REG_PC] = next_PC; \
+ } while (0)
+#define fVIRTINSN_GETIE(IMM, REG) \
+ do { \
+ (REG) = CCR_FIELD_SET(env, CCR_GIE); \
+ env->gpr[HEX_REG_PC] = next_PC; \
+ } while (0)
+#define fVIRTINSN_SETIE(IMM, REG) \
+ do { \
+ uint32_t old_gie = CCR_FIELD_SET(env, CCR_GIE); \
+ uint32_t new_gie = (REG) & 1; \
+ SET_SYSTEM_FIELD(env, HEX_SREG_CCR, CCR_GIE, new_gie); \
+ (REG) = old_gie; \
+ env->gpr[HEX_REG_PC] = next_PC; \
+ } while (0)
+#define fVIRTINSN_RTE(IMM, REG) hexagon_vmrte(env)
#define fGRE_ENABLED() \
GET_FIELD(CCR_GRE, env->t_sreg[HEX_SREG_CCR])
+/* Virtual instructions execute only in guest mode. */
#define fTRAP1_VIRTINSN(IMM) \
- (fGRE_ENABLED() && \
- (((IMM) == 1) || ((IMM) == 3) || ((IMM) == 4) || ((IMM) == 6)))
+ (get_cpu_mode(env) == HEX_CPU_MODE_GUEST && fGRE_ENABLED() && \
+ (((IMM) == 1) || ((IMM) == 3) || ((IMM) == 4) || \
+ ((IMM) == 6)))
/* Not modeled in qemu */
diff --git a/target/hexagon/hexswi.c b/target/hexagon/hexswi.c
index 9d94eef96a7..e2d8233701d 100644
--- a/target/hexagon/hexswi.c
+++ b/target/hexagon/hexswi.c
@@ -821,6 +821,34 @@ static void guest_event_entry(CPUHexagonState *env,
uint32_t cause,
env->gpr[HEX_REG_PC] = gevb + vec_offset;
}
+void hexagon_vmrte(CPUHexagonState *env)
+{
+ uint32_t gsr = env->greg[HEX_GREG_GSR];
+ uint32_t old_ssr = env->t_sreg[HEX_SREG_SSR];
+ CPUState *cs = env_cpu(env);
+
+ if (GET_FIELD(GSR_UM, gsr)) {
+ uint32_t sp = env->gpr[HEX_REG_SP];
+
+ env->gpr[HEX_REG_SP] = env->greg[HEX_GREG_GOSP];
+ env->greg[HEX_GREG_GOSP] = sp;
+ }
+ SET_SYSTEM_FIELD(env, HEX_SREG_SSR, SSR_SS,
+ GET_FIELD(GSR_SS, gsr));
+ SET_SYSTEM_FIELD(env, HEX_SREG_SSR, SSR_GM,
+ !GET_FIELD(GSR_UM, gsr));
+ {
+ BQL_LOCK_GUARD();
+ hexagon_modify_ssr(env, env->t_sreg[HEX_SREG_SSR], old_ssr);
+ }
+ SET_SYSTEM_FIELD(env, HEX_SREG_CCR, CCR_GIE,
+ GET_FIELD(GSR_IE, gsr));
+ env->cfi_active = GET_FIELD(GSR_CFI, gsr);
+ fSET_FIELD(env->greg[HEX_GREG_GSR], GSR_CFI, 0);
+ env->gpr[HEX_REG_PC] = env->greg[HEX_GREG_GELR] & ~3;
+ cpu_loop_exit(cs);
+}
+
void hexagon_cpu_do_interrupt(CPUState *cs)
{
diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py
index 94e70b8657d..0c78b4044ef 100755
--- a/target/hexagon/hex_common.py
+++ b/target/hexagon/hex_common.py
@@ -288,7 +288,7 @@ def need_PC(tag):
def need_next_PC(tag):
- return "A_CALL" in attribdict[tag]
+ return "A_CALL" in attribdict[tag] or tag == "J2_trap1"
def need_pkt_has_multi_cof(tag):
--
2.34.1