hw/timer: fix several bug related to timings, both in cycle count and TimerGroup for the ESP32-C3
This commit is contained in:
+17
-5
@@ -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
@@ -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. */
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user