1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
"""RISC-V local (PRISCV) register block.
Evidence kind: **hardware register/field header + observed access pattern.**
Reached through the PRIV aperture at ``PRIV + 0x111000`` and through the libos
kernel's private mapping at ``0x3_0000_1000`` (the firmware reads the trace
and error-status registers there during boot). Modelled registers:
================================ ====== ===== ==============================
register offset access semantics
================================ ====== ===== ==============================
``RISCV_IRQMSET`` 0x2ac W ``irq_mask |= value``
``RISCV_IRQMCLR`` 0x2b0 W ``irq_mask &= ~value``
``RISCV_IRQMASK`` 0x2b4 R ``irq_mask``
``RISCV_IRQDEST`` 0x2b8 RW storage
``RISCV_IRQTYPE`` 0x2bc RW storage
``RISCV_TRACECTL`` 0x344 RW storage
``RISCV_TRACE_RDIDX`` 0x348 RW storage
``RISCV_TRACE_WTIDX`` 0x34c RW storage
``RISCV_PRIV_ERR_STAT`` 0x360 RW storage
``RISCV_HUB_ERR_STAT`` 0x36c RW storage
================================ ====== ===== ==============================
The IRQ mask semantics (set/clear/read) follow the header access types and the
observed boot reads; core interrupt *delivery* (mtvec/mip) is not part of this
device and remains unmodelled (documented unknown).
"""
from __future__ import annotations
from .base import Device
IRQMSET = 0x2AC
IRQMCLR = 0x2B0
IRQMASK = 0x2B4
IRQDEST = 0x2B8
IRQTYPE = 0x2BC
TRACECTL = 0x344
TRACE_RDIDX = 0x348
TRACE_WTIDX = 0x34C
PRIV_ERR_STAT = 0x360
PRIV_ERR_INFO = 0x364
PRIV_ERR_ADDR = 0x368
HUB_ERR_STAT = 0x36C
_RW = {IRQDEST, IRQTYPE, TRACECTL, TRACE_RDIDX, TRACE_WTIDX,
PRIV_ERR_STAT, HUB_ERR_STAT}
#: Read-only error capture registers (header R-I4R); the boot panic path
#: reads them after a trap (observed reads at PC 0x40106BC).
_RO = {PRIV_ERR_INFO, PRIV_ERR_ADDR}
class PriscvBlock(Device):
"""RISC-V-local control/trace/error registers."""
name = "priscv"
def __init__(self, *, base: int = 0, size: int = 0x1000):
super().__init__(base=base, size=size)
self.reset()
def reset(self) -> None:
self.irq_mask = 0
self.regs: dict[int, int] = {off: 0 for off in _RW}
self.error: dict[int, int] = {off: 0 for off in _RO}
def read(self, offset: int, size: int) -> int | None:
if size != 4:
return None
if offset == IRQMASK:
return self.irq_mask
if offset in self.regs:
return self.regs[offset]
if offset in self.error:
return self.error[offset]
return None
def write(self, offset: int, size: int, value: int) -> bool:
if size != 4:
return False
value &= 0xFFFFFFFF
if offset == IRQMSET:
self.irq_mask = (self.irq_mask | value) & 0xFFFFFFFF
return True
if offset == IRQMCLR:
self.irq_mask = (self.irq_mask & ~value) & 0xFFFFFFFF
return True
if offset == IRQMASK:
return False # read-only
if offset in self.regs:
self.regs[offset] = value
return True
return False
def peek(self, offset: int, size: int) -> int | None:
if size != 4:
return None
if offset == IRQMASK:
return self.irq_mask
if offset in self.error:
return self.error[offset]
return self.regs.get(offset)
def state(self) -> dict:
return {"irq_mask": self.irq_mask,
"regs": {str(k): v for k, v in sorted(self.regs.items())},
"error": {str(k): v for k, v in sorted(self.error.items())}}
def load_state(self, data: dict) -> None:
self.irq_mask = int(data.get("irq_mask", 0))
regs = {int(k): int(v) for k, v in data.get("regs", {}).items()}
self.regs = {off: regs.get(off, 0) for off in _RW}
err = {int(k): int(v) for k, v in data.get("error", {}).items()}
self.error = {off: err.get(off, 0) for off in _RO}
|