python-library-ralf-model 0.1.1__tar.gz → 0.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_library_ralf_model-0.1.1 → python_library_ralf_model-0.1.2}/PKG-INFO +3 -1
- {python_library_ralf_model-0.1.1 → python_library_ralf_model-0.1.2}/README.md +2 -0
- {python_library_ralf_model-0.1.1 → python_library_ralf_model-0.1.2}/pyproject.toml +1 -1
- {python_library_ralf_model-0.1.1 → python_library_ralf_model-0.1.2}/ralf_model/emit.py +4 -0
- {python_library_ralf_model-0.1.1 → python_library_ralf_model-0.1.2}/ralf_model/nodes.py +8 -0
- {python_library_ralf_model-0.1.1 → python_library_ralf_model-0.1.2}/ralf_model/parse.py +13 -1
- {python_library_ralf_model-0.1.1 → python_library_ralf_model-0.1.2}/tests/test_ralf_model.py +63 -0
- {python_library_ralf_model-0.1.1 → python_library_ralf_model-0.1.2}/.gitignore +0 -0
- {python_library_ralf_model-0.1.1 → python_library_ralf_model-0.1.2}/example/__main__.py +0 -0
- {python_library_ralf_model-0.1.1 → python_library_ralf_model-0.1.2}/example.bat +0 -0
- {python_library_ralf_model-0.1.1 → python_library_ralf_model-0.1.2}/ralf_model/__init__.py +0 -0
- {python_library_ralf_model-0.1.1 → python_library_ralf_model-0.1.2}/ralf_model/abc.py +0 -0
- {python_library_ralf_model-0.1.1 → python_library_ralf_model-0.1.2}/ralf_model/errors.py +0 -0
- {python_library_ralf_model-0.1.1 → python_library_ralf_model-0.1.2}/ralf_model/io.py +0 -0
- {python_library_ralf_model-0.1.1 → python_library_ralf_model-0.1.2}/ralf_model/source_expand.py +0 -0
- {python_library_ralf_model-0.1.1 → python_library_ralf_model-0.1.2}/test.bat +0 -0
- {python_library_ralf_model-0.1.1 → python_library_ralf_model-0.1.2}/tests/__init__.py +0 -0
- {python_library_ralf_model-0.1.1 → python_library_ralf_model-0.1.2}/tests/test_source_include.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-library-ralf-model
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Requires-Python: >=3.10
|
|
5
5
|
Requires-Dist: pydantic<3,>=2.0
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -41,6 +41,8 @@ doc = load_ralf_file(
|
|
|
41
41
|
## 能力范围
|
|
42
42
|
|
|
43
43
|
- **block**:定义 ``block 名 { ... }``;简单映射 ``block 名 @地址;``;赋值与可选路径、地址 ``block 左名 = 右名``、``block 左名 = 右名 (hdl路径)``、``... @地址``,可与 ``{ ... }`` 组合。
|
|
44
|
+
- **register**:``register 名 [ (hdl路径) ] [ @字节偏移 ] { ... }`` 或 ``register 名;`` 前向引用。
|
|
45
|
+
- **field**:``field 名 [(hdl路径)] [ @位偏移 ] { ... }``(括号路径可紧贴字段名,如 ``field f(hdl.f)``)。
|
|
44
46
|
- `field` 花括号内按**源顺序**保留各条语句(含 `enum { ... };` 等),便于往返。
|
|
45
47
|
- `@` 后的偏移在写出时统一为 Verilog 风格十六进制字面量(如 `'h5`);`bytes` 等为十进制。
|
|
46
48
|
|
|
@@ -34,6 +34,8 @@ doc = load_ralf_file(
|
|
|
34
34
|
## 能力范围
|
|
35
35
|
|
|
36
36
|
- **block**:定义 ``block 名 { ... }``;简单映射 ``block 名 @地址;``;赋值与可选路径、地址 ``block 左名 = 右名``、``block 左名 = 右名 (hdl路径)``、``... @地址``,可与 ``{ ... }`` 组合。
|
|
37
|
+
- **register**:``register 名 [ (hdl路径) ] [ @字节偏移 ] { ... }`` 或 ``register 名;`` 前向引用。
|
|
38
|
+
- **field**:``field 名 [(hdl路径)] [ @位偏移 ] { ... }``(括号路径可紧贴字段名,如 ``field f(hdl.f)``)。
|
|
37
39
|
- `field` 花括号内按**源顺序**保留各条语句(含 `enum { ... };` 等),便于往返。
|
|
38
40
|
- `@` 后的偏移在写出时统一为 Verilog 风格十六进制字面量(如 `'h5`);`bytes` 等为十进制。
|
|
39
41
|
|
|
@@ -12,6 +12,8 @@ def _fmt_at_int(v: int) -> str:
|
|
|
12
12
|
|
|
13
13
|
def _emit_field(f: FieldNode, indent: str) -> list[str]:
|
|
14
14
|
head = f"{indent}field {f.name}"
|
|
15
|
+
if f.paren_path is not None:
|
|
16
|
+
head += f"({f.paren_path})"
|
|
15
17
|
if f.offset_bits is not None:
|
|
16
18
|
head += f" @{_fmt_at_int(f.offset_bits)}"
|
|
17
19
|
head += " {"
|
|
@@ -26,6 +28,8 @@ def _emit_field(f: FieldNode, indent: str) -> list[str]:
|
|
|
26
28
|
|
|
27
29
|
def _emit_register(r: RegisterNode, indent: str) -> list[str]:
|
|
28
30
|
head = f"{indent}register {r.name}"
|
|
31
|
+
if r.paren_path is not None:
|
|
32
|
+
head += f" ({r.paren_path})"
|
|
29
33
|
if r.offset_bytes is not None:
|
|
30
34
|
head += f" @{_fmt_at_int(r.offset_bytes)}"
|
|
31
35
|
if r.declaration_only:
|
|
@@ -9,6 +9,10 @@ class FieldNode(BaseModel):
|
|
|
9
9
|
model_config = ConfigDict(extra="forbid")
|
|
10
10
|
|
|
11
11
|
name: str
|
|
12
|
+
paren_path: str | None = Field(
|
|
13
|
+
default=None,
|
|
14
|
+
description="紧跟在 field 名后的圆括号路径内容(不含括号),如 ``field f(hdl.sig)``",
|
|
15
|
+
)
|
|
12
16
|
offset_bits: int | None = Field(default=None, description="field 内 `@` 后的位偏移")
|
|
13
17
|
inner_statements: list[str] = Field(
|
|
14
18
|
default_factory=list,
|
|
@@ -22,6 +26,10 @@ class RegisterNode(BaseModel):
|
|
|
22
26
|
model_config = ConfigDict(extra="forbid")
|
|
23
27
|
|
|
24
28
|
name: str
|
|
29
|
+
paren_path: str | None = Field(
|
|
30
|
+
default=None,
|
|
31
|
+
description="紧跟在 register 名后的圆括号路径内容(不含括号),如 ``register r (dut.reg)``",
|
|
32
|
+
)
|
|
25
33
|
offset_bytes: int | None = Field(default=None, description="register 后的 `@` 字节偏移")
|
|
26
34
|
bytes_width: int | None = None
|
|
27
35
|
fields: list[FieldNode] = Field(default_factory=list)
|
|
@@ -349,6 +349,10 @@ class _Parser:
|
|
|
349
349
|
self.expect_keyword("register")
|
|
350
350
|
name = self.read_ident()
|
|
351
351
|
self.skip_ws_and_comments()
|
|
352
|
+
paren_path: str | None = None
|
|
353
|
+
if self._peek() == "(":
|
|
354
|
+
paren_path = self.read_round_paren_inner()
|
|
355
|
+
self.skip_ws_and_comments()
|
|
352
356
|
offset: int | None = None
|
|
353
357
|
if self._peek() == "@":
|
|
354
358
|
self._advance()
|
|
@@ -358,6 +362,7 @@ class _Parser:
|
|
|
358
362
|
self._advance()
|
|
359
363
|
return RegisterNode(
|
|
360
364
|
name=name,
|
|
365
|
+
paren_path=paren_path,
|
|
361
366
|
offset_bytes=offset,
|
|
362
367
|
declaration_only=True,
|
|
363
368
|
)
|
|
@@ -367,6 +372,7 @@ class _Parser:
|
|
|
367
372
|
self.expect_char("}")
|
|
368
373
|
return RegisterNode(
|
|
369
374
|
name=name,
|
|
375
|
+
paren_path=paren_path,
|
|
370
376
|
offset_bytes=offset,
|
|
371
377
|
bytes_width=rbw,
|
|
372
378
|
fields=fields,
|
|
@@ -396,6 +402,10 @@ class _Parser:
|
|
|
396
402
|
self.expect_keyword("field")
|
|
397
403
|
name = self.read_ident()
|
|
398
404
|
self.skip_ws_and_comments()
|
|
405
|
+
paren_path: str | None = None
|
|
406
|
+
if self._peek() == "(":
|
|
407
|
+
paren_path = self.read_round_paren_inner()
|
|
408
|
+
self.skip_ws_and_comments()
|
|
399
409
|
off_bits: int | None = None
|
|
400
410
|
if self._peek() == "@":
|
|
401
411
|
self._advance()
|
|
@@ -403,7 +413,9 @@ class _Parser:
|
|
|
403
413
|
self.expect_char("{")
|
|
404
414
|
fn = self._parse_field_body()
|
|
405
415
|
self.expect_char("}")
|
|
406
|
-
return fn.model_copy(
|
|
416
|
+
return fn.model_copy(
|
|
417
|
+
update={"name": name, "paren_path": paren_path, "offset_bits": off_bits}
|
|
418
|
+
)
|
|
407
419
|
|
|
408
420
|
def _parse_field_body(self) -> FieldNode:
|
|
409
421
|
inner: list[str] = []
|
{python_library_ralf_model-0.1.1 → python_library_ralf_model-0.1.2}/tests/test_ralf_model.py
RENAMED
|
@@ -148,6 +148,69 @@ block top {
|
|
|
148
148
|
out = dump_ralf(doc)
|
|
149
149
|
self.assertIn("register R0;", out)
|
|
150
150
|
|
|
151
|
+
def test_register_paren_path_at_offset(self) -> None:
|
|
152
|
+
src = """
|
|
153
|
+
block top {
|
|
154
|
+
bytes 4;
|
|
155
|
+
register CTRL (dut.ctrl_reg) @'h0 {
|
|
156
|
+
bytes 4;
|
|
157
|
+
field ena(dut.ctrl_reg.en) @1 {
|
|
158
|
+
bits 1;
|
|
159
|
+
access rw;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
"""
|
|
164
|
+
doc = parse_ralf(src)
|
|
165
|
+
reg = doc.blocks[0].registers[0]
|
|
166
|
+
self.assertEqual(reg.name, "CTRL")
|
|
167
|
+
self.assertEqual(reg.paren_path, "dut.ctrl_reg")
|
|
168
|
+
self.assertEqual(reg.offset_bytes, 0)
|
|
169
|
+
fld = reg.fields[0]
|
|
170
|
+
self.assertEqual(fld.name, "ena")
|
|
171
|
+
self.assertEqual(fld.paren_path, "dut.ctrl_reg.en")
|
|
172
|
+
self.assertEqual(fld.offset_bits, 1)
|
|
173
|
+
out = dump_ralf(doc)
|
|
174
|
+
self.assertIn("register CTRL (dut.ctrl_reg) @'h0", out)
|
|
175
|
+
self.assertIn("field ena(dut.ctrl_reg.en) @'h1", out)
|
|
176
|
+
doc2 = parse_ralf(out)
|
|
177
|
+
self.assertEqual(doc.model_dump(), doc2.model_dump())
|
|
178
|
+
|
|
179
|
+
def test_register_paren_path_forward_decl(self) -> None:
|
|
180
|
+
src = """
|
|
181
|
+
block top {
|
|
182
|
+
register R0 (hdl.r0) @'h10;
|
|
183
|
+
}
|
|
184
|
+
"""
|
|
185
|
+
doc = parse_ralf(src)
|
|
186
|
+
r = doc.blocks[0].registers[0]
|
|
187
|
+
self.assertTrue(r.declaration_only)
|
|
188
|
+
self.assertEqual(r.paren_path, "hdl.r0")
|
|
189
|
+
self.assertEqual(r.offset_bytes, 0x10)
|
|
190
|
+
out = dump_ralf(doc)
|
|
191
|
+
self.assertIn("register R0 (hdl.r0) @'h10;", out)
|
|
192
|
+
doc2 = parse_ralf(out)
|
|
193
|
+
self.assertEqual(doc.model_dump(), doc2.model_dump())
|
|
194
|
+
|
|
195
|
+
def test_field_paren_path_no_space(self) -> None:
|
|
196
|
+
src = """
|
|
197
|
+
block top {
|
|
198
|
+
register r {
|
|
199
|
+
bytes 4;
|
|
200
|
+
field sig(hdl.sig) @0 {
|
|
201
|
+
bits 4;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
"""
|
|
206
|
+
doc = parse_ralf(src)
|
|
207
|
+
fld = doc.blocks[0].registers[0].fields[0]
|
|
208
|
+
self.assertEqual(fld.paren_path, "hdl.sig")
|
|
209
|
+
out = dump_ralf(doc)
|
|
210
|
+
self.assertIn("field sig(hdl.sig)", out)
|
|
211
|
+
doc2 = parse_ralf(out)
|
|
212
|
+
self.assertEqual(doc.model_dump(), doc2.model_dump())
|
|
213
|
+
|
|
151
214
|
def test_block_ref_rhs_with_parentheses(self) -> None:
|
|
152
215
|
src = """
|
|
153
216
|
block top {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_library_ralf_model-0.1.1 → python_library_ralf_model-0.1.2}/ralf_model/source_expand.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_library_ralf_model-0.1.1 → python_library_ralf_model-0.1.2}/tests/test_source_include.py
RENAMED
|
File without changes
|