aboutsummaryrefslogtreecommitdiff
path: root/target-cris/translate.c
diff options
context:
space:
mode:
authorEdgar E. Iglesias <edgar.iglesias@gmail.com>2010-02-15 12:18:57 +0100
committerEdgar E. Iglesias <edgar.iglesias@gmail.com>2010-02-15 12:18:57 +0100
commit40e9eddd3850e7c732c4a80e5e5ce5c490dcf07c (patch)
treeef4fd78f253b2b8e420dea11d019c553f3bc0259 /target-cris/translate.c
parent46e246c911651b79323e7865d4114311cab0260b (diff)
downloadqemu-40e9eddd3850e7c732c4a80e5e5ce5c490dcf07c.zip
qemu-40e9eddd3850e7c732c4a80e5e5ce5c490dcf07c.tar.gz
qemu-40e9eddd3850e7c732c4a80e5e5ce5c490dcf07c.tar.bz2
cris: Add support for CRISv10 translation.
Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Diffstat (limited to 'target-cris/translate.c')
-rw-r--r--target-cris/translate.c162
1 files changed, 132 insertions, 30 deletions
diff --git a/target-cris/translate.c b/target-cris/translate.c
index 91e3972..f8baa88 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -86,6 +86,7 @@ typedef struct DisasContext {
target_ulong pc, ppc;
/* Decoder. */
+ unsigned int (*decoder)(struct DisasContext *dc);
uint32_t ir;
uint32_t opcode;
unsigned int op1;
@@ -94,6 +95,11 @@ typedef struct DisasContext {
unsigned int mode;
unsigned int postinc;
+ unsigned int size;
+ unsigned int src;
+ unsigned int dst;
+ unsigned int cond;
+
int update_cc;
int cc_op;
int cc_size;
@@ -108,6 +114,8 @@ typedef struct DisasContext {
int flags_x;
int clear_x; /* Clear x after this insn? */
+ int clear_prefix; /* Clear prefix after this insn? */
+ int clear_locked_irq; /* Clear the irq lockout. */
int cpustate_changed;
unsigned int tb_flags; /* tb dependent flags. */
int is_jmp;
@@ -219,6 +227,12 @@ static inline void t_gen_mov_preg_TN(DisasContext *dc, int r, TCGv tn)
}
}
+static void cris_lock_irq(DisasContext *dc)
+{
+ dc->clear_locked_irq = 0;
+ t_gen_mov_env_TN(locked_irq, tcg_const_tl(1));
+}
+
static inline void t_gen_raise_exception(uint32_t index)
{
TCGv_i32 tmp = tcg_const_i32(index);
@@ -332,6 +346,24 @@ static void t_gen_cris_dstep(TCGv d, TCGv a, TCGv b)
gen_set_label(l1);
}
+static void t_gen_cris_mstep(TCGv d, TCGv a, TCGv b, TCGv ccs)
+{
+ TCGv t;
+
+ /*
+ * d <<= 1
+ * if (n)
+ * d += s;
+ */
+ t = tcg_temp_new();
+ tcg_gen_shli_tl(d, a, 1);
+ tcg_gen_shli_tl(t, ccs, 31 - 3);
+ tcg_gen_sari_tl(t, t, 31);
+ tcg_gen_and_tl(t, t, b);
+ tcg_gen_add_tl(d, d, t);
+ tcg_temp_free(t);
+}
+
/* Extended arithmetics on CRIS. */
static inline void t_gen_add_flag(TCGv d, int flag)
{
@@ -634,7 +666,7 @@ static void cris_evaluate_flags(DisasContext *dc)
if (dc->flags_x)
tcg_gen_ori_tl(cpu_PR[PR_CCS],
cpu_PR[PR_CCS], X_FLAG);
- else
+ else if (dc->cc_op == CC_OP_FLAGS)
tcg_gen_andi_tl(cpu_PR[PR_CCS],
cpu_PR[PR_CCS], ~X_FLAG);
}
@@ -774,6 +806,9 @@ static void cris_alu_op_exec(DisasContext *dc, int op,
case CC_OP_DSTEP:
t_gen_cris_dstep(dst, a, b);
break;
+ case CC_OP_MSTEP:
+ t_gen_cris_mstep(dst, a, b, cpu_PR[PR_CCS]);
+ break;
case CC_OP_BOUND:
{
int l1;
@@ -878,7 +913,8 @@ static void gen_tst_cc (DisasContext *dc, TCGv cc, int cond)
move_opt = (dc->cc_op == CC_OP_MOVE);
switch (cond) {
case CC_EQ:
- if (arith_opt || move_opt) {
+ if ((arith_opt || move_opt)
+ && dc->cc_x_uptodate != (2 | X_FLAG)) {
/* If cc_result is zero, T0 should be
non-zero otherwise T0 should be zero. */
int l1;
@@ -896,9 +932,10 @@ static void gen_tst_cc (DisasContext *dc, TCGv cc, int cond)
}
break;
case CC_NE:
- if (arith_opt || move_opt)
+ if ((arith_opt || move_opt)
+ && dc->cc_x_uptodate != (2 | X_FLAG)) {
tcg_gen_mov_tl(cc, cc_result);
- else {
+ } else {
cris_evaluate_flags(dc);
tcg_gen_xori_tl(cc, cpu_PR[PR_CCS],
Z_FLAG);
@@ -2058,16 +2095,17 @@ static unsigned int dec_setclrf(DisasContext *dc)
dc->flags_x = 0;
}
- /* Break the TB if the P flag changes. */
- if (flags & P_FLAG) {
- if ((set && !(dc->tb_flags & P_FLAG))
- || (!set && (dc->tb_flags & P_FLAG))) {
- tcg_gen_movi_tl(env_pc, dc->pc + 2);
- dc->is_jmp = DISAS_UPDATE;
- dc->cpustate_changed = 1;
- }
+ /* Break the TB if any of the SPI flag changes. */
+ if (flags & (P_FLAG | S_FLAG)) {
+ tcg_gen_movi_tl(env_pc, dc->pc + 2);
+ dc->is_jmp = DISAS_UPDATE;
+ dc->cpustate_changed = 1;
}
- if (flags & S_FLAG) {
+
+ /* For the I flag, only act on posedge. */
+ if ((flags & I_FLAG)) {
+ tcg_gen_movi_tl(env_pc, dc->pc + 2);
+ dc->is_jmp = DISAS_UPDATE;
dc->cpustate_changed = 1;
}
@@ -2143,17 +2181,22 @@ static unsigned int dec_move_rp(DisasContext *dc)
static unsigned int dec_move_pr(DisasContext *dc)
{
TCGv t0;
- LOG_DIS("move $p%u, $r%u\n", dc->op1, dc->op2);
+ LOG_DIS("move $p%u, $r%u\n", dc->op2, dc->op1);
cris_cc_mask(dc, 0);
if (dc->op2 == PR_CCS)
cris_evaluate_flags(dc);
- t0 = tcg_temp_new();
- t_gen_mov_TN_preg(t0, dc->op2);
- cris_alu(dc, CC_OP_MOVE,
- cpu_R[dc->op1], cpu_R[dc->op1], t0, preg_sizes[dc->op2]);
- tcg_temp_free(t0);
+ if (dc->op2 == PR_DZ) {
+ tcg_gen_movi_tl(cpu_R[dc->op1], 0);
+ } else {
+ t0 = tcg_temp_new();
+ t_gen_mov_TN_preg(t0, dc->op2);
+ cris_alu(dc, CC_OP_MOVE,
+ cpu_R[dc->op1], cpu_R[dc->op1], t0,
+ preg_sizes[dc->op2]);
+ tcg_temp_free(t0);
+ }
return 2;
}
@@ -3026,8 +3069,7 @@ static struct decoder_info {
{{0, 0}, dec_null}
};
-static inline unsigned int
-cris_decoder(DisasContext *dc)
+static unsigned int crisv32_decoder(DisasContext *dc)
{
unsigned int insn_len = 2;
int i;
@@ -3090,6 +3132,7 @@ static void check_breakpoint(CPUState *env, DisasContext *dc)
}
}
+#include "translate_v10.c"
/*
* Delay slots on QEMU/CRIS.
@@ -3132,7 +3175,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
{
uint16_t *gen_opc_end;
uint32_t pc_start;
- unsigned int insn_len;
+ unsigned int insn_len, orig_flags;
int j, lj;
struct DisasContext ctx;
struct DisasContext *dc = &ctx;
@@ -3143,6 +3186,11 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
qemu_log_try_set_file(stderr);
+ if (env->pregs[PR_VR] == 32)
+ dc->decoder = crisv32_decoder;
+ else
+ dc->decoder = crisv10_decoder;
+
/* Odd PC indicates that branch is rexecuting due to exception in the
* delayslot, like in real hw.
*/
@@ -3162,12 +3210,15 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
dc->cc_x_uptodate = 0;
dc->cc_mask = 0;
dc->update_cc = 0;
+ dc->clear_prefix = 0;
+ dc->clear_locked_irq = 1;
cris_update_cc_op(dc, CC_OP_FLAGS, 4);
dc->cc_size_uptodate = -1;
/* Decode TB flags. */
- dc->tb_flags = tb->flags & (S_FLAG | P_FLAG | U_FLAG | X_FLAG);
+ orig_flags = dc->tb_flags = tb->flags & (S_FLAG | P_FLAG | U_FLAG \
+ | X_FLAG | PFIX_FLAG);
dc->delayed_branch = !!(tb->flags & 7);
if (dc->delayed_branch)
dc->jmp = JMP_INDIRECT;
@@ -3233,7 +3284,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
gen_io_start();
dc->clear_x = 1;
- insn_len = cris_decoder(dc);
+ insn_len = dc->decoder(dc);
dc->ppc = dc->pc;
dc->pc += insn_len;
if (dc->clear_x)
@@ -3271,6 +3322,13 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
&& (dc->pc < next_page_start)
&& num_insns < max_insns);
+ if (dc->tb_flags != orig_flags) {
+ dc->cpustate_changed = 1;
+ }
+
+ if (dc->clear_locked_irq)
+ t_gen_mov_env_TN(locked_irq, tcg_const_tl(0));
+
npc = dc->pc;
if (dc->jmp == JMP_DIRECT && !dc->delayed_branch)
npc = dc->jmp_pc;
@@ -3330,7 +3388,8 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
#ifdef DEBUG_DISAS
#if !DISAS_CRIS
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
- log_target_disas(pc_start, dc->pc - pc_start, 0);
+ log_target_disas(pc_start, dc->pc - pc_start,
+ dc->env->pregs[PR_VR]);
qemu_log("\nisize=%d osize=%zd\n",
dc->pc - pc_start, gen_opc_ptr - gen_opc_buf);
}
@@ -3390,6 +3449,39 @@ void cpu_dump_state (CPUState *env, FILE *f,
}
+struct
+{
+ uint32_t vr;
+ const char *name;
+} cris_cores[] = {
+ {8, "crisv8"},
+ {9, "crisv9"},
+ {10, "crisv10"},
+ {11, "crisv11"},
+ {32, "crisv32"},
+};
+
+void cris_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+{
+ unsigned int i;
+
+ (*cpu_fprintf)(f, "Available CPUs:\n");
+ for (i = 0; i < ARRAY_SIZE(cris_cores); i++) {
+ (*cpu_fprintf)(f, " %s\n", cris_cores[i].name);
+ }
+}
+
+static uint32_t vr_by_name(const char *name)
+{
+ unsigned int i;
+ for (i = 0; i < ARRAY_SIZE(cris_cores); i++) {
+ if (strcmp(name, cris_cores[i].name) == 0) {
+ return cris_cores[i].vr;
+ }
+ }
+ return 32;
+}
+
CPUCRISState *cpu_cris_init (const char *cpu_model)
{
CPUCRISState *env;
@@ -3398,6 +3490,7 @@ CPUCRISState *cpu_cris_init (const char *cpu_model)
env = qemu_mallocz(sizeof(CPUCRISState));
+ env->pregs[PR_VR] = vr_by_name(cpu_model);
cpu_exec_init(env);
cpu_reset(env);
qemu_init_vcpu(env);
@@ -3407,6 +3500,15 @@ CPUCRISState *cpu_cris_init (const char *cpu_model)
tcg_initialized = 1;
+#define GEN_HELPER 2
+#include "helper.h"
+
+ if (env->pregs[PR_VR] < 32) {
+ cpu_crisv10_init(env);
+ return env;
+ }
+
+
cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
cc_x = tcg_global_mem_new(TCG_AREG0,
offsetof(CPUState, cc_x), "cc_x");
@@ -3447,26 +3549,26 @@ CPUCRISState *cpu_cris_init (const char *cpu_model)
pregnames[i]);
}
-#define GEN_HELPER 2
-#include "helper.h"
-
return env;
}
void cpu_reset (CPUCRISState *env)
{
+ uint32_t vr;
+
if (qemu_loglevel_mask(CPU_LOG_RESET)) {
qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
log_cpu_state(env, 0);
}
+ vr = env->pregs[PR_VR];
memset(env, 0, offsetof(CPUCRISState, breakpoints));
+ env->pregs[PR_VR] = vr;
tlb_flush(env, 1);
- env->pregs[PR_VR] = 32;
#if defined(CONFIG_USER_ONLY)
/* start in user mode with interrupts enabled. */
- env->pregs[PR_CCS] |= U_FLAG | I_FLAG;
+ env->pregs[PR_CCS] |= U_FLAG | I_FLAG | P_FLAG;
#else
cris_mmu_init(env);
env->pregs[PR_CCS] = 0;