Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions sw-sysemu/devices/rvtimer.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ struct RVTimer
agent.chip->clear_machine_timer_interrupt(shire);
}
}
} else if (!had_interrupt && interrupt) {
// raise immediately if mtimecmp is written in the past.
for (unsigned shire = 0; shire < EMU_NUM_SHIRES; ++shire) {
if ((interrupt_shire_mask >> shire) & 1) {
agent.chip->raise_machine_timer_interrupt(shire);
}
}
}
}

Expand Down
53 changes: 53 additions & 0 deletions sw-sysemu/tests/erbium/src/rvtimer_mtimecmp_past.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*-------------------------------------------------------------------------
* Copyright (c) 2026 Ainekko, Co.
* SPDX-License-Identifier: Apache-2.0
*-------------------------------------------------------------------------*/

/*
* Test: MTIMECMP written "in the past" immediately asserts MTIP.
* Expected: PASS (mip.MTIP set immediately after write)
*/

#include "test.h"
#include <stdint.h>

#define ESR_MTIME 0x80F40200ull
#define ESR_MTIMECMP 0x80F40208ull
#define ESR_MTIME_LOCAL_TARGET 0x80F40218ull

#define MIP_MTIP (1UL << 7)

static inline uint64_t read_mip(void)
{
uint64_t val;
asm volatile("csrr %0, mip" : "=r"(val));
return val;
}

int main(void)
{
volatile uint64_t *mtime = (volatile uint64_t *)ESR_MTIME;
volatile uint64_t *mtimecmp = (volatile uint64_t *)ESR_MTIMECMP;
volatile uint64_t *mtime_target = (volatile uint64_t *)ESR_MTIME_LOCAL_TARGET;

/* Enable timer interrupt delivery for minion 0. */
*mtime_target = 0x1;

/* Start from a known state with no pending timer interrupt. */
*mtime = 1000;
*mtimecmp = 1000000;

if (read_mip() & MIP_MTIP) {
TEST_FAIL;
}

/* Write MTIMECMP "in the past": should assert MTIP immediately. */
*mtimecmp = 500;

if (read_mip() & MIP_MTIP) {
TEST_PASS;
}

TEST_FAIL;
return 0;
}