mirror of
https://github.com/qemu/qemu.git
synced 2024-11-24 11:23:43 +08:00
CRIS updates:
* Support both the I and D MMUs and improve the accuracy of the MMU model. * Handle the automatic user/kernel stack pointer switching when leaving or entering user mode. * Move the CCS evaluation into helper funcs. * Make sure user-mode cannot change flags only writeable in kernel mode. * More conversion of the translator into TCG. * Handle exceptions while in a delayslot. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4299 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
ff56ff7a07
commit
b41f7df018
@ -257,7 +257,7 @@ static inline TranslationBlock *tb_find_fast(void)
|
||||
cs_base = 0;
|
||||
pc = env->pc;
|
||||
#elif defined(TARGET_CRIS)
|
||||
flags = 0;
|
||||
flags = env->pregs[PR_CCS];
|
||||
cs_base = 0;
|
||||
pc = env->pc;
|
||||
#else
|
||||
|
@ -38,6 +38,28 @@
|
||||
#define EXCP_MMU_FAULT 4
|
||||
#define EXCP_BREAK 16 /* trap. */
|
||||
|
||||
/* Register aliases. R0 - R15 */
|
||||
#define R_FP 8
|
||||
#define R_SP 14
|
||||
#define R_ACR 15
|
||||
|
||||
/* Support regs, P0 - P15 */
|
||||
#define PR_BZ 0
|
||||
#define PR_VR 1
|
||||
#define PR_PID 2
|
||||
#define PR_SRS 3
|
||||
#define PR_WZ 4
|
||||
#define PR_EXS 5
|
||||
#define PR_EDA 6
|
||||
#define PR_MOF 7
|
||||
#define PR_DZ 8
|
||||
#define PR_EBP 9
|
||||
#define PR_ERP 10
|
||||
#define PR_SRP 11
|
||||
#define PR_CCS 13
|
||||
#define PR_USP 14
|
||||
#define PR_SPC 15
|
||||
|
||||
/* CPU flags. */
|
||||
#define S_FLAG 0x200
|
||||
#define R_FLAG 0x100
|
||||
@ -77,27 +99,16 @@
|
||||
#define NB_MMU_MODES 2
|
||||
|
||||
typedef struct CPUCRISState {
|
||||
uint32_t debug1;
|
||||
uint32_t debug2;
|
||||
uint32_t debug3;
|
||||
|
||||
/*
|
||||
* We just store the stores to the tlbset here for later evaluation
|
||||
* when the hw needs access to them.
|
||||
*
|
||||
* One for I and another for D.
|
||||
*/
|
||||
struct
|
||||
{
|
||||
uint32_t hi;
|
||||
uint32_t lo;
|
||||
} tlbsets[2][4][16];
|
||||
|
||||
uint32_t sregs[256][16]; /* grrr why so many?? */
|
||||
uint32_t regs[16];
|
||||
/* P0 - P15 are referred to as special registers in the docs. */
|
||||
uint32_t pregs[16];
|
||||
|
||||
/* Pseudo register for the PC. Not directly accessable on CRIS. */
|
||||
uint32_t pc;
|
||||
|
||||
/* Pseudo register for the kernel stack. */
|
||||
uint32_t ksp;
|
||||
|
||||
/* These are setup up by the guest code just before transfering the
|
||||
control back to the host. */
|
||||
int jmp;
|
||||
@ -114,20 +125,19 @@ typedef struct CPUCRISState {
|
||||
/* size of the operation, 1 = byte, 2 = word, 4 = dword. */
|
||||
int cc_size;
|
||||
|
||||
/* extended arithmetics. */
|
||||
/* Extended arithmetics. */
|
||||
int cc_x_live;
|
||||
int cc_x;
|
||||
|
||||
int features;
|
||||
|
||||
int exception_index;
|
||||
int interrupt_request;
|
||||
int interrupt_vector;
|
||||
int fault_vector;
|
||||
int trap_vector;
|
||||
|
||||
int user_mode_only;
|
||||
int halted;
|
||||
uint32_t debug1;
|
||||
uint32_t debug2;
|
||||
uint32_t debug3;
|
||||
|
||||
struct
|
||||
{
|
||||
@ -136,6 +146,31 @@ typedef struct CPUCRISState {
|
||||
int exec_stores;
|
||||
} stats;
|
||||
|
||||
/* FIXME: add a check in the translator to avoid writing to support
|
||||
register sets beyond the 4th. The ISA allows up to 256! but in
|
||||
practice there is no core that implements more than 4.
|
||||
|
||||
Support function registers are used to control units close to the
|
||||
core. Accesses do not pass down the normal hierarchy.
|
||||
*/
|
||||
uint32_t sregs[4][16];
|
||||
|
||||
/*
|
||||
* We just store the stores to the tlbset here for later evaluation
|
||||
* when the hw needs access to them.
|
||||
*
|
||||
* One for I and another for D.
|
||||
*/
|
||||
struct
|
||||
{
|
||||
uint32_t hi;
|
||||
uint32_t lo;
|
||||
} tlbsets[2][4][16];
|
||||
|
||||
int features;
|
||||
int user_mode_only;
|
||||
int halted;
|
||||
|
||||
jmp_buf jmp_env;
|
||||
CPU_COMMON
|
||||
} CPUCRISState;
|
||||
@ -225,40 +260,20 @@ void register_cris_insns (CPUCRISState *env);
|
||||
#define MMU_MODE0_SUFFIX _kernel
|
||||
#define MMU_MODE1_SUFFIX _user
|
||||
#define MMU_USER_IDX 1
|
||||
/* CRIS FIXME: I guess we want to validate supervisor mode acceses here. */
|
||||
static inline int cpu_mmu_index (CPUState *env)
|
||||
{
|
||||
return 0;
|
||||
return !!(env->pregs[PR_CCS] & U_FLAG);
|
||||
}
|
||||
|
||||
#include "cpu-all.h"
|
||||
|
||||
/* Register aliases. R0 - R15 */
|
||||
#define R_FP 8
|
||||
#define R_SP 14
|
||||
#define R_ACR 15
|
||||
|
||||
/* Support regs, P0 - P15 */
|
||||
#define PR_BZ 0
|
||||
#define PR_VR 1
|
||||
#define PR_PID 2
|
||||
#define PR_SRS 3
|
||||
#define PR_WZ 4
|
||||
#define PR_MOF 7
|
||||
#define PR_DZ 8
|
||||
#define PR_EBP 9
|
||||
#define PR_ERP 10
|
||||
#define PR_SRP 11
|
||||
#define PR_CCS 13
|
||||
|
||||
/* Support function regs. */
|
||||
#define SFR_RW_GC_CFG 0][0
|
||||
#define SFR_RW_MM_CFG 2][0
|
||||
#define SFR_RW_MM_KBASE_LO 2][1
|
||||
#define SFR_RW_MM_KBASE_HI 2][2
|
||||
#define SFR_R_MM_CAUSE 2][3
|
||||
#define SFR_RW_MM_TLB_SEL 2][4
|
||||
#define SFR_RW_MM_TLB_LO 2][5
|
||||
#define SFR_RW_MM_TLB_HI 2][6
|
||||
#define SFR_RW_MM_CFG env->pregs[PR_SRS]][0
|
||||
#define SFR_RW_MM_KBASE_LO env->pregs[PR_SRS]][1
|
||||
#define SFR_RW_MM_KBASE_HI env->pregs[PR_SRS]][2
|
||||
#define SFR_R_MM_CAUSE env->pregs[PR_SRS]][3
|
||||
#define SFR_RW_MM_TLB_SEL env->pregs[PR_SRS]][4
|
||||
#define SFR_RW_MM_TLB_LO env->pregs[PR_SRS]][5
|
||||
#define SFR_RW_MM_TLB_HI env->pregs[PR_SRS]][6
|
||||
|
||||
#include "cpu-all.h"
|
||||
#endif
|
||||
|
@ -61,7 +61,7 @@ static void cris_shift_ccs(CPUState *env)
|
||||
uint32_t ccs;
|
||||
/* Apply the ccs shift. */
|
||||
ccs = env->pregs[PR_CCS];
|
||||
ccs = (ccs & 0xc0000000) | ((ccs << 12) >> 2);
|
||||
ccs = ((ccs & 0xc0000000) | ((ccs << 12) >> 2)) & ~0x3ff;
|
||||
env->pregs[PR_CCS] = ccs;
|
||||
}
|
||||
|
||||
@ -73,7 +73,7 @@ int cpu_cris_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
||||
int r = -1;
|
||||
target_ulong phy;
|
||||
|
||||
D(printf ("%s addr=%x pc=%x\n", __func__, address, env->pc));
|
||||
D(printf ("%s addr=%x pc=%x rw=%x\n", __func__, address, env->pc, rw));
|
||||
address &= TARGET_PAGE_MASK;
|
||||
prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
|
||||
miss = cris_mmu_translate(&res, env, address, rw, mmu_idx);
|
||||
@ -86,12 +86,14 @@ int cpu_cris_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
||||
else
|
||||
{
|
||||
phy = res.phy;
|
||||
prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
|
||||
prot = res.prot;
|
||||
address &= TARGET_PAGE_MASK;
|
||||
r = tlb_set_page(env, address, phy, prot, mmu_idx, is_softmmu);
|
||||
}
|
||||
D(printf("%s returns %d irqreq=%x addr=%x ismmu=%d\n",
|
||||
__func__, r, env->interrupt_request,
|
||||
address, is_softmmu));
|
||||
if (r > 0)
|
||||
D(fprintf(logfile, "%s returns %d irqreq=%x addr=%x ismmu=%d vec=%x\n",
|
||||
__func__, r, env->interrupt_request,
|
||||
address, is_softmmu, res.bf_vec));
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -100,8 +102,8 @@ void do_interrupt(CPUState *env)
|
||||
int ex_vec = -1;
|
||||
|
||||
D(fprintf (stderr, "exception index=%d interrupt_req=%d\n",
|
||||
env->exception_index,
|
||||
env->interrupt_request));
|
||||
env->exception_index,
|
||||
env->interrupt_request));
|
||||
|
||||
switch (env->exception_index)
|
||||
{
|
||||
@ -113,40 +115,46 @@ void do_interrupt(CPUState *env)
|
||||
break;
|
||||
|
||||
case EXCP_MMU_FAULT:
|
||||
/* ERP is already setup by translate-all.c through
|
||||
re-translation of the aborted TB combined with
|
||||
pc searching. */
|
||||
ex_vec = env->fault_vector;
|
||||
env->pregs[PR_ERP] = env->pc;
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
/* Maybe the irq was acked by sw before we got a
|
||||
change to take it. */
|
||||
if (env->interrupt_request & CPU_INTERRUPT_HARD) {
|
||||
/* Vectors below 0x30 are internal
|
||||
exceptions, i.e not interrupt requests
|
||||
from the interrupt controller. */
|
||||
if (env->interrupt_vector < 0x30)
|
||||
return;
|
||||
/* Is the core accepting interrupts? */
|
||||
if (!(env->pregs[PR_CCS] & I_FLAG)) {
|
||||
return;
|
||||
}
|
||||
/* The interrupt controller gives us the
|
||||
vector. */
|
||||
ex_vec = env->interrupt_vector;
|
||||
/* Normal interrupts are taken between
|
||||
TB's. env->pc is valid here. */
|
||||
env->pregs[PR_ERP] = env->pc;
|
||||
}
|
||||
}
|
||||
break;
|
||||
/* Is the core accepting interrupts? */
|
||||
if (!(env->pregs[PR_CCS] & I_FLAG))
|
||||
return;
|
||||
/* The interrupt controller gives us the
|
||||
vector. */
|
||||
ex_vec = env->interrupt_vector;
|
||||
/* Normal interrupts are taken between
|
||||
TB's. env->pc is valid here. */
|
||||
env->pregs[PR_ERP] = env->pc;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((env->pregs[PR_CCS] & U_FLAG)) {
|
||||
D(fprintf(logfile, "excp isr=%x PC=%x ERP=%x pid=%x ccs=%x cc=%d %x\n",
|
||||
ex_vec, env->pc,
|
||||
env->pregs[PR_ERP], env->pregs[PR_PID],
|
||||
env->pregs[PR_CCS],
|
||||
env->cc_op, env->cc_mask));
|
||||
}
|
||||
|
||||
env->pc = ldl_code(env->pregs[PR_EBP] + ex_vec * 4);
|
||||
/* Apply the CRIS CCS shift. */
|
||||
|
||||
if (env->pregs[PR_CCS] & U_FLAG) {
|
||||
/* Swap stack pointers. */
|
||||
env->pregs[PR_USP] = env->regs[R_SP];
|
||||
env->regs[R_SP] = env->ksp;
|
||||
}
|
||||
|
||||
/* Apply the CRIS CCS shift. Clears U if set. */
|
||||
cris_shift_ccs(env);
|
||||
D(printf ("%s ebp=%x isr=%x vec=%x\n", __func__, ebp, isr, ex_vec));
|
||||
D(fprintf (logfile, "%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n",
|
||||
__func__, env->pc, ex_vec,
|
||||
env->pregs[PR_CCS],
|
||||
env->pregs[PR_PID],
|
||||
env->pregs[PR_ERP]));
|
||||
}
|
||||
|
||||
target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
|
||||
|
@ -1,3 +1,15 @@
|
||||
#define TCG_HELPER_PROTO
|
||||
void TCG_HELPER_PROTO helper_tlb_update(uint32_t T0);
|
||||
void TCG_HELPER_PROTO helper_tlb_flush(void);
|
||||
void TCG_HELPER_PROTO helper_dump(uint32_t a0, uint32_t a1, uint32_t a2);
|
||||
void TCG_HELPER_PROTO helper_dummy(void);
|
||||
void TCG_HELPER_PROTO helper_rfe(void);
|
||||
void TCG_HELPER_PROTO helper_store(uint32_t a0);
|
||||
|
||||
void TCG_HELPER_PROTO helper_evaluate_flags_muls(void);
|
||||
void TCG_HELPER_PROTO helper_evaluate_flags_mulu(void);
|
||||
void TCG_HELPER_PROTO helper_evaluate_flags_mcp(void);
|
||||
void TCG_HELPER_PROTO helper_evaluate_flags_alu_4(void);
|
||||
void TCG_HELPER_PROTO helper_evaluate_flags_move_4 (void);
|
||||
void TCG_HELPER_PROTO helper_evaluate_flags_move_2 (void);
|
||||
void TCG_HELPER_PROTO helper_evaluate_flags (void);
|
||||
|
@ -73,11 +73,30 @@ static inline void set_field(uint32_t *dst, unsigned int val,
|
||||
val <<= offset;
|
||||
|
||||
val &= mask;
|
||||
D(printf ("val=%x mask=%x dst=%x\n", val, mask, *dst));
|
||||
*dst &= ~(mask);
|
||||
*dst |= val;
|
||||
}
|
||||
|
||||
static void dump_tlb(CPUState *env, int mmu)
|
||||
{
|
||||
int set;
|
||||
int idx;
|
||||
uint32_t hi, lo, tlb_vpn, tlb_pfn;
|
||||
|
||||
for (set = 0; set < 4; set++) {
|
||||
for (idx = 0; idx < 16; idx++) {
|
||||
lo = env->tlbsets[mmu][set][idx].lo;
|
||||
hi = env->tlbsets[mmu][set][idx].hi;
|
||||
tlb_vpn = EXTRACT_FIELD(hi, 13, 31);
|
||||
tlb_pfn = EXTRACT_FIELD(lo, 13, 31);
|
||||
|
||||
printf ("TLB: [%d][%d] hi=%x lo=%x v=%x p=%x\n",
|
||||
set, idx, hi, lo, tlb_vpn, tlb_pfn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* rw 0 = read, 1 = write, 2 = exec. */
|
||||
static int cris_mmu_translate_page(struct cris_mmu_result_t *res,
|
||||
CPUState *env, uint32_t vaddr,
|
||||
int rw, int usermode)
|
||||
@ -88,53 +107,63 @@ static int cris_mmu_translate_page(struct cris_mmu_result_t *res,
|
||||
uint32_t tlb_vpn, tlb_pfn = 0;
|
||||
int tlb_pid, tlb_g, tlb_v, tlb_k, tlb_w, tlb_x;
|
||||
int cfg_v, cfg_k, cfg_w, cfg_x;
|
||||
int i, match = 0;
|
||||
int set, match = 0;
|
||||
uint32_t r_cause;
|
||||
uint32_t r_cfg;
|
||||
int rwcause;
|
||||
int update_sel = 0;
|
||||
int mmu = 1; /* Data mmu is default. */
|
||||
int vect_base;
|
||||
|
||||
r_cause = env->sregs[SFR_R_MM_CAUSE];
|
||||
r_cfg = env->sregs[SFR_RW_MM_CFG];
|
||||
rwcause = rw ? CRIS_MMU_ERR_WRITE : CRIS_MMU_ERR_READ;
|
||||
|
||||
switch (rw) {
|
||||
case 2: rwcause = CRIS_MMU_ERR_EXEC; mmu = 0; break;
|
||||
case 1: rwcause = CRIS_MMU_ERR_WRITE; break;
|
||||
default:
|
||||
case 0: rwcause = CRIS_MMU_ERR_READ; break;
|
||||
}
|
||||
|
||||
/* I exception vectors 4 - 7, D 8 - 11. */
|
||||
vect_base = (mmu + 1) * 4;
|
||||
|
||||
vpage = vaddr >> 13;
|
||||
idx = vpage & 15;
|
||||
|
||||
/* We know the index which to check on each set.
|
||||
Scan both I and D. */
|
||||
#if 0
|
||||
for (i = 0; i < 4; i++) {
|
||||
int j;
|
||||
for (j = 0; j < 16; j++) {
|
||||
lo = env->tlbsets[1][i][j].lo;
|
||||
hi = env->tlbsets[1][i][j].hi;
|
||||
for (set = 0; set < 4; set++) {
|
||||
for (idx = 0; idx < 16; idx++) {
|
||||
lo = env->tlbsets[mmu][set][idx].lo;
|
||||
hi = env->tlbsets[mmu][set][idx].hi;
|
||||
tlb_vpn = EXTRACT_FIELD(hi, 13, 31);
|
||||
tlb_pfn = EXTRACT_FIELD(lo, 13, 31);
|
||||
|
||||
printf ("TLB: [%d][%d] hi=%x lo=%x v=%x p=%x\n",
|
||||
i, j, hi, lo, tlb_vpn, tlb_pfn);
|
||||
set, idx, hi, lo, tlb_vpn, tlb_pfn);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
for (i = 0; i < 4; i++)
|
||||
|
||||
idx = vpage & 15;
|
||||
for (set = 0; set < 4; set++)
|
||||
{
|
||||
lo = env->tlbsets[1][i][idx].lo;
|
||||
hi = env->tlbsets[1][i][idx].hi;
|
||||
lo = env->tlbsets[mmu][set][idx].lo;
|
||||
hi = env->tlbsets[mmu][set][idx].hi;
|
||||
|
||||
tlb_vpn = EXTRACT_FIELD(hi, 13, 31);
|
||||
tlb_pfn = EXTRACT_FIELD(lo, 13, 31);
|
||||
|
||||
D(printf ("TLB[%d][%d] tlbv=%x vpage=%x -> pfn=%x\n",
|
||||
i, idx, tlb_vpn, vpage, tlb_pfn));
|
||||
D(printf("TLB[%d][%d] v=%x vpage=%x -> pfn=%x lo=%x hi=%x\n",
|
||||
i, idx, tlb_vpn, vpage, tlb_pfn, lo, hi));
|
||||
if (tlb_vpn == vpage) {
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
res->bf_vec = vect_base;
|
||||
if (match) {
|
||||
|
||||
cfg_w = EXTRACT_FIELD(r_cfg, 19, 19);
|
||||
cfg_k = EXTRACT_FIELD(r_cfg, 18, 18);
|
||||
cfg_x = EXTRACT_FIELD(r_cfg, 17, 17);
|
||||
@ -158,54 +187,67 @@ static int cris_mmu_translate_page(struct cris_mmu_result_t *res,
|
||||
set_exception_vector(0x0a, d_mmu_access);
|
||||
set_exception_vector(0x0b, d_mmu_write);
|
||||
*/
|
||||
if (cfg_v && !tlb_v) {
|
||||
printf ("tlb: invalid\n");
|
||||
if (!tlb_g
|
||||
&& tlb_pid != (env->pregs[PR_PID] & 0xff)) {
|
||||
D(printf ("tlb: wrong pid %x %x pc=%x\n",
|
||||
tlb_pid, env->pregs[PR_PID], env->pc));
|
||||
match = 0;
|
||||
res->bf_vec = vect_base;
|
||||
} else if (rw == 1 && cfg_w && !tlb_w) {
|
||||
D(printf ("tlb: write protected %x lo=%x\n",
|
||||
vaddr, lo));
|
||||
match = 0;
|
||||
res->bf_vec = vect_base + 3;
|
||||
} else if (cfg_v && !tlb_v) {
|
||||
D(printf ("tlb: invalid %x\n", vaddr));
|
||||
set_field(&r_cause, rwcause, 8, 9);
|
||||
match = 0;
|
||||
res->bf_vec = 0x9;
|
||||
update_sel = 1;
|
||||
res->bf_vec = vect_base + 1;
|
||||
}
|
||||
else if (!tlb_g
|
||||
&& tlb_pid != 0xff
|
||||
&& tlb_pid != env->pregs[PR_PID]
|
||||
&& cfg_w && !tlb_w) {
|
||||
printf ("tlb: wrong pid\n");
|
||||
match = 0;
|
||||
res->bf_vec = 0xa;
|
||||
}
|
||||
else if (rw && cfg_w && !tlb_w) {
|
||||
printf ("tlb: write protected\n");
|
||||
match = 0;
|
||||
res->bf_vec = 0xb;
|
||||
}
|
||||
} else
|
||||
update_sel = 1;
|
||||
|
||||
if (update_sel) {
|
||||
/* miss. */
|
||||
env->sregs[SFR_RW_MM_TLB_SEL] = 0;
|
||||
D(printf ("tlb: miss %x vp=%x\n",
|
||||
env->sregs[SFR_RW_MM_TLB_SEL], vpage & 15));
|
||||
set_field(&env->sregs[SFR_RW_MM_TLB_SEL], vpage & 15, 0, 4);
|
||||
set_field(&env->sregs[SFR_RW_MM_TLB_SEL], 0, 4, 5);
|
||||
res->bf_vec = 0x8;
|
||||
res->prot = 0;
|
||||
if (match) {
|
||||
res->prot |= PAGE_READ;
|
||||
if (tlb_w)
|
||||
res->prot |= PAGE_WRITE;
|
||||
if (tlb_x)
|
||||
res->prot |= PAGE_EXEC;
|
||||
}
|
||||
else
|
||||
D(dump_tlb(env, mmu));
|
||||
|
||||
env->sregs[SFR_RW_MM_TLB_HI] = hi;
|
||||
env->sregs[SFR_RW_MM_TLB_LO] = lo;
|
||||
}
|
||||
|
||||
if (!match) {
|
||||
set_field(&r_cause, rwcause, 8, 9);
|
||||
/* miss. */
|
||||
idx = vpage & 15;
|
||||
set = 0;
|
||||
|
||||
/* Update RW_MM_TLB_SEL. */
|
||||
env->sregs[SFR_RW_MM_TLB_SEL] = 0;
|
||||
set_field(&env->sregs[SFR_RW_MM_TLB_SEL], idx, 0, 4);
|
||||
set_field(&env->sregs[SFR_RW_MM_TLB_SEL], set, 4, 5);
|
||||
|
||||
/* Update RW_MM_CAUSE. */
|
||||
set_field(&r_cause, rwcause, 8, 2);
|
||||
set_field(&r_cause, vpage, 13, 19);
|
||||
set_field(&r_cause, env->pregs[PR_PID], 0, 8);
|
||||
env->sregs[SFR_R_MM_CAUSE] = r_cause;
|
||||
D(printf("refill vaddr=%x pc=%x\n", vaddr, env->pc));
|
||||
}
|
||||
D(printf ("%s mtch=%d pc=%x va=%x vpn=%x tlbvpn=%x pfn=%x pid=%x"
|
||||
" %x cause=%x sel=%x r13=%x\n",
|
||||
__func__, match, env->pc,
|
||||
|
||||
|
||||
D(printf ("%s rw=%d mtch=%d pc=%x va=%x vpn=%x tlbvpn=%x pfn=%x pid=%x"
|
||||
" %x cause=%x sel=%x sp=%x %x %x\n",
|
||||
__func__, rw, match, env->pc,
|
||||
vaddr, vpage,
|
||||
tlb_vpn, tlb_pfn, tlb_pid,
|
||||
env->pregs[PR_PID],
|
||||
r_cause,
|
||||
env->sregs[SFR_RW_MM_TLB_SEL],
|
||||
env->regs[13]));
|
||||
env->regs[R_SP], env->pregs[PR_USP], env->ksp));
|
||||
|
||||
res->pfn = tlb_pfn;
|
||||
return !match;
|
||||
@ -236,10 +278,17 @@ int cris_mmu_translate(struct cris_mmu_result_t *res,
|
||||
int seg;
|
||||
int miss = 0;
|
||||
int is_user = mmu_idx == MMU_USER_IDX;
|
||||
uint32_t old_srs;
|
||||
|
||||
old_srs= env->pregs[PR_SRS];
|
||||
|
||||
/* rw == 2 means exec, map the access to the insn mmu. */
|
||||
env->pregs[PR_SRS] = rw == 2 ? 1 : 2;
|
||||
|
||||
if (!cris_mmu_enabled(env->sregs[SFR_RW_GC_CFG])) {
|
||||
res->phy = vaddr;
|
||||
return 0;
|
||||
res->prot = PAGE_BITS;
|
||||
goto done;
|
||||
}
|
||||
|
||||
seg = vaddr >> 28;
|
||||
@ -251,17 +300,16 @@ int cris_mmu_translate(struct cris_mmu_result_t *res,
|
||||
base = cris_mmu_translate_seg(env, seg);
|
||||
phy = base | (0x0fffffff & vaddr);
|
||||
res->phy = phy;
|
||||
res->prot = PAGE_BITS;
|
||||
}
|
||||
else
|
||||
{
|
||||
miss = cris_mmu_translate_page(res, env, vaddr, rw, is_user);
|
||||
if (!miss) {
|
||||
phy &= 8191;
|
||||
phy |= (res->pfn << 13);
|
||||
res->phy = phy;
|
||||
}
|
||||
phy = (res->pfn << 13);
|
||||
res->phy = phy;
|
||||
}
|
||||
D(printf ("miss=%d v=%x -> p=%x\n", miss, vaddr, phy));
|
||||
done:
|
||||
env->pregs[PR_SRS] = old_srs;
|
||||
return miss;
|
||||
}
|
||||
#endif
|
||||
|
@ -7,6 +7,7 @@ struct cris_mmu_result_t
|
||||
{
|
||||
uint32_t phy;
|
||||
uint32_t pfn;
|
||||
int prot;
|
||||
int bf_vec;
|
||||
};
|
||||
|
||||
|
397
target-cris/op.c
397
target-cris/op.c
@ -192,17 +192,32 @@ void OPPROTO op_ccs_lshift (void)
|
||||
}
|
||||
void OPPROTO op_ccs_rshift (void)
|
||||
{
|
||||
uint32_t ccs;
|
||||
register uint32_t ccs;
|
||||
|
||||
/* Apply the ccs shift. */
|
||||
ccs = env->pregs[PR_CCS];
|
||||
ccs = (ccs & 0xc0000000) | ((ccs & 0x0fffffff) >> 10);
|
||||
if (ccs & U_FLAG)
|
||||
{
|
||||
/* Enter user mode. */
|
||||
env->ksp = env->regs[R_SP];
|
||||
env->regs[R_SP] = env->pregs[PR_USP];
|
||||
}
|
||||
|
||||
env->pregs[PR_CCS] = ccs;
|
||||
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_setf (void)
|
||||
{
|
||||
if (!(env->pregs[PR_CCS] & U_FLAG) && (PARAM1 & U_FLAG))
|
||||
{
|
||||
/* Enter user mode. */
|
||||
env->ksp = env->regs[R_SP];
|
||||
env->regs[R_SP] = env->pregs[PR_USP];
|
||||
}
|
||||
|
||||
env->pregs[PR_CCS] |= PARAM1;
|
||||
RETURN();
|
||||
}
|
||||
@ -265,7 +280,11 @@ void OPPROTO op_movl_flags_T0 (void)
|
||||
|
||||
void OPPROTO op_movl_sreg_T0 (void)
|
||||
{
|
||||
env->sregs[env->pregs[PR_SRS]][PARAM1] = T0;
|
||||
uint32_t srs;
|
||||
srs = env->pregs[PR_SRS];
|
||||
srs &= 3;
|
||||
|
||||
env->sregs[srs][PARAM1] = T0;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@ -285,7 +304,10 @@ void OPPROTO op_movl_tlb_hi_T0 (void)
|
||||
void OPPROTO op_movl_tlb_lo_T0 (void)
|
||||
{
|
||||
uint32_t srs;
|
||||
|
||||
env->pregs[PR_SRS] &= 3;
|
||||
srs = env->pregs[PR_SRS];
|
||||
|
||||
if (srs == 1 || srs == 2)
|
||||
{
|
||||
uint32_t set;
|
||||
@ -309,7 +331,28 @@ void OPPROTO op_movl_tlb_lo_T0 (void)
|
||||
|
||||
void OPPROTO op_movl_T0_sreg (void)
|
||||
{
|
||||
T0 = env->sregs[env->pregs[PR_SRS]][PARAM1];
|
||||
uint32_t srs;
|
||||
env->pregs[PR_SRS] &= 3;
|
||||
srs = env->pregs[PR_SRS];
|
||||
|
||||
if (srs == 1 || srs == 2)
|
||||
{
|
||||
uint32_t set;
|
||||
uint32_t idx;
|
||||
uint32_t lo, hi;
|
||||
|
||||
idx = set = env->sregs[SFR_RW_MM_TLB_SEL];
|
||||
set >>= 4;
|
||||
set &= 3;
|
||||
idx &= 15;
|
||||
|
||||
/* Update the mirror regs. */
|
||||
hi = env->tlbsets[srs - 1][set][idx].hi;
|
||||
lo = env->tlbsets[srs - 1][set][idx].lo;
|
||||
env->sregs[SFR_RW_MM_TLB_HI] = hi;
|
||||
env->sregs[SFR_RW_MM_TLB_LO] = lo;
|
||||
}
|
||||
T0 = env->sregs[srs][PARAM1];
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@ -363,340 +406,6 @@ void OPPROTO op_update_cc_x (void)
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* FIXME: is this allowed? */
|
||||
extern inline void evaluate_flags_writeback(uint32_t flags)
|
||||
{
|
||||
int x;
|
||||
|
||||
/* Extended arithmetics, leave the z flag alone. */
|
||||
env->debug3 = env->pregs[PR_CCS];
|
||||
|
||||
if (env->cc_x_live)
|
||||
x = env->cc_x;
|
||||
else
|
||||
x = env->pregs[PR_CCS] & X_FLAG;
|
||||
|
||||
if ((x || env->cc_op == CC_OP_ADDC)
|
||||
&& flags & Z_FLAG)
|
||||
env->cc_mask &= ~Z_FLAG;
|
||||
|
||||
/* all insn clear the x-flag except setf or clrf. */
|
||||
env->pregs[PR_CCS] &= ~(env->cc_mask | X_FLAG);
|
||||
flags &= env->cc_mask;
|
||||
env->pregs[PR_CCS] |= flags;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_evaluate_flags_muls(void)
|
||||
{
|
||||
uint32_t src;
|
||||
uint32_t dst;
|
||||
uint32_t res;
|
||||
uint32_t flags = 0;
|
||||
/* were gonna have to redo the muls. */
|
||||
int64_t tmp, t0 ,t1;
|
||||
int32_t mof;
|
||||
int dneg;
|
||||
|
||||
src = env->cc_src;
|
||||
dst = env->cc_dest;
|
||||
res = env->cc_result;
|
||||
|
||||
|
||||
/* cast into signed values to make GCC sign extend. */
|
||||
t0 = (int32_t)src;
|
||||
t1 = (int32_t)dst;
|
||||
dneg = ((int32_t)res) < 0;
|
||||
|
||||
tmp = t0 * t1;
|
||||
mof = tmp >> 32;
|
||||
if (tmp == 0)
|
||||
flags |= Z_FLAG;
|
||||
else if (tmp < 0)
|
||||
flags |= N_FLAG;
|
||||
if ((dneg && mof != -1)
|
||||
|| (!dneg && mof != 0))
|
||||
flags |= V_FLAG;
|
||||
evaluate_flags_writeback(flags);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_evaluate_flags_mulu(void)
|
||||
{
|
||||
uint32_t src;
|
||||
uint32_t dst;
|
||||
uint32_t res;
|
||||
uint32_t flags = 0;
|
||||
/* were gonna have to redo the muls. */
|
||||
uint64_t tmp, t0 ,t1;
|
||||
uint32_t mof;
|
||||
|
||||
src = env->cc_src;
|
||||
dst = env->cc_dest;
|
||||
res = env->cc_result;
|
||||
|
||||
|
||||
/* cast into signed values to make GCC sign extend. */
|
||||
t0 = src;
|
||||
t1 = dst;
|
||||
|
||||
tmp = t0 * t1;
|
||||
mof = tmp >> 32;
|
||||
if (tmp == 0)
|
||||
flags |= Z_FLAG;
|
||||
else if (tmp >> 63)
|
||||
flags |= N_FLAG;
|
||||
if (mof)
|
||||
flags |= V_FLAG;
|
||||
|
||||
evaluate_flags_writeback(flags);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_evaluate_flags_mcp(void)
|
||||
{
|
||||
uint32_t src;
|
||||
uint32_t dst;
|
||||
uint32_t res;
|
||||
uint32_t flags = 0;
|
||||
|
||||
src = env->cc_src;
|
||||
dst = env->cc_dest;
|
||||
res = env->cc_result;
|
||||
|
||||
if ((res & 0x80000000L) != 0L)
|
||||
{
|
||||
flags |= N_FLAG;
|
||||
if (((src & 0x80000000L) == 0L)
|
||||
&& ((dst & 0x80000000L) == 0L))
|
||||
{
|
||||
flags |= V_FLAG;
|
||||
}
|
||||
else if (((src & 0x80000000L) != 0L) &&
|
||||
((dst & 0x80000000L) != 0L))
|
||||
{
|
||||
flags |= R_FLAG;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (res == 0L)
|
||||
flags |= Z_FLAG;
|
||||
if (((src & 0x80000000L) != 0L)
|
||||
&& ((dst & 0x80000000L) != 0L))
|
||||
flags |= V_FLAG;
|
||||
if ((dst & 0x80000000L) != 0L
|
||||
|| (src & 0x80000000L) != 0L)
|
||||
flags |= R_FLAG;
|
||||
}
|
||||
|
||||
evaluate_flags_writeback(flags);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_evaluate_flags_alu_4(void)
|
||||
{
|
||||
uint32_t src;
|
||||
uint32_t dst;
|
||||
uint32_t res;
|
||||
uint32_t flags = 0;
|
||||
|
||||
src = env->cc_src;
|
||||
dst = env->cc_dest;
|
||||
res = env->cc_result;
|
||||
|
||||
if ((res & 0x80000000L) != 0L)
|
||||
{
|
||||
flags |= N_FLAG;
|
||||
if (((src & 0x80000000L) == 0L)
|
||||
&& ((dst & 0x80000000L) == 0L))
|
||||
{
|
||||
flags |= V_FLAG;
|
||||
}
|
||||
else if (((src & 0x80000000L) != 0L) &&
|
||||
((dst & 0x80000000L) != 0L))
|
||||
{
|
||||
flags |= C_FLAG;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (res == 0L)
|
||||
flags |= Z_FLAG;
|
||||
if (((src & 0x80000000L) != 0L)
|
||||
&& ((dst & 0x80000000L) != 0L))
|
||||
flags |= V_FLAG;
|
||||
if ((dst & 0x80000000L) != 0L
|
||||
|| (src & 0x80000000L) != 0L)
|
||||
flags |= C_FLAG;
|
||||
}
|
||||
|
||||
if (env->cc_op == CC_OP_SUB
|
||||
|| env->cc_op == CC_OP_CMP) {
|
||||
flags ^= C_FLAG;
|
||||
}
|
||||
evaluate_flags_writeback(flags);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_evaluate_flags_move_4 (void)
|
||||
{
|
||||
uint32_t src;
|
||||
uint32_t res;
|
||||
uint32_t flags = 0;
|
||||
|
||||
src = env->cc_src;
|
||||
res = env->cc_result;
|
||||
|
||||
if ((int32_t)res < 0)
|
||||
flags |= N_FLAG;
|
||||
else if (res == 0L)
|
||||
flags |= Z_FLAG;
|
||||
|
||||
evaluate_flags_writeback(flags);
|
||||
RETURN();
|
||||
}
|
||||
void OPPROTO op_evaluate_flags_move_2 (void)
|
||||
{
|
||||
uint32_t src;
|
||||
uint32_t flags = 0;
|
||||
uint16_t res;
|
||||
|
||||
src = env->cc_src;
|
||||
res = env->cc_result;
|
||||
|
||||
if ((int16_t)res < 0L)
|
||||
flags |= N_FLAG;
|
||||
else if (res == 0)
|
||||
flags |= Z_FLAG;
|
||||
|
||||
evaluate_flags_writeback(flags);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* TODO: This is expensive. We could split things up and only evaluate part of
|
||||
CCR on a need to know basis. For now, we simply re-evaluate everything. */
|
||||
void OPPROTO op_evaluate_flags (void)
|
||||
{
|
||||
uint32_t src;
|
||||
uint32_t dst;
|
||||
uint32_t res;
|
||||
uint32_t flags = 0;
|
||||
|
||||
src = env->cc_src;
|
||||
dst = env->cc_dest;
|
||||
res = env->cc_result;
|
||||
|
||||
|
||||
/* Now, evaluate the flags. This stuff is based on
|
||||
Per Zander's CRISv10 simulator. */
|
||||
switch (env->cc_size)
|
||||
{
|
||||
case 1:
|
||||
if ((res & 0x80L) != 0L)
|
||||
{
|
||||
flags |= N_FLAG;
|
||||
if (((src & 0x80L) == 0L)
|
||||
&& ((dst & 0x80L) == 0L))
|
||||
{
|
||||
flags |= V_FLAG;
|
||||
}
|
||||
else if (((src & 0x80L) != 0L)
|
||||
&& ((dst & 0x80L) != 0L))
|
||||
{
|
||||
flags |= C_FLAG;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((res & 0xFFL) == 0L)
|
||||
{
|
||||
flags |= Z_FLAG;
|
||||
}
|
||||
if (((src & 0x80L) != 0L)
|
||||
&& ((dst & 0x80L) != 0L))
|
||||
{
|
||||
flags |= V_FLAG;
|
||||
}
|
||||
if ((dst & 0x80L) != 0L
|
||||
|| (src & 0x80L) != 0L)
|
||||
{
|
||||
flags |= C_FLAG;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if ((res & 0x8000L) != 0L)
|
||||
{
|
||||
flags |= N_FLAG;
|
||||
if (((src & 0x8000L) == 0L)
|
||||
&& ((dst & 0x8000L) == 0L))
|
||||
{
|
||||
flags |= V_FLAG;
|
||||
}
|
||||
else if (((src & 0x8000L) != 0L)
|
||||
&& ((dst & 0x8000L) != 0L))
|
||||
{
|
||||
flags |= C_FLAG;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((res & 0xFFFFL) == 0L)
|
||||
{
|
||||
flags |= Z_FLAG;
|
||||
}
|
||||
if (((src & 0x8000L) != 0L)
|
||||
&& ((dst & 0x8000L) != 0L))
|
||||
{
|
||||
flags |= V_FLAG;
|
||||
}
|
||||
if ((dst & 0x8000L) != 0L
|
||||
|| (src & 0x8000L) != 0L)
|
||||
{
|
||||
flags |= C_FLAG;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if ((res & 0x80000000L) != 0L)
|
||||
{
|
||||
flags |= N_FLAG;
|
||||
if (((src & 0x80000000L) == 0L)
|
||||
&& ((dst & 0x80000000L) == 0L))
|
||||
{
|
||||
flags |= V_FLAG;
|
||||
}
|
||||
else if (((src & 0x80000000L) != 0L) &&
|
||||
((dst & 0x80000000L) != 0L))
|
||||
{
|
||||
flags |= C_FLAG;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (res == 0L)
|
||||
flags |= Z_FLAG;
|
||||
if (((src & 0x80000000L) != 0L)
|
||||
&& ((dst & 0x80000000L) != 0L))
|
||||
flags |= V_FLAG;
|
||||
if ((dst & 0x80000000L) != 0L
|
||||
|| (src & 0x80000000L) != 0L)
|
||||
flags |= C_FLAG;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (env->cc_op == CC_OP_SUB
|
||||
|| env->cc_op == CC_OP_CMP) {
|
||||
flags ^= C_FLAG;
|
||||
}
|
||||
evaluate_flags_writeback(flags);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_extb_T0_T0 (void)
|
||||
{
|
||||
T0 = ((int8_t)T0);
|
||||
@ -1274,17 +983,3 @@ void OPPROTO op_jmp1 (void)
|
||||
env->pc = env->btarget;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* Load and store */
|
||||
#define MEMSUFFIX _raw
|
||||
#include "op_mem.c"
|
||||
#undef MEMSUFFIX
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#define MEMSUFFIX _user
|
||||
#include "op_mem.c"
|
||||
#undef MEMSUFFIX
|
||||
|
||||
#define MEMSUFFIX _kernel
|
||||
#include "op_mem.c"
|
||||
#undef MEMSUFFIX
|
||||
#endif
|
||||
|
@ -59,6 +59,9 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
|
||||
generated code */
|
||||
saved_env = env;
|
||||
env = cpu_single_env;
|
||||
|
||||
D(fprintf(logfile, "%s ra=%x acr=%x %x\n", __func__, retaddr,
|
||||
env->regs[R_ACR], saved_env->regs[R_ACR]));
|
||||
ret = cpu_cris_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
|
||||
if (__builtin_expect(ret, 0)) {
|
||||
if (retaddr) {
|
||||
@ -80,16 +83,380 @@ void helper_tlb_update(uint32_t T0)
|
||||
{
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
uint32_t vaddr;
|
||||
uint32_t srs = env->pregs[PR_SRS];
|
||||
|
||||
if (srs != 1 && srs != 2)
|
||||
return;
|
||||
|
||||
vaddr = cris_mmu_tlb_latest_update(env, T0);
|
||||
D(printf("flush vaddr %x\n", vaddr));
|
||||
D(printf("flush old_vaddr=%x vaddr=%x T0=%x\n", vaddr,
|
||||
env->sregs[SFR_R_MM_CAUSE] & TARGET_PAGE_MASK, T0));
|
||||
tlb_flush_page(env, vaddr);
|
||||
#endif
|
||||
}
|
||||
|
||||
void helper_tlb_flush(void)
|
||||
{
|
||||
tlb_flush(env, 1);
|
||||
}
|
||||
|
||||
void helper_dump(uint32_t a0, uint32_t a1)
|
||||
{
|
||||
(fprintf(logfile, "%s: a0=%x a1=%x\n", __func__, a0, a1));
|
||||
}
|
||||
|
||||
void helper_dummy(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/* Only used for debugging at the moment. */
|
||||
void helper_rfe(void)
|
||||
{
|
||||
D(fprintf(logfile, "rfe: erp=%x pid=%x ccs=%x btarget=%x\n",
|
||||
env->pregs[PR_ERP], env->pregs[PR_PID],
|
||||
env->pregs[PR_CCS],
|
||||
env->btarget));
|
||||
}
|
||||
|
||||
void helper_store(uint32_t a0)
|
||||
{
|
||||
if (env->pregs[PR_CCS] & P_FLAG )
|
||||
{
|
||||
cpu_abort(env, "cond_store_failed! pc=%x a0=%x\n",
|
||||
env->pc, a0);
|
||||
}
|
||||
}
|
||||
|
||||
void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
|
||||
int is_asi)
|
||||
{
|
||||
D(printf("%s addr=%x w=%d ex=%d asi=%d\n",
|
||||
__func__, addr, is_write, is_exec, is_asi));
|
||||
}
|
||||
|
||||
static void evaluate_flags_writeback(uint32_t flags)
|
||||
{
|
||||
int x;
|
||||
|
||||
/* Extended arithmetics, leave the z flag alone. */
|
||||
env->debug3 = env->pregs[PR_CCS];
|
||||
|
||||
if (env->cc_x_live)
|
||||
x = env->cc_x;
|
||||
else
|
||||
x = env->pregs[PR_CCS] & X_FLAG;
|
||||
|
||||
if ((x || env->cc_op == CC_OP_ADDC)
|
||||
&& flags & Z_FLAG)
|
||||
env->cc_mask &= ~Z_FLAG;
|
||||
|
||||
/* all insn clear the x-flag except setf or clrf. */
|
||||
env->pregs[PR_CCS] &= ~(env->cc_mask | X_FLAG);
|
||||
flags &= env->cc_mask;
|
||||
env->pregs[PR_CCS] |= flags;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void helper_evaluate_flags_muls(void)
|
||||
{
|
||||
uint32_t src;
|
||||
uint32_t dst;
|
||||
uint32_t res;
|
||||
uint32_t flags = 0;
|
||||
/* were gonna have to redo the muls. */
|
||||
int64_t tmp, t0 ,t1;
|
||||
int32_t mof;
|
||||
int dneg;
|
||||
|
||||
src = env->cc_src;
|
||||
dst = env->cc_dest;
|
||||
res = env->cc_result;
|
||||
|
||||
|
||||
/* cast into signed values to make GCC sign extend. */
|
||||
t0 = (int32_t)src;
|
||||
t1 = (int32_t)dst;
|
||||
dneg = ((int32_t)res) < 0;
|
||||
|
||||
tmp = t0 * t1;
|
||||
mof = tmp >> 32;
|
||||
if (tmp == 0)
|
||||
flags |= Z_FLAG;
|
||||
else if (tmp < 0)
|
||||
flags |= N_FLAG;
|
||||
if ((dneg && mof != -1)
|
||||
|| (!dneg && mof != 0))
|
||||
flags |= V_FLAG;
|
||||
evaluate_flags_writeback(flags);
|
||||
}
|
||||
|
||||
void helper_evaluate_flags_mulu(void)
|
||||
{
|
||||
uint32_t src;
|
||||
uint32_t dst;
|
||||
uint32_t res;
|
||||
uint32_t flags = 0;
|
||||
/* were gonna have to redo the muls. */
|
||||
uint64_t tmp, t0 ,t1;
|
||||
uint32_t mof;
|
||||
|
||||
src = env->cc_src;
|
||||
dst = env->cc_dest;
|
||||
res = env->cc_result;
|
||||
|
||||
|
||||
/* cast into signed values to make GCC sign extend. */
|
||||
t0 = src;
|
||||
t1 = dst;
|
||||
|
||||
tmp = t0 * t1;
|
||||
mof = tmp >> 32;
|
||||
if (tmp == 0)
|
||||
flags |= Z_FLAG;
|
||||
else if (tmp >> 63)
|
||||
flags |= N_FLAG;
|
||||
if (mof)
|
||||
flags |= V_FLAG;
|
||||
|
||||
evaluate_flags_writeback(flags);
|
||||
}
|
||||
|
||||
void helper_evaluate_flags_mcp(void)
|
||||
{
|
||||
uint32_t src;
|
||||
uint32_t dst;
|
||||
uint32_t res;
|
||||
uint32_t flags = 0;
|
||||
|
||||
src = env->cc_src;
|
||||
dst = env->cc_dest;
|
||||
res = env->cc_result;
|
||||
|
||||
if ((res & 0x80000000L) != 0L)
|
||||
{
|
||||
flags |= N_FLAG;
|
||||
if (((src & 0x80000000L) == 0L)
|
||||
&& ((dst & 0x80000000L) == 0L))
|
||||
{
|
||||
flags |= V_FLAG;
|
||||
}
|
||||
else if (((src & 0x80000000L) != 0L) &&
|
||||
((dst & 0x80000000L) != 0L))
|
||||
{
|
||||
flags |= R_FLAG;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (res == 0L)
|
||||
flags |= Z_FLAG;
|
||||
if (((src & 0x80000000L) != 0L)
|
||||
&& ((dst & 0x80000000L) != 0L))
|
||||
flags |= V_FLAG;
|
||||
if ((dst & 0x80000000L) != 0L
|
||||
|| (src & 0x80000000L) != 0L)
|
||||
flags |= R_FLAG;
|
||||
}
|
||||
|
||||
evaluate_flags_writeback(flags);
|
||||
}
|
||||
|
||||
void helper_evaluate_flags_alu_4(void)
|
||||
{
|
||||
uint32_t src;
|
||||
uint32_t dst;
|
||||
uint32_t res;
|
||||
uint32_t flags = 0;
|
||||
|
||||
src = env->cc_src;
|
||||
dst = env->cc_dest;
|
||||
res = env->cc_result;
|
||||
|
||||
if ((res & 0x80000000L) != 0L)
|
||||
{
|
||||
flags |= N_FLAG;
|
||||
if (((src & 0x80000000L) == 0L)
|
||||
&& ((dst & 0x80000000L) == 0L))
|
||||
{
|
||||
flags |= V_FLAG;
|
||||
}
|
||||
else if (((src & 0x80000000L) != 0L) &&
|
||||
((dst & 0x80000000L) != 0L))
|
||||
{
|
||||
flags |= C_FLAG;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (res == 0L)
|
||||
flags |= Z_FLAG;
|
||||
if (((src & 0x80000000L) != 0L)
|
||||
&& ((dst & 0x80000000L) != 0L))
|
||||
flags |= V_FLAG;
|
||||
if ((dst & 0x80000000L) != 0L
|
||||
|| (src & 0x80000000L) != 0L)
|
||||
flags |= C_FLAG;
|
||||
}
|
||||
|
||||
if (env->cc_op == CC_OP_SUB
|
||||
|| env->cc_op == CC_OP_CMP) {
|
||||
flags ^= C_FLAG;
|
||||
}
|
||||
evaluate_flags_writeback(flags);
|
||||
}
|
||||
|
||||
void helper_evaluate_flags_move_4 (void)
|
||||
{
|
||||
uint32_t src;
|
||||
uint32_t res;
|
||||
uint32_t flags = 0;
|
||||
|
||||
src = env->cc_src;
|
||||
res = env->cc_result;
|
||||
|
||||
if ((int32_t)res < 0)
|
||||
flags |= N_FLAG;
|
||||
else if (res == 0L)
|
||||
flags |= Z_FLAG;
|
||||
|
||||
evaluate_flags_writeback(flags);
|
||||
}
|
||||
void helper_evaluate_flags_move_2 (void)
|
||||
{
|
||||
uint32_t src;
|
||||
uint32_t flags = 0;
|
||||
uint16_t res;
|
||||
|
||||
src = env->cc_src;
|
||||
res = env->cc_result;
|
||||
|
||||
if ((int16_t)res < 0L)
|
||||
flags |= N_FLAG;
|
||||
else if (res == 0)
|
||||
flags |= Z_FLAG;
|
||||
|
||||
evaluate_flags_writeback(flags);
|
||||
}
|
||||
|
||||
/* TODO: This is expensive. We could split things up and only evaluate part of
|
||||
CCR on a need to know basis. For now, we simply re-evaluate everything. */
|
||||
void helper_evaluate_flags (void)
|
||||
{
|
||||
uint32_t src;
|
||||
uint32_t dst;
|
||||
uint32_t res;
|
||||
uint32_t flags = 0;
|
||||
|
||||
src = env->cc_src;
|
||||
dst = env->cc_dest;
|
||||
res = env->cc_result;
|
||||
|
||||
|
||||
/* Now, evaluate the flags. This stuff is based on
|
||||
Per Zander's CRISv10 simulator. */
|
||||
switch (env->cc_size)
|
||||
{
|
||||
case 1:
|
||||
if ((res & 0x80L) != 0L)
|
||||
{
|
||||
flags |= N_FLAG;
|
||||
if (((src & 0x80L) == 0L)
|
||||
&& ((dst & 0x80L) == 0L))
|
||||
{
|
||||
flags |= V_FLAG;
|
||||
}
|
||||
else if (((src & 0x80L) != 0L)
|
||||
&& ((dst & 0x80L) != 0L))
|
||||
{
|
||||
flags |= C_FLAG;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((res & 0xFFL) == 0L)
|
||||
{
|
||||
flags |= Z_FLAG;
|
||||
}
|
||||
if (((src & 0x80L) != 0L)
|
||||
&& ((dst & 0x80L) != 0L))
|
||||
{
|
||||
flags |= V_FLAG;
|
||||
}
|
||||
if ((dst & 0x80L) != 0L
|
||||
|| (src & 0x80L) != 0L)
|
||||
{
|
||||
flags |= C_FLAG;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if ((res & 0x8000L) != 0L)
|
||||
{
|
||||
flags |= N_FLAG;
|
||||
if (((src & 0x8000L) == 0L)
|
||||
&& ((dst & 0x8000L) == 0L))
|
||||
{
|
||||
flags |= V_FLAG;
|
||||
}
|
||||
else if (((src & 0x8000L) != 0L)
|
||||
&& ((dst & 0x8000L) != 0L))
|
||||
{
|
||||
flags |= C_FLAG;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((res & 0xFFFFL) == 0L)
|
||||
{
|
||||
flags |= Z_FLAG;
|
||||
}
|
||||
if (((src & 0x8000L) != 0L)
|
||||
&& ((dst & 0x8000L) != 0L))
|
||||
{
|
||||
flags |= V_FLAG;
|
||||
}
|
||||
if ((dst & 0x8000L) != 0L
|
||||
|| (src & 0x8000L) != 0L)
|
||||
{
|
||||
flags |= C_FLAG;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if ((res & 0x80000000L) != 0L)
|
||||
{
|
||||
flags |= N_FLAG;
|
||||
if (((src & 0x80000000L) == 0L)
|
||||
&& ((dst & 0x80000000L) == 0L))
|
||||
{
|
||||
flags |= V_FLAG;
|
||||
}
|
||||
else if (((src & 0x80000000L) != 0L) &&
|
||||
((dst & 0x80000000L) != 0L))
|
||||
{
|
||||
flags |= C_FLAG;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (res == 0L)
|
||||
flags |= Z_FLAG;
|
||||
if (((src & 0x80000000L) != 0L)
|
||||
&& ((dst & 0x80000000L) != 0L))
|
||||
flags |= V_FLAG;
|
||||
if ((dst & 0x80000000L) != 0L
|
||||
|| (src & 0x80000000L) != 0L)
|
||||
flags |= C_FLAG;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (env->cc_op == CC_OP_SUB
|
||||
|| env->cc_op == CC_OP_CMP) {
|
||||
flags ^= C_FLAG;
|
||||
}
|
||||
evaluate_flags_writeback(flags);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user