Add identifier filter. closes #14
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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:
|
||||
|
||||
52
src/peakrdl_regblock/identifier_filter.py
Normal file
52
src/peakrdl_regblock/identifier_filter.py
Normal file
@@ -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
|
||||
@@ -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 %}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user