Skip to content

Commit 3e63b4d

Browse files
committed
Tentatively implement Sv32 address translation (untested)
1 parent e509cdf commit 3e63b4d

File tree

16 files changed

+615
-213
lines changed

16 files changed

+615
-213
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ rust: $(RUST_PROGRAMS)
1515

1616
.PHONY: mlog
1717
mlog: $(MLOG_PROGRAMS) mlog-configs
18+
poe build -s 16
1819

1920
.PHONY: coremark
2021
coremark:

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,9 @@ This non-standard extension adds instructions to control the mlogv32 processor's
124124

125125
The MLOG instructions are encoded with an I-type instruction format using the _custom-0_ opcode. The zero-extended immediate is used as a minor opcode (funct12) for implementation reasons.
126126

127-
The MLOGSYS instruction is used for simple system controls, currently only including icache initialization.
127+
The MLOGSYS instruction is used for simple system controls.
128128

129-
The `mlogsys.icache` instruction uses register _rs1_ as the number of bytes to decode. This can be generated by using a linker script to find the end address of the `.text` section and load it using `li`. The actual number of bytes decoded will be the smallest of _rs1_, the size of the icache, and the size of ROM.
129+
The `mlogsys.icache` M-mode instruction uses register _rs1_ as the number of bytes to decode. This can be generated by using a linker script to find the end address of the `.text` section and load it using `li`. The actual number of bytes decoded will be the smallest of _rs1_, the size of the icache, and the size of ROM.
130130

131131
| funct12 | rs1 | name |
132132
| ------- | ------ | --------------------- |

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ exclude = [
8686
"**/__pycache__",
8787
]
8888

89-
typeCheckingMode = "basic"
89+
typeCheckingMode = "standard"
9090

9191
strictDictionaryInference = true
9292
strictListInference = true

python/src/mlogv32/preprocessor/app.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,13 @@
2121
)
2222
from .filters import FILTERS
2323
from .models import BuildConfig
24-
from .parser import check_unsaved_variables, iter_labels, parse_mlog
24+
from .parser import (
25+
AssertCounterError,
26+
Statement,
27+
check_unsaved_variables,
28+
iter_labels,
29+
parse_mlog,
30+
)
2531

2632
app = Typer(
2733
pretty_exceptions_show_locals=False,
@@ -135,8 +141,20 @@ def build(
135141
print(f"Local variable count: {i}")
136142

137143
worker_ast = parse_mlog(worker_code)
144+
138145
check_unsaved_variables(worker_ast)
139-
worker_labels = dict(iter_labels(worker_ast))
146+
print(
147+
f"""\
148+
Code size:
149+
Instructions: {len(list(n for n in worker_ast if isinstance(n, Statement)))} / 1000
150+
Bytes: {len(worker_code.encode())} / {1024 * 100}"""
151+
)
152+
153+
try:
154+
worker_labels = dict(iter_labels(worker_ast))
155+
except AssertCounterError as e:
156+
e.add_note(f"{worker_output}:{e.token.line}")
157+
raise
140158

141159
controller_output = get_template_output_path(config.templates.controller)
142160
controller_code = render_template(

python/src/mlogv32/preprocessor/filters.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from typing import Any, Callable
33

44
from jinja2.runtime import Context
5+
from jinja2.utils import Namespace
56

67
from mlogv32.scripts.ram_proc import VariableFormat
78

@@ -69,6 +70,14 @@ def memory_size(size: int):
6970
return hex(size)
7071

7172

73+
@make_jinja_exceptions_suck_a_bit_less
74+
@register_filter
75+
def namespace_dict(namespace: Namespace):
76+
# cursed
77+
attrs: dict[str, Any] = namespace._Namespace__attrs
78+
return attrs
79+
80+
7281
CSRS: dict[str, int] = {
7382
# unprivileged
7483
"cycle": 0xC00,

python/src/mlogv32/preprocessor/models.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from typing import Annotated
77

88
import yaml
9-
from pydantic import AfterValidator, BaseModel
9+
from pydantic import AfterValidator, BaseModel, Field, field_validator
1010

1111
_relative_path_root_var = ContextVar[Path]("_relative_path_root_var")
1212

@@ -41,6 +41,31 @@ class Schematics(BaseModel):
4141

4242
class Instruction(BaseModel):
4343
label: str
44+
count: int = Field(default=1, ge=1)
45+
up_to: int | None = None
46+
47+
@field_validator("instructions", mode="after")
48+
@classmethod
49+
def _resolve_instructions(cls, instructions: list[Instruction]):
50+
result = list[BuildConfig.Instruction]()
51+
address = 0
52+
53+
for i, value in enumerate(instructions):
54+
if value.up_to is not None:
55+
value = value.model_copy()
56+
assert value.up_to is not None
57+
58+
if value.up_to < address:
59+
raise ValueError(
60+
f"Instruction {i} is at address {address}, but up_to is {value.up_to}: {value}"
61+
)
62+
63+
value.count = value.up_to - address + 1
64+
65+
result.append(value)
66+
address += value.count
67+
68+
return result
4469

4570
@classmethod
4671
def load(cls, path: str | Path):
Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
11
__all__ = [
2+
"AssertCounterError",
3+
"Directive",
24
"Label",
35
"Statement",
46
"check_unsaved_variables",
57
"iter_labels",
68
"parse_mlog",
79
]
810

9-
from .mlog import Label, Statement, check_unsaved_variables, iter_labels, parse_mlog
11+
from .mlog import (
12+
AssertCounterError,
13+
Directive,
14+
Label,
15+
Statement,
16+
check_unsaved_variables,
17+
iter_labels,
18+
parse_mlog,
19+
)

python/src/mlogv32/preprocessor/parser/mlog.lark

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ start: (line? _NEWLINE)*
66

77
statement: TOKEN (TOKEN | LABEL | STRING)*
88

9-
directive: _DIRECTIVE TOKEN+
9+
directive: _DIRECTIVE /assert_counter|(begin|end)_fetch|(push|pop)_saved/ TOKEN*
1010

1111
STRING.2: /"[^\n]*"/
1212

python/src/mlogv32/preprocessor/parser/mlog.py

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,19 @@ def v_args[T](
1717

1818
@dataclass
1919
class Label:
20-
name: str
20+
name: Token
2121

2222

2323
@dataclass
2424
class Statement:
25-
name: str
26-
args: list[str]
25+
name: Token
26+
args: list[Token]
2727

2828

2929
@dataclass
3030
class Directive:
31-
name: str
32-
args: list[str]
31+
name: Token
32+
args: list[Token]
3333

3434

3535
type ASTNode = Label | Statement | Directive
@@ -41,18 +41,15 @@ class MlogTransformer(Transformer[Token, list[ASTNode]]):
4141
def start(self, *children: ASTNode):
4242
return list(children)
4343

44-
def label(self, name: str):
45-
return Label(name[:-1])
44+
def label(self, name: Token):
45+
return Label(name.update(value=name[:-1]))
4646

47-
def statement(self, name: str, *args: str):
47+
def statement(self, name: Token, *args: Token):
4848
return Statement(name, list(args))
4949

50-
def directive(self, name: str, *args: str):
50+
def directive(self, name: Token, *args: Token):
5151
return Directive(name, list(args))
5252

53-
def TOKEN(self, token: Token):
54-
return str(token)
55-
5653

5754
GRAMMAR = (resources.files() / "mlog.lark").read_text("utf-8")
5855

@@ -68,18 +65,25 @@ def parse_mlog(text: str):
6865
return MlogTransformer().transform(tree)
6966

7067

68+
class AssertCounterError(AssertionError):
69+
def __init__(self, message: str, token: Token, *args: object) -> None:
70+
super().__init__(message, *args)
71+
self.token = token
72+
73+
7174
def iter_labels(ast: Iterable[ASTNode]) -> Iterator[tuple[str, int]]:
72-
line_num = 0
75+
counter = 0
7376
for node in ast:
7477
match node:
7578
case Label(name=name):
76-
yield (name, line_num)
79+
yield (name, counter)
7780
case Statement():
78-
line_num += 1
79-
case Directive(name="assert_line", args=[n]):
80-
assert line_num == int(n), (
81-
f"Expected next line to be {n}, but got {line_num}"
82-
)
81+
counter += 1
82+
case Directive(name="assert_counter", args=[n]):
83+
if counter != int(n):
84+
raise AssertCounterError(
85+
f"Expected @counter to be {n}, but got {counter}", node.name
86+
)
8387
case Directive():
8488
pass
8589

riscof/mlogv32/env/reloc.ld

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ OUTPUT_ARCH( "riscv" )
22
ENTRY(rvtest_entry_point)
33

44
MEMORY {
5-
ROM (rx) : ORIGIN = 0x00000000, LENGTH = 0x480000
6-
RAM (rwx) : ORIGIN = 0x80000000, LENGTH = 0x480000
5+
ROM (rx) : ORIGIN = 0x00000000, LENGTH = 18M
6+
RAM (rwx) : ORIGIN = 0x80000000, LENGTH = 18M
77
}
88

99
SECTIONS

0 commit comments

Comments
 (0)