From: Lucjan Bryndza <lbryndza.oss@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.oss@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