feat: add lab-rv32i-c-machine-timer card

This commit is contained in:
user
2026-07-21 19:14:20 +02:00
commit a0e116f24e
23 changed files with 4720 additions and 0 deletions
+65
View File
@@ -0,0 +1,65 @@
# C11 — machine timer na RV32I/Hazard3
Karta pokazuje trzy osobne, wykonywalne przykłady obsługi 64-bitowego timera
z 32-bitowego rdzenia:
1. spójny odczyt `mtime` sekwencją highlowhigh, również przez rollover;
2. jednorazowe przerwanie machine timer z `mtimecmp`, `mie.MTIE`,
`mstatus.MIE`, wektorem 7 i powrotem `mret`;
3. okresowe deadliney `deadline += period`, z zapisem czasu planowanego,
obserwowanego i spóźnienia każdego ticka.
To nie jest model hostowy. Programy są kompilowane jako freestanding
RV32I+Zicsr+Zifencei i wykonywane przez RTL Hazard3/Verilator. Testbench
inkrementuje `mtime` w każdym kroku oraz wystawia poziomowe żądanie timera,
gdy `mtime >= mtimecmp[hart]`.
## Budowanie i dowód wykonania
```sh
make tasks
./tests/test_hazard3.sh
```
Test zewnętrzny wymaga kodu wyjścia 0, braku nieobsłużonej pułapki i braku
timeoutu, a następnie sprawdza raportowane relacje. Przy bieżącym RTL uzyskano:
- Task01: wybrany offset `0x13`, 2 próby, poprawny high po rolloverze;
- Task02: dokładnie 1 ISR, `mcause=0x80000007`, pending 0 przed i po,
wznowienie po `wfi`;
- Task03: 4 ISR, okres `0x640` (1600), deadliney oddalone dokładnie o okres,
obserwowane spóźnienie `0x28` (40) dla każdego ticka.
Wartość 40 nie jest kontraktem architektury — zależy od RTL, magistrali,
prologu wygenerowanego przez kompilator i chwili próbkowania. Kontraktem karty
jest `observed >= scheduled`, poprawna arytmetyka spóźnienia i stały krok
deadline’ów.
## Granice i ważne rozróżnienia
- Zapis do `mtime` w Task01 jest wyłącznie fixtureem dostępnego testbencha;
kod produkcyjny nie powinien zakładać, że licznik czasu jest zapisywalny.
- `mtime` i `mtimecmp` są urządzeniami 64-bitowymi widzianymi przez cztery
rejestry 32-bitowe. Zwykłe C `uint64_t` nie daje atomowej transakcji MMIO.
- Źródłem zdarzenia jest porównanie `mtime >= mtimecmp`. Bity MTIE i MIE tylko
przepuszczają pending do rdzenia; nie tworzą zdarzenia i go nie kasują.
- Machine timer jest poziomowy. Handler przesuwa `mtimecmp`; samo wejście do
ISR ani odczyt `mcause` nie czyści źródła.
- `common/init.S` ustawia `mtvec` w tryb wektorowy. Slot 7 wybiera symbol
`isr_machine_timer`; atrybut GCC `interrupt("machine")` generuje `mret`.
- Model `deadline += period` zachowuje fazę. `now + period` użyte jako jedyna
reguła przenosi każde spóźnienie na kolejne wyzwolenie i powoduje dryf.
- Karta nie obejmuje jeszcze sterownika RP2350, ticka RTOS, współdzielenia
danych z wieloma hartami ani polityki nadrabiania wielu pominiętych okresów.
## Materiały karty
```sh
./scripts/render_card_layouts.sh
./scripts/render_new_pdf.sh
./tests/test_card.sh
```
Każdy z trzech przykładów ma dokładnie widoki A1A8. Widok A3 jest N/D tylko
w Task01; w Task02 i Task03 dowodem dispatchu jest faktyczny wybór slotu
`mtvec` na podstawie przyczyny przerwania.