diff --git a/srdl2sv/cli/cli.py b/srdl2sv/cli/cli.py index e93c170..b5a2cb4 100644 --- a/srdl2sv/cli/cli.py +++ b/srdl2sv/cli/cli.py @@ -19,6 +19,14 @@ class CliArguments(): self.parser = argparse.ArgumentParser( description="SystemRDL 2 SystemVerilog compiler") + self.parser.add_argument( + "-b", + "--bus", + choices=['amba3ahblite'], + default='amba3ahblite', + help="Set the bus protocol that shall be used by software to ',\ + communicate with the registers. (default: %(default)s)") + self.parser.add_argument( "-o", "--out_dir", @@ -129,4 +137,7 @@ class CliArguments(): # Set enums config['enums'] = not args.disable_enums + # Set bus + config['bus'] = args.bus + return config diff --git a/srdl2sv/components/addrmap.py b/srdl2sv/components/addrmap.py index ce9dccf..84c7640 100644 --- a/srdl2sv/components/addrmap.py +++ b/srdl2sv/components/addrmap.py @@ -11,6 +11,7 @@ from components.component import Component from components.regfile import RegFile from components.register import Register from . import templates +from . import widgets class AddrMap(Component): @@ -32,6 +33,10 @@ class AddrMap(Component): (glbl_settings['field_reset'], glbl_settings['cpuif_reset']) = \ self.__process_global_resets() + # Set defaults so that some of the common component methods work + self.total_dimensions = 0 + self.total_array_dimensions = [] + # Use global settings to define whether a component is already in a generate block glbl_settings['generate_active'] = False @@ -69,6 +74,9 @@ class AddrMap(Component): self.logger.info("Done generating all child-regfiles/registers") + # Add bus widget ports + self.__add_bus_widget_ports() + # Start assembling addrmap module self.logger.info("Starting to assemble input & output ports") @@ -147,18 +155,61 @@ class AddrMap(Component): inputs = '\n'.join(input_ports_rtl), outputs = '\n'.join(output_ports_rtl))) + # Add wire/register instantiations + self.__add_signal_instantiation() + + # Add bus widget RTL + self.__add_bus_widget_instantiation() + # Append genvars + self.__append_genvars() + + # Add endmodule keyword + self.rtl_footer.append('endmodule') + + def __add_signal_instantiation(self): + dict_list = [(key, value) for (key, value) in self.get_signals(True).items()] + signal_width = min(max([len(value[0]) for (_, value) in dict_list]), 40) + name_width = min(max([len(key) for (key, _) in dict_list]), 40) + + self.rtl_header = [ + *self.rtl_header, + '', + '// Internal signals', + *[AddrMap.templ_dict['signal_declaration'].format( + name = key, + type = value[0], + signal_width = signal_width, + name_width = name_width, + unpacked_dim = '[{}]'.format( + ']['.join( + [str(y) for y in value[1]])) + if value[1] else '') + for (key, value) in dict_list], + '' + ] + + def __add_bus_widget_ports(self): + self.widget_templ_dict = yaml.load( + pkg_resources.read_text(widgets, '{}.yaml'.format(self.config['bus'])), + Loader=yaml.FullLoader) + + self.yaml_signals_to_list(self.widget_templ_dict['module_instantiation']) + + def __add_bus_widget_instantiation(self): + self.rtl_header.append( + self.widget_templ_dict['module_instantiation']['rtl']) + + + def __append_genvars(self): genvars = ''.join([ '\ngenvar ', - ','.join([chr(97+i) for i in range(self.get_max_dim_depth())]), + ', '.join([chr(97+i) for i in range(self.get_max_dim_depth())]), ';\n' ]) self.rtl_header.append(genvars) - # Add endmodule keyword - self.rtl_footer.append('endmodule') - def __process_global_resets(self): field_reset_list = \ [x for x in self.obj.signals() if x.get_property('field_reset')] diff --git a/srdl2sv/components/component.py b/srdl2sv/components/component.py index 6d6bb7f..e38be92 100644 --- a/srdl2sv/components/component.py +++ b/srdl2sv/components/component.py @@ -66,25 +66,20 @@ class Component(): return self.ports[port_type] def get_max_dim_depth(self) -> int: - try: - total_dimensions = self.total_dimensions - total_array_dimensions = self.total_array_dimensions - except AttributeError: - total_dimensions = 0 - total_array_dimensions = [] - self.logger.debug("Return depth '{}' for dimensions (including "\ - "parents) '{}'".format(total_dimensions, total_array_dimensions)) + "parents) '{}'".format(self.total_dimensions, + self.total_array_dimensions)) return max([ - total_dimensions, + self.total_dimensions, *[x.get_max_dim_depth() for x in self.children] ]) - def get_signals(self): + def get_signals(self, no_children = False): self.logger.debug("Return signal list") - for x in self.children: - self.signals |= x.get_signals() + if not no_children: + for x in self.children: + self.signals |= x.get_signals() return self.signals @@ -171,7 +166,7 @@ class Component(): return path\ .replace('[]', '')\ .replace('{}.'.format(owning_addrmap), '')\ - .replace('.', '_') + .replace('.', '__') @staticmethod def split_dimensions(path: str): @@ -179,8 +174,7 @@ class Component(): new_path = re_dimensions.sub('', path) return (new_path, ''.join(re_dimensions.findall(path))) - @staticmethod - def get_signal_name(obj): + def get_signal_name(self, obj): name = [] try: @@ -199,9 +193,11 @@ class Component(): if isinstance(obj, node.FieldNode): name.append('_q') elif isinstance(obj, node.SignalNode): - pass + # Must add it to signal list + self.ports['input'][obj.inst_name] =\ + ("logic" if obj.width == 1 else 'logic [{}:0]'.format(obj.width), []) else: - name.append('_') + name.append('__') name.append(obj.name) name.append(split_name[1]) diff --git a/srdl2sv/components/field.py b/srdl2sv/components/field.py index 0a64e8f..ab8ac0f 100644 --- a/srdl2sv/components/field.py +++ b/srdl2sv/components/field.py @@ -133,10 +133,7 @@ class Field(Component): except AttributeError: # In case of an AttributeError, the encode property is None. Hence, # the field has a simple width - if self.obj.width > 1: - self.field_type = 'logic [{}:0]'.format(self.obj.width-1) - else: - self.field_type = 'logic' + self.field_type = 'logic [{}:0]'.format(self.obj.width-1) def __process_variables(self, obj: FieldNode, array_dimensions: list, glbl_settings: dict): # Create full name @@ -213,7 +210,6 @@ class Field(Component): self.rtl_header.append( Field.templ_dict[sense_list]['rtl'].format( - clk_name = "clk", rst_edge = self.rst['edge'], rst_name = self.rst['name'])) @@ -252,25 +248,25 @@ class Field(Component): # Define hardware access (if applicable) if self.hw_access in (AccessType.rw, AccessType.w): - if self.we_or_wel: - access_rtl['hw_write'] = ([ - Field.templ_dict['hw_access_we_wel']['rtl'].format( - negl = '!' if self.obj.get_property('wel') else '', - path = self.path_underscored, - genvars = self.genvars_str) - ], - False) - else: - access_rtl['hw_write'] = ([ - Field.templ_dict['hw_access_no_we_wel']['rtl'] - ], - True) + write_condition = 'hw_access_we_wel' if self.we_or_wel else 'hw_access_no_we_wel' + # if-line of hw-access + access_rtl['hw_write'] = ([ + Field.templ_dict[write_condition]['rtl'].format( + negl = '!' if self.obj.get_property('wel') else '', + path = self.path_underscored, + genvars = self.genvars_str) + ], + write_condition == 'hw_access_no_we_wel') # Abort if no condition is set + + # Actual assignment of register access_rtl['hw_write'][0].append( Field.templ_dict['hw_access_field']['rtl'].format( path = self.path_underscored, genvars = self.genvars_str)) + # Get ports/signals from list + self.yaml_signals_to_list(Field.templ_dict[write_condition]) self.yaml_signals_to_list(Field.templ_dict['hw_access_field']) else: access_rtl['hw_write'] = ([], False) @@ -287,13 +283,13 @@ class Field(Component): Field.templ_dict['sw_access_field_swwe']['rtl'].format( path_wo_field = self.path_wo_field, genvars = self.genvars_str, - swwe = Component.get_signal_name(swwe))) + swwe = self.get_signal_name(swwe))) elif isinstance(swwel, (FieldNode, SignalNode)): access_rtl['sw_write'][0].append( Field.templ_dict['sw_access_field_swwel']['rtl'].format( path_wo_field = self.path_wo_field, genvars = self.genvars_str, - swwel = Component.get_signal_name(swwel))) + swwel = self.get_signal_name(swwel))) else: access_rtl['sw_write'][0].append( Field.templ_dict['sw_access_field']['rtl'].format( diff --git a/srdl2sv/components/templates/addrmap.yaml b/srdl2sv/components/templates/addrmap.yaml index 0ef5bff..f3c8fba 100644 --- a/srdl2sv/components/templates/addrmap.yaml +++ b/srdl2sv/components/templates/addrmap.yaml @@ -7,6 +7,7 @@ module_declaration: // Clock & Resets input reg_clk, input bus_clk, + input bus_rst_n, {resets} // Bus I/O @@ -30,6 +31,8 @@ input_port: output_port: rtl: output {signal_type:{signal_width}} {name:{name_width}}{unpacked_dim}, +signal_declaration: |- + {type:{signal_width}} {name:{name_width}}{unpacked_dim}; package_declaration: rtl: |- package {name}_pkg; diff --git a/srdl2sv/components/templates/fields.yaml b/srdl2sv/components/templates/fields.yaml index 21f82ec..9ef54e1 100644 --- a/srdl2sv/components/templates/fields.yaml +++ b/srdl2sv/components/templates/fields.yaml @@ -1,10 +1,10 @@ --- sense_list_rst: rtl: |- - always_ff @(posedge {clk_name} or {rst_edge} {rst_name}) + always_ff @(posedge reg_clk or {rst_edge} {rst_name}) sense_list_no_rst: rtl: |- - always_ff @(posedge {clk_name}) + always_ff @(posedge reg_clk) rst_field_assign: rtl: |- if ({rst_negl}{rst_name}) @@ -37,6 +37,9 @@ sw_access_byte: hw_access_we_wel: rtl: |- if ({negl}{path}_hw_wr{genvars}) + input_ports: + - name: '{path}_hw_wr' + signal_type: '{field_type}' hw_access_no_we_wel: rtl: |- // we or wel property not set diff --git a/srdl2sv/components/widgets/__init__.py b/srdl2sv/components/widgets/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/srdl2sv/components/widgets/amba3ahblite.sv b/srdl2sv/components/widgets/amba3ahblite.sv new file mode 100644 index 0000000..26cd696 --- /dev/null +++ b/srdl2sv/components/widgets/amba3ahblite.sv @@ -0,0 +1,31 @@ +module amba3ahblite_widget +( + // Register clock + input reg_clk, + + // Outputs to internal logic + output [31:0] addr, + output w_vld, + output r_vld, + output [ 3:0] byte_enable, + output [31:0] sw_wr_bus, + + // Bus protocol + input HRESETn, + input HCLK, + input [31:0] HADDR, + input HWRITE, + input [ 2:0] HSIZE, + input [ 2:0] HBURST, + input [ 3:0] HPROT, + input [ 1:0] HTRANS, + input HMASTLOCK, + input HREADY, + + output HREADYOUT, + output HRESP, + output [31:0] HRDATA +); + + +endmodule diff --git a/srdl2sv/components/widgets/amba3ahblite.yaml b/srdl2sv/components/widgets/amba3ahblite.yaml new file mode 100644 index 0000000..396b647 --- /dev/null +++ b/srdl2sv/components/widgets/amba3ahblite.yaml @@ -0,0 +1,72 @@ +# This file only contains the instantiation of the module +module_instantiation: + rtl: |- + /**************************** + * AMBA 3 AHB Lite Widget + ****************************/ + amba3ahblite_widget + amba3ahblite_widget_inst + (// Register clock + .reg_clk, + + // Outputs to internal logic + .addr, + .w_vld, + .r_vld, + .byte_enable, + .sw_wr_bus, + + // Bus protocol + .HRESETn, + .HCLK, + .HADDR, + .HWRITE, + .HSIZE, + .HBURST, + .HPROT, + .HTRANS, + .HMASTLOCK, + .HREADY, + + .HREADYOUT, + .HRESP, + .HRDATA); + signals: + - name: 'addr' + signal_type: 'logic [31:0]' + - name: 'w_vld' + signal_type: 'logic' + - name: 'r_vld' + signal_type: 'logic' + - name: 'byte_enable' + signal_type: 'logic [ 3:0]' + - name: 'sw_wr_bus' + signal_type: 'logic [31:0]' + input_ports: + - name: 'HRESETn' + signal_type: '' + - name: 'HCLK' + signal_type: '' + - name: 'HADDR' + signal_type: '[31:0]' + - name: 'HWRITE' + signal_type: '' + - name: 'HSIZE' + signal_type: '[2:0]' + - name: 'HBURST' + signal_type: '[2:0]' + - name: 'HPROT' + signal_type: '[3:0]' + - name: 'HTRANS' + signal_type: '[1:0]' + - name: 'HMASTLOCK' + signal_type: '' + - name: 'HREADY' + signal_type: '' + output_ports: + - name: 'HREADYOUT' + signal_type: '' + - name: 'HRESP' + signal_type: '' + - name: 'HRDATA' + signal_type: '[31:0]' diff --git a/srdl2sv/main.py b/srdl2sv/main.py index bfdb633..29f74d0 100755 --- a/srdl2sv/main.py +++ b/srdl2sv/main.py @@ -4,6 +4,7 @@ import sys import time import os +import importlib.resources as pkg_resources # Imported modules from systemrdl import RDLCompiler, RDLCompileError @@ -12,6 +13,7 @@ from systemrdl import RDLCompiler, RDLCompileError from components.addrmap import AddrMap from cli.cli import CliArguments from log.log import create_logger +from components import widgets if __name__ == "__main__": # Take start timestamp @@ -74,4 +76,12 @@ if __name__ == "__main__": with open('{}/{}_pkg.sv'.format(config['output_dir'], key), 'w') as file: file.write(value) + # Copy over widget RTL from widget directory + widget_rtl = pkg_resources.read_text(widgets, '{}.sv'.format(config['bus'])) + + out_widget_file = "{}/{}.sv".format(config['output_dir'], config['bus']) + + with open(out_widget_file, 'w') as file: + file.write(widget_rtl) + logger.info("Elapsed time: %f seconds", time.time() - start)