diff options
| author | Frédéric Desbiens <[email protected]> | 2026-10-02 10:42:44 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-10-02 10:42:44 -0400 |
| commit | 93387b0a60382a29579bbad5045c68328e3751df (patch) | |
| tree | 42be790d602cb76f55090e5a7c418df7ea2b3428 /ports/risc-v32/gnu/example_build/qemu_virt/hwtimer.c | |
| parent | 44d7c95c582d415c4ad84527180b29c93c3bf664 (diff) | |
| parent | 28281cd5647d4671236ca08d19bd18ed15b2265a (diff) | |
Merge pull request #783 from eclipse-threadx/devv6.5.2.202603_rel
Merged changes ahead of the v6.5.2.202603 release
Diffstat (limited to 'ports/risc-v32/gnu/example_build/qemu_virt/hwtimer.c')
| -rw-r--r-- | ports/risc-v32/gnu/example_build/qemu_virt/hwtimer.c | 69 |
1 files changed, 59 insertions, 10 deletions
diff --git a/ports/risc-v32/gnu/example_build/qemu_virt/hwtimer.c b/ports/risc-v32/gnu/example_build/qemu_virt/hwtimer.c index 33c49b63..8d2f4e15 100644 --- a/ports/risc-v32/gnu/example_build/qemu_virt/hwtimer.c +++ b/ports/risc-v32/gnu/example_build/qemu_virt/hwtimer.c @@ -8,7 +8,7 @@ * SPDX-License-Identifier: MIT **************************************************************************/ -#include "tx_port.h" +#include "tx_api.h" #include "csr.h" #include "hwtimer.h" @@ -16,20 +16,69 @@ #define CLINT_TIME (CLINT+0xBFF8) #define CLINT_TIMECMP(hart_id) (CLINT+0x4000+8*(hart_id)) +/* RV32 has no 64-bit load/store, so the 64-bit CLINT registers are + accessed as two volatile 32-bit MMIO words. */ +#define MTIME_LO (*(volatile uint32_t *)(CLINT_TIME)) +#define MTIME_HI (*(volatile uint32_t *)(CLINT_TIME + 4)) +#define MTIMECMP_LO(hart) (*(volatile uint32_t *)(CLINT_TIMECMP(hart))) +#define MTIMECMP_HI(hart) (*(volatile uint32_t *)(CLINT_TIMECMP(hart) + 4)) + +/* RV32 mtime re-read the high word until it is stable, so a + low-word rollover between the two loads cannot tear the value. */ +static uint64_t clint_time_read(void) +{ + uint32_t hi; + uint32_t lo; + + do + { + hi = MTIME_HI; + lo = MTIME_LO; + } while (hi != MTIME_HI); + + return ((uint64_t)hi << 32) | lo; +} + +/* Only this hart writes its own mtimecmp, so a plain two-word read + cannot tear. */ +static uint64_t clint_timecmp_read(int hart) +{ + uint32_t lo = MTIMECMP_LO(hart); + uint32_t hi = MTIMECMP_HI(hart); + + return ((uint64_t)hi << 32) | lo; +} + +/* RV32 mtimecmp write, safe sequence: park the low word at all-ones + first, so no intermediate 64-bit value compares below mtime and + raises a spurious timer interrupt. */ +static void clint_timecmp_write(int hart, uint64_t value) +{ + MTIMECMP_LO(hart) = 0xFFFFFFFF; + MTIMECMP_HI(hart) = (uint32_t)(value >> 32); + MTIMECMP_LO(hart) = (uint32_t)value; +} int hwtimer_init(void) { - int hart = riscv_get_core(); - uint64_t time = *((uint64_t*)CLINT_TIME); - *((uint64_t*)CLINT_TIMECMP(hart)) = time + TICKNUM_PER_TIMER; - return 0; + int hart = riscv_get_core(); + + clint_timecmp_write(hart, clint_time_read() + TICKNUM_PER_TIMER); + return 0; } int hwtimer_handler(void) { - int hart = riscv_get_core(); - uint64_t time = *((uint64_t*)CLINT_TIME); - *((uint64_t*)CLINT_TIMECMP(hart)) = time + TICKNUM_PER_TIMER; - return 0; -} + int hart = riscv_get_core(); + + /* Advance from the previous compare value, so trap + latency does not accumulate as tick drift */ + uint64_t next = clint_timecmp_read(hart) + TICKNUM_PER_TIMER; + uint64_t now = clint_time_read(); + if (next <= now) + next = now + TICKNUM_PER_TIMER; + + clint_timecmp_write(hart, next); + return 0; +} |
