From c52e59abd01b4476961640bcec4578364aa0b0c4 Mon Sep 17 00:00:00 2001 From: Dennis Date: Sat, 25 Sep 2021 20:49:39 -0700 Subject: [PATCH] Add basic interrupt framework Up to this point, interrupt outputs are generated and intr, enable, mask, haltenable, and haltmask are supported. stick, stikcybit and the different types of interrupts are not yet supported. This commit also removes the option to turn off santiy checking. This is a bad idea anyway... --- srdl2sv/cli/cli.py | 11 ----- srdl2sv/components/component.py | 8 +++- srdl2sv/components/field.py | 51 ++++++++++++++++++++++ srdl2sv/components/register.py | 50 ++++++++++++++++++--- srdl2sv/components/templates/fields.yaml | 2 + srdl2sv/components/templates/register.yaml | 20 +++++++++ 6 files changed, 125 insertions(+), 17 deletions(-) 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'