diff --git a/hw/timer/renesas_cmt.c b/hw/timer/renesas_cmt.c index 93e7f58cc200d..53de3c2aff104 100644 --- a/hw/timer/renesas_cmt.c +++ b/hw/timer/renesas_cmt.c @@ -51,56 +51,44 @@ REG16(CMCR, 0) REG16(CMCNT, 2) REG16(CMCOR, 4) -static void update_events(RCMTState *cmt, int ch) -{ - int64_t next_time; +static uint16_t read_cmcnt(RCMTState *cmt, int ch) { + if (!(cmt->cmstr & (1 << ch))) { + return cmt->cmcnt[ch]; + } + int64_t elapsed_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - cmt->tick[ch]; + uint64_t ticks = (elapsed_ns * cmt->cmt_freq[ch]) / (NANOSECONDS_PER_SECOND); + uint32_t limit = cmt->cmcor[ch] + 1; + return (cmt->cmcnt[ch] + ticks) % limit; +} - if ((cmt->cmstr & (1 << ch)) == 0) { - /* count disable, so not happened next event. */ +static void update_events(RCMTState *cmt, int ch) { + if (!(cmt->cmstr & (1 << ch))) { return; } - next_time = cmt->cmcor[ch] - cmt->cmcnt[ch]; - next_time *= NANOSECONDS_PER_SECOND; - next_time /= cmt->input_freq; - /* - * CKS -> div rate - * 0 -> 8 (1 << 3) - * 1 -> 32 (1 << 5) - * 2 -> 128 (1 << 7) - * 3 -> 512 (1 << 9) - */ - next_time *= 1 << (3 + FIELD_EX16(cmt->cmcr[ch], CMCR, CKS) * 2); - next_time += qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - timer_mod(&cmt->timer[ch], next_time); -} + uint16_t current = read_cmcnt(cmt, ch); + uint32_t remain = (cmt->cmcor[ch] + 1) - current; + if (remain == 0) { + remain = cmt->cmcor[ch] + 1; + } + int64_t next_time = (int64_t)remain * NANOSECONDS_PER_SECOND / cmt->cmt_freq[ch]; -static int64_t read_cmcnt(RCMTState *cmt, int ch) -{ - int64_t delta, now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + int64_t fire_time = now + next_time; - if (cmt->cmstr & (1 << ch)) { - delta = (now - cmt->tick[ch]); - delta /= NANOSECONDS_PER_SECOND; - delta /= cmt->input_freq; - delta /= 1 << (3 + FIELD_EX16(cmt->cmcr[ch], CMCR, CKS) * 2); - cmt->tick[ch] = now; - return cmt->cmcnt[ch] + delta; - } else { - return cmt->cmcnt[ch]; + if (fire_time <= now) { + fire_time = now + 1; } + + timer_mod(&cmt->timer[ch], fire_time); } static uint64_t cmt_read(void *opaque, hwaddr offset, unsigned size) { RCMTState *cmt = opaque; int ch = offset / 0x08; - uint64_t ret; if (offset == A_CMSTR) { - ret = 0; - ret = FIELD_DP16(ret, CMSTR, STR, - FIELD_EX16(cmt->cmstr, CMSTR, STR)); - return ret; + return FIELD_EX16(cmt->cmstr, CMSTR, STR); } else { offset &= 0x07; if (ch == 0) { @@ -108,12 +96,7 @@ static uint64_t cmt_read(void *opaque, hwaddr offset, unsigned size) } switch (offset) { case A_CMCR: - ret = 0; - ret = FIELD_DP16(ret, CMCR, CKS, - FIELD_EX16(cmt->cmstr, CMCR, CKS)); - ret = FIELD_DP16(ret, CMCR, CMIE, - FIELD_EX16(cmt->cmstr, CMCR, CMIE)); - return ret; + return cmt->cmcr[ch]; case A_CMCNT: return read_cmcnt(cmt, ch); case A_CMCOR: @@ -123,12 +106,13 @@ static uint64_t cmt_read(void *opaque, hwaddr offset, unsigned size) qemu_log_mask(LOG_UNIMP, "renesas_cmt: Register 0x%" HWADDR_PRIX " " "not implemented\n", offset); - return UINT64_MAX; + return UINT16_MAX; } -static void start_stop(RCMTState *cmt, int ch, int st) -{ - if (st) { +static void start_stop(RCMTState *cmt, int ch, int enable) { + if (enable) { + cmt->cmcnt[ch] = 0; + cmt->tick[ch] = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); update_events(cmt, ch); } else { timer_del(&cmt->timer[ch]); @@ -155,9 +139,13 @@ static void cmt_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) FIELD_EX16(val, CMCR, CKS)); cmt->cmcr[ch] = FIELD_DP16(cmt->cmcr[ch], CMCR, CMIE, FIELD_EX16(val, CMCR, CMIE)); + cmt->cmt_freq[ch] = + cmt->input_freq / (8u << (2 * FIELD_EX16(cmt->cmcr[ch], CMCR, CKS))); + update_events(cmt, ch); break; case 2: cmt->cmcnt[ch] = val; + cmt->tick[ch] = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); break; case 4: cmt->cmcor[ch] = val; @@ -216,26 +204,29 @@ static void rcmt_reset(DeviceState *dev) { RCMTState *cmt = RCMT(dev); cmt->cmstr = 0; - cmt->cmcr[0] = cmt->cmcr[1] = 0; - cmt->cmcnt[0] = cmt->cmcnt[1] = 0; - cmt->cmcor[0] = cmt->cmcor[1] = 0xffff; + for (int i = 0; i < CMT_CH; i++) { + cmt->cmcr[i] = 0; + cmt->cmcnt[i] = 0; + cmt->cmcor[i] = 0xFFFF; + cmt->tick[i] = 0; + } } static void rcmt_init(Object *obj) { SysBusDevice *d = SYS_BUS_DEVICE(obj); RCMTState *cmt = RCMT(obj); - int i; memory_region_init_io(&cmt->memory, OBJECT(cmt), &cmt_ops, cmt, "renesas-cmt", 0x10); sysbus_init_mmio(d, &cmt->memory); - for (i = 0; i < ARRAY_SIZE(cmt->cmi); i++) { + for (int i = 0; i < CMT_CH; i++) { sysbus_init_irq(d, &cmt->cmi[i]); + cmt->cmt_freq[i] = cmt->input_freq >> 3; + timer_init_ns(&cmt->timer[i], QEMU_CLOCK_VIRTUAL, + (i == 0 ? timer_event0 : timer_event1), cmt); } - timer_init_ns(&cmt->timer[0], QEMU_CLOCK_VIRTUAL, timer_event0, cmt); - timer_init_ns(&cmt->timer[1], QEMU_CLOCK_VIRTUAL, timer_event1, cmt); } static const VMStateDescription vmstate_rcmt = { diff --git a/include/hw/timer/renesas_cmt.h b/include/hw/timer/renesas_cmt.h index 1c0b65c1d5a70..3d7a3c624f5b4 100644 --- a/include/hw/timer/renesas_cmt.h +++ b/include/hw/timer/renesas_cmt.h @@ -29,6 +29,7 @@ struct RCMTState { /*< public >*/ uint64_t input_freq; + uint64_t cmt_freq[CMT_CH]; MemoryRegion memory; uint16_t cmstr; diff --git a/target/rx/cpu.c b/target/rx/cpu.c index 0ba0d55ab5bdb..5a412746db5c2 100644 --- a/target/rx/cpu.c +++ b/target/rx/cpu.c @@ -27,6 +27,7 @@ #include "hw/loader.h" #include "fpu/softfloat.h" #include "tcg/debug-assert.h" +#include "system/reset.h" static void rx_cpu_set_pc(CPUState *cs, vaddr value) { @@ -129,6 +130,13 @@ static ObjectClass *rx_cpu_class_by_name(const char *cpu_model) return oc; } +static void rx_cpu_reset(void *opaque) +{ + RXCPU *cpu = opaque; + + cpu_reset(CPU(cpu)); +} + static void rx_cpu_realize(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); @@ -142,7 +150,7 @@ static void rx_cpu_realize(DeviceState *dev, Error **errp) } qemu_init_vcpu(cs); - cpu_reset(cs); + qemu_register_reset(rx_cpu_reset, RX_CPU(cs)); rcc->parent_realize(dev, errp); } diff --git a/target/rx/helper.c b/target/rx/helper.c index e8aabf40ffb41..60958ad032cec 100644 --- a/target/rx/helper.c +++ b/target/rx/helper.c @@ -48,7 +48,6 @@ void rx_cpu_do_interrupt(CPUState *cs) uint32_t save_psw; env->in_sleep = 0; - if (env->psw_u) { env->usp = env->regs[0]; } else { @@ -56,8 +55,9 @@ void rx_cpu_do_interrupt(CPUState *cs) } save_psw = rx_cpu_pack_psw(env); env->psw_pm = env->psw_i = env->psw_u = 0; + int32_t vec = cs->exception_index; - if (do_irq) { + if (do_irq && vec < 0) { if (do_irq & CPU_INTERRUPT_FIR) { env->bpc = env->pc; env->bpsw = save_psw; @@ -79,7 +79,6 @@ void rx_cpu_do_interrupt(CPUState *cs) "interrupt 0x%02x raised\n", env->ack_irq); } } else { - uint32_t vec = cs->exception_index; const char *expname = "unknown exception"; env->isp -= 4;