diff --git a/hw/openrisc/cputimer.c b/hw/openrisc/cputimer.c index 988ca20898..9c54945107 100644 --- a/hw/openrisc/cputimer.c +++ b/hw/openrisc/cputimer.c @@ -30,19 +30,28 @@ static int is_counting; void cpu_openrisc_count_update(OpenRISCCPU *cpu) { - uint64_t now, next; - uint32_t wait; + uint64_t now; - now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); if (!is_counting) { - timer_del(cpu->env.timer); - last_clk = now; return; } - + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); cpu->env.ttcr += (uint32_t)muldiv64(now - last_clk, TIMER_FREQ, get_ticks_per_sec()); last_clk = now; +} + +void cpu_openrisc_timer_update(OpenRISCCPU *cpu) +{ + uint32_t wait; + uint64_t now, next; + + if (!is_counting) { + return; + } + + cpu_openrisc_count_update(cpu); + now = last_clk; if ((cpu->env.ttmr & TTMR_TP) <= (cpu->env.ttcr & TTMR_TP)) { wait = TTMR_TP - (cpu->env.ttcr & TTMR_TP) + 1; @@ -50,7 +59,6 @@ void cpu_openrisc_count_update(OpenRISCCPU *cpu) } else { wait = (cpu->env.ttmr & TTMR_TP) - (cpu->env.ttcr & TTMR_TP); } - next = now + muldiv64(wait, get_ticks_per_sec(), TIMER_FREQ); timer_mod(cpu->env.timer, next); } @@ -63,8 +71,9 @@ void cpu_openrisc_count_start(OpenRISCCPU *cpu) void cpu_openrisc_count_stop(OpenRISCCPU *cpu) { - is_counting = 0; + timer_del(cpu->env.timer); cpu_openrisc_count_update(cpu); + is_counting = 0; } static void openrisc_timer_cb(void *opaque) @@ -84,15 +93,15 @@ static void openrisc_timer_cb(void *opaque) break; case TIMER_INTR: cpu->env.ttcr = 0; - cpu_openrisc_count_start(cpu); break; case TIMER_SHOT: cpu_openrisc_count_stop(cpu); break; case TIMER_CONT: - cpu_openrisc_count_start(cpu); break; } + + cpu_openrisc_timer_update(cpu); } void cpu_openrisc_clock_init(OpenRISCCPU *cpu) diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h index 8fd0bc0bf0..0f9efdf6de 100644 --- a/target-openrisc/cpu.h +++ b/target-openrisc/cpu.h @@ -373,6 +373,7 @@ void cpu_openrisc_pic_init(OpenRISCCPU *cpu); /* hw/openrisc_timer.c */ void cpu_openrisc_clock_init(OpenRISCCPU *cpu); void cpu_openrisc_count_update(OpenRISCCPU *cpu); +void cpu_openrisc_timer_update(OpenRISCCPU *cpu); void cpu_openrisc_count_start(OpenRISCCPU *cpu); void cpu_openrisc_count_stop(OpenRISCCPU *cpu); diff --git a/target-openrisc/interrupt.c b/target-openrisc/interrupt.c index 16ef4b3e79..2153e7ea7e 100644 --- a/target-openrisc/interrupt.c +++ b/target-openrisc/interrupt.c @@ -30,26 +30,15 @@ void openrisc_cpu_do_interrupt(CPUState *cs) OpenRISCCPU *cpu = OPENRISC_CPU(cs); CPUOpenRISCState *env = &cpu->env; #ifndef CONFIG_USER_ONLY - if (env->flags & D_FLAG) { /* Delay Slot insn */ + + env->epcr = env->pc; + if (env->flags & D_FLAG) { env->flags &= ~D_FLAG; env->sr |= SR_DSX; - if (env->exception_index == EXCP_TICK || - env->exception_index == EXCP_INT || - env->exception_index == EXCP_SYSCALL || - env->exception_index == EXCP_FPE) { - env->epcr = env->jmp_pc; - } else { - env->epcr = env->pc - 4; - } - } else { - if (env->exception_index == EXCP_TICK || - env->exception_index == EXCP_INT || - env->exception_index == EXCP_SYSCALL || - env->exception_index == EXCP_FPE) { - env->epcr = env->npc; - } else { - env->epcr = env->pc; - } + env->epcr -= 4; + } + if (env->exception_index == EXCP_SYSCALL) { + env->epcr += 4; } /* For machine-state changed between user-mode and supervisor mode, diff --git a/target-openrisc/mmu.c b/target-openrisc/mmu.c index 22d7cbec18..dd487bd0d1 100644 --- a/target-openrisc/mmu.c +++ b/target-openrisc/mmu.c @@ -32,7 +32,7 @@ int cpu_openrisc_get_phys_nommu(OpenRISCCPU *cpu, int *prot, target_ulong address, int rw) { *physical = address; - *prot = PAGE_READ | PAGE_WRITE; + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; return TLBRET_MATCH; } @@ -187,7 +187,7 @@ int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env, if (ret == TLBRET_MATCH) { tlb_set_page(env, address & TARGET_PAGE_MASK, - physical & TARGET_PAGE_MASK, prot | PAGE_EXEC, + physical & TARGET_PAGE_MASK, prot, mmu_idx, TARGET_PAGE_SIZE); ret = 0; } else if (ret < 0) { diff --git a/target-openrisc/sys_helper.c b/target-openrisc/sys_helper.c index cccbc0e939..be06c4565b 100644 --- a/target-openrisc/sys_helper.c +++ b/target-openrisc/sys_helper.c @@ -81,7 +81,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env, case TO_SPR(0, 64): /* ESR */ env->esr = rb; break; - case TO_SPR(1, 512) ... TO_SPR(1, 639): /* DTLBW0MR 0-127 */ + case TO_SPR(1, 512) ... TO_SPR(1, 512+DTLB_SIZE-1): /* DTLBW0MR 0-127 */ idx = spr - TO_SPR(1, 512); if (!(rb & 1)) { tlb_flush_page(env, env->tlb->dtlb[0][idx].mr & TARGET_PAGE_MASK); @@ -89,7 +89,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env, env->tlb->dtlb[0][idx].mr = rb; break; - case TO_SPR(1, 640) ... TO_SPR(1, 767): /* DTLBW0TR 0-127 */ + case TO_SPR(1, 640) ... TO_SPR(1, 640+DTLB_SIZE-1): /* DTLBW0TR 0-127 */ idx = spr - TO_SPR(1, 640); env->tlb->dtlb[0][idx].tr = rb; break; @@ -100,7 +100,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env, case TO_SPR(1, 1280) ... TO_SPR(1, 1407): /* DTLBW3MR 0-127 */ case TO_SPR(1, 1408) ... TO_SPR(1, 1535): /* DTLBW3TR 0-127 */ break; - case TO_SPR(2, 512) ... TO_SPR(2, 639): /* ITLBW0MR 0-127 */ + case TO_SPR(2, 512) ... TO_SPR(2, 512+ITLB_SIZE-1): /* ITLBW0MR 0-127 */ idx = spr - TO_SPR(2, 512); if (!(rb & 1)) { tlb_flush_page(env, env->tlb->itlb[0][idx].mr & TARGET_PAGE_MASK); @@ -108,7 +108,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env, env->tlb->itlb[0][idx].mr = rb; break; - case TO_SPR(2, 640) ... TO_SPR(2, 767): /* ITLBW0TR 0-127 */ + case TO_SPR(2, 640) ... TO_SPR(2, 640+ITLB_SIZE-1): /* ITLBW0TR 0-127 */ idx = spr - TO_SPR(2, 640); env->tlb->itlb[0][idx].tr = rb; break; @@ -127,33 +127,31 @@ void HELPER(mtspr)(CPUOpenRISCState *env, break; case TO_SPR(10, 0): /* TTMR */ { + if ((env->ttmr & TTMR_M) ^ (rb & TTMR_M)) { + switch (rb & TTMR_M) { + case TIMER_NONE: + cpu_openrisc_count_stop(cpu); + break; + case TIMER_INTR: + case TIMER_SHOT: + case TIMER_CONT: + cpu_openrisc_count_start(cpu); + break; + default: + break; + } + } + int ip = env->ttmr & TTMR_IP; if (rb & TTMR_IP) { /* Keep IP bit. */ - env->ttmr = (rb & ~TTMR_IP) + ip; + env->ttmr = (rb & ~TTMR_IP) | ip; } else { /* Clear IP bit. */ env->ttmr = rb & ~TTMR_IP; cs->interrupt_request &= ~CPU_INTERRUPT_TIMER; } - cpu_openrisc_count_update(cpu); - - switch (env->ttmr & TTMR_M) { - case TIMER_NONE: - cpu_openrisc_count_stop(cpu); - break; - case TIMER_INTR: - cpu_openrisc_count_start(cpu); - break; - case TIMER_SHOT: - cpu_openrisc_count_start(cpu); - break; - case TIMER_CONT: - cpu_openrisc_count_start(cpu); - break; - default: - break; - } + cpu_openrisc_timer_update(cpu); } break; @@ -162,7 +160,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env, if (env->ttmr & TIMER_NONE) { return; } - cpu_openrisc_count_start(cpu); + cpu_openrisc_timer_update(cpu); break; default: @@ -214,11 +212,11 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, case TO_SPR(0, 64): /* ESR */ return env->esr; - case TO_SPR(1, 512) ... TO_SPR(1, 639): /* DTLBW0MR 0-127 */ + case TO_SPR(1, 512) ... TO_SPR(1, 512+DTLB_SIZE-1): /* DTLBW0MR 0-127 */ idx = spr - TO_SPR(1, 512); return env->tlb->dtlb[0][idx].mr; - case TO_SPR(1, 640) ... TO_SPR(1, 767): /* DTLBW0TR 0-127 */ + case TO_SPR(1, 640) ... TO_SPR(1, 640+DTLB_SIZE-1): /* DTLBW0TR 0-127 */ idx = spr - TO_SPR(1, 640); return env->tlb->dtlb[0][idx].tr; @@ -230,11 +228,11 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, case TO_SPR(1, 1408) ... TO_SPR(1, 1535): /* DTLBW3TR 0-127 */ break; - case TO_SPR(2, 512) ... TO_SPR(2, 639): /* ITLBW0MR 0-127 */ + case TO_SPR(2, 512) ... TO_SPR(2, 512+ITLB_SIZE-1): /* ITLBW0MR 0-127 */ idx = spr - TO_SPR(2, 512); return env->tlb->itlb[0][idx].mr; - case TO_SPR(2, 640) ... TO_SPR(2, 767): /* ITLBW0TR 0-127 */ + case TO_SPR(2, 640) ... TO_SPR(2, 640+ITLB_SIZE-1): /* ITLBW0TR 0-127 */ idx = spr - TO_SPR(2, 640); return env->tlb->itlb[0][idx].tr; diff --git a/target-openrisc/translate.c b/target-openrisc/translate.c index 8908a2e32b..91c60ebaae 100644 --- a/target-openrisc/translate.c +++ b/target-openrisc/translate.c @@ -209,42 +209,49 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) static void gen_jump(DisasContext *dc, uint32_t imm, uint32_t reg, uint32_t op0) { target_ulong tmp_pc; - int lab = gen_new_label(); - TCGv sr_f = tcg_temp_new(); /* N26, 26bits imm */ tmp_pc = sign_extend((imm<<2), 26) + dc->pc; - tcg_gen_andi_tl(sr_f, cpu_sr, SR_F); - if (op0 == 0x00) { /* l.j */ + switch (op0) { + case 0x00: /* l.j */ tcg_gen_movi_tl(jmp_pc, tmp_pc); - } else if (op0 == 0x01) { /* l.jal */ + break; + case 0x01: /* l.jal */ tcg_gen_movi_tl(cpu_R[9], (dc->pc + 8)); tcg_gen_movi_tl(jmp_pc, tmp_pc); - } else if (op0 == 0x03) { /* l.bnf */ - tcg_gen_movi_tl(jmp_pc, dc->pc+8); - tcg_gen_brcondi_i32(TCG_COND_EQ, sr_f, SR_F, lab); - tcg_gen_movi_tl(jmp_pc, tmp_pc); - gen_set_label(lab); - } else if (op0 == 0x04) { /* l.bf */ - tcg_gen_movi_tl(jmp_pc, dc->pc+8); - tcg_gen_brcondi_i32(TCG_COND_NE, sr_f, SR_F, lab); - tcg_gen_movi_tl(jmp_pc, tmp_pc); - gen_set_label(lab); - } else if (op0 == 0x11) { /* l.jr */ + break; + case 0x03: /* l.bnf */ + case 0x04: /* l.bf */ + { + int lab = gen_new_label(); + TCGv sr_f = tcg_temp_new(); + tcg_gen_movi_tl(jmp_pc, dc->pc+8); + tcg_gen_andi_tl(sr_f, cpu_sr, SR_F); + tcg_gen_brcondi_i32(op0 == 0x03 ? TCG_COND_EQ : TCG_COND_NE, + sr_f, SR_F, lab); + tcg_gen_movi_tl(jmp_pc, tmp_pc); + gen_set_label(lab); + tcg_temp_free(sr_f); + } + break; + case 0x11: /* l.jr */ tcg_gen_mov_tl(jmp_pc, cpu_R[reg]); - } else if (op0 == 0x12) { /* l.jalr */ + break; + case 0x12: /* l.jalr */ tcg_gen_movi_tl(cpu_R[9], (dc->pc + 8)); tcg_gen_mov_tl(jmp_pc, cpu_R[reg]); - } else { + break; + default: gen_illegal_exception(dc); + break; } - tcg_temp_free(sr_f); dc->delayed_branch = 2; dc->tb_flags |= D_FLAG; gen_sync_flags(dc); } + static void dec_calc(DisasContext *dc, uint32_t insn) { uint32_t op0, op1, op2; @@ -904,29 +911,33 @@ static void dec_misc(DisasContext *dc, uint32_t insn) case 0x27: /* l.addi */ LOG_DIS("l.addi r%d, r%d, %d\n", rd, ra, I16); { - int lab = gen_new_label(); - TCGv_i64 ta = tcg_temp_new_i64(); - TCGv_i64 td = tcg_temp_local_new_i64(); - TCGv_i32 res = tcg_temp_local_new_i32(); - TCGv_i32 sr_ove = tcg_temp_local_new_i32(); - tcg_gen_extu_i32_i64(ta, cpu_R[ra]); - tcg_gen_addi_i64(td, ta, sign_extend(I16, 16)); - tcg_gen_trunc_i64_i32(res, td); - tcg_gen_shri_i64(td, td, 32); - tcg_gen_andi_i64(td, td, 0x3); - /* Jump to lab when no overflow. */ - tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x0, lab); - tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x3, lab); - tcg_gen_ori_i32(cpu_sr, cpu_sr, (SR_OV | SR_CY)); - tcg_gen_andi_i32(sr_ove, cpu_sr, SR_OVE); - tcg_gen_brcondi_i32(TCG_COND_NE, sr_ove, SR_OVE, lab); - gen_exception(dc, EXCP_RANGE); - gen_set_label(lab); - tcg_gen_mov_i32(cpu_R[rd], res); - tcg_temp_free_i64(ta); - tcg_temp_free_i64(td); - tcg_temp_free_i32(res); - tcg_temp_free_i32(sr_ove); + if (I16 == 0) { + tcg_gen_mov_tl(cpu_R[rd], cpu_R[ra]); + } else { + int lab = gen_new_label(); + TCGv_i64 ta = tcg_temp_new_i64(); + TCGv_i64 td = tcg_temp_local_new_i64(); + TCGv_i32 res = tcg_temp_local_new_i32(); + TCGv_i32 sr_ove = tcg_temp_local_new_i32(); + tcg_gen_extu_i32_i64(ta, cpu_R[ra]); + tcg_gen_addi_i64(td, ta, sign_extend(I16, 16)); + tcg_gen_trunc_i64_i32(res, td); + tcg_gen_shri_i64(td, td, 32); + tcg_gen_andi_i64(td, td, 0x3); + /* Jump to lab when no overflow. */ + tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x0, lab); + tcg_gen_brcondi_i64(TCG_COND_EQ, td, 0x3, lab); + tcg_gen_ori_i32(cpu_sr, cpu_sr, (SR_OV | SR_CY)); + tcg_gen_andi_i32(sr_ove, cpu_sr, SR_OVE); + tcg_gen_brcondi_i32(TCG_COND_NE, sr_ove, SR_OVE, lab); + gen_exception(dc, EXCP_RANGE); + gen_set_label(lab); + tcg_gen_mov_i32(cpu_R[rd], res); + tcg_temp_free_i64(ta); + tcg_temp_free_i64(td); + tcg_temp_free_i32(res); + tcg_temp_free_i32(sr_ove); + } } break; diff --git a/tests/tcg/openrisc/test_addc.c b/tests/tcg/openrisc/test_addc.c index 05d18f8ce5..a8f756a69b 100644 --- a/tests/tcg/openrisc/test_addc.c +++ b/tests/tcg/openrisc/test_addc.c @@ -7,9 +7,10 @@ int main(void) b = 0x01; c = 0xffffffff; - result = 1; + result = 0; __asm - ("l.addc %0, %1, %2\n\t" + ("l.add r1, r1, r0\n\t" /* clear carry */ + "l.addc %0, %1, %2\n\t" : "=r"(a) : "r"(b), "r"(c) ); @@ -22,7 +23,8 @@ int main(void) c = 0xffffffff; result = 0x80000001; __asm - ("l.addc %0, %1, %2\n\t" + ("l.add r1, r1, r0\n\t" /* clear carry */ + "l.addc %0, %1, %2\n\t" "l.movhi %2, 0x7fff\n\t" "l.ori %2, %2, 0xffff\n\t" "l.addc %0, %1, %2\n\t" diff --git a/tests/tcg/openrisc/test_addic.c b/tests/tcg/openrisc/test_addic.c index 4ba7432521..857aaa1330 100644 --- a/tests/tcg/openrisc/test_addic.c +++ b/tests/tcg/openrisc/test_addic.c @@ -6,9 +6,10 @@ int main(void) int result; a = 1; - result = 0x1; + result = 0x0; __asm - ("l.addic %0, %0, 0xffff\n\t" + ("l.add r1, r1, r0\n\t" /* clear carry */ + "l.addic %0, %0, 0xffff\n\t" : "+r"(a) ); if (a != result) { @@ -16,10 +17,11 @@ int main(void) return -1; } - a = 0x1; + a = -1; result = 0x201; __asm - ("l.addic %0, %0, 0xffff\n\t" + ("l.add r1, r1, r0\n\t" /* clear carry */ + "l.addic %0, %0, 0x1\n\t" "l.ori %0, r0, 0x100\n\t" "l.addic %0, %0, 0x100\n\t" : "+r"(a)