hw/timer: fix several bug related to timings, both in cycle count and TimerGroup for the ESP32-C3

This commit is contained in:
Omar Chebib
2025-03-18 15:29:43 +08:00
parent 16a219aac8
commit fd97b40f5a
3 changed files with 30 additions and 10 deletions
+17 -5
View File
@@ -83,7 +83,7 @@ static void esp32c3_virtual_counter_reset(ESP32C3VirtualCounter* counter)
timer_del(&counter->timer);
counter->base = 0;
counter->value = 0;
counter->frequency = 160000000; // Hz
counter->frequency = ESP32C3_APB_CLK;
}
@@ -320,8 +320,8 @@ static void esp32c3_t0_cb(void* opaque)
{
ESP32C3T0State* t = (ESP32C3T0State*) opaque;
/* Update the value of the counter and disable the alarm timer */
esp32c3_virtual_counter_reset(&t->counter);
/* Disable the alarm timer */
timer_del(&t->counter.timer);
esp32c3_virtual_counter_reenabled(&t->counter);
/* In practice, the counter is bigger than the requested value, this is due to the fact
@@ -336,7 +336,7 @@ static void esp32c3_t0_cb(void* opaque)
/* Alarm was triggered, clear alarm bit, set the IRQ if interrupts enabled */
t->config &= ~R_TIMG_T0CONFIG_ALARM_EN_MASK;
t->raw_st = true;
t->raw_st = 1;
if (t->int_enabled) {
qemu_irq_raise(t->interrupt_irq);
}
@@ -628,10 +628,22 @@ static void esp32c3_timg_write(void *opaque, hwaddr addr,
break;
/* Interrupt related registers */
case A_TIMG_INT_ENA_TIMG:
case A_TIMG_INT_ENA_TIMG: {
bool former = s->wdt.int_enabled;
s->wdt.int_enabled = FIELD_EX32(value, TIMG_INT_ENA_TIMG, WDT_ENA) ? true : false;
if (s->wdt.int_enabled != former) {
qemu_set_irq(s->wdt.interrupt_irq,
s->wdt.raw_st && s->wdt.int_enabled ? 1 : 0);
}
former = s->t0.int_enabled;
s->t0.int_enabled = FIELD_EX32(value, TIMG_INT_ENA_TIMG, T0_ENA) ? true : false;
if (s->t0.int_enabled != former) {
qemu_set_irq(s->t0.interrupt_irq,
s->t0.raw_st && s->t0.int_enabled ? 1 : 0);
}
break;
}
case A_TIMG_INT_CLR_TIMG:
if (FIELD_EX32(value, TIMG_INT_CLR_TIMG, WDT_CLR)) {
s->wdt.raw_st = 0;
+11 -4
View File
@@ -59,9 +59,16 @@ static uint64_t esp_cpu_get_cycles(ESPCPUCycleCounter* cc)
/* If we are not in the first call, calculate the difference */
if (cc->former_time != 0) {
/* Let's say that we have 1 instruction/clock cycle, so 1 instruction/6.25ns */
/* The divider is in picoseconds, for a more precise result. It would be possible to simpyl return
* cc->cycles = (now * 1000 / cc->divider). However, doing so would prevent a future implementation
* of CPU frequency change as the cycles count would go backward as soon as the frequency is higher
*/
assert(cc->divider != 0);
diff = (now - cc->former_time) / cc->divider;
const uint64_t num = (now - cc->former_time) * 1000 + cc->former_rem_cycles;
diff = num / cc->divider;
/* Store the remaining executed clock cycles that were not taken into account in the division,
* they will be added back in the next run */
cc->former_rem_cycles = num % cc->divider;
}
cc->former_time = now;
cc->cycles += diff;
@@ -307,10 +314,10 @@ static void esp_cpu_init(Object *obj)
riscv_set_csr_ops(ESP_CPU_CSR_MCYCLE_U, &esp_cpu_csr_ops);
s->cc_machine = (ESPCPUCycleCounter) {
.divider = 6, /* 6.25ns per instruction at 160MHz. */
.divider = 6250, /* 6.25ns per instruction at 160MHz. */
};
s->cc_user = (ESPCPUCycleCounter) {
.divider = 6, /* Should be using the target configured CPU clock frequency instead. */
.divider = 6250, /* Should be using the target configured CPU clock frequency instead. */
};
}
+2 -1
View File
@@ -35,8 +35,9 @@
/* Define a type that will be used to generate a cycle counter */
typedef struct {
uint64_t former_time;
uint64_t former_rem_cycles;
uint64_t cycles;
/* The number of nanosecond an instruction takes to execute */
/* The number of picoseconds an instruction takes to execute */
uint64_t divider;
} ESPCPUCycleCounter;