Skip to content

Commit 43a74a8

Browse files
committed
Use a lookup table for CSRs and reimplement Zicntr
1 parent c747e5c commit 43a74a8

File tree

12 files changed

+570
-433
lines changed

12 files changed

+570
-433
lines changed

.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@
2424
"python.languageServer": "Pylance",
2525
"python.analysis.diagnosticMode": "workspace",
2626
"python.analysis.packageIndexDepths": [{ "name": "jinja2", "depth": 2 }],
27-
"files.eol": "\n"
27+
"files.eol": "\n",
28+
"yaml.customTags": ["tag:yaml.org,2002:python/object/apply:builtins.range sequence"]
2829
}

README.md

Lines changed: 3 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Instructions are cached in the following format, utilizing the full 54 bits of `
1616
| ----------------- | ----- | ----- | ----- | ---- |
1717
| op_id (-64 to 63) | rs2 | rs1 | rd | imm |
1818

19-
The CPU is implemented using a variable-size build-order-independent subframe architecture. There is one controller processor (`src/cpu/controller.mlog.jinja`) and an arbitrary number of worker processors (`src/cpu/worker.mlog.jinja`). Schematics are generated using a custom preprocessor (`python/src/mlogv32/preprocessor`) based on Jinja and pymsch.
19+
The CPU is implemented using a variable-size build-order-independent subframe architecture. There is one [controller processor](src/cpu/controller.mlog.jinja) and an arbitrary number of [worker processors](src/cpu/worker.mlog.jinja). Schematics are generated using a [custom preprocessor](python/src/mlogv32/preprocessor) based on Jinja and pymsch.
2020

2121
## Memory
2222

@@ -112,6 +112,7 @@ Supported address translation schemes: Bare, Sv32
112112
| I | 2.1 |
113113
| M | 2.0 |
114114
| A | 2.1 |
115+
| Zicntr | 2.0 |
115116
| Zicsr | 2.0 |
116117
| Zifencei\* | 2.0 |
117118
| Zihintpause | 2.0 |
@@ -140,46 +141,7 @@ The `mlogsys.icache` M-mode instruction uses register _rs1_ as the number of byt
140141

141142
## CSRs
142143

143-
CSR values are stored either in a RAM processor (CSRS) or in a variable in the CPU, depending on the CSR. Following is a table of CSRs, their storage location, and any relevant notes (eg. supported fields).
144-
145-
| CSR | Location | Notes |
146-
| ----------------- | -------- | --------------------------------------------------------------------------------------- |
147-
| `sstatus` | CPU | Subset of `mstatus`. |
148-
| `sie` | CPU | Subset of `mie`. |
149-
| `stvec` | CSRS | Bits 1:0 read-only zero. |
150-
| `scounteren` | CSRS | |
151-
| `senvcfg` | CSRS | Bits 31:1 read-only zero. |
152-
| `sscratch` | CSRS | |
153-
| `sepc` | CSRS | Bits 1:0 read-only zero. |
154-
| `scause` | CSRS | |
155-
| `stval` | CSRS | |
156-
| `sip` | CPU | Subset of `mip`. |
157-
| `satp` | CPU | |
158-
| `mvendorid` | CSRS | Read-only zero. |
159-
| `marchid` | CSRS | Read-only zero. |
160-
| `mimpid` | CSRS | Read-only zero. |
161-
| `mhartid` | CSRS | Read-only zero. |
162-
| `mstatus` | CPU | |
163-
| `mstatush` | CSRS | Read-only zero. |
164-
| `misa` | CSRS | Read-only. |
165-
| `medeleg` | CSRS | Read-only zero. |
166-
| `medelegh` | CSRS | Read-only zero. |
167-
| `mideleg` | CSRS | Read-only. Supervisor-level interrupts are always delegated to S-mode. |
168-
| `mie` | CPU | |
169-
| `mtvec` | CSRS | Bits 1:0 read-only zero. |
170-
| `mcounteren` | CSRS | |
171-
| `mscratch` | CSRS | |
172-
| `mepc` | CSRS | Bits 1:0 read-only zero. |
173-
| `mcause` | CSRS | Stored in CSRS because the CPU often speculatively sets the corresponding CPU variable. |
174-
| `mtval` | CSRS | Same reasoning as `mcause`. |
175-
| `mip` | CPU | |
176-
| `menvcfg` | CSRS | Bits 31:1 read-only zero. |
177-
| `menvcfgh` | CSRS | Read-only zero. |
178-
| `pmpcfg*` | CSRS | Read-only zero. |
179-
| `pmpaddr*` | CSRS | Read-only zero. |
180-
| `mcycle[h]` | CSRS | Frequency: ticks \* ipt. |
181-
| `minstret[h]` | CPU | |
182-
| `mhpmcounter*[h]` | CSRS | See `hpmcounter*[h]`. |
144+
CSR values are stored either in a RAM processor (CSRS), in a variable in the CPU, or as an implicit read-only zero value, depending on the CSR. See [cpu.yaml](src/cpu/cpu.yaml) for the full list of implemented CSRs. Attempts to access a CSR that is not in this list will raise an illegal instruction exception.
183145

184146
## riscv-arch-test
185147

python/src/mlogv32/preprocessor/app.py

Lines changed: 9 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import re
44
from pathlib import Path
5-
from typing import Annotated, Any, Iterable, Literal, TypedDict, Unpack, cast, overload
5+
from typing import Annotated, Any, Iterable, Literal, Unpack, cast, overload
66

77
import yaml
88
from jinja2 import Environment, FileSystemLoader, StrictUndefined
@@ -31,6 +31,7 @@
3131
iter_labels,
3232
parse_mlog,
3333
)
34+
from .types import ConfigArgs, ConfigsYaml, Labels
3435

3536
app = Typer(
3637
pretty_exceptions_show_locals=False,
@@ -273,6 +274,7 @@ def _render_template(
273274
[LocalVariables],
274275
force=True,
275276
instructions=config.instructions,
277+
csrs=config.csrs,
276278
labels=worker_labels,
277279
VARIABLE_0_TO_PAGE_OFFSET="".join(variable_0_to_page_offset),
278280
)
@@ -344,7 +346,7 @@ def add_with_label(block: Block, **labels: Unpack[Labels]):
344346
for y in lenrange(0, 16):
345347
add_peripheral(simple_block(BEContent.TILE_LOGIC_DISPLAY, x, y))
346348

347-
display_link = ProcessorLink(0, 0, "cell2")
349+
display_link = ProcessorLink(0, 0, "")
348350

349351
add_peripheral(lookups_schem, 0, 16)
350352
lookup_links = [
@@ -354,9 +356,11 @@ def add_with_label(block: Block, **labels: Unpack[Labels]):
354356

355357
add_label(4, 19, right="UART0, UART2", down="LABELS")
356358
add_peripheral(simple_block(Content.WORLD_CELL, 4, 18))
357-
add_label(4, 16, right="UART1, UART3")
359+
add_peripheral(ram_schem, 4, 17)
360+
add_label(4, 16, up="CSR_LABELS", right="UART1, UART3")
358361

359362
labels_link = ProcessorLink(4, 18, "")
363+
csr_labels_link = ProcessorLink(4, 17, "processor20")
360364

361365
uart_links = list[ProcessorLink]()
362366
for x in lenrange(5, 4, 2):
@@ -457,6 +461,7 @@ def add_with_label(block: Block, **labels: Unpack[Labels]):
457461
csrs_link,
458462
incr_link,
459463
config_link,
464+
csr_labels_link,
460465
error_output_link,
461466
power_switch_link,
462467
pause_switch_link,
@@ -490,6 +495,7 @@ def add_with_label(block: Block, **labels: Unpack[Labels]):
490495
csrs_link,
491496
incr_link,
492497
config_link,
498+
csr_labels_link,
493499
controller_link,
494500
error_output_link,
495501
x=x,
@@ -656,13 +662,6 @@ def relative_links(*links: ProcessorLink, x: int, y: int):
656662
return [ProcessorLink(link.x - x, link.y - y, link.name) for link in links]
657663

658664

659-
class Labels(TypedDict, total=False):
660-
up: str
661-
left: str
662-
right: str
663-
down: str
664-
665-
666665
def create_jinja_env(
667666
template_dir: Path,
668667
extensions: Iterable[type[Extension] | str] = (),
@@ -716,23 +715,5 @@ def get_template_output_path(path: Path):
716715
return path.with_suffix("")
717716

718717

719-
class ConfigsYaml(TypedDict):
720-
template: str
721-
defaults: dict[str, Any]
722-
configs: dict[str, dict[str, Any]]
723-
724-
725-
class ConfigArgs(TypedDict):
726-
UART_FIFO_CAPACITY: int
727-
DATA_ROM_ROWS: int
728-
729-
MEMORY_X_OFFSET: int
730-
MEMORY_Y_OFFSET: int
731-
MEMORY_WIDTH: int
732-
PROGRAM_ROM_ROWS: int
733-
RAM_ROWS: int
734-
ICACHE_ROWS: int
735-
736-
737718
if __name__ == "__main__":
738719
app()
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# https://sourceware.org/binutils/docs/ld/Constants.html#Constants
2+
MEMORY_K = 1024
3+
MEMORY_M = 1024 * 1024
4+
5+
CSRS: dict[str, int] = {
6+
# unprivileged
7+
"cycle": 0xC00,
8+
"time": 0xC01,
9+
"instret": 0xC02,
10+
**{f"hpmcounter{i}": 0xC00 + i for i in range(3, 32)},
11+
"cycleh": 0xC80,
12+
"timeh": 0xC81,
13+
"instreth": 0xC82,
14+
**{f"hpmcounter{i}h": 0xC80 + i for i in range(3, 32)},
15+
# supervisor
16+
"sstatus": 0x100,
17+
"sie": 0x104,
18+
"stvec": 0x105,
19+
"scounteren": 0x106,
20+
"senvcfg": 0x10A,
21+
"scountinhibit": 0x120,
22+
"sscratch": 0x140,
23+
"sepc": 0x141,
24+
"scause": 0x142,
25+
"stval": 0x143,
26+
"sip": 0x144,
27+
"scountovf": 0xDA0,
28+
"satp": 0x180,
29+
"scontext": 0x5A8,
30+
"sstateen0": 0x10C,
31+
"sstateen1": 0x10D,
32+
"sstateen2": 0x10E,
33+
"sstateen3": 0x10F,
34+
# machine
35+
"mvendorid": 0xF11,
36+
"marchid": 0xF12,
37+
"mimpid": 0xF13,
38+
"mhartid": 0xF14,
39+
"mconfigptr": 0xF15,
40+
"mstatus": 0x300,
41+
"misa": 0x301,
42+
"medeleg": 0x302,
43+
"mideleg": 0x303,
44+
"mie": 0x304,
45+
"mtvec": 0x305,
46+
"mcounteren": 0x306,
47+
"mstatush": 0x310,
48+
"medelegh": 0x312,
49+
"mscratch": 0x340,
50+
"mepc": 0x341,
51+
"mcause": 0x342,
52+
"mtval": 0x343,
53+
"mip": 0x344,
54+
"mtinst": 0x34A,
55+
"mtval2": 0x34B,
56+
"menvcfg": 0x30A,
57+
"menvcfgh": 0x31A,
58+
"mseccfg": 0x747,
59+
"mseccfgh": 0x757,
60+
**{f"pmpcfg{i}": 0x3A0 + i for i in range(0, 16)},
61+
**{f"pmpaddr{i}": 0x3B0 + i for i in range(0, 64)},
62+
"mstateen0": 0x30C,
63+
"mstateen1": 0x30D,
64+
"mstateen2": 0x30E,
65+
"mstateen3": 0x30F,
66+
"mstateen0h": 0x31C,
67+
"mstateen1h": 0x31D,
68+
"mstateen2h": 0x31E,
69+
"mstateen3h": 0x31F,
70+
"mnscratch": 0x740,
71+
"mnepc": 0x741,
72+
"mncause": 0x742,
73+
"mnstatus": 0x744,
74+
"mcycle": 0xB00,
75+
"minstret": 0xB02,
76+
**{f"mhpmcounter{i}": 0xB00 + i for i in range(3, 32)},
77+
"mcycleh": 0xB80,
78+
"minstreth": 0xB82,
79+
**{f"mhpmcounter{i}h": 0xB80 + i for i in range(3, 32)},
80+
"mcountinhibit": 0x320,
81+
**{f"mhpmevent{i}": 0x320 + i for i in range(3, 32)},
82+
**{f"mhpmevent{i}h": 0x720 + i for i in range(3, 32)},
83+
}

python/src/mlogv32/preprocessor/extensions.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,8 @@ def reset_locals(self, i: int = 1):
192192
self._env.local_variable_index = i
193193
self._env.local_variable_cache.clear()
194194

195-
def declare_locals(self, *names: str | list[str]):
195+
def declare_locals(self, *names: str | list[str], i: int = 1):
196+
self.reset_locals(i)
196197
for name in names:
197198
if isinstance(name, list):
198199
self.declare_locals(*name)

0 commit comments

Comments
 (0)