From: Lucjan Bryndza <lbryndza....@icloud.com> The current implementation of timers does not work properly even in basic functionality. A counter configured to report an interrupt every 10ms reports the first interrupts after a few seconds. There are also no properly implemented count up an count down modes. This commit fixes bugs with interrupt reporting and implements the basic modes of the counter's time-base block.
Update timer write function Signed-off-by: Lucjan Bryndza <lbryndza....@icloud.com> --- hw/timer/stm32f2xx_timer.c | 67 +++++++++++++++----------------------- 1 file changed, 27 insertions(+), 40 deletions(-) diff --git a/hw/timer/stm32f2xx_timer.c b/hw/timer/stm32f2xx_timer.c index 800172a3ff..bb10a276da 100644 --- a/hw/timer/stm32f2xx_timer.c +++ b/hw/timer/stm32f2xx_timer.c @@ -265,92 +265,79 @@ static void stm32f2xx_update_arr(STM32F2XXTimerState *s, uint64_t value) ptimer_transaction_commit(s->timer); DB_PRINT("write arr = %x\n", s->tim_arr); } + static void stm32f2xx_timer_write(void *opaque, hwaddr offset, - uint64_t val64, unsigned size) + uint64_t value, unsigned size) { STM32F2XXTimerState *s = opaque; - uint32_t value = val64; - int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - uint32_t timer_val = 0; - - DB_PRINT("Write 0x%x, 0x%"HWADDR_PRIx"\n", value, offset); switch (offset) { case TIM_CR1: - s->tim_cr1 = value; + stm32f2xx_update_cr1(s, value); return; case TIM_CR2: - s->tim_cr2 = value; + qemu_log_mask(LOG_GUEST_ERROR, "stm32_timer: CR2 not supported"); return; case TIM_SMCR: - s->tim_smcr = value; + qemu_log_mask(LOG_GUEST_ERROR, "stm32_timer: SCMR not supported"); return; case TIM_DIER: - s->tim_dier = value; + s->tim_dier = value & 0x5F5F; + DB_PRINT("write dier = %x\n", s->tim_dier); return; case TIM_SR: - /* This is set by hardware and cleared by software */ - s->tim_sr &= value; + stm32f2xx_update_sr(s, value); return; case TIM_EGR: - s->tim_egr = value; - if (s->tim_egr & TIM_EGR_UG) { - timer_val = 0; - break; - } + stm32f2xx_update_egr(s, value); return; case TIM_CCMR1: - s->tim_ccmr1 = value; + s->tim_ccmr1 = value & 0xffff; + DB_PRINT("write ccmr1 = %x\n", s->tim_ccmr1); return; case TIM_CCMR2: - s->tim_ccmr2 = value; + s->tim_ccmr2 = value & 0xffff; + DB_PRINT("write ccmr2 = %x\n", s->tim_ccmr2); return; case TIM_CCER: - s->tim_ccer = value; + s->tim_ccer = value & 0x3333; + DB_PRINT("write ccer = %x\n", s->tim_ccer); return; case TIM_PSC: - timer_val = stm32f2xx_ns_to_ticks(s, now) - s->tick_offset; - s->tim_psc = value & 0xFFFF; - break; + stm32f2xx_update_psc(s, value); + return; case TIM_CNT: - timer_val = value; - break; + stm32f2xx_update_cnt(s, value); + return; case TIM_ARR: - s->tim_arr = value; - stm32f2xx_timer_set_alarm(s, now); + stm32f2xx_update_arr(s, value); return; case TIM_CCR1: - s->tim_ccr1 = value; + s->tim_ccr1 = value & 0xffff; return; case TIM_CCR2: - s->tim_ccr2 = value; + s->tim_ccr2 = value & 0xffff; return; case TIM_CCR3: - s->tim_ccr3 = value; + s->tim_ccr3 = value & 0xffff; return; case TIM_CCR4: - s->tim_ccr4 = value; + s->tim_ccr4 = value & 0xffff; return; case TIM_DCR: - s->tim_dcr = value; + qemu_log_mask(LOG_GUEST_ERROR, "stm32_timer: DCR not supported"); return; case TIM_DMAR: - s->tim_dmar = value; + qemu_log_mask(LOG_GUEST_ERROR, "stm32_timer: DMAR not supported"); return; case TIM_OR: - s->tim_or = value; + qemu_log_mask(LOG_GUEST_ERROR, "stm32_timer: OR not supported"); return; default: qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, offset); return; } - - /* This means that a register write has affected the timer in a way that - * requires a refresh of both tick_offset and the alarm. - */ - s->tick_offset = stm32f2xx_ns_to_ticks(s, now) - timer_val; - stm32f2xx_timer_set_alarm(s, now); } static const MemoryRegionOps stm32f2xx_timer_ops = { -- 2.38.5