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:
Catherine 2024-03-28 23:42:44 +00:00
parent d3c5b958d3
commit d94c97981a
5 changed files with 160 additions and 27 deletions

View file

@ -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)),

View file

@ -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")

View file

@ -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'.