back.rtlil: implement remaining format specifiers.
This requires a Yosys version from git. The requirement should be bumped to a proper release before Amaranth 0.5.
This commit is contained in:
parent
d3c5b958d3
commit
d94c97981a
|
@ -1090,35 +1090,42 @@ class ModuleEmitter:
|
|||
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")
|
||||
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)),
|
||||
|
|
|
@ -9,7 +9,7 @@ __all__ = ["YosysError", "convert", "convert_fragment"]
|
|||
|
||||
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")
|
||||
|
|
|
@ -2691,7 +2691,8 @@ class Format:
|
|||
(?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])?
|
||||
|
@ -2713,9 +2714,9 @@ class Format:
|
|||
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}")
|
||||
|
@ -2723,15 +2724,20 @@ class Format:
|
|||
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'.
|
||||
|
|
|
@ -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]
|
||||
|
@ -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 = [
|
||||
|
|
|
@ -1889,6 +1889,127 @@ class PrintTestCase(RTLILTestCase):
|
|||
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):
|
||||
|
@ -1907,4 +2028,3 @@ class ComponentTestCase(RTLILTestCase):
|
|||
connect \o 8'00000000
|
||||
end
|
||||
""")
|
||||
|
||||
|
|
Loading…
Reference in a new issue