diff --git a/srdl2sv/components/addrmap.py b/srdl2sv/components/addrmap.py index 62b33a7..08ef0c8 100644 --- a/srdl2sv/components/addrmap.py +++ b/srdl2sv/components/addrmap.py @@ -29,15 +29,22 @@ class AddrMap(Component): template = pkg_resources.read_text(templates, 'addrmap.sv') + # Check if global resets are defined + glbl_settings = dict() + + (glbl_settings['field_reset'], glbl_settings['cpuif_reset']) = \ + self.__process_global_resets() + # Empty dictionary of register objects # We need a dictionary since it might be required to access the objects later # by name (for example, in case of aliases) self.registers = dict() - self.rdl_nodes = dict() # Traverse through children for child in obj.children(): if isinstance(child, node.AddrmapNode): + # This addressmap opens a completely new scope. For example, + # a field_reset does not propagate through to this scope. self.logger.info('Found hierarchical addrmap. Entering it...') self.logger.error('Child addrmaps are not implemented yet!') elif isinstance(child, node.RegfileNode): @@ -49,7 +56,8 @@ class AddrMap(Component): # additional properties self.logger.error('Alias registers are not implemented yet!') else: - self.registers[child.inst_name] = Register(child, config) + self.registers[child.inst_name] = \ + Register(child, config, glbl_settings) # Add regfiles and registers to children self.children = [x for x in self.registers.values()] @@ -59,6 +67,13 @@ class AddrMap(Component): # Start assembling addrmap module self.logger.info("Starting to assemble input/output/inout ports") + # Reset ports + reset_ports_rtl = [ + AddrMap.templ_dict['reset_port'].format( + name = name) + for name in [x for x in self.get_resets()] + ] + # Prefetch dictionaries in local array input_dict_list = [(key, value) for (key, value) in self.get_ports('input').items()] output_dict_list = [(key, value) for (key, value) in self.get_ports('output').items()] @@ -110,6 +125,7 @@ class AddrMap(Component): self.rtl_header.append( AddrMap.templ_dict['module_declaration'].format( name = obj.inst_name, + resets = '\n'.join(reset_ports_rtl), inputs = '\n'.join(input_ports_rtl), outputs = '\n'.join(output_ports_rtl))) @@ -126,3 +142,43 @@ class AddrMap(Component): self.path_underscored = self.path.replace('.', '_') self.name = obj.inst_name + + def __process_global_resets(self): + field_reset_list = \ + [x for x in self.obj.signals() if x.get_property('field_reset')] + cpuif_reset_list = \ + [x for x in self.obj.signals() if x.get_property('cpuif_reset')] + + if field_reset_list: + rst_name = field_reset_list[0].inst_name + self.logger.info("Found field_reset signal '{}'".format(rst_name)) + + # Save to set to generate input + self.resets.add(rst_name) + + # Save position 0 of list + field_reset_item = field_reset_list[0] + else: + field_reset_item = None + + if cpuif_reset_list: + rst_name = cpuif_reset_list[0].inst_name + self.logger.info("Found cpuif_reset signal '{}'".format(rst_name)) + + # Save to set to generate input + self.resets.add(rst_name) + + # Save position 0 of list + cpuif_reset_item = cpuif_reset_list[0] + else: + cpuif_reset_item = None + + # Method is only called once on a global level. Otherwise, process_reset_signal + # is called several times to calculate the dictionary, although it will always + # return the same result. + field_reset = AddrMap.process_reset_signal(field_reset_item) + cpuif_reset = AddrMap.process_reset_signal(cpuif_reset_item) + + return (field_reset, cpuif_reset) + + diff --git a/srdl2sv/components/component.py b/srdl2sv/components/component.py index 6f245e1..ad09702 100644 --- a/srdl2sv/components/component.py +++ b/srdl2sv/components/component.py @@ -18,6 +18,7 @@ class Component(): self.children = [] self.typedef = dict() self.ports = dict() + self.resets = set() self.signals = dict() self.ports['input'] = dict() self.ports['output'] = dict() @@ -31,6 +32,14 @@ class Component(): file_name=config['file_log_location']) self.logger.propagate = False + def get_resets(self): + self.logger.debug("Return reset list") + + for x in self.children: + self.resets |= x.get_resets() + + return self.resets + def get_ports(self, port_type: str): self.logger.debug("Return port list") @@ -169,3 +178,29 @@ class Component(): self.array_dimensions) except (TypeError, KeyError): pass + + @staticmethod + def process_reset_signal(reset_signal): + rst = dict() + + try: + rst['name'] = reset_signal.inst_name + rst['async'] = reset_signal.get_property("async") + rst['type'] = "asynchronous" if rst['async'] else "synchronous" + + # Active low or active high? + if reset_signal.get_property("activelow"): + rst['edge'] = "negedge" + rst['active'] = "active_low" + else: + rst['edge'] = "posedge" + rst['active'] = "active_high" + except: + rst['async'] = False + rst['name'] = None + rst['edge'] = None + rst['value'] = "'x" + rst['active'] = "-" + rst['type'] = "-" + + return rst diff --git a/srdl2sv/components/field.py b/srdl2sv/components/field.py index 7271fd0..2300f2e 100644 --- a/srdl2sv/components/field.py +++ b/srdl2sv/components/field.py @@ -16,11 +16,11 @@ class Field(Component): pkg_resources.read_text(templates, 'fields.yaml'), Loader=yaml.FullLoader) - def __init__(self, obj: FieldNode, array_dimensions: list, config:dict): + def __init__(self, obj: FieldNode, array_dimensions: list, config:dict, glbl_settings: dict): super().__init__() # Save and/or process important variables - self.__process_variables(obj, array_dimensions) + self.__process_variables(obj, array_dimensions, glbl_settings) # Create logger object self.create_logger("{}.{}".format(self.owning_addrmap, self.path), config) @@ -136,7 +136,7 @@ class Field(Component): else: self.field_type = 'logic' - def __process_variables(self, obj: FieldNode, array_dimensions: list): + def __process_variables(self, obj: FieldNode, array_dimensions: list, glbl_settings: dict): # Save object self.obj = obj @@ -168,32 +168,22 @@ class Field(Component): # the reset value, and whether the field actually has a reset self.rst = dict() - try: - rst_signal = obj.get_property("resetsignal") + reset_signal = obj.get_property("resetsignal") - self.rst['name'] = rst_signal.inst_name - self.rst['async'] = rst_signal.get_property("async") - self.rst['type'] = "asynchronous" if self.rst['async'] else "synchronous" + if (reset_signal): + self.rst = Field.process_reset_signal(reset_signal) + else: + # Only use global reset (if present) if no local reset is set + self.rst = glbl_settings['field_reset'] - # Active low or active high? - if rst_signal.get_property("activelow"): - self.rst['edge'] = "negedge" - self.rst['active'] = "active_low" - else: - self.rst['edge'] = "posedge" - self.rst['active'] = "active_high" + self.resets.add(self.rst['name']) - # Value of reset? - self.rst['value'] = '\'x' if obj.get_property("reset") == None else\ - obj.get_property('reset') - except: - self.rst['async'] = False - self.rst['name'] = None - self.rst['edge'] = None - self.rst['value'] = "'x" - self.rst['active'] = "-" - self.rst['type'] = "-" + # Value of reset must always be determined on field level + self.rst['value'] = \ + '\'x' if obj.get_property("reset") == None else\ + obj.get_property('reset') + # Define hardware access self.hw_access = obj.get_property('hw') self.sw_access = obj.get_property('sw') self.precedence = obj.get_property('precedence') diff --git a/srdl2sv/components/register.py b/srdl2sv/components/register.py index 98af9a5..543d012 100644 --- a/srdl2sv/components/register.py +++ b/srdl2sv/components/register.py @@ -1,8 +1,7 @@ import importlib.resources as pkg_resources import yaml -from systemrdl import RDLCompiler, RDLCompileError, RDLWalker, RDLListener, node -from systemrdl.node import FieldNode +from systemrdl import node # Local modules from components.component import Component @@ -15,7 +14,7 @@ class Register(Component): pkg_resources.read_text(templates, 'regs.yaml'), Loader=yaml.FullLoader) - def __init__(self, obj: node.RootNode, config: dict): + def __init__(self, obj: node.RootNode, config: dict, glbl_settings: dict): super().__init__() # Save and/or process important variables @@ -28,7 +27,7 @@ class Register(Component): # Create RTL for fields # Fields should be in order in RTL,therefore, use list for field in obj.fields(): - field_obj = Field(field, self.array_dimensions, config) + field_obj = Field(field, self.array_dimensions, config, glbl_settings) if not config['disable_sanity']: field_obj.sanity_checks() diff --git a/srdl2sv/components/templates/addrmap.yaml b/srdl2sv/components/templates/addrmap.yaml index e0d2391..dd4919d 100644 --- a/srdl2sv/components/templates/addrmap.yaml +++ b/srdl2sv/components/templates/addrmap.yaml @@ -1,6 +1,11 @@ --- module_declaration: |- module {name} ( + // Clock & Resets + input reg_clk, + input bus_clk, + {resets} + // Bus I/O // TODO @@ -10,6 +15,8 @@ module_declaration: |- // Outputs {outputs} ); +reset_port: |- + input {name}, input_port: |- input {signal_type:{signal_width}} {name:{name_width}}{unpacked_dim}, output_port: |-