diff --git a/srdl2sv/cli/cli.py b/srdl2sv/cli/cli.py index e55dc9c..8de1b44 100644 --- a/srdl2sv/cli/cli.py +++ b/srdl2sv/cli/cli.py @@ -51,13 +51,6 @@ class CliArguments(): help="If set, the dependency directories will be\ searched recursively.") - self.parser.add_argument( - "-x", - "--disable_sanity", - action="store_true", - help="Disable sanity checks or components. This might speed\ - up the compiler but is generally not recommended!") - self.parser.add_argument( "-e", "--disable_enums", @@ -141,10 +134,6 @@ class CliArguments(): config['list_args'].append('Use Real Tabs : {}'.format(config['real_tabs'])) config['list_args'].append('Tab Width : {}'.format(config['tab_width'])) - # Sanity check related - config['disable_sanity'] = args.disable_sanity - config['list_args'].append('Sanity Disabled : {}'.format(config['disable_sanity'])) - # Set enums config['enums'] = not args.disable_enums config['list_args'].append('Enums Enabled : {}'.format(config['enums'])) diff --git a/srdl2sv/components/component.py b/srdl2sv/components/component.py index fb2efc6..9b68868 100644 --- a/srdl2sv/components/component.py +++ b/srdl2sv/components/component.py @@ -39,6 +39,10 @@ class Component(): # Save config self.config = config.copy() + # By default, registers and fields are not interrupt registers + self.intr = False + self.halt = False + # Create logger object self.create_logger("{}".format(self.full_path), config) self.logger.debug('Starting to process {} "{}"'.format( @@ -210,7 +214,9 @@ class Component(): name.append(obj.name) # This is a property. Check if the original field actually has this property - if not obj.node.get_property(obj.name): + if obj.name == "intr" or obj.name == "halt": + pass + elif not obj.node.get_property(obj.name): self.logger.fatal("Reference to the property '{}' of instance '{}' found. " "This instance does hold the reference property! Please " "fix this if you want me to do my job properly." diff --git a/srdl2sv/components/field.py b/srdl2sv/components/field.py index 69cb700..43b0c2c 100644 --- a/srdl2sv/components/field.py +++ b/srdl2sv/components/field.py @@ -47,6 +47,7 @@ class Field(Component): if not self.config['external']: self.__add_always_ff() self.__add_hw_access() + self.__add_interrupt() self.__add_combo() self.__add_swmod_swacc() self.__add_counter() @@ -685,6 +686,47 @@ class Field(Component): self.rtl_footer = [*self.rtl_footer, swmod_props, swacc_props] + def __add_interrupt(self): + if self.obj.get_property('intr'): + self.intr = True + + # Generate masked & enabled version of interrupt to be + # picked up by the register at the top level + if mask := self.obj.get_property('mask'): + self.itr_masked = ' && !'.join([ + self.register_name, + self.get_signal_name(mask) + ]) + elif enable := self.obj.get_property('enable'): + self.itr_masked = ' && '.join([ + self.register_name, + self.get_signal_name(enable) + ]) + else: + self.itr_masked = self.register_name + + # Generate haltmasked & haltenabled version of interrupt to be + # picked up by the register at the top level + if haltmask := self.obj.get_property('haltmask'): + self.itr_haltmasked = ' && !'.join([ + self.register_name, + self.get_signal_name(haltmask) + ]) + + self.halt = True + elif haltenable := self.obj.get_property('haltenable'): + self.itr_haltmasked = ' && '.join([ + self.register_name, + self.get_signal_name(haltenable) + ]) + + self.halt = True + else: + self.itr_haltmasked = self.register_name + else: + self.itr_masked = False + self.itr_haltmasked = False + def __add_hw_access(self): # Mutually exclusive. systemrdl-compiler performs check for this enable_mask_negl = '' @@ -1037,6 +1079,7 @@ class Field(Component): def __process_variables(self, obj: FieldNode, array_dimensions: list, glbl_settings: dict): # Create full name self.path_wo_field = '__'.join(self.path.split('.', -1)[0:-1]) + self.register_name = ''.join([self.path_underscored, '_q']) self.path_underscored_vec = [] self.path_wo_field_vec = [] @@ -1153,3 +1196,11 @@ class Field(Component): # TODO: Counter & hw=r shouldn't work + + # If hw=ro and the next property is set, throw a fatal + if self.obj.get_property('hw') == AccessType.r\ + and self.obj.get_property('next'): + self.logger.error("Hardware property of field is set to read-only "\ + "but simultanously, the next property is set. Since "\ + "this would reflect wrong behavior in documentation, "\ + "the next property is ignored.") diff --git a/srdl2sv/components/register.py b/srdl2sv/components/register.py index b64be45..3ed673b 100644 --- a/srdl2sv/components/register.py +++ b/srdl2sv/components/register.py @@ -42,8 +42,12 @@ class Register(Component): self.config, glbl_settings) - if not config['disable_sanity']: - self.children[field_range].sanity_checks() + # Get certain properties from field that apply to whole register + self.intr = self.intr or self.children[field_range].intr + self.halt = self.halt or self.children[field_range].halt + + # Perform sanity check + self.children[field_range].sanity_checks() def create_rtl(self): # Create RTL of children @@ -68,6 +72,9 @@ class Register(Component): # Fields will be added by get_rtl() + # Add interrupt logic + self.__add_interrupts() + # Add assignment of read-wires self.__add_sw_mux_assignments() @@ -95,6 +102,42 @@ class Register(Component): *self.rtl_header ] + def __add_interrupts(self): + + # Semantics on the intr and halt property: + # a) The intr and halt register properties are outputs; they should only + # occur on the right-hand side of an assignment in SystemRDL. + # b) The intr property shall always be present on a intr register even if + # no mask or enables are specified. + # c) The halt property shall only be present if haltmask or haltenable is + # specified on at least one field in the register. + if self.intr: + self.rtl_footer.append(Register.templ_dict['interrupt_comment']['rtl']) + + self.rtl_footer.append( + self.process_yaml( + Register.templ_dict['interrupt_intr'], + {'path': self.path_underscored, + 'genvars': self.genvars_str, + 'list': ') || ('.join([ + x.itr_masked for x in self.children.values() if x.itr_masked]) + } + ) + ) + + if self.halt: + self.rtl_footer.append( + self.process_yaml( + Register.templ_dict['interrupt_halt'], + {'path': self.path_underscored, + 'genvars': self.genvars_str, + 'list': ') || ('.join([ + x.itr_haltmasked for x in self.children.values() if x.itr_haltmasked]) + } + ) + ) + + def __add_sw_mux_assignments(self): accesswidth = self.obj.get_property('accesswidth') - 1 self.rtl_footer.append("") @@ -383,9 +426,6 @@ class Register(Component): (self.create_underscored_path_static(obj)[3], obj.absolute_address) ] - # Create full name - self.create_underscored_path() - # Gnerate already started? self.generate_active = glbl_settings['generate_active'] diff --git a/srdl2sv/components/templates/fields.yaml b/srdl2sv/components/templates/fields.yaml index 8cfce55..590feb7 100644 --- a/srdl2sv/components/templates/fields.yaml +++ b/srdl2sv/components/templates/fields.yaml @@ -54,7 +54,9 @@ hw_access_we_wel: signal_type: 'logic' hw_access_no_we_wel: rtl: |- + <> // we or wel property not set + <> hw_access_hwset: rtl: |- if ({path}_hwset{genvars}) diff --git a/srdl2sv/components/templates/register.yaml b/srdl2sv/components/templates/register.yaml index c04bedd..910be96 100644 --- a/srdl2sv/components/templates/register.yaml +++ b/srdl2sv/components/templates/register.yaml @@ -122,3 +122,23 @@ external_err_condition: signal_type: 'logic' - name: '{path}_ext_{rd_or_wr}_ack' signal_type: 'logic' +interrupt_comment: + rtl: |- + /************************************** + * Register contains interrupts * + **************************************/ +interrupt_intr: + rtl: |- + // Register has at least one interrupt field + assign {path}_intr{genvars} = ({list}); + output_ports: + - name: '{path}_intr' + signal_type: 'logic' +interrupt_halt: + rtl: |- + + // Register has at least one interrupt field with halt property set + assign {path}_halt{genvars} = {list}; + output_ports: + - name: '{path}_halt' + signal_type: 'logic'