@@ -53,6 +53,8 @@ enum {
TILEGX_SPR_CMPEXCH = 0,
TILEGX_SPR_CRITICAL_SEC = 1,
TILEGX_SPR_SIM_CONTROL = 2,
+ TILEGX_SPR_EX_CONTEXT_0_0 = 3,
+ TILEGX_SPR_EX_CONTEXT_0_1 = 4,
TILEGX_SPR_COUNT
};
@@ -48,7 +48,7 @@ static const char * const reg_names[] = {
};
static const char * const spreg_names[] = {
- "cmpexch", "criticalsec", "simcontrol"
+ "cmpexch", "criticalsec", "simcontrol", "excontext00", "excontext01"
};
/* It is for temporary registers */
@@ -174,6 +174,71 @@ static void gen_swint1(struct DisasContext *dc)
}
/*
+ * Description
+ *
+ * Returns from an interrupt. Transfers control flow to the program counter
+ * location and protection level contained in the current PL ’s EX_CONTEXT
+ * registers, and restores the interrupt critical section bit to the value
+ * contained in those registers.
+ *
+ * Functional Description
+ *
+ * setNextPC(sprf [EX_CONTEXT_SPRF_OFFSET +
+ * (getCurrentProtectionLevel() * EX_CONTEXT_SIZE) +
+ * PC_EX_CONTEXT_OFFSET]);
+ * branchPredictedIncorrect();
+ * setProtectionLevel(sprf [EX_CONTEXT_SPRF_OFFSET +
+ * (getCurrentProtectionLevel() * EX_CONTEXT_SIZE) +
+ * PROTECTION_LEVEL_EX_CONTEXT_OFFSET]);
+ * setInterruptCriticalSection(
+ * sprf [EX_CONTEXT_SPRF_OFFSET +
+ * (getCurrentProtectionLevel() * EX_CONTEXT_SIZE) +
+ * INTERRUPT_CRITICAL_SECTION_EX_CONTEXT_OFFSET]);
+ *
+ * besides the PC we need to set our new protection level, and set the interrupt
+ * critical section bit atomically inside of this instruction
+ */
+static void gen_iret(struct DisasContext *dc)
+{
+ qemu_log_mask(CPU_LOG_TB_IN_ASM, "iret\n");
+ /*
+ * In user mode, all related things are already done by previous and next
+ * instructions, so just skip it. Can reference __longjmp code for it.
+ *
+ * ENTRY (__longjmp)
+ * FEEDBACK_ENTER(__longjmp)
+ *
+ * #define RESTORE(r) { LD r, r0 ; ADDI_PTR r0, r0, REGSIZE }
+ * FOR_EACH_CALLEE_SAVED_REG(RESTORE)
+ *
+ * {
+ * LD r2, r0 ; retrieve ICS bit from jmp_buf
+ * movei r3, 1
+ * CMPEQI r0, r1, 0
+ * }
+ *
+ * {
+ * mtspr INTERRUPT_CRITICAL_SECTION, r3
+ * shli r2, r2, SPR_EX_CONTEXT_0_1__ICS_SHIFT
+ * }
+ *
+ * {
+ * mtspr EX_CONTEXT_0_0, lr
+ * ori r2, r2, RETURN_PL
+ * }
+ *
+ * {
+ * or r0, r1, r0
+ * mtspr EX_CONTEXT_0_1, r2
+ * }
+ *
+ * iret
+ *
+ * jrp lr
+ */
+}
+
+/*
* Many SPR reads/writes have side effects and cannot be buffered. However, they
* are all in the X1 pipe, which we are excuting last, therefore we need not do
* additional buffering.
@@ -197,6 +262,12 @@ static void gen_mfspr(struct DisasContext *dc, uint8_t rdst, uint16_t imm14)
case SPR_SIM_CONTROL:
tcg_gen_mov_i64(cpu_regs[rdst], cpu_spregs[TILEGX_SPR_SIM_CONTROL]);
return;
+ case SPR_EX_CONTEXT_0_0:
+ tcg_gen_mov_i64(cpu_regs[rdst], cpu_spregs[TILEGX_SPR_EX_CONTEXT_0_0]);
+ return;
+ case SPR_EX_CONTEXT_0_1:
+ tcg_gen_mov_i64(cpu_regs[rdst], cpu_spregs[TILEGX_SPR_EX_CONTEXT_0_1]);
+ return;
default:
qemu_log_mask(LOG_UNIMP, "UNIMP mfspr 0x%x.\n", imm14);
}
@@ -218,6 +289,12 @@ static void gen_mtspr(struct DisasContext *dc, uint8_t rsrc, uint16_t imm14)
case SPR_SIM_CONTROL:
tcg_gen_mov_i64(cpu_spregs[TILEGX_SPR_SIM_CONTROL], load_gr(dc, rsrc));
return;
+ case SPR_EX_CONTEXT_0_0:
+ tcg_gen_mov_i64(cpu_spregs[TILEGX_SPR_EX_CONTEXT_0_0], load_gr(dc, rsrc));
+ return;
+ case SPR_EX_CONTEXT_0_1:
+ tcg_gen_mov_i64(cpu_spregs[TILEGX_SPR_EX_CONTEXT_0_1], load_gr(dc, rsrc));
+ return;
default:
qemu_log_mask(LOG_UNIMP, "UNIMP mtspr 0x%x.\n", imm14);
}
@@ -2257,6 +2334,12 @@ static void decode_u_opcode_ex_x1(struct DisasContext *dc,
return;
}
break;
+ case IRET_UNARY_OPCODE_X1:
+ if (!rdst && !rsrc) {
+ gen_iret(dc);
+ return;
+ }
+ break;
case SWINT1_UNARY_OPCODE_X1:
if (!rsrc && !rdst) {
gen_swint1(dc);
@@ -2277,7 +2360,6 @@ static void decode_u_opcode_ex_x1(struct DisasContext *dc,
case ICOH_UNARY_OPCODE_X1:
case ILL_UNARY_OPCODE_X1:
case INV_UNARY_OPCODE_X1:
- case IRET_UNARY_OPCODE_X1:
case LDNT1S_UNARY_OPCODE_X1:
case LDNT1U_UNARY_OPCODE_X1:
case LDNT2S_UNARY_OPCODE_X1:
In fact, iret itself needs nothing, but the related previous and next instructions need to be implemented. SPR_EX_CONTEXT_0_0 and SPR_EX_CONTEXT_0_1 are related with iret, so let them in a patch. Signed-off-by: Chen Gang <gang.chen.5i5j@gmail.com> --- target-tilegx/cpu.h | 2 ++ target-tilegx/translate.c | 86 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 86 insertions(+), 2 deletions(-)