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:
edgar_igl 2008-05-02 22:16:17 +00:00
parent ff56ff7a07
commit b41f7df018
9 changed files with 938 additions and 639 deletions

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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);

View file

@ -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

View file

@ -7,6 +7,7 @@ struct cris_mmu_result_t
{
uint32_t phy;
uint32_t pfn;
int prot;
int bf_vec;
};

View file

@ -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

View file

@ -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