Commit cf1d97f07480b6197aebc489938b4e1fed78d3e7
1 parent
3bd8c5e4
CRIS: Improve TLB management and handle delayslots at page boundaries.
* Dont flush the entire qemu tlb when the $pid changes. Instead we go through the guests TLB and choose entries that need to be flushed. * Add env->dslot and handle delayslots at pageboundaries. * Remove some unused code. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4450 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
8 changed files
with
196 additions
and
140 deletions
cpu-exec.c
| @@ -261,6 +261,7 @@ static inline TranslationBlock *tb_find_fast(void) | @@ -261,6 +261,7 @@ static inline TranslationBlock *tb_find_fast(void) | ||
| 261 | pc = env->pc; | 261 | pc = env->pc; |
| 262 | #elif defined(TARGET_CRIS) | 262 | #elif defined(TARGET_CRIS) |
| 263 | flags = env->pregs[PR_CCS] & U_FLAG; | 263 | flags = env->pregs[PR_CCS] & U_FLAG; |
| 264 | + flags |= env->dslot; | ||
| 264 | cs_base = 0; | 265 | cs_base = 0; |
| 265 | pc = env->pc; | 266 | pc = env->pc; |
| 266 | #else | 267 | #else |
target-cris/cpu.h
| @@ -107,11 +107,10 @@ typedef struct CPUCRISState { | @@ -107,11 +107,10 @@ typedef struct CPUCRISState { | ||
| 107 | /* Pseudo register for the kernel stack. */ | 107 | /* Pseudo register for the kernel stack. */ |
| 108 | uint32_t ksp; | 108 | uint32_t ksp; |
| 109 | 109 | ||
| 110 | - /* These are setup up by the guest code just before transfering the | ||
| 111 | - control back to the host. */ | ||
| 112 | - int jmp; | ||
| 113 | - uint32_t btarget; | 110 | + /* Branch. */ |
| 111 | + int dslot; | ||
| 114 | int btaken; | 112 | int btaken; |
| 113 | + uint32_t btarget; | ||
| 115 | 114 | ||
| 116 | /* Condition flag tracking. */ | 115 | /* Condition flag tracking. */ |
| 117 | uint32_t cc_op; | 116 | uint32_t cc_op; |
| @@ -119,10 +118,8 @@ typedef struct CPUCRISState { | @@ -119,10 +118,8 @@ typedef struct CPUCRISState { | ||
| 119 | uint32_t cc_dest; | 118 | uint32_t cc_dest; |
| 120 | uint32_t cc_src; | 119 | uint32_t cc_src; |
| 121 | uint32_t cc_result; | 120 | uint32_t cc_result; |
| 122 | - | ||
| 123 | /* size of the operation, 1 = byte, 2 = word, 4 = dword. */ | 121 | /* size of the operation, 1 = byte, 2 = word, 4 = dword. */ |
| 124 | int cc_size; | 122 | int cc_size; |
| 125 | - | ||
| 126 | /* Extended arithmetics. */ | 123 | /* Extended arithmetics. */ |
| 127 | int cc_x_live; | 124 | int cc_x_live; |
| 128 | int cc_x; | 125 | int cc_x; |
| @@ -137,13 +134,6 @@ typedef struct CPUCRISState { | @@ -137,13 +134,6 @@ typedef struct CPUCRISState { | ||
| 137 | uint32_t debug2; | 134 | uint32_t debug2; |
| 138 | uint32_t debug3; | 135 | uint32_t debug3; |
| 139 | 136 | ||
| 140 | - struct | ||
| 141 | - { | ||
| 142 | - int exec_insns; | ||
| 143 | - int exec_loads; | ||
| 144 | - int exec_stores; | ||
| 145 | - } stats; | ||
| 146 | - | ||
| 147 | /* FIXME: add a check in the translator to avoid writing to support | 137 | /* FIXME: add a check in the translator to avoid writing to support |
| 148 | register sets beyond the 4th. The ISA allows up to 256! but in | 138 | register sets beyond the 4th. The ISA allows up to 256! but in |
| 149 | practice there is no core that implements more than 4. | 139 | practice there is no core that implements more than 4. |
target-cris/helper.c
| @@ -97,9 +97,10 @@ int cpu_cris_handle_mmu_fault (CPUState *env, target_ulong address, int rw, | @@ -97,9 +97,10 @@ int cpu_cris_handle_mmu_fault (CPUState *env, target_ulong address, int rw, | ||
| 97 | r = tlb_set_page(env, address, phy, prot, mmu_idx, is_softmmu); | 97 | r = tlb_set_page(env, address, phy, prot, mmu_idx, is_softmmu); |
| 98 | } | 98 | } |
| 99 | if (r > 0) | 99 | if (r > 0) |
| 100 | - D(fprintf(logfile, "%s returns %d irqreq=%x addr=%x ismmu=%d vec=%x\n", | ||
| 101 | - __func__, r, env->interrupt_request, | ||
| 102 | - address, is_softmmu, res.bf_vec)); | 100 | + D(fprintf(logfile, "%s returns %d irqreq=%x addr=%x" |
| 101 | + " phy=%x ismmu=%d vec=%x pc=%x\n", | ||
| 102 | + __func__, r, env->interrupt_request, | ||
| 103 | + address, res.phy, is_softmmu, res.bf_vec, env->pc)); | ||
| 103 | return r; | 104 | return r; |
| 104 | } | 105 | } |
| 105 | 106 | ||
| @@ -138,13 +139,19 @@ void do_interrupt(CPUState *env) | @@ -138,13 +139,19 @@ void do_interrupt(CPUState *env) | ||
| 138 | break; | 139 | break; |
| 139 | } | 140 | } |
| 140 | 141 | ||
| 141 | - if ((env->pregs[PR_CCS] & U_FLAG)) { | ||
| 142 | - D(fprintf(logfile, "excp isr=%x PC=%x SP=%x ERP=%x pid=%x ccs=%x cc=%d %x\n", | ||
| 143 | - ex_vec, env->pc, | 142 | + if (env->dslot) { |
| 143 | + D(fprintf(logfile, "excp isr=%x PC=%x ds=%d SP=%x" | ||
| 144 | + " ERP=%x pid=%x ccs=%x cc=%d %x\n", | ||
| 145 | + ex_vec, env->pc, env->dslot, | ||
| 144 | env->regs[R_SP], | 146 | env->regs[R_SP], |
| 145 | env->pregs[PR_ERP], env->pregs[PR_PID], | 147 | env->pregs[PR_ERP], env->pregs[PR_PID], |
| 146 | env->pregs[PR_CCS], | 148 | env->pregs[PR_CCS], |
| 147 | env->cc_op, env->cc_mask)); | 149 | env->cc_op, env->cc_mask)); |
| 150 | + /* We loose the btarget, btaken state here so rexec the | ||
| 151 | + branch. */ | ||
| 152 | + env->pregs[PR_ERP] -= env->dslot; | ||
| 153 | + /* Exception starts with dslot cleared. */ | ||
| 154 | + env->dslot = 0; | ||
| 148 | } | 155 | } |
| 149 | 156 | ||
| 150 | env->pc = ldl_code(env->pregs[PR_EBP] + ex_vec * 4); | 157 | env->pc = ldl_code(env->pregs[PR_EBP] + ex_vec * 4); |
target-cris/helper.h
| 1 | #define TCG_HELPER_PROTO | 1 | #define TCG_HELPER_PROTO |
| 2 | 2 | ||
| 3 | void TCG_HELPER_PROTO helper_raise_exception(uint32_t index); | 3 | void TCG_HELPER_PROTO helper_raise_exception(uint32_t index); |
| 4 | +void TCG_HELPER_PROTO helper_tlb_flush_pid(uint32_t pid); | ||
| 4 | void TCG_HELPER_PROTO helper_tlb_flush(void); | 5 | void TCG_HELPER_PROTO helper_tlb_flush(void); |
| 5 | void TCG_HELPER_PROTO helper_dump(uint32_t a0, uint32_t a1, uint32_t a2); | 6 | void TCG_HELPER_PROTO helper_dump(uint32_t a0, uint32_t a1, uint32_t a2); |
| 6 | void TCG_HELPER_PROTO helper_dummy(void); | 7 | void TCG_HELPER_PROTO helper_dummy(void); |
target-cris/mmu.c
| @@ -174,8 +174,9 @@ static int cris_mmu_translate_page(struct cris_mmu_result_t *res, | @@ -174,8 +174,9 @@ static int cris_mmu_translate_page(struct cris_mmu_result_t *res, | ||
| 174 | tlb_pfn = EXTRACT_FIELD(lo, 13, 31); | 174 | tlb_pfn = EXTRACT_FIELD(lo, 13, 31); |
| 175 | tlb_g = EXTRACT_FIELD(lo, 4, 4); | 175 | tlb_g = EXTRACT_FIELD(lo, 4, 4); |
| 176 | 176 | ||
| 177 | - D(printf("TLB[%d][%d] v=%x vpage=%x -> pfn=%x lo=%x hi=%x\n", | ||
| 178 | - i, idx, tlb_vpn, vpage, tlb_pfn, lo, hi)); | 177 | + D(fprintf(logfile, |
| 178 | + "TLB[%d][%d][%d] v=%x vpage=%x->pfn=%x lo=%x hi=%x\n", | ||
| 179 | + mmu, set, idx, tlb_vpn, vpage, tlb_pfn, lo, hi)); | ||
| 179 | if ((tlb_g || (tlb_pid == (env->pregs[PR_PID] & 0xff))) | 180 | if ((tlb_g || (tlb_pid == (env->pregs[PR_PID] & 0xff))) |
| 180 | && tlb_vpn == vpage) { | 181 | && tlb_vpn == vpage) { |
| 181 | match = 1; | 182 | match = 1; |
| @@ -224,7 +225,6 @@ static int cris_mmu_translate_page(struct cris_mmu_result_t *res, | @@ -224,7 +225,6 @@ static int cris_mmu_translate_page(struct cris_mmu_result_t *res, | ||
| 224 | res->bf_vec = vect_base + 3; | 225 | res->bf_vec = vect_base + 3; |
| 225 | } else if (cfg_v && !tlb_v) { | 226 | } else if (cfg_v && !tlb_v) { |
| 226 | D(printf ("tlb: invalid %x\n", vaddr)); | 227 | D(printf ("tlb: invalid %x\n", vaddr)); |
| 227 | - set_field(&r_cause, rwcause, 8, 9); | ||
| 228 | match = 0; | 228 | match = 0; |
| 229 | res->bf_vec = vect_base + 1; | 229 | res->bf_vec = vect_base + 1; |
| 230 | } | 230 | } |
| @@ -287,21 +287,42 @@ static int cris_mmu_translate_page(struct cris_mmu_result_t *res, | @@ -287,21 +287,42 @@ static int cris_mmu_translate_page(struct cris_mmu_result_t *res, | ||
| 287 | return !match; | 287 | return !match; |
| 288 | } | 288 | } |
| 289 | 289 | ||
| 290 | -/* Give us the vaddr corresponding to the latest TLB update. */ | ||
| 291 | -target_ulong cris_mmu_tlb_latest_update(CPUState *env) | 290 | +void cris_mmu_flush_pid(CPUState *env, uint32_t pid) |
| 292 | { | 291 | { |
| 293 | - uint32_t sel = env->sregs[SFR_RW_MM_TLB_SEL]; | ||
| 294 | - uint32_t vaddr; | ||
| 295 | - uint32_t hi; | ||
| 296 | - int set; | ||
| 297 | - int idx; | ||
| 298 | - | ||
| 299 | - idx = EXTRACT_FIELD(sel, 0, 4); | ||
| 300 | - set = EXTRACT_FIELD(sel, 4, 5); | ||
| 301 | - | ||
| 302 | - hi = env->tlbsets[1][set][idx].hi; | ||
| 303 | - vaddr = EXTRACT_FIELD(hi, 13, 31); | ||
| 304 | - return vaddr << TARGET_PAGE_BITS; | 292 | + target_ulong vaddr; |
| 293 | + unsigned int idx; | ||
| 294 | + uint32_t lo, hi; | ||
| 295 | + uint32_t tlb_vpn; | ||
| 296 | + int tlb_pid, tlb_g, tlb_v, tlb_k; | ||
| 297 | + unsigned int set; | ||
| 298 | + unsigned int mmu; | ||
| 299 | + | ||
| 300 | + pid &= 0xff; | ||
| 301 | + for (mmu = 0; mmu < 2; mmu++) { | ||
| 302 | + for (set = 0; set < 4; set++) | ||
| 303 | + { | ||
| 304 | + for (idx = 0; idx < 16; idx++) { | ||
| 305 | + lo = env->tlbsets[mmu][set][idx].lo; | ||
| 306 | + hi = env->tlbsets[mmu][set][idx].hi; | ||
| 307 | + | ||
| 308 | + tlb_vpn = EXTRACT_FIELD(hi, 13, 31); | ||
| 309 | + tlb_pid = EXTRACT_FIELD(hi, 0, 7); | ||
| 310 | + tlb_g = EXTRACT_FIELD(lo, 4, 4); | ||
| 311 | + tlb_v = EXTRACT_FIELD(lo, 3, 3); | ||
| 312 | + tlb_k = EXTRACT_FIELD(lo, 2, 2); | ||
| 313 | + | ||
| 314 | + /* Kernel protected areas need to be flushed | ||
| 315 | + as well. */ | ||
| 316 | + if (tlb_v && !tlb_g) { | ||
| 317 | + vaddr = tlb_vpn << TARGET_PAGE_BITS; | ||
| 318 | + D(fprintf(logfile, | ||
| 319 | + "flush pid=%x vaddr=%x\n", | ||
| 320 | + pid, vaddr)); | ||
| 321 | + tlb_flush_page(env, vaddr); | ||
| 322 | + } | ||
| 323 | + } | ||
| 324 | + } | ||
| 325 | + } | ||
| 305 | } | 326 | } |
| 306 | 327 | ||
| 307 | int cris_mmu_translate(struct cris_mmu_result_t *res, | 328 | int cris_mmu_translate(struct cris_mmu_result_t *res, |
target-cris/mmu.h
| @@ -11,7 +11,7 @@ struct cris_mmu_result_t | @@ -11,7 +11,7 @@ struct cris_mmu_result_t | ||
| 11 | int bf_vec; | 11 | int bf_vec; |
| 12 | }; | 12 | }; |
| 13 | 13 | ||
| 14 | -target_ulong cris_mmu_tlb_latest_update(CPUState *env); | 14 | +void cris_mmu_flush_pid(CPUState *env, uint32_t pid); |
| 15 | int cris_mmu_translate(struct cris_mmu_result_t *res, | 15 | int cris_mmu_translate(struct cris_mmu_result_t *res, |
| 16 | CPUState *env, uint32_t vaddr, | 16 | CPUState *env, uint32_t vaddr, |
| 17 | int rw, int mmu_idx); | 17 | int rw, int mmu_idx); |
target-cris/op_helper.c
| @@ -85,6 +85,13 @@ void helper_raise_exception(uint32_t index) | @@ -85,6 +85,13 @@ void helper_raise_exception(uint32_t index) | ||
| 85 | cpu_loop_exit(); | 85 | cpu_loop_exit(); |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | +void helper_tlb_flush_pid(uint32_t pid) | ||
| 89 | +{ | ||
| 90 | +#if !defined(CONFIG_USER_ONLY) | ||
| 91 | + cris_mmu_flush_pid(env, pid); | ||
| 92 | +#endif | ||
| 93 | +} | ||
| 94 | + | ||
| 88 | void helper_tlb_flush(void) | 95 | void helper_tlb_flush(void) |
| 89 | { | 96 | { |
| 90 | tlb_flush(env, 1); | 97 | tlb_flush(env, 1); |
| @@ -100,6 +107,10 @@ void helper_dummy(void) | @@ -100,6 +107,10 @@ void helper_dummy(void) | ||
| 100 | 107 | ||
| 101 | } | 108 | } |
| 102 | 109 | ||
| 110 | +/* Used by the tlb decoder. */ | ||
| 111 | +#define EXTRACT_FIELD(src, start, end) \ | ||
| 112 | + (((src) >> start) & ((1 << (end - start + 1)) - 1)) | ||
| 113 | + | ||
| 103 | void helper_movl_sreg_reg (uint32_t sreg, uint32_t reg) | 114 | void helper_movl_sreg_reg (uint32_t sreg, uint32_t reg) |
| 104 | { | 115 | { |
| 105 | uint32_t srs; | 116 | uint32_t srs; |
| @@ -120,10 +131,7 @@ void helper_movl_sreg_reg (uint32_t sreg, uint32_t reg) | @@ -120,10 +131,7 @@ void helper_movl_sreg_reg (uint32_t sreg, uint32_t reg) | ||
| 120 | uint32_t idx; | 131 | uint32_t idx; |
| 121 | uint32_t lo, hi; | 132 | uint32_t lo, hi; |
| 122 | uint32_t vaddr; | 133 | uint32_t vaddr; |
| 123 | - | ||
| 124 | - vaddr = cris_mmu_tlb_latest_update(env); | ||
| 125 | - D(fprintf(logfile, "tlb flush vaddr=%x\n", vaddr)); | ||
| 126 | - tlb_flush_page(env, vaddr); | 134 | + int tlb_v; |
| 127 | 135 | ||
| 128 | idx = set = env->sregs[SFR_RW_MM_TLB_SEL]; | 136 | idx = set = env->sregs[SFR_RW_MM_TLB_SEL]; |
| 129 | set >>= 4; | 137 | set >>= 4; |
| @@ -134,8 +142,19 @@ void helper_movl_sreg_reg (uint32_t sreg, uint32_t reg) | @@ -134,8 +142,19 @@ void helper_movl_sreg_reg (uint32_t sreg, uint32_t reg) | ||
| 134 | lo = env->sregs[SFR_RW_MM_TLB_LO]; | 142 | lo = env->sregs[SFR_RW_MM_TLB_LO]; |
| 135 | /* Writes are done via r_mm_cause. */ | 143 | /* Writes are done via r_mm_cause. */ |
| 136 | hi = env->sregs[SFR_R_MM_CAUSE]; | 144 | hi = env->sregs[SFR_R_MM_CAUSE]; |
| 145 | + | ||
| 146 | + vaddr = EXTRACT_FIELD(env->tlbsets[srs-1][set][idx].hi, | ||
| 147 | + 13, 31); | ||
| 148 | + vaddr <<= TARGET_PAGE_BITS; | ||
| 149 | + tlb_v = EXTRACT_FIELD(env->tlbsets[srs-1][set][idx].lo, | ||
| 150 | + 3, 3); | ||
| 137 | env->tlbsets[srs - 1][set][idx].lo = lo; | 151 | env->tlbsets[srs - 1][set][idx].lo = lo; |
| 138 | env->tlbsets[srs - 1][set][idx].hi = hi; | 152 | env->tlbsets[srs - 1][set][idx].hi = hi; |
| 153 | + | ||
| 154 | + D(fprintf(logfile, | ||
| 155 | + "tlb flush vaddr=%x v=%d pc=%x\n", | ||
| 156 | + vaddr, tlb_v, env->pc)); | ||
| 157 | + tlb_flush_page(env, vaddr); | ||
| 139 | } | 158 | } |
| 140 | } | 159 | } |
| 141 | #endif | 160 | #endif |
target-cris/translate.c
| @@ -21,8 +21,7 @@ | @@ -21,8 +21,7 @@ | ||
| 21 | 21 | ||
| 22 | /* | 22 | /* |
| 23 | * FIXME: | 23 | * FIXME: |
| 24 | - * The condition code translation is in desperate need of attention. It's slow | ||
| 25 | - * and for system simulation it seems buggy. It sucks. | 24 | + * The condition code translation is in need of attention. |
| 26 | */ | 25 | */ |
| 27 | 26 | ||
| 28 | #include <stdarg.h> | 27 | #include <stdarg.h> |
| @@ -40,13 +39,6 @@ | @@ -40,13 +39,6 @@ | ||
| 40 | #include "crisv32-decode.h" | 39 | #include "crisv32-decode.h" |
| 41 | #include "qemu-common.h" | 40 | #include "qemu-common.h" |
| 42 | 41 | ||
| 43 | -#define CRIS_STATS 0 | ||
| 44 | -#if CRIS_STATS | ||
| 45 | -#define STATS(x) x | ||
| 46 | -#else | ||
| 47 | -#define STATS(x) | ||
| 48 | -#endif | ||
| 49 | - | ||
| 50 | #define DISAS_CRIS 0 | 42 | #define DISAS_CRIS 0 |
| 51 | #if DISAS_CRIS | 43 | #if DISAS_CRIS |
| 52 | #define DIS(x) x | 44 | #define DIS(x) x |
| @@ -109,25 +101,18 @@ typedef struct DisasContext { | @@ -109,25 +101,18 @@ typedef struct DisasContext { | ||
| 109 | 101 | ||
| 110 | int user; /* user or kernel mode. */ | 102 | int user; /* user or kernel mode. */ |
| 111 | int is_jmp; | 103 | int is_jmp; |
| 112 | - int dyn_jmp; | ||
| 113 | 104 | ||
| 114 | - uint32_t delayed_pc; | ||
| 115 | int delayed_branch; | 105 | int delayed_branch; |
| 116 | - int bcc; | ||
| 117 | - uint32_t condlabel; | ||
| 118 | 106 | ||
| 119 | struct TranslationBlock *tb; | 107 | struct TranslationBlock *tb; |
| 120 | int singlestep_enabled; | 108 | int singlestep_enabled; |
| 121 | } DisasContext; | 109 | } DisasContext; |
| 122 | 110 | ||
| 123 | -void cris_prepare_jmp (DisasContext *dc, uint32_t dst); | ||
| 124 | static void gen_BUG(DisasContext *dc, char *file, int line) | 111 | static void gen_BUG(DisasContext *dc, char *file, int line) |
| 125 | { | 112 | { |
| 126 | printf ("BUG: pc=%x %s %d\n", dc->pc, file, line); | 113 | printf ("BUG: pc=%x %s %d\n", dc->pc, file, line); |
| 127 | fprintf (logfile, "BUG: pc=%x %s %d\n", dc->pc, file, line); | 114 | fprintf (logfile, "BUG: pc=%x %s %d\n", dc->pc, file, line); |
| 128 | - cpu_dump_state (dc->env, stdout, fprintf, 0); | ||
| 129 | - fflush(NULL); | ||
| 130 | - cris_prepare_jmp (dc, 0x70000000 + line); | 115 | + cpu_abort(dc->env, "%s:%d\n", file, line); |
| 131 | } | 116 | } |
| 132 | 117 | ||
| 133 | const char *regnames[] = | 118 | const char *regnames[] = |
| @@ -207,7 +192,7 @@ static inline void t_gen_mov_TN_preg(TCGv tn, int r) | @@ -207,7 +192,7 @@ static inline void t_gen_mov_TN_preg(TCGv tn, int r) | ||
| 207 | else | 192 | else |
| 208 | tcg_gen_mov_tl(tn, cpu_PR[r]); | 193 | tcg_gen_mov_tl(tn, cpu_PR[r]); |
| 209 | } | 194 | } |
| 210 | -static inline void t_gen_mov_preg_TN(int r, TCGv tn) | 195 | +static inline void t_gen_mov_preg_TN(DisasContext *dc, int r, TCGv tn) |
| 211 | { | 196 | { |
| 212 | if (r < 0 || r > 15) | 197 | if (r < 0 || r > 15) |
| 213 | fprintf(stderr, "wrong register write $p%d\n", r); | 198 | fprintf(stderr, "wrong register write $p%d\n", r); |
| @@ -216,10 +201,9 @@ static inline void t_gen_mov_preg_TN(int r, TCGv tn) | @@ -216,10 +201,9 @@ static inline void t_gen_mov_preg_TN(int r, TCGv tn) | ||
| 216 | else if (r == PR_SRS) | 201 | else if (r == PR_SRS) |
| 217 | tcg_gen_andi_tl(cpu_PR[r], tn, 3); | 202 | tcg_gen_andi_tl(cpu_PR[r], tn, 3); |
| 218 | else { | 203 | else { |
| 219 | - if (r == PR_PID) { | ||
| 220 | - tcg_gen_helper_0_0(helper_tlb_flush); | ||
| 221 | - } | ||
| 222 | tcg_gen_mov_tl(cpu_PR[r], tn); | 204 | tcg_gen_mov_tl(cpu_PR[r], tn); |
| 205 | + if (r == PR_PID) | ||
| 206 | + tcg_gen_helper_0_1(helper_tlb_flush_pid, tn); | ||
| 223 | } | 207 | } |
| 224 | } | 208 | } |
| 225 | 209 | ||
| @@ -596,7 +580,7 @@ static inline void t_gen_swapr(TCGv d, TCGv s) | @@ -596,7 +580,7 @@ static inline void t_gen_swapr(TCGv d, TCGv s) | ||
| 596 | tcg_gen_discard_tl(org_s); | 580 | tcg_gen_discard_tl(org_s); |
| 597 | } | 581 | } |
| 598 | 582 | ||
| 599 | -static void t_gen_cc_jmp(target_ulong pc_true, target_ulong pc_false) | 583 | +static void t_gen_cc_jmp(TCGv pc_true, TCGv pc_false) |
| 600 | { | 584 | { |
| 601 | TCGv btaken; | 585 | TCGv btaken; |
| 602 | int l1; | 586 | int l1; |
| @@ -606,9 +590,9 @@ static void t_gen_cc_jmp(target_ulong pc_true, target_ulong pc_false) | @@ -606,9 +590,9 @@ static void t_gen_cc_jmp(target_ulong pc_true, target_ulong pc_false) | ||
| 606 | 590 | ||
| 607 | /* Conditional jmp. */ | 591 | /* Conditional jmp. */ |
| 608 | t_gen_mov_TN_env(btaken, btaken); | 592 | t_gen_mov_TN_env(btaken, btaken); |
| 609 | - tcg_gen_movi_tl(env_pc, pc_false); | 593 | + tcg_gen_mov_tl(env_pc, pc_false); |
| 610 | tcg_gen_brcond_tl(TCG_COND_EQ, btaken, tcg_const_tl(0), l1); | 594 | tcg_gen_brcond_tl(TCG_COND_EQ, btaken, tcg_const_tl(0), l1); |
| 611 | - tcg_gen_movi_tl(env_pc, pc_true); | 595 | + tcg_gen_mov_tl(env_pc, pc_true); |
| 612 | gen_set_label(l1); | 596 | gen_set_label(l1); |
| 613 | 597 | ||
| 614 | tcg_gen_discard_tl(btaken); | 598 | tcg_gen_discard_tl(btaken); |
| @@ -740,10 +724,11 @@ static void crisv32_alu_op(DisasContext *dc, int op, int rd, int size) | @@ -740,10 +724,11 @@ static void crisv32_alu_op(DisasContext *dc, int op, int rd, int size) | ||
| 740 | int writeback = 1; | 724 | int writeback = 1; |
| 741 | if (dc->update_cc) { | 725 | if (dc->update_cc) { |
| 742 | cris_update_cc_op(dc, op, size); | 726 | cris_update_cc_op(dc, op, size); |
| 743 | - tcg_gen_mov_tl(cc_dest, cpu_T[0]); | 727 | + if (op != CC_OP_MOVE) |
| 728 | + tcg_gen_mov_tl(cc_dest, cpu_T[0]); | ||
| 744 | 729 | ||
| 745 | /* FIXME: This shouldn't be needed. But we don't pass the | 730 | /* FIXME: This shouldn't be needed. But we don't pass the |
| 746 | - tests without it. Investigate. */ | 731 | + tests without it. Investigate. */ |
| 747 | t_gen_mov_env_TN(cc_x_live, tcg_const_tl(dc->flagx_live)); | 732 | t_gen_mov_env_TN(cc_x_live, tcg_const_tl(dc->flagx_live)); |
| 748 | t_gen_mov_env_TN(cc_x, tcg_const_tl(dc->flags_x)); | 733 | t_gen_mov_env_TN(cc_x, tcg_const_tl(dc->flags_x)); |
| 749 | } | 734 | } |
| @@ -812,7 +797,7 @@ static void crisv32_alu_op(DisasContext *dc, int op, int rd, int size) | @@ -812,7 +797,7 @@ static void crisv32_alu_op(DisasContext *dc, int op, int rd, int size) | ||
| 812 | TCGv mof; | 797 | TCGv mof; |
| 813 | mof = tcg_temp_new(TCG_TYPE_TL); | 798 | mof = tcg_temp_new(TCG_TYPE_TL); |
| 814 | t_gen_muls(cpu_T[0], mof, cpu_T[0], cpu_T[1]); | 799 | t_gen_muls(cpu_T[0], mof, cpu_T[0], cpu_T[1]); |
| 815 | - t_gen_mov_preg_TN(PR_MOF, mof); | 800 | + t_gen_mov_preg_TN(dc, PR_MOF, mof); |
| 816 | tcg_gen_discard_tl(mof); | 801 | tcg_gen_discard_tl(mof); |
| 817 | } | 802 | } |
| 818 | break; | 803 | break; |
| @@ -821,7 +806,7 @@ static void crisv32_alu_op(DisasContext *dc, int op, int rd, int size) | @@ -821,7 +806,7 @@ static void crisv32_alu_op(DisasContext *dc, int op, int rd, int size) | ||
| 821 | TCGv mof; | 806 | TCGv mof; |
| 822 | mof = tcg_temp_new(TCG_TYPE_TL); | 807 | mof = tcg_temp_new(TCG_TYPE_TL); |
| 823 | t_gen_mulu(cpu_T[0], mof, cpu_T[0], cpu_T[1]); | 808 | t_gen_mulu(cpu_T[0], mof, cpu_T[0], cpu_T[1]); |
| 824 | - t_gen_mov_preg_TN(PR_MOF, mof); | 809 | + t_gen_mov_preg_TN(dc, PR_MOF, mof); |
| 825 | tcg_gen_discard_tl(mof); | 810 | tcg_gen_discard_tl(mof); |
| 826 | } | 811 | } |
| 827 | break; | 812 | break; |
| @@ -875,12 +860,6 @@ static void crisv32_alu_op(DisasContext *dc, int op, int rd, int size) | @@ -875,12 +860,6 @@ static void crisv32_alu_op(DisasContext *dc, int op, int rd, int size) | ||
| 875 | } | 860 | } |
| 876 | if (dc->update_cc) | 861 | if (dc->update_cc) |
| 877 | tcg_gen_mov_tl(cc_result, cpu_T[0]); | 862 | tcg_gen_mov_tl(cc_result, cpu_T[0]); |
| 878 | - | ||
| 879 | - { | ||
| 880 | - /* TODO: Optimize this. */ | ||
| 881 | - if (!dc->flagx_live) | ||
| 882 | - cris_evaluate_flags(dc); | ||
| 883 | - } | ||
| 884 | } | 863 | } |
| 885 | 864 | ||
| 886 | static int arith_cc(DisasContext *dc) | 865 | static int arith_cc(DisasContext *dc) |
| @@ -1073,7 +1052,6 @@ static void gen_tst_cc (DisasContext *dc, int cond) | @@ -1073,7 +1052,6 @@ static void gen_tst_cc (DisasContext *dc, int cond) | ||
| 1073 | tcg_gen_andi_tl(cpu_T[0], cpu_PR[PR_CCS], P_FLAG); | 1052 | tcg_gen_andi_tl(cpu_T[0], cpu_PR[PR_CCS], P_FLAG); |
| 1074 | break; | 1053 | break; |
| 1075 | case CC_A: | 1054 | case CC_A: |
| 1076 | - cris_evaluate_flags(dc); | ||
| 1077 | tcg_gen_movi_tl(cpu_T[0], 1); | 1055 | tcg_gen_movi_tl(cpu_T[0], 1); |
| 1078 | break; | 1056 | break; |
| 1079 | default: | 1057 | default: |
| @@ -1087,14 +1065,13 @@ static void cris_prepare_cc_branch (DisasContext *dc, int offset, int cond) | @@ -1087,14 +1065,13 @@ static void cris_prepare_cc_branch (DisasContext *dc, int offset, int cond) | ||
| 1087 | /* This helps us re-schedule the micro-code to insns in delay-slots | 1065 | /* This helps us re-schedule the micro-code to insns in delay-slots |
| 1088 | before the actual jump. */ | 1066 | before the actual jump. */ |
| 1089 | dc->delayed_branch = 2; | 1067 | dc->delayed_branch = 2; |
| 1090 | - dc->delayed_pc = dc->pc + offset; | ||
| 1091 | - dc->bcc = cond; | ||
| 1092 | if (cond != CC_A) | 1068 | if (cond != CC_A) |
| 1093 | { | 1069 | { |
| 1094 | gen_tst_cc (dc, cond); | 1070 | gen_tst_cc (dc, cond); |
| 1095 | t_gen_mov_env_TN(btaken, cpu_T[0]); | 1071 | t_gen_mov_env_TN(btaken, cpu_T[0]); |
| 1096 | - } | ||
| 1097 | - tcg_gen_movi_tl(env_btarget, dc->delayed_pc); | 1072 | + } else |
| 1073 | + t_gen_mov_env_TN(btaken, tcg_const_tl(1)); | ||
| 1074 | + tcg_gen_movi_tl(env_btarget, dc->pc + offset); | ||
| 1098 | } | 1075 | } |
| 1099 | 1076 | ||
| 1100 | 1077 | ||
| @@ -1104,18 +1081,7 @@ void cris_prepare_dyn_jmp (DisasContext *dc) | @@ -1104,18 +1081,7 @@ void cris_prepare_dyn_jmp (DisasContext *dc) | ||
| 1104 | /* This helps us re-schedule the micro-code to insns in delay-slots | 1081 | /* This helps us re-schedule the micro-code to insns in delay-slots |
| 1105 | before the actual jump. */ | 1082 | before the actual jump. */ |
| 1106 | dc->delayed_branch = 2; | 1083 | dc->delayed_branch = 2; |
| 1107 | - dc->dyn_jmp = 1; | ||
| 1108 | - dc->bcc = CC_A; | ||
| 1109 | -} | ||
| 1110 | - | ||
| 1111 | -void cris_prepare_jmp (DisasContext *dc, uint32_t dst) | ||
| 1112 | -{ | ||
| 1113 | - /* This helps us re-schedule the micro-code to insns in delay-slots | ||
| 1114 | - before the actual jump. */ | ||
| 1115 | - dc->delayed_branch = 2; | ||
| 1116 | - dc->delayed_pc = dst; | ||
| 1117 | - dc->dyn_jmp = 0; | ||
| 1118 | - dc->bcc = CC_A; | 1084 | + t_gen_mov_env_TN(btaken, tcg_const_tl(1)); |
| 1119 | } | 1085 | } |
| 1120 | 1086 | ||
| 1121 | void gen_load(DisasContext *dc, TCGv dst, TCGv addr, | 1087 | void gen_load(DisasContext *dc, TCGv dst, TCGv addr, |
| @@ -1123,6 +1089,7 @@ void gen_load(DisasContext *dc, TCGv dst, TCGv addr, | @@ -1123,6 +1089,7 @@ void gen_load(DisasContext *dc, TCGv dst, TCGv addr, | ||
| 1123 | { | 1089 | { |
| 1124 | int mem_index = cpu_mmu_index(dc->env); | 1090 | int mem_index = cpu_mmu_index(dc->env); |
| 1125 | 1091 | ||
| 1092 | + cris_evaluate_flags(dc); | ||
| 1126 | if (size == 1) { | 1093 | if (size == 1) { |
| 1127 | if (sign) | 1094 | if (sign) |
| 1128 | tcg_gen_qemu_ld8s(dst, addr, mem_index); | 1095 | tcg_gen_qemu_ld8s(dst, addr, mem_index); |
| @@ -1236,10 +1203,7 @@ static void dec_prep_alu_r(DisasContext *dc, int rs, int rd, | @@ -1236,10 +1203,7 @@ static void dec_prep_alu_r(DisasContext *dc, int rs, int rd, | ||
| 1236 | t_gen_zext(cpu_T[0], cpu_R[rd], size); | 1203 | t_gen_zext(cpu_T[0], cpu_R[rd], size); |
| 1237 | } | 1204 | } |
| 1238 | 1205 | ||
| 1239 | -/* Prepare T0 and T1 for a memory + alu operation. | ||
| 1240 | - s_ext decides if the operand1 should be sign-extended or zero-extended when | ||
| 1241 | - needed. */ | ||
| 1242 | -static int dec_prep_alu_m(DisasContext *dc, int s_ext, int memsize) | 1206 | +static int dec_prep_move_m(DisasContext *dc, int s_ext, int memsize) |
| 1243 | { | 1207 | { |
| 1244 | unsigned int rs, rd; | 1208 | unsigned int rs, rd; |
| 1245 | uint32_t imm; | 1209 | uint32_t imm; |
| @@ -1272,7 +1236,7 @@ static int dec_prep_alu_m(DisasContext *dc, int s_ext, int memsize) | @@ -1272,7 +1236,7 @@ static int dec_prep_alu_m(DisasContext *dc, int s_ext, int memsize) | ||
| 1272 | imm = ldl_code(dc->pc + 2); | 1236 | imm = ldl_code(dc->pc + 2); |
| 1273 | 1237 | ||
| 1274 | DIS(fprintf (logfile, "imm=%x rd=%d sext=%d ms=%d\n", | 1238 | DIS(fprintf (logfile, "imm=%x rd=%d sext=%d ms=%d\n", |
| 1275 | - imm, rd, s_ext, memsize)); | 1239 | + imm, rd, s_ext, memsize)); |
| 1276 | tcg_gen_movi_tl(cpu_T[1], imm); | 1240 | tcg_gen_movi_tl(cpu_T[1], imm); |
| 1277 | dc->postinc = 0; | 1241 | dc->postinc = 0; |
| 1278 | } else { | 1242 | } else { |
| @@ -1282,9 +1246,20 @@ static int dec_prep_alu_m(DisasContext *dc, int s_ext, int memsize) | @@ -1282,9 +1246,20 @@ static int dec_prep_alu_m(DisasContext *dc, int s_ext, int memsize) | ||
| 1282 | else | 1246 | else |
| 1283 | t_gen_zext(cpu_T[1], cpu_T[1], memsize); | 1247 | t_gen_zext(cpu_T[1], cpu_T[1], memsize); |
| 1284 | } | 1248 | } |
| 1249 | + return insn_len; | ||
| 1250 | +} | ||
| 1251 | + | ||
| 1252 | +/* Prepare T0 and T1 for a memory + alu operation. | ||
| 1253 | + s_ext decides if the operand1 should be sign-extended or zero-extended when | ||
| 1254 | + needed. */ | ||
| 1255 | +static int dec_prep_alu_m(DisasContext *dc, int s_ext, int memsize) | ||
| 1256 | +{ | ||
| 1257 | + int insn_len; | ||
| 1258 | + | ||
| 1259 | + insn_len = dec_prep_move_m(dc, s_ext, memsize); | ||
| 1285 | 1260 | ||
| 1286 | /* put dest in T0. */ | 1261 | /* put dest in T0. */ |
| 1287 | - t_gen_mov_TN_reg(cpu_T[0], rd); | 1262 | + tcg_gen_mov_tl(cpu_T[0], cpu_R[dc->op2]); |
| 1288 | return insn_len; | 1263 | return insn_len; |
| 1289 | } | 1264 | } |
| 1290 | 1265 | ||
| @@ -1421,7 +1396,7 @@ static unsigned int dec_btstq(DisasContext *dc) | @@ -1421,7 +1396,7 @@ static unsigned int dec_btstq(DisasContext *dc) | ||
| 1421 | crisv32_alu_op(dc, CC_OP_BTST, dc->op2, 4); | 1396 | crisv32_alu_op(dc, CC_OP_BTST, dc->op2, 4); |
| 1422 | 1397 | ||
| 1423 | cris_update_cc_op(dc, CC_OP_FLAGS, 4); | 1398 | cris_update_cc_op(dc, CC_OP_FLAGS, 4); |
| 1424 | - t_gen_mov_preg_TN(PR_CCS, cpu_T[0]); | 1399 | + t_gen_mov_preg_TN(dc, PR_CCS, cpu_T[0]); |
| 1425 | dc->flags_live = 1; | 1400 | dc->flags_live = 1; |
| 1426 | return 2; | 1401 | return 2; |
| 1427 | } | 1402 | } |
| @@ -1702,7 +1677,9 @@ static char * swapmode_name(int mode, char *modename) { | @@ -1702,7 +1677,9 @@ static char * swapmode_name(int mode, char *modename) { | ||
| 1702 | 1677 | ||
| 1703 | static unsigned int dec_swap_r(DisasContext *dc) | 1678 | static unsigned int dec_swap_r(DisasContext *dc) |
| 1704 | { | 1679 | { |
| 1705 | - DIS(char modename[4]); | 1680 | +#if DISAS_CRIS |
| 1681 | + char modename[4]; | ||
| 1682 | +#endif | ||
| 1706 | DIS(fprintf (logfile, "swap%s $r%u\n", | 1683 | DIS(fprintf (logfile, "swap%s $r%u\n", |
| 1707 | swapmode_name(dc->op2, modename), dc->op1)); | 1684 | swapmode_name(dc->op2, modename), dc->op1)); |
| 1708 | 1685 | ||
| @@ -1777,7 +1754,7 @@ static unsigned int dec_btst_r(DisasContext *dc) | @@ -1777,7 +1754,7 @@ static unsigned int dec_btst_r(DisasContext *dc) | ||
| 1777 | crisv32_alu_op(dc, CC_OP_BTST, dc->op2, 4); | 1754 | crisv32_alu_op(dc, CC_OP_BTST, dc->op2, 4); |
| 1778 | 1755 | ||
| 1779 | cris_update_cc_op(dc, CC_OP_FLAGS, 4); | 1756 | cris_update_cc_op(dc, CC_OP_FLAGS, 4); |
| 1780 | - t_gen_mov_preg_TN(PR_CCS, cpu_T[0]); | 1757 | + t_gen_mov_preg_TN(dc, PR_CCS, cpu_T[0]); |
| 1781 | dc->flags_live = 1; | 1758 | dc->flags_live = 1; |
| 1782 | return 2; | 1759 | return 2; |
| 1783 | } | 1760 | } |
| @@ -1900,14 +1877,16 @@ static unsigned int dec_setclrf(DisasContext *dc) | @@ -1900,14 +1877,16 @@ static unsigned int dec_setclrf(DisasContext *dc) | ||
| 1900 | flags = (EXTRACT_FIELD(dc->ir, 12, 15) << 4) | 1877 | flags = (EXTRACT_FIELD(dc->ir, 12, 15) << 4) |
| 1901 | | EXTRACT_FIELD(dc->ir, 0, 3); | 1878 | | EXTRACT_FIELD(dc->ir, 0, 3); |
| 1902 | DIS(fprintf (logfile, "set=%d flags=%x\n", set, flags)); | 1879 | DIS(fprintf (logfile, "set=%d flags=%x\n", set, flags)); |
| 1903 | - if (set && flags == 0) | 1880 | + if (set && flags == 0) { |
| 1904 | DIS(fprintf (logfile, "nop\n")); | 1881 | DIS(fprintf (logfile, "nop\n")); |
| 1905 | - else if (!set && (flags & 0x20)) | 1882 | + } else if (!set && (flags & 0x20)) { |
| 1906 | DIS(fprintf (logfile, "di\n")); | 1883 | DIS(fprintf (logfile, "di\n")); |
| 1907 | - else | 1884 | + } |
| 1885 | + else { | ||
| 1908 | DIS(fprintf (logfile, "%sf %x\n", | 1886 | DIS(fprintf (logfile, "%sf %x\n", |
| 1909 | - set ? "set" : "clr", | 1887 | + set ? "set" : "clr", |
| 1910 | flags)); | 1888 | flags)); |
| 1889 | + } | ||
| 1911 | 1890 | ||
| 1912 | if (set && (flags & X_FLAG)) { | 1891 | if (set && (flags & X_FLAG)) { |
| 1913 | dc->flagx_live = 1; | 1892 | dc->flagx_live = 1; |
| @@ -1924,7 +1903,7 @@ static unsigned int dec_setclrf(DisasContext *dc) | @@ -1924,7 +1903,7 @@ static unsigned int dec_setclrf(DisasContext *dc) | ||
| 1924 | /* Enter user mode. */ | 1903 | /* Enter user mode. */ |
| 1925 | t_gen_mov_env_TN(ksp, cpu_R[R_SP]); | 1904 | t_gen_mov_env_TN(ksp, cpu_R[R_SP]); |
| 1926 | tcg_gen_mov_tl(cpu_R[R_SP], cpu_PR[PR_USP]); | 1905 | tcg_gen_mov_tl(cpu_R[R_SP], cpu_PR[PR_USP]); |
| 1927 | - dc->is_jmp = DISAS_UPDATE; | 1906 | + dc->is_jmp = DISAS_NEXT; |
| 1928 | } | 1907 | } |
| 1929 | tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], flags); | 1908 | tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], flags); |
| 1930 | } | 1909 | } |
| @@ -1971,7 +1950,7 @@ static unsigned int dec_move_rp(DisasContext *dc) | @@ -1971,7 +1950,7 @@ static unsigned int dec_move_rp(DisasContext *dc) | ||
| 1971 | else | 1950 | else |
| 1972 | t_gen_mov_TN_reg(cpu_T[0], dc->op1); | 1951 | t_gen_mov_TN_reg(cpu_T[0], dc->op1); |
| 1973 | 1952 | ||
| 1974 | - t_gen_mov_preg_TN(dc->op2, cpu_T[0]); | 1953 | + t_gen_mov_preg_TN(dc, dc->op2, cpu_T[0]); |
| 1975 | if (dc->op2 == PR_CCS) { | 1954 | if (dc->op2 == PR_CCS) { |
| 1976 | cris_update_cc_op(dc, CC_OP_FLAGS, 4); | 1955 | cris_update_cc_op(dc, CC_OP_FLAGS, 4); |
| 1977 | dc->flags_live = 1; | 1956 | dc->flags_live = 1; |
| @@ -2004,7 +1983,7 @@ static unsigned int dec_move_mr(DisasContext *dc) | @@ -2004,7 +1983,7 @@ static unsigned int dec_move_mr(DisasContext *dc) | ||
| 2004 | dc->op1, dc->postinc ? "+]" : "]", | 1983 | dc->op1, dc->postinc ? "+]" : "]", |
| 2005 | dc->op2)); | 1984 | dc->op2)); |
| 2006 | 1985 | ||
| 2007 | - insn_len = dec_prep_alu_m(dc, 0, memsize); | 1986 | + insn_len = dec_prep_move_m(dc, 0, memsize); |
| 2008 | cris_cc_mask(dc, CC_MASK_NZ); | 1987 | cris_cc_mask(dc, CC_MASK_NZ); |
| 2009 | crisv32_alu_op(dc, CC_OP_MOVE, dc->op2, memsize); | 1988 | crisv32_alu_op(dc, CC_OP_MOVE, dc->op2, memsize); |
| 2010 | do_postinc(dc, memsize); | 1989 | do_postinc(dc, memsize); |
| @@ -2317,7 +2296,7 @@ static unsigned int dec_move_mp(DisasContext *dc) | @@ -2317,7 +2296,7 @@ static unsigned int dec_move_mp(DisasContext *dc) | ||
| 2317 | } | 2296 | } |
| 2318 | } | 2297 | } |
| 2319 | 2298 | ||
| 2320 | - t_gen_mov_preg_TN(dc->op2, cpu_T[1]); | 2299 | + t_gen_mov_preg_TN(dc, dc->op2, cpu_T[1]); |
| 2321 | 2300 | ||
| 2322 | do_postinc(dc, memsize); | 2301 | do_postinc(dc, memsize); |
| 2323 | return insn_len; | 2302 | return insn_len; |
| @@ -2337,7 +2316,6 @@ static unsigned int dec_move_pm(DisasContext *dc) | @@ -2337,7 +2316,6 @@ static unsigned int dec_move_pm(DisasContext *dc) | ||
| 2337 | if (dc->op2 == PR_CCS) | 2316 | if (dc->op2 == PR_CCS) |
| 2338 | cris_evaluate_flags(dc); | 2317 | cris_evaluate_flags(dc); |
| 2339 | t_gen_mov_TN_preg(cpu_T[1], dc->op2); | 2318 | t_gen_mov_TN_preg(cpu_T[1], dc->op2); |
| 2340 | - | ||
| 2341 | gen_store(dc, cpu_R[dc->op1], cpu_T[1], memsize); | 2319 | gen_store(dc, cpu_R[dc->op1], cpu_T[1], memsize); |
| 2342 | 2320 | ||
| 2343 | cris_cc_mask(dc, 0); | 2321 | cris_cc_mask(dc, 0); |
| @@ -2482,7 +2460,7 @@ static unsigned int dec_jas_im(DisasContext *dc) | @@ -2482,7 +2460,7 @@ static unsigned int dec_jas_im(DisasContext *dc) | ||
| 2482 | cris_cc_mask(dc, 0); | 2460 | cris_cc_mask(dc, 0); |
| 2483 | /* Store the return address in Pd. */ | 2461 | /* Store the return address in Pd. */ |
| 2484 | tcg_gen_movi_tl(env_btarget, imm); | 2462 | tcg_gen_movi_tl(env_btarget, imm); |
| 2485 | - t_gen_mov_preg_TN(dc->op2, tcg_const_tl(dc->pc + 8)); | 2463 | + t_gen_mov_preg_TN(dc, dc->op2, tcg_const_tl(dc->pc + 8)); |
| 2486 | cris_prepare_dyn_jmp(dc); | 2464 | cris_prepare_dyn_jmp(dc); |
| 2487 | return 6; | 2465 | return 6; |
| 2488 | } | 2466 | } |
| @@ -2499,7 +2477,7 @@ static unsigned int dec_jasc_im(DisasContext *dc) | @@ -2499,7 +2477,7 @@ static unsigned int dec_jasc_im(DisasContext *dc) | ||
| 2499 | tcg_gen_movi_tl(cpu_T[0], imm); | 2477 | tcg_gen_movi_tl(cpu_T[0], imm); |
| 2500 | tcg_gen_mov_tl(env_btarget, cpu_T[0]); | 2478 | tcg_gen_mov_tl(env_btarget, cpu_T[0]); |
| 2501 | tcg_gen_movi_tl(cpu_T[0], dc->pc + 8 + 4); | 2479 | tcg_gen_movi_tl(cpu_T[0], dc->pc + 8 + 4); |
| 2502 | - t_gen_mov_preg_TN(dc->op2, cpu_T[0]); | 2480 | + t_gen_mov_preg_TN(dc, dc->op2, cpu_T[0]); |
| 2503 | cris_prepare_dyn_jmp(dc); | 2481 | cris_prepare_dyn_jmp(dc); |
| 2504 | return 6; | 2482 | return 6; |
| 2505 | } | 2483 | } |
| @@ -2512,7 +2490,7 @@ static unsigned int dec_jasc_r(DisasContext *dc) | @@ -2512,7 +2490,7 @@ static unsigned int dec_jasc_r(DisasContext *dc) | ||
| 2512 | t_gen_mov_TN_reg(cpu_T[0], dc->op1); | 2490 | t_gen_mov_TN_reg(cpu_T[0], dc->op1); |
| 2513 | tcg_gen_mov_tl(env_btarget, cpu_T[0]); | 2491 | tcg_gen_mov_tl(env_btarget, cpu_T[0]); |
| 2514 | tcg_gen_movi_tl(cpu_T[0], dc->pc + 4 + 4); | 2492 | tcg_gen_movi_tl(cpu_T[0], dc->pc + 4 + 4); |
| 2515 | - t_gen_mov_preg_TN(dc->op2, cpu_T[0]); | 2493 | + t_gen_mov_preg_TN(dc, dc->op2, cpu_T[0]); |
| 2516 | cris_prepare_dyn_jmp(dc); | 2494 | cris_prepare_dyn_jmp(dc); |
| 2517 | return 2; | 2495 | return 2; |
| 2518 | } | 2496 | } |
| @@ -2547,7 +2525,7 @@ static unsigned int dec_bas_im(DisasContext *dc) | @@ -2547,7 +2525,7 @@ static unsigned int dec_bas_im(DisasContext *dc) | ||
| 2547 | tcg_gen_movi_tl(cpu_T[0], dc->pc + simm); | 2525 | tcg_gen_movi_tl(cpu_T[0], dc->pc + simm); |
| 2548 | tcg_gen_mov_tl(env_btarget, cpu_T[0]); | 2526 | tcg_gen_mov_tl(env_btarget, cpu_T[0]); |
| 2549 | tcg_gen_movi_tl(cpu_T[0], dc->pc + 8); | 2527 | tcg_gen_movi_tl(cpu_T[0], dc->pc + 8); |
| 2550 | - t_gen_mov_preg_TN(dc->op2, cpu_T[0]); | 2528 | + t_gen_mov_preg_TN(dc, dc->op2, cpu_T[0]); |
| 2551 | cris_prepare_dyn_jmp(dc); | 2529 | cris_prepare_dyn_jmp(dc); |
| 2552 | return 6; | 2530 | return 6; |
| 2553 | } | 2531 | } |
| @@ -2563,7 +2541,7 @@ static unsigned int dec_basc_im(DisasContext *dc) | @@ -2563,7 +2541,7 @@ static unsigned int dec_basc_im(DisasContext *dc) | ||
| 2563 | tcg_gen_movi_tl(cpu_T[0], dc->pc + simm); | 2541 | tcg_gen_movi_tl(cpu_T[0], dc->pc + simm); |
| 2564 | tcg_gen_mov_tl(env_btarget, cpu_T[0]); | 2542 | tcg_gen_mov_tl(env_btarget, cpu_T[0]); |
| 2565 | tcg_gen_movi_tl(cpu_T[0], dc->pc + 12); | 2543 | tcg_gen_movi_tl(cpu_T[0], dc->pc + 12); |
| 2566 | - t_gen_mov_preg_TN(dc->op2, cpu_T[0]); | 2544 | + t_gen_mov_preg_TN(dc, dc->op2, cpu_T[0]); |
| 2567 | cris_prepare_dyn_jmp(dc); | 2545 | cris_prepare_dyn_jmp(dc); |
| 2568 | return 6; | 2546 | return 6; |
| 2569 | } | 2547 | } |
| @@ -2785,8 +2763,42 @@ static void check_breakpoint(CPUState *env, DisasContext *dc) | @@ -2785,8 +2763,42 @@ static void check_breakpoint(CPUState *env, DisasContext *dc) | ||
| 2785 | } | 2763 | } |
| 2786 | } | 2764 | } |
| 2787 | 2765 | ||
| 2766 | + | ||
| 2767 | +/* | ||
| 2768 | + * Delay slots on QEMU/CRIS. | ||
| 2769 | + * | ||
| 2770 | + * If an exception hits on a delayslot, the core will let ERP (the Exception | ||
| 2771 | + * Return Pointer) point to the branch (the previous) insn and set the lsb to | ||
| 2772 | + * to give SW a hint that the exception actually hit on the dslot. | ||
| 2773 | + * | ||
| 2774 | + * CRIS expects all PC addresses to be 16-bit aligned. The lsb is ignored by | ||
| 2775 | + * the core and any jmp to an odd addresses will mask off that lsb. It is | ||
| 2776 | + * simply there to let sw know there was an exception on a dslot. | ||
| 2777 | + * | ||
| 2778 | + * When the software returns from an exception, the branch will re-execute. | ||
| 2779 | + * On QEMU care needs to be taken when a branch+delayslot sequence is broken | ||
| 2780 | + * and the branch and delayslot dont share pages. | ||
| 2781 | + * | ||
| 2782 | + * The TB contaning the branch insn will set up env->btarget and evaluate | ||
| 2783 | + * env->btaken. When the translation loop exits we will note that the branch | ||
| 2784 | + * sequence is broken and let env->dslot be the size of the branch insn (those | ||
| 2785 | + * vary in length). | ||
| 2786 | + * | ||
| 2787 | + * The TB contaning the delayslot will have the PC of its real insn (i.e no lsb | ||
| 2788 | + * set). It will also expect to have env->dslot setup with the size of the | ||
| 2789 | + * delay slot so that env->pc - env->dslot point to the branch insn. This TB | ||
| 2790 | + * will execute the dslot and take the branch, either to btarget or just one | ||
| 2791 | + * insn ahead. | ||
| 2792 | + * | ||
| 2793 | + * When exceptions occur, we check for env->dslot in do_interrupt to detect | ||
| 2794 | + * broken branch sequences and setup $erp accordingly (i.e let it point to the | ||
| 2795 | + * branch and set lsb). Then env->dslot gets cleared so that the exception | ||
| 2796 | + * handler can enter. When returning from exceptions (jump $erp) the lsb gets | ||
| 2797 | + * masked off and we will reexecute the branch insn. | ||
| 2798 | + * | ||
| 2799 | + */ | ||
| 2800 | + | ||
| 2788 | /* generate intermediate code for basic block 'tb'. */ | 2801 | /* generate intermediate code for basic block 'tb'. */ |
| 2789 | -struct DisasContext ctx; | ||
| 2790 | static int | 2802 | static int |
| 2791 | gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | 2803 | gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, |
| 2792 | int search_pc) | 2804 | int search_pc) |
| @@ -2795,6 +2807,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | @@ -2795,6 +2807,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | ||
| 2795 | uint32_t pc_start; | 2807 | uint32_t pc_start; |
| 2796 | unsigned int insn_len; | 2808 | unsigned int insn_len; |
| 2797 | int j, lj; | 2809 | int j, lj; |
| 2810 | + struct DisasContext ctx; | ||
| 2798 | struct DisasContext *dc = &ctx; | 2811 | struct DisasContext *dc = &ctx; |
| 2799 | uint32_t next_page_start; | 2812 | uint32_t next_page_start; |
| 2800 | 2813 | ||
| @@ -2803,8 +2816,6 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | @@ -2803,8 +2816,6 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | ||
| 2803 | 2816 | ||
| 2804 | /* Odd PC indicates that branch is rexecuting due to exception in the | 2817 | /* Odd PC indicates that branch is rexecuting due to exception in the |
| 2805 | * delayslot, like in real hw. | 2818 | * delayslot, like in real hw. |
| 2806 | - * FIXME: we need to handle the case were the branch and the insn in | ||
| 2807 | - * the delayslot do not share pages. | ||
| 2808 | */ | 2819 | */ |
| 2809 | pc_start = tb->pc & ~1; | 2820 | pc_start = tb->pc & ~1; |
| 2810 | dc->env = env; | 2821 | dc->env = env; |
| @@ -2820,19 +2831,24 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | @@ -2820,19 +2831,24 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | ||
| 2820 | dc->flagx_live = 0; | 2831 | dc->flagx_live = 0; |
| 2821 | dc->flags_x = 0; | 2832 | dc->flags_x = 0; |
| 2822 | dc->cc_mask = 0; | 2833 | dc->cc_mask = 0; |
| 2834 | + dc->update_cc = 0; | ||
| 2823 | cris_update_cc_op(dc, CC_OP_FLAGS, 4); | 2835 | cris_update_cc_op(dc, CC_OP_FLAGS, 4); |
| 2824 | 2836 | ||
| 2825 | - dc->user = env->pregs[PR_CCS] & U_FLAG; | ||
| 2826 | - dc->delayed_branch = 0; | 2837 | + /* Decode TB flags. */ |
| 2838 | + dc->user = tb->flags & U_FLAG; | ||
| 2839 | + dc->delayed_branch = !!(tb->flags & 7); | ||
| 2827 | 2840 | ||
| 2828 | if (loglevel & CPU_LOG_TB_IN_ASM) { | 2841 | if (loglevel & CPU_LOG_TB_IN_ASM) { |
| 2829 | fprintf(logfile, | 2842 | fprintf(logfile, |
| 2830 | - "search=%d pc=%x ccs=%x pid=%x usp=%x dbg=%x %x %x\n" | 2843 | + "srch=%d pc=%x %x bt=%x ds=%lld ccs=%x\n" |
| 2844 | + "pid=%x usp=%x dbg=%x %x %x\n" | ||
| 2831 | "%x.%x.%x.%x\n" | 2845 | "%x.%x.%x.%x\n" |
| 2832 | "%x.%x.%x.%x\n" | 2846 | "%x.%x.%x.%x\n" |
| 2833 | "%x.%x.%x.%x\n" | 2847 | "%x.%x.%x.%x\n" |
| 2834 | "%x.%x.%x.%x\n", | 2848 | "%x.%x.%x.%x\n", |
| 2835 | - search_pc, env->pc, env->pregs[PR_CCS], | 2849 | + search_pc, dc->pc, dc->ppc, |
| 2850 | + env->btarget, tb->flags & 7, | ||
| 2851 | + env->pregs[PR_CCS], | ||
| 2836 | env->pregs[PR_PID], env->pregs[PR_USP], | 2852 | env->pregs[PR_PID], env->pregs[PR_USP], |
| 2837 | env->debug1, env->debug2, env->debug3, | 2853 | env->debug1, env->debug2, env->debug3, |
| 2838 | env->regs[0], env->regs[1], env->regs[2], env->regs[3], | 2854 | env->regs[0], env->regs[1], env->regs[2], env->regs[3], |
| @@ -2860,14 +2876,17 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | @@ -2860,14 +2876,17 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | ||
| 2860 | while (lj < j) | 2876 | while (lj < j) |
| 2861 | gen_opc_instr_start[lj++] = 0; | 2877 | gen_opc_instr_start[lj++] = 0; |
| 2862 | } | 2878 | } |
| 2863 | - if (dc->delayed_branch == 1) { | 2879 | + if (dc->delayed_branch == 1) |
| 2864 | gen_opc_pc[lj] = dc->ppc | 1; | 2880 | gen_opc_pc[lj] = dc->ppc | 1; |
| 2865 | - gen_opc_instr_start[lj] = 0; | ||
| 2866 | - } | ||
| 2867 | - else { | 2881 | + else |
| 2868 | gen_opc_pc[lj] = dc->pc; | 2882 | gen_opc_pc[lj] = dc->pc; |
| 2869 | - gen_opc_instr_start[lj] = 1; | ||
| 2870 | - } | 2883 | + gen_opc_instr_start[lj] = 1; |
| 2884 | + } | ||
| 2885 | + | ||
| 2886 | + /* Pretty disas. */ | ||
| 2887 | + DIS(fprintf(logfile, "%x ", dc->pc)); | ||
| 2888 | + if (search_pc) { | ||
| 2889 | + DIS(fprintf(logfile, "%x ", dc->pc)); | ||
| 2871 | } | 2890 | } |
| 2872 | 2891 | ||
| 2873 | dc->clear_x = 1; | 2892 | dc->clear_x = 1; |
| @@ -2881,17 +2900,13 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | @@ -2881,17 +2900,13 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | ||
| 2881 | actually genereating any host code, the simulator will just | 2900 | actually genereating any host code, the simulator will just |
| 2882 | loop doing nothing for on this program location. */ | 2901 | loop doing nothing for on this program location. */ |
| 2883 | if (dc->delayed_branch) { | 2902 | if (dc->delayed_branch) { |
| 2903 | + t_gen_mov_env_TN(dslot, tcg_const_tl(0)); | ||
| 2884 | dc->delayed_branch--; | 2904 | dc->delayed_branch--; |
| 2885 | if (dc->delayed_branch == 0) | 2905 | if (dc->delayed_branch == 0) |
| 2886 | { | 2906 | { |
| 2887 | - if (dc->bcc == CC_A) { | ||
| 2888 | - tcg_gen_mov_tl(env_pc, env_btarget); | ||
| 2889 | - dc->is_jmp = DISAS_JUMP; | ||
| 2890 | - } | ||
| 2891 | - else { | ||
| 2892 | - t_gen_cc_jmp(dc->delayed_pc, dc->pc); | ||
| 2893 | - dc->is_jmp = DISAS_JUMP; | ||
| 2894 | - } | 2907 | + t_gen_cc_jmp(env_btarget, |
| 2908 | + tcg_const_tl(dc->pc)); | ||
| 2909 | + dc->is_jmp = DISAS_JUMP; | ||
| 2895 | } | 2910 | } |
| 2896 | } | 2911 | } |
| 2897 | 2912 | ||
| @@ -2900,15 +2915,16 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | @@ -2900,15 +2915,16 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, | ||
| 2900 | if (!(tb->pc & 1) && env->singlestep_enabled) | 2915 | if (!(tb->pc & 1) && env->singlestep_enabled) |
| 2901 | break; | 2916 | break; |
| 2902 | } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end | 2917 | } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end |
| 2903 | - && ((dc->pc < next_page_start) || dc->delayed_branch)); | 2918 | + && (dc->pc < next_page_start)); |
| 2904 | 2919 | ||
| 2920 | + /* Broken branch+delayslot sequence. */ | ||
| 2905 | if (dc->delayed_branch == 1) { | 2921 | if (dc->delayed_branch == 1) { |
| 2906 | - /* Reexecute the last insn. */ | ||
| 2907 | - dc->pc = dc->ppc | 1; | 2922 | + /* Set env->dslot to the size of the branch insn. */ |
| 2923 | + t_gen_mov_env_TN(dslot, tcg_const_tl(dc->pc - dc->ppc)); | ||
| 2908 | } | 2924 | } |
| 2909 | 2925 | ||
| 2910 | if (!dc->is_jmp) { | 2926 | if (!dc->is_jmp) { |
| 2911 | - D(printf("!jmp pc=%x jmp=%d db=%d\n", dc->pc, | 2927 | + D(fprintf(logfile, "!jmp pc=%x jmp=%d db=%d\n", dc->pc, |
| 2912 | dc->is_jmp, dc->delayed_branch)); | 2928 | dc->is_jmp, dc->delayed_branch)); |
| 2913 | /* T0 and env_pc should hold the new pc. */ | 2929 | /* T0 and env_pc should hold the new pc. */ |
| 2914 | tcg_gen_movi_tl(cpu_T[0], dc->pc); | 2930 | tcg_gen_movi_tl(cpu_T[0], dc->pc); |
| @@ -3079,6 +3095,7 @@ CPUCRISState *cpu_cris_init (const char *cpu_model) | @@ -3079,6 +3095,7 @@ CPUCRISState *cpu_cris_init (const char *cpu_model) | ||
| 3079 | TCG_HELPER(helper_dummy); | 3095 | TCG_HELPER(helper_dummy); |
| 3080 | 3096 | ||
| 3081 | TCG_HELPER(helper_tlb_flush); | 3097 | TCG_HELPER(helper_tlb_flush); |
| 3098 | + TCG_HELPER(helper_tlb_flush_pid); | ||
| 3082 | TCG_HELPER(helper_movl_sreg_reg); | 3099 | TCG_HELPER(helper_movl_sreg_reg); |
| 3083 | TCG_HELPER(helper_movl_reg_sreg); | 3100 | TCG_HELPER(helper_movl_reg_sreg); |
| 3084 | TCG_HELPER(helper_rfe); | 3101 | TCG_HELPER(helper_rfe); |