Skip to content

back.rtlil: implement remaining format specifiers. #1280

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 23 additions & 16 deletions amaranth/back/rtlil.py
Original file line number Diff line number Diff line change
Expand Up @@ -1090,35 +1090,42 @@
args += chunk.value
if type is None:
type = "d"
if type == "x" or type == "X":
# TODO(yosys): "H" type
elif type == "x":
type = "h"
if type == "s":
# TODO(yosys): support for single unicode character?
elif type == "X":
type = "H"
elif type == "c":
type = "U"
elif type == "s":
type = "c"
width = spec["width"]
align = spec["align"]
if align is None:
align = ">" if type != "c" else "<"
if align == "=":
# TODO(yosys): "=" alignment
align = ">"
align = "<" if type in ("c", "U") else ">"
fill = spec["fill"]
if fill not in (" ", "0"):
# TODO(yosys): arbitrary fill
fill = " "
# TODO(yosys): support for options, grouping
if fill is None:
fill = ' '
if ord(fill) >= 0x80:
raise NotImplementedError(f"non-ASCII fill character {fill!r} is not supported in RTLIL")

Check warning on line 1109 in amaranth/back/rtlil.py

View check run for this annotation

Codecov / codecov/patch

amaranth/back/rtlil.py#L1109

Added line #L1109 was not covered by tests
sign = spec["sign"]
if sign != "+":
# TODO(yosys): support " " sign
if sign is None:
sign = ""
if type == "c":
if type in ("c", "U"):
signed = ""
elif chunk.signed:
signed = "s"
else:
signed = "u"
format.append(f"{{{len(chunk.value)}:{align}{fill}{width or ''}{type}{sign}{signed}}}")
show_base = "#" if spec["show_base"] and type != "d" else ""
grouping = spec["grouping"] or ""
if type == "U":
if align != "<" and width != 0:
format.append(fill * (width - 1))
format.append(f"{{{len(chunk.value)}:U}}")
if align == "<" and width != 0:
format.append(fill * (width - 1))
else:
format.append(f"{{{len(chunk.value)}:{align}{fill}{width or ''}{type}{sign}{show_base}{grouping}{signed}}}")
ports = {
"EN": self.sigspec(cell.en),
"ARGS": self.sigspec(_nir.Value(args)),
Expand Down
2 changes: 1 addition & 1 deletion amaranth/back/verilog.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

def _convert_rtlil_text(rtlil_text, *, strip_internal_attrs=False, write_verilog_opts=()):
# This version requirement needs to be synchronized with the one in pyproject.toml!
yosys = find_yosys(lambda ver: ver >= (0, 38))
yosys = find_yosys(lambda ver: ver >= (0, 39, 0, 165))

script = []
script.append(f"read_ilang <<rtlil\n{rtlil_text}\nrtlil")
Expand Down
20 changes: 13 additions & 7 deletions amaranth/hdl/_ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -2691,7 +2691,8 @@ def __format__(self, format_desc):
(?P<align>[<>=^])
)?
(?P<sign>[-+ ])?
(?P<options>[#]?[0]?)
(?P<show_base>[#]?)
(?P<width_zero>[0]?)
(?P<width>[1-9][0-9]*)?
(?P<grouping>[_,])?
(?P<type>[bodxXcsn])?
Expand All @@ -2713,25 +2714,30 @@ def _parse_format_spec(spec: str, shape: Shape):
raise ValueError(f"Cannot print signed value with format specifier {match['type']!r}")
if match["align"] == "=":
raise ValueError(f"Alignment {match['align']!r} is not allowed with format specifier {match['type']!r}")
if "#" in match["options"]:
if match["show_base"]:
raise ValueError(f"Alternate form is not allowed with format specifier {match['type']!r}")
if "0" in match["options"]:
if match["width_zero"] != "":
raise ValueError(f"Zero fill is not allowed with format specifier {match['type']!r}")
if match["sign"] is not None:
raise ValueError(f"Sign is not allowed with format specifier {match['type']!r}")
if match["grouping"] is not None:
raise ValueError(f"Cannot specify {match['grouping']!r} with format specifier {match['type']!r}")
if match["type"] == "s" and shape.width % 8 != 0:
raise ValueError(f"Value width must be divisible by 8 with format specifier {match['type']!r}")
fill = match["fill"]
align = match["align"]
if match["width_zero"] and align is None:
fill = "0"
align = "="
return {
# Single character or None.
"fill": match["fill"],
"fill": fill,
# '<', '>', '=', or None. Cannot be '=' for types 'c' and 's'.
"align": match["align"],
"align": align,
# '-', '+', ' ', or None. Always None for types 'c' and 's'.
"sign": match["sign"],
# "", "#", "0", or "#0". Always "" for types 'c' and 's'.
"options": match["options"],
# A bool. Always False for types 'c' and 's'.
"show_base": match["show_base"] == "#",
# An int.
"width": int(match["width"]) if match["width"] is not None else 0,
# '_' or None. Always None for types 'c' and 's'.
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ dependencies = [
# - pyproject.toml: tool.pdm.dev-dependencies.test
# - amaranth/back/verilog.py: _convert_rtlil_text
# - docs/install.rst: yosys-version
builtin-yosys = ["amaranth-yosys>=0.38"]
builtin-yosys = ["amaranth-yosys>=0.39.0.165.post92"]
remote-build = ["paramiko~=2.7"]

[project.scripts]
Expand Down Expand Up @@ -65,7 +65,7 @@ source-includes = [
[tool.pdm.dev-dependencies]
# This version requirement needs to be synchronized with the one in pyproject.toml above!
test = [
"yowasp-yosys>=0.38",
"yowasp-yosys>=0.39.0.165.post92",
"coverage",
]
docs = [
Expand Down
122 changes: 121 additions & 1 deletion tests/test_back_rtlil.py
Original file line number Diff line number Diff line change
Expand Up @@ -1889,6 +1889,127 @@ def test_assume_msg(self):
end
""")

def test_print_char(self):
i = Signal(21)
m = Module()
m.d.comb += [
Print(Format("{:c} {:-<5c} {:->5c}", i, i, i)),
]
self.assertRTLIL(m, [i], R"""
attribute \generator "Amaranth"
attribute \top 1
module \top
wire width 21 input 0 \i
wire width 1 $1
process $2
assign $1 [0] 1'0
assign $1 [0] 1'1
end
cell $print $3
parameter \FORMAT "{21:U} {21:U}---- ----{21:U}\n"
parameter \ARGS_WIDTH 63
parameter signed \PRIORITY 32'11111111111111111111111111111110
parameter \TRG_ENABLE 0
parameter \TRG_WIDTH 0
parameter \TRG_POLARITY 0
connect \EN $1 [0]
connect \ARGS { \i [20:0] \i [20:0] \i [20:0] }
connect \TRG { }
end
end
""")

def test_print_base(self):
i = Signal(8)
m = Module()
m.d.comb += [
Print(Format("{:b} {:o} {:d} {:x} {:X} {:#x} {:#d} {:#_x}", i, i, i, i, i, i, i, i)),
]
self.assertRTLIL(m, [i], R"""
attribute \generator "Amaranth"
attribute \top 1
module \top
wire width 8 input 0 \i
wire width 1 $1
process $2
assign $1 [0] 1'0
assign $1 [0] 1'1
end
cell $print $3
parameter \FORMAT "{8:> bu} {8:> ou} {8:> du} {8:> hu} {8:> Hu} {8:> h#u} {8:> du} {8:> h#_u}\n"
parameter \ARGS_WIDTH 64
parameter signed \PRIORITY 32'11111111111111111111111111111110
parameter \TRG_ENABLE 0
parameter \TRG_WIDTH 0
parameter \TRG_POLARITY 0
connect \EN $1 [0]
connect \ARGS { \i [7:0] \i [7:0] \i [7:0] \i [7:0] \i [7:0] \i [7:0] \i [7:0] \i [7:0] }
connect \TRG { }
end
end
""")

def test_print_sign(self):
i = Signal(8)
m = Module()
m.d.comb += [
Print(Format("{:5x} {:-5x} {:+5x} {: 5x}", i, i, i, i)),
]
self.assertRTLIL(m, [i], R"""
attribute \generator "Amaranth"
attribute \top 1
module \top
wire width 8 input 0 \i
wire width 1 $1
process $2
assign $1 [0] 1'0
assign $1 [0] 1'1
end
cell $print $3
parameter \FORMAT "{8:> 5hu} {8:> 5h-u} {8:> 5h+u} {8:> 5h u}\n"
parameter \ARGS_WIDTH 32
parameter signed \PRIORITY 32'11111111111111111111111111111110
parameter \TRG_ENABLE 0
parameter \TRG_WIDTH 0
parameter \TRG_POLARITY 0
connect \EN $1 [0]
connect \ARGS { \i [7:0] \i [7:0] \i [7:0] \i [7:0] }
connect \TRG { }
end
end
""")

def test_print_align(self):
i = Signal(8)
m = Module()
m.d.comb += [
Print(Format("{:<5x} {:>5x} {:=5x} {:05x} {:-<5x}", i, i, i, i, i)),
]
self.assertRTLIL(m, [i], R"""
attribute \generator "Amaranth"
attribute \top 1
module \top
wire width 8 input 0 \i
wire width 1 $1
process $2
assign $1 [0] 1'0
assign $1 [0] 1'1
end
cell $print $3
parameter \FORMAT "{8:< 5hu} {8:> 5hu} {8:= 5hu} {8:=05hu} {8:<-5hu}\n"
parameter \ARGS_WIDTH 40
parameter signed \PRIORITY 32'11111111111111111111111111111110
parameter \TRG_ENABLE 0
parameter \TRG_WIDTH 0
parameter \TRG_POLARITY 0
connect \EN $1 [0]
connect \ARGS { \i [7:0] \i [7:0] \i [7:0] \i [7:0] \i [7:0] }
connect \TRG { }
end
end
""")


class ComponentTestCase(RTLILTestCase):
def test_component(self):
class MyComponent(wiring.Component):
Expand All @@ -1907,4 +2028,3 @@ def elaborate(self, platform):
connect \o 8'00000000
end
""")

Loading