From 135b7174861cb949bb42b131ef5ce3e463a43e4d Mon Sep 17 00:00:00 2001 From: Alex Mykyta Date: Wed, 20 Jul 2022 23:35:17 -0700 Subject: [PATCH] Add identifier filter. closes #14 --- src/peakrdl_regblock/addr_decode.py | 3 +- src/peakrdl_regblock/exporter.py | 4 +- .../field_logic/generators.py | 5 +- src/peakrdl_regblock/hwif/__init__.py | 3 +- src/peakrdl_regblock/hwif/generators.py | 7 +-- src/peakrdl_regblock/identifier_filter.py | 52 +++++++++++++++++++ src/peakrdl_regblock/module_tmpl.sv | 4 +- src/peakrdl_regblock/struct_generator.py | 18 ++++--- src/peakrdl_regblock/utils.py | 14 ++++- 9 files changed, 90 insertions(+), 20 deletions(-) create mode 100644 src/peakrdl_regblock/identifier_filter.py diff --git a/src/peakrdl_regblock/addr_decode.py b/src/peakrdl_regblock/addr_decode.py index 695ae2c..3dfaf25 100644 --- a/src/peakrdl_regblock/addr_decode.py +++ b/src/peakrdl_regblock/addr_decode.py @@ -5,6 +5,7 @@ from systemrdl.node import AddrmapNode, AddressableNode, RegNode, FieldNode from .utils import get_indexed_path from .struct_generator import RDLStructGenerator from .forloop_generator import RDLForLoopGenerator +from .identifier_filter import kw_filter as kwf if TYPE_CHECKING: from .exporter import RegblockExporter @@ -43,7 +44,7 @@ class AddressDecode: class DecodeStructGenerator(RDLStructGenerator): def enter_Reg(self, node: 'RegNode') -> None: - self.add_member(node.inst_name, array_dimensions=node.array_dimensions) + self.add_member(kwf(node.inst_name), array_dimensions=node.array_dimensions) # Stub out def exit_Reg(self, node: 'RegNode') -> None: diff --git a/src/peakrdl_regblock/exporter.py b/src/peakrdl_regblock/exporter.py index 58546f3..de104e1 100644 --- a/src/peakrdl_regblock/exporter.py +++ b/src/peakrdl_regblock/exporter.py @@ -8,6 +8,7 @@ from .addr_decode import AddressDecode from .field_logic import FieldLogic from .dereferencer import Dereferencer from .readback import Readback +from .identifier_filter import kw_filter as kwf from .cpuif import CpuifBase from .cpuif.apb3 import APB3_Cpuif @@ -100,7 +101,7 @@ class RegblockExporter: cpuif_cls = kwargs.pop("cpuif_cls", None) or APB3_Cpuif # type: Type[CpuifBase] - module_name = kwargs.pop("module_name", None) or self.top_node.inst_name # type: str + module_name = kwargs.pop("module_name", None) or kwf(self.top_node.inst_name) # type: str package_name = kwargs.pop("package_name", None) or (module_name + "_pkg") # type: str reuse_hwif_typedefs = kwargs.pop("reuse_hwif_typedefs", True) # type: bool @@ -158,6 +159,7 @@ class RegblockExporter: "retime_read_response": retime_read_response, "min_read_latency": self.min_read_latency, "min_write_latency": self.min_write_latency, + "kwf": kwf, } # Write out design diff --git a/src/peakrdl_regblock/field_logic/generators.py b/src/peakrdl_regblock/field_logic/generators.py index 09dc640..a84b70f 100644 --- a/src/peakrdl_regblock/field_logic/generators.py +++ b/src/peakrdl_regblock/field_logic/generators.py @@ -5,6 +5,7 @@ from collections import OrderedDict from ..struct_generator import RDLStructGenerator from ..forloop_generator import RDLForLoopGenerator from ..utils import get_always_ff_event +from ..identifier_filter import kw_filter as kwf if TYPE_CHECKING: from . import FieldLogic @@ -34,7 +35,7 @@ class CombinationalStructGenerator(RDLStructGenerator): else: extra_combo_signals[signal.name] = signal - self.push_struct(node.inst_name) + self.push_struct(kwf(node.inst_name)) self.add_member("next", node.width) self.add_member("load_next") for signal in extra_combo_signals.values(): @@ -67,7 +68,7 @@ class FieldStorageStructGenerator(RDLStructGenerator): self.field_logic = field_logic def enter_Field(self, node: 'FieldNode') -> None: - self.push_struct(node.inst_name) + self.push_struct(kwf(node.inst_name)) if node.implements_storage: self.add_member("value", node.width) diff --git a/src/peakrdl_regblock/hwif/__init__.py b/src/peakrdl_regblock/hwif/__init__.py index 88175bd..f9fdc37 100644 --- a/src/peakrdl_regblock/hwif/__init__.py +++ b/src/peakrdl_regblock/hwif/__init__.py @@ -4,6 +4,7 @@ from systemrdl.node import AddrmapNode, Node, SignalNode, FieldNode, Addressable from systemrdl.rdltypes import PropertyReference from ..utils import get_indexed_path +from ..identifier_filter import kw_filter as kwf from .generators import InputStructGenerator_Hier, OutputStructGenerator_Hier from .generators import InputStructGenerator_TypeScope, OutputStructGenerator_TypeScope @@ -141,7 +142,7 @@ class Hwif: return "hwif_in." + path + ".next" elif isinstance(obj, SignalNode): if obj.get_path() in self.out_of_hier_signals: - return obj.inst_name + return kwf(obj.inst_name) path = get_indexed_path(self.top_node, obj) return "hwif_in." + path elif isinstance(obj, PropertyReference): diff --git a/src/peakrdl_regblock/hwif/generators.py b/src/peakrdl_regblock/hwif/generators.py index 90a31bb..fa48b77 100644 --- a/src/peakrdl_regblock/hwif/generators.py +++ b/src/peakrdl_regblock/hwif/generators.py @@ -3,6 +3,7 @@ from typing import TYPE_CHECKING from systemrdl.node import FieldNode from ..struct_generator import RDLFlatStructGenerator +from ..identifier_filter import kw_filter as kwf if TYPE_CHECKING: from systemrdl.node import Node, SignalNode, RegNode @@ -27,11 +28,11 @@ class InputStructGenerator_Hier(RDLFlatStructGenerator): # only emit the signal if design scanner detected it is actually being used path = node.get_path() if path in self.hwif.in_hier_signal_paths: - self.add_member(node.inst_name, node.width) + self.add_member(kwf(node.inst_name), node.width) def enter_Field(self, node: 'FieldNode') -> None: type_name = self.get_typdef_name(node) - self.push_struct(type_name, node.inst_name) + self.push_struct(type_name, kwf(node.inst_name)) # Provide input to field's next value if it is writable by hw, and it # was not overridden by the 'next' property @@ -87,7 +88,7 @@ class OutputStructGenerator_Hier(RDLFlatStructGenerator): def enter_Field(self, node: 'FieldNode') -> None: type_name = self.get_typdef_name(node) - self.push_struct(type_name, node.inst_name) + self.push_struct(type_name, kwf(node.inst_name)) # Expose field's value if it is readable by hw if node.is_hw_readable: diff --git a/src/peakrdl_regblock/identifier_filter.py b/src/peakrdl_regblock/identifier_filter.py new file mode 100644 index 0000000..f701a28 --- /dev/null +++ b/src/peakrdl_regblock/identifier_filter.py @@ -0,0 +1,52 @@ + +# All SystemVerilog 2017 keywords +SV_KEYWORDS = { + 'accept_on', 'alias', 'always', 'always_comb', 'always_ff', 'always_latch', + 'and', 'assert', 'assign', 'assume', 'automatic', 'before', 'begin', 'bind', + 'bins', 'binsof', 'bit', 'break', 'buf', 'bufif0', 'bufif1', 'byte', 'case', + 'casex', 'casez', 'cell', 'chandle', 'checker', 'class', 'clocking', 'cmos', + 'config', 'const', 'constraint', 'context', 'continue', 'cover', 'covergroup', + 'coverpoint', 'cross', 'deassign', 'default', 'defparam', 'design', 'disable', + 'dist', 'do', 'edge', 'else', 'end', 'endcase', 'endchecker', 'endclass', + 'endclocking', 'endconfig', 'endfunction', 'endgenerate', 'endgroup', + 'endinterface', 'endmodule', 'endpackage', 'endprimitive', 'endprogram', + 'endproperty', 'endspecify', 'endsequence', 'endtable', 'endtask', 'enum', + 'event', 'eventually', 'expect', 'export', 'extends', 'extern', 'final', + 'first_match', 'for', 'force', 'foreach', 'forever', 'fork', 'forkjoin', + 'function', 'generate', 'genvar', 'global', 'highz0', 'highz1', 'if', 'iff', + 'ifnone', 'ignore_bins', 'illegal_bins', 'implements', 'implies', 'import', + 'incdir', 'include', 'initial', 'inout', 'input', 'inside', 'instance', + 'int', 'integer', 'interconnect', 'interface', 'intersect', 'join', + 'join_any', 'join_none', 'large', 'let', 'liblist', 'library', 'local', + 'localparam', 'logic', 'longint', 'macromodule', 'matches', 'medium', + 'modport', 'module', 'nand', 'negedge', 'nettype', 'new', 'nexttime', 'nmos', + 'nor', 'noshowcancelled', 'not', 'notif0', 'notif1', 'null', 'or', 'output', + 'package', 'packed', 'parameter', 'pmos', 'posedge', 'primitive', 'priority', + 'program', 'property', 'protected', 'pull0', 'pull1', 'pulldown', 'pullup', + 'pulsestyle_ondetect', 'pulsestyle_onevent', 'pure', 'rand', 'randc', + 'randcase', 'randsequence', 'rcmos', 'real', 'realtime', 'ref', 'reg', + 'reject_on', 'release', 'repeat', 'restrict', 'return', 'rnmos', 'rpmos', + 'rtran', 'rtranif0', 'rtranif1', 's_always', 's_eventually', 's_nexttime', + 's_until', 's_until_with', 'scalared', 'sequence', 'shortint', 'shortreal', + 'showcancelled', 'signed', 'small', 'soft', 'solve', 'specify', 'specparam', + 'static', 'string', 'strong', 'strong0', 'strong1', 'struct', 'super', + 'supply0', 'supply1', 'sync_accept_on', 'sync_reject_on', 'table', 'tagged', + 'task', 'this', 'throughout', 'time', 'timeprecision', 'timeunit', 'tran', + 'tranif0', 'tranif1', 'tri', 'tri0', 'tri1', 'triand', 'trior', 'trireg', + 'type', 'typedef', 'union', 'unique', 'unique0', 'unsigned', 'until', + 'until_with', 'untyped', 'use', 'uwire', 'var', 'vectored', 'virtual', 'void', + 'wait', 'wait_order', 'wand', 'weak', 'weak0', 'weak1', 'while', 'wildcard', + 'wire', 'with', 'within', 'wor', 'xnor', 'xor' +} + + +def kw_filter(s: str) -> str: + """ + Make all user identifiers 'safe' and ensure they do not collide with + SystemVerilog keywords. + + If an SV keyword is encountered, add an underscore suffix + """ + if s in SV_KEYWORDS: + s += "_" + return s diff --git a/src/peakrdl_regblock/module_tmpl.sv b/src/peakrdl_regblock/module_tmpl.sv index 88a0ba4..8acff50 100644 --- a/src/peakrdl_regblock/module_tmpl.sv +++ b/src/peakrdl_regblock/module_tmpl.sv @@ -7,9 +7,9 @@ module {{module_name}} ( {%- for signal in user_out_of_hier_signals %} {%- if signal.width == 1 %} - input wire {{signal.inst_name}}, + input wire {{kwf(signal.inst_name)}}, {%- else %} - input wire [{{signal.width-1}}:0] {{signal.inst_name}}, + input wire [{{signal.width-1}}:0] {{kwf(signal.inst_name)}}, {%- endif %} {%- endfor %} diff --git a/src/peakrdl_regblock/struct_generator.py b/src/peakrdl_regblock/struct_generator.py index 787411c..9ec9d89 100644 --- a/src/peakrdl_regblock/struct_generator.py +++ b/src/peakrdl_regblock/struct_generator.py @@ -4,6 +4,8 @@ from collections import OrderedDict from systemrdl.walker import RDLListener, RDLWalker +from .identifier_filter import kw_filter as kwf + if TYPE_CHECKING: from typing import Union @@ -131,25 +133,25 @@ class RDLStructGenerator(StructGenerator, RDLListener): def enter_Addrmap(self, node: 'AddrmapNode') -> None: - self.push_struct(node.inst_name, node.array_dimensions) + self.push_struct(kwf(node.inst_name), node.array_dimensions) def exit_Addrmap(self, node: 'AddrmapNode') -> None: self.pop_struct() def enter_Regfile(self, node: 'RegfileNode') -> None: - self.push_struct(node.inst_name, node.array_dimensions) + self.push_struct(kwf(node.inst_name), node.array_dimensions) def exit_Regfile(self, node: 'RegfileNode') -> None: self.pop_struct() def enter_Reg(self, node: 'RegNode') -> None: - self.push_struct(node.inst_name, node.array_dimensions) + self.push_struct(kwf(node.inst_name), node.array_dimensions) def exit_Reg(self, node: 'RegNode') -> None: self.pop_struct() def enter_Field(self, node: 'FieldNode') -> None: - self.add_member(node.inst_name, node.width) + self.add_member(kwf(node.inst_name), node.width) #------------------------------------------------------------------------------- @@ -214,24 +216,24 @@ class RDLFlatStructGenerator(FlatStructGenerator, RDLListener): def enter_Addrmap(self, node: 'AddrmapNode') -> None: type_name = self.get_typdef_name(node) - self.push_struct(type_name, node.inst_name, node.array_dimensions) + self.push_struct(type_name, kwf(node.inst_name), node.array_dimensions) def exit_Addrmap(self, node: 'AddrmapNode') -> None: self.pop_struct() def enter_Regfile(self, node: 'RegfileNode') -> None: type_name = self.get_typdef_name(node) - self.push_struct(type_name, node.inst_name, node.array_dimensions) + self.push_struct(type_name, kwf(node.inst_name), node.array_dimensions) def exit_Regfile(self, node: 'RegfileNode') -> None: self.pop_struct() def enter_Reg(self, node: 'RegNode') -> None: type_name = self.get_typdef_name(node) - self.push_struct(type_name, node.inst_name, node.array_dimensions) + self.push_struct(type_name, kwf(node.inst_name), node.array_dimensions) def exit_Reg(self, node: 'RegNode') -> None: self.pop_struct() def enter_Field(self, node: 'FieldNode') -> None: - self.add_member(node.inst_name, node.width) + self.add_member(kwf(node.inst_name), node.width) diff --git a/src/peakrdl_regblock/utils.py b/src/peakrdl_regblock/utils.py index 2e10940..d3a9cb0 100644 --- a/src/peakrdl_regblock/utils.py +++ b/src/peakrdl_regblock/utils.py @@ -1,6 +1,8 @@ import re from typing import TYPE_CHECKING, Match +from .identifier_filter import kw_filter as kwf + if TYPE_CHECKING: from systemrdl.node import Node, SignalNode from typing import Optional @@ -11,15 +13,23 @@ def get_indexed_path(top_node: 'Node', target_node: 'Node') -> str: TODO: Add words about indexing and why i'm doing this. Copy from logbook """ path = target_node.get_rel_path(top_node, empty_array_suffix="[!]") + # replace unknown indexes with incrementing iterators i0, i1, ... - class repl: + class ReplaceUnknown: def __init__(self) -> None: self.i = 0 def __call__(self, match: Match) -> str: s = f'i{self.i}' self.i += 1 return s - return re.sub(r'!', repl(), path) + path = re.sub(r'!', ReplaceUnknown(), path) + + # Sanitize any SV keywords + def kw_filter_repl(m: Match) -> str: + return kwf(m.group(0)) + path = re.sub(r'\w+', kw_filter_repl, path) + + return path def get_always_ff_event(dereferencer: 'Dereferencer', resetsignal: 'Optional[SignalNode]') -> str: