* [Qemu-devel] [PATCH 1/3] target/xtensa: sort FLIX instruction opcodes
2019-01-30 23:54 [Qemu-devel] [PATCH 0/3] target/xtensa: add basic FLIX support Max Filippov
@ 2019-01-30 23:54 ` Max Filippov
2019-01-30 23:54 ` [Qemu-devel] [PATCH 2/3] target/xtensa: add generic instruction post-processing Max Filippov
2019-01-30 23:54 ` [Qemu-devel] [PATCH 3/3] target/xtensa: move WINDOW_BASE SR update to postprocessing Max Filippov
2 siblings, 0 replies; 4+ messages in thread
From: Max Filippov @ 2019-01-30 23:54 UTC (permalink / raw)
To: qemu-devel; +Cc: Richard Henderson, Max Filippov
Opcodes in different slots may read and write same resources (registers,
states). In the absence of resource dependency loops it must be possible
to sort opcodes to avoid interference.
Record resources used by each opcode in the bundle. Build opcode
dependency graph and use topological sort to order its nodes. In case of
success translate opcodes in sort order. In case of failure report and
raise invalid opcode exception for now.
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
target/xtensa/translate.c | 202 ++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 194 insertions(+), 8 deletions(-)
diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c
index a068b6e8335d..b3718d33eec8 100644
--- a/target/xtensa/translate.c
+++ b/target/xtensa/translate.c
@@ -855,6 +855,138 @@ static inline unsigned xtensa_op0_insn_len(DisasContext *dc, uint8_t op0)
return xtensa_isa_length_from_chars(dc->config->isa, &op0);
}
+struct slot_prop {
+ XtensaOpcodeOps *ops;
+ uint32_t arg[MAX_OPCODE_ARGS];
+ uint32_t raw_arg[MAX_OPCODE_ARGS];
+ uint32_t in[MAX_OPCODE_ARGS];
+ uint32_t out[MAX_OPCODE_ARGS];
+ unsigned n_in;
+ unsigned n_out;
+};
+
+enum resource_type {
+ XTENSA_CONTROL_FLOW, /* must be first, see op_depends_on */
+ XTENSA_REGFILE,
+ XTENSA_STATE,
+};
+
+static uint32_t encode_resource(enum resource_type r, unsigned g, unsigned n)
+{
+ assert(r < 256 && g < 256 && n < 65536);
+ return (r << 24) | (g << 16) | n;
+}
+
+static bool op_depends_on(const struct slot_prop *a,
+ const struct slot_prop *b)
+{
+ unsigned i = 0;
+ unsigned j = 0;
+
+ if (a->n_out && a->out[0] == encode_resource(XTENSA_CONTROL_FLOW, 0, 0)) {
+ return true;
+ }
+ while (i < a->n_out && j < b->n_in) {
+ if (a->out[i] < b->in[j]) {
+ ++i;
+ } else if (a->out[i] > b->in[j]) {
+ ++j;
+ } else {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool tsort(struct slot_prop *slot,
+ struct slot_prop *sorted[],
+ unsigned n)
+{
+ struct {
+ unsigned n_in_edge;
+ unsigned n_out_edge;
+ unsigned out_edge[MAX_INSN_SLOTS];
+ } node[MAX_INSN_SLOTS];
+
+ unsigned in[MAX_INSN_SLOTS];
+ unsigned i, j;
+ unsigned n_in = 0;
+ unsigned n_out = 0;
+ unsigned n_edge = 0;
+
+ for (i = 0; i < n; ++i) {
+ node[i].n_in_edge = 0;
+ node[i].n_out_edge = 0;
+ }
+
+ for (i = 0; i < n; ++i) {
+ unsigned n_out_edge = 0;
+
+ for (j = 0; j < n; ++j) {
+ if (i != j && op_depends_on(slot + j, slot + i)) {
+ node[i].out_edge[n_out_edge] = j;
+ ++node[j].n_in_edge;
+ ++n_out_edge;
+ ++n_edge;
+ }
+ }
+ node[i].n_out_edge = n_out_edge;
+ }
+
+ for (i = 0; i < n; ++i) {
+ if (!node[i].n_in_edge) {
+ in[n_in] = i;
+ ++n_in;
+ }
+ }
+
+ for (i = 0; i < n_in; ++i) {
+ unsigned k = in[i];
+
+ sorted[n_out] = slot + k;
+ ++n_out;
+ for (j = 0; j < node[k].n_out_edge; ++j) {
+ --n_edge;
+ if (--node[node[k].out_edge[j]].n_in_edge == 0) {
+ in[n_in] = node[k].out_edge[j];
+ ++n_in;
+ }
+ }
+ }
+ return n_edge == 0;
+}
+
+static void opcode_add_resource(struct slot_prop *op,
+ uint32_t resource, char direction)
+{
+ switch (direction) {
+ case 'i':
+ assert(op->n_in < ARRAY_SIZE(op->in));
+ op->in[op->n_in++] = resource;
+ break;
+ case 'o':
+ assert(op->n_out < ARRAY_SIZE(op->out));
+ op->out[op->n_out++] = resource;
+ break;
+ case 'm':
+ assert(op->n_in < ARRAY_SIZE(op->in));
+ assert(op->n_out < ARRAY_SIZE(op->out));
+ op->in[op->n_in++] = resource;
+ op->out[op->n_out++] = resource;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static int resource_compare(const void *a, const void *b)
+{
+ const uint32_t *pa = a;
+ const uint32_t *pb = b;
+
+ return *pa < *pb ? -1 : (*pa > *pb ? 1 : 0);
+}
+
static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
{
xtensa_isa isa = dc->config->isa;
@@ -864,11 +996,8 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
int slot, slots;
unsigned i;
uint32_t op_flags = 0;
- struct {
- XtensaOpcodeOps *ops;
- uint32_t arg[MAX_OPCODE_ARGS];
- uint32_t raw_arg[MAX_OPCODE_ARGS];
- } slot_prop[MAX_INSN_SLOTS];
+ struct slot_prop slot_prop[MAX_INSN_SLOTS];
+ struct slot_prop *ordered[MAX_INSN_SLOTS];
uint32_t debug_cause = 0;
uint32_t windowed_register = 0;
uint32_t coprocessor = 0;
@@ -963,6 +1092,62 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
}
}
coprocessor |= ops->coprocessor;
+
+ if (slots > 1) {
+ slot_prop[slot].n_in = 0;
+ slot_prop[slot].n_out = 0;
+
+ opnds = xtensa_opcode_num_operands(isa, opc);
+
+ for (opnd = 0; opnd < opnds; ++opnd) {
+ if (xtensa_operand_is_register(isa, opc, opnd)) {
+ xtensa_regfile rf = xtensa_operand_regfile(isa, opc, opnd);
+ uint32_t v = 0;
+
+ xtensa_operand_get_field(isa, opc, opnd, fmt, slot,
+ dc->slotbuf, &v);
+ xtensa_operand_decode(isa, opc, opnd, &v);
+ opcode_add_resource(slot_prop + slot,
+ encode_resource(XTENSA_REGFILE, rf, v),
+ xtensa_operand_inout(isa, opc, opnd));
+ }
+ }
+
+ opnds = xtensa_opcode_num_stateOperands(isa, opc);
+
+ for (opnd = 0; opnd < opnds; ++opnd) {
+ xtensa_state state = xtensa_stateOperand_state(isa, opc, opnd);
+
+ opcode_add_resource(slot_prop + slot,
+ encode_resource(XTENSA_STATE, 0, state),
+ xtensa_stateOperand_inout(isa, opc, opnd));
+ }
+ if (xtensa_opcode_is_branch(isa, opc) ||
+ xtensa_opcode_is_jump(isa, opc) ||
+ xtensa_opcode_is_loop(isa, opc) ||
+ xtensa_opcode_is_call(isa, opc)) {
+ opcode_add_resource(slot_prop + slot,
+ encode_resource(XTENSA_CONTROL_FLOW, 0, 0),
+ 'o');
+ }
+
+ qsort(slot_prop[slot].in, slot_prop[slot].n_in, sizeof(uint32_t),
+ resource_compare);
+ qsort(slot_prop[slot].out, slot_prop[slot].n_out, sizeof(uint32_t),
+ resource_compare);
+ }
+ }
+
+ if (slots > 1) {
+ if (!tsort(slot_prop, ordered, slots)) {
+ qemu_log_mask(LOG_UNIMP,
+ "Circular resource dependencies (pc = %08x)\n",
+ dc->pc);
+ gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE);
+ return;
+ }
+ } else {
+ ordered[0] = slot_prop + 0;
}
if ((op_flags & XTENSA_OP_PRIVILEGED) &&
@@ -1011,10 +1196,11 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
}
for (slot = 0; slot < slots; ++slot) {
- XtensaOpcodeOps *ops = slot_prop[slot].ops;
+ struct slot_prop *pslot = ordered[slot];
+ XtensaOpcodeOps *ops = pslot->ops;
- dc->raw_arg = slot_prop[slot].raw_arg;
- ops->translate(dc, slot_prop[slot].arg, ops->par);
+ dc->raw_arg = pslot->raw_arg;
+ ops->translate(dc, pslot->arg, ops->par);
}
if (dc->base.is_jmp == DISAS_NEXT) {
--
2.11.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [Qemu-devel] [PATCH 2/3] target/xtensa: add generic instruction post-processing
2019-01-30 23:54 [Qemu-devel] [PATCH 0/3] target/xtensa: add basic FLIX support Max Filippov
2019-01-30 23:54 ` [Qemu-devel] [PATCH 1/3] target/xtensa: sort FLIX instruction opcodes Max Filippov
@ 2019-01-30 23:54 ` Max Filippov
2019-01-30 23:54 ` [Qemu-devel] [PATCH 3/3] target/xtensa: move WINDOW_BASE SR update to postprocessing Max Filippov
2 siblings, 0 replies; 4+ messages in thread
From: Max Filippov @ 2019-01-30 23:54 UTC (permalink / raw)
To: qemu-devel; +Cc: Richard Henderson, Max Filippov
Some opcodes may need additional actions at every exit from the
translated instruction or may need to amend TB exit slots available to
jumps generated for the instruction. Add gen_postprocess function and
call it from the gen_jump_slot and from the disas_xtensa_insn.
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
target/xtensa/cpu.h | 4 ++++
target/xtensa/translate.c | 33 +++++++++++++++++++++++++--------
2 files changed, 29 insertions(+), 8 deletions(-)
diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h
index b665bfc0068a..e1002c626954 100644
--- a/target/xtensa/cpu.h
+++ b/target/xtensa/cpu.h
@@ -368,9 +368,13 @@ enum {
XTENSA_OP_DIVIDE_BY_ZERO = 0x100,
+ /* Postprocessing flags */
XTENSA_OP_CHECK_INTERRUPTS = 0x200,
XTENSA_OP_EXIT_TB_M1 = 0x400,
XTENSA_OP_EXIT_TB_0 = 0x800,
+ XTENSA_OP_SYNC_REGISTER_WINDOW = 0x1000,
+
+ XTENSA_OP_POSTPROCESS = 0x1e00,
};
typedef struct XtensaOpcodeOps {
diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c
index b3718d33eec8..f5f5bcfb179a 100644
--- a/target/xtensa/translate.c
+++ b/target/xtensa/translate.c
@@ -71,6 +71,7 @@ struct DisasContext {
unsigned cpenable;
+ uint32_t op_flags;
uint32_t *raw_arg;
xtensa_insnbuf insnbuf;
xtensa_insnbuf slotbuf;
@@ -363,6 +364,8 @@ static bool gen_check_cpenable(DisasContext *dc, uint32_t cp_mask)
return true;
}
+static int gen_postprocess(DisasContext *dc, int slot);
+
static void gen_jump_slot(DisasContext *dc, TCGv dest, int slot)
{
tcg_gen_mov_i32(cpu_pc, dest);
@@ -372,6 +375,9 @@ static void gen_jump_slot(DisasContext *dc, TCGv dest, int slot)
if (dc->base.singlestep_enabled) {
gen_exception(dc, EXCP_DEBUG);
} else {
+ if (dc->op_flags & XTENSA_OP_POSTPROCESS) {
+ slot = gen_postprocess(dc, slot);
+ }
if (slot >= 0) {
tcg_gen_goto_tb(slot);
tcg_gen_exit_tb(dc->base.tb, slot);
@@ -855,6 +861,19 @@ static inline unsigned xtensa_op0_insn_len(DisasContext *dc, uint8_t op0)
return xtensa_isa_length_from_chars(dc->config->isa, &op0);
}
+static int gen_postprocess(DisasContext *dc, int slot)
+{
+ uint32_t op_flags = dc->op_flags;
+
+ if (op_flags & XTENSA_OP_CHECK_INTERRUPTS) {
+ gen_check_interrupts(dc);
+ }
+ if (op_flags & XTENSA_OP_EXIT_TB_M1) {
+ slot = -1;
+ }
+ return slot;
+}
+
struct slot_prop {
XtensaOpcodeOps *ops;
uint32_t arg[MAX_OPCODE_ARGS];
@@ -1195,6 +1214,8 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
}
}
+ dc->op_flags = op_flags;
+
for (slot = 0; slot < slots; ++slot) {
struct slot_prop *pslot = ordered[slot];
XtensaOpcodeOps *ops = pslot->ops;
@@ -1204,21 +1225,17 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
}
if (dc->base.is_jmp == DISAS_NEXT) {
- if (op_flags & XTENSA_OP_CHECK_INTERRUPTS) {
- gen_check_interrupts(dc);
- }
-
+ gen_postprocess(dc, 0);
+ dc->op_flags = 0;
if (op_flags & XTENSA_OP_EXIT_TB_M1) {
/* Change in mmu index, memory mapping or tb->flags; exit tb */
gen_jumpi_check_loop_end(dc, -1);
} else if (op_flags & XTENSA_OP_EXIT_TB_0) {
gen_jumpi_check_loop_end(dc, 0);
+ } else {
+ gen_check_loop_end(dc, 0);
}
}
-
- if (dc->base.is_jmp == DISAS_NEXT) {
- gen_check_loop_end(dc, 0);
- }
dc->pc = dc->base.pc_next;
}
--
2.11.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [Qemu-devel] [PATCH 3/3] target/xtensa: move WINDOW_BASE SR update to postprocessing
2019-01-30 23:54 [Qemu-devel] [PATCH 0/3] target/xtensa: add basic FLIX support Max Filippov
2019-01-30 23:54 ` [Qemu-devel] [PATCH 1/3] target/xtensa: sort FLIX instruction opcodes Max Filippov
2019-01-30 23:54 ` [Qemu-devel] [PATCH 2/3] target/xtensa: add generic instruction post-processing Max Filippov
@ 2019-01-30 23:54 ` Max Filippov
2 siblings, 0 replies; 4+ messages in thread
From: Max Filippov @ 2019-01-30 23:54 UTC (permalink / raw)
To: qemu-devel; +Cc: Richard Henderson, Max Filippov
Opcodes that modify WINDOW_BASE SR don't have dependency on opcodes that
use windowed registers. If such opcodes are combined in a single
instruction they may not be correctly ordered. Instead of adding said
dependency use temporary register to store changed WINDOW_BASE value and
do actual register window rotation as a postprocessing step.
Not all opcodes that change WINDOW_BASE need this: retw, rfwo and rfwu
are also jump opcodes, so they are guaranteed to be translated last and
thus will not affect other opcodes in the same instruction.
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
target/xtensa/cpu.h | 1 +
target/xtensa/helper.h | 3 +--
target/xtensa/translate.c | 30 ++++++++++++++++++++++--------
target/xtensa/win_helper.c | 14 ++++----------
4 files changed, 28 insertions(+), 20 deletions(-)
diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h
index e1002c626954..c2b492e175bd 100644
--- a/target/xtensa/cpu.h
+++ b/target/xtensa/cpu.h
@@ -478,6 +478,7 @@ typedef struct CPUXtensaState {
float64 f64;
} fregs[16];
float_status fp_status;
+ uint32_t windowbase_next;
#ifndef CONFIG_USER_ONLY
xtensa_tlb_entry itlb[7][MAX_TLB_WAY_SIZE];
diff --git a/target/xtensa/helper.h b/target/xtensa/helper.h
index 2a7db35874fe..b6529a8925f3 100644
--- a/target/xtensa/helper.h
+++ b/target/xtensa/helper.h
@@ -3,12 +3,11 @@ DEF_HELPER_3(exception_cause, noreturn, env, i32, i32)
DEF_HELPER_4(exception_cause_vaddr, noreturn, env, i32, i32, i32)
DEF_HELPER_3(debug_exception, noreturn, env, i32, i32)
-DEF_HELPER_2(wsr_windowbase, void, env, i32)
+DEF_HELPER_1(sync_windowbase, void, env)
DEF_HELPER_4(entry, void, env, i32, i32, i32)
DEF_HELPER_2(test_ill_retw, void, env, i32)
DEF_HELPER_2(test_underflow_retw, void, env, i32)
DEF_HELPER_2(retw, i32, env, i32)
-DEF_HELPER_2(rotw, void, env, i32)
DEF_HELPER_3(window_check, noreturn, env, i32, i32)
DEF_HELPER_1(restore_owb, void, env)
DEF_HELPER_2(movsp, void, env, i32)
diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c
index f5f5bcfb179a..a61598030dee 100644
--- a/target/xtensa/translate.c
+++ b/target/xtensa/translate.c
@@ -82,6 +82,7 @@ static TCGv_i32 cpu_R[16];
static TCGv_i32 cpu_FR[16];
static TCGv_i32 cpu_SR[256];
static TCGv_i32 cpu_UR[256];
+static TCGv_i32 cpu_windowbase_next;
#include "exec/gen-icount.h"
@@ -253,6 +254,11 @@ void xtensa_translate_init(void)
uregnames[i].name);
}
}
+
+ cpu_windowbase_next =
+ tcg_global_mem_new_i32(cpu_env,
+ offsetof(CPUXtensaState, windowbase_next),
+ "windowbase_next");
}
static inline bool option_enabled(DisasContext *dc, int opt)
@@ -566,7 +572,7 @@ static void gen_wsr_acchi(DisasContext *dc, uint32_t sr, TCGv_i32 s)
#ifndef CONFIG_USER_ONLY
static void gen_wsr_windowbase(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
- gen_helper_wsr_windowbase(cpu_env, v);
+ tcg_gen_mov_i32(cpu_windowbase_next, v);
}
static void gen_wsr_windowstart(DisasContext *dc, uint32_t sr, TCGv_i32 v)
@@ -868,6 +874,9 @@ static int gen_postprocess(DisasContext *dc, int slot)
if (op_flags & XTENSA_OP_CHECK_INTERRUPTS) {
gen_check_interrupts(dc);
}
+ if (op_flags & XTENSA_OP_SYNC_REGISTER_WINDOW) {
+ gen_helper_sync_windowbase(cpu_env);
+ }
if (op_flags & XTENSA_OP_EXIT_TB_M1) {
slot = -1;
}
@@ -2270,9 +2279,7 @@ static void translate_rfw(DisasContext *dc, const uint32_t arg[],
static void translate_rotw(DisasContext *dc, const uint32_t arg[],
const uint32_t par[])
{
- TCGv_i32 tmp = tcg_const_i32(arg[0]);
- gen_helper_rotw(cpu_env, tmp);
- tcg_temp_free(tmp);
+ tcg_gen_addi_i32(cpu_windowbase_next, cpu_SR[WINDOW_BASE], arg[0]);
}
static void translate_rsil(DisasContext *dc, const uint32_t arg[],
@@ -3092,7 +3099,8 @@ static const XtensaOpcodeOps core_ops[] = {
.translate = translate_entry,
.test_ill = test_ill_entry,
.test_overflow = test_overflow_entry,
- .op_flags = XTENSA_OP_EXIT_TB_M1,
+ .op_flags = XTENSA_OP_EXIT_TB_M1 |
+ XTENSA_OP_SYNC_REGISTER_WINDOW,
}, {
.name = "esync",
.translate = translate_nop,
@@ -3781,7 +3789,9 @@ static const XtensaOpcodeOps core_ops[] = {
}, {
.name = "rotw",
.translate = translate_rotw,
- .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1,
+ .op_flags = XTENSA_OP_PRIVILEGED |
+ XTENSA_OP_EXIT_TB_M1 |
+ XTENSA_OP_SYNC_REGISTER_WINDOW,
}, {
.name = "rsil",
.translate = translate_rsil,
@@ -5044,7 +5054,9 @@ static const XtensaOpcodeOps core_ops[] = {
.translate = translate_wsr,
.test_ill = test_ill_wsr,
.par = (const uint32_t[]){WINDOW_BASE},
- .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1,
+ .op_flags = XTENSA_OP_PRIVILEGED |
+ XTENSA_OP_EXIT_TB_M1 |
+ XTENSA_OP_SYNC_REGISTER_WINDOW,
.windowed_register_op = 0x1,
}, {
.name = "wsr.windowstart",
@@ -5611,7 +5623,9 @@ static const XtensaOpcodeOps core_ops[] = {
.translate = translate_xsr,
.test_ill = test_ill_xsr,
.par = (const uint32_t[]){WINDOW_BASE},
- .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1,
+ .op_flags = XTENSA_OP_PRIVILEGED |
+ XTENSA_OP_EXIT_TB_M1 |
+ XTENSA_OP_SYNC_REGISTER_WINDOW,
.windowed_register_op = 0x1,
}, {
.name = "xsr.windowstart",
diff --git a/target/xtensa/win_helper.c b/target/xtensa/win_helper.c
index 7d793d4f9cff..d7a4e2782186 100644
--- a/target/xtensa/win_helper.c
+++ b/target/xtensa/win_helper.c
@@ -96,9 +96,9 @@ void xtensa_rotate_window(CPUXtensaState *env, uint32_t delta)
xtensa_rotate_window_abs(env, env->sregs[WINDOW_BASE] + delta);
}
-void HELPER(wsr_windowbase)(CPUXtensaState *env, uint32_t v)
+void HELPER(sync_windowbase)(CPUXtensaState *env)
{
- xtensa_rotate_window_abs(env, v);
+ xtensa_rotate_window_abs(env, env->windowbase_next);
}
void HELPER(entry)(CPUXtensaState *env, uint32_t pc, uint32_t s, uint32_t imm)
@@ -106,9 +106,8 @@ void HELPER(entry)(CPUXtensaState *env, uint32_t pc, uint32_t s, uint32_t imm)
int callinc = (env->sregs[PS] & PS_CALLINC) >> PS_CALLINC_SHIFT;
env->regs[(callinc << 2) | (s & 3)] = env->regs[s] - imm;
- xtensa_rotate_window(env, callinc);
- env->sregs[WINDOW_START] |=
- windowstart_bit(env->sregs[WINDOW_BASE], env);
+ env->windowbase_next = env->sregs[WINDOW_BASE] + callinc;
+ env->sregs[WINDOW_START] |= windowstart_bit(env->windowbase_next, env);
}
void HELPER(window_check)(CPUXtensaState *env, uint32_t pc, uint32_t w)
@@ -196,11 +195,6 @@ uint32_t HELPER(retw)(CPUXtensaState *env, uint32_t pc)
return ret_pc;
}
-void HELPER(rotw)(CPUXtensaState *env, uint32_t imm4)
-{
- xtensa_rotate_window(env, imm4);
-}
-
void xtensa_restore_owb(CPUXtensaState *env)
{
xtensa_rotate_window_abs(env, (env->sregs[PS] & PS_OWB) >> PS_OWB_SHIFT);
--
2.11.0
^ permalink raw reply related [flat|nested] 4+ messages in thread