From dc37c879446aa69b609ad3481667b25d031a565d Mon Sep 17 00:00:00 2001 From: Dennis Date: Sat, 2 Oct 2021 00:32:04 -0700 Subject: [PATCH] Ensure that sw_rd/sw_wr wires are only generated if they are required --- srdl2sv/components/component.py | 12 +- srdl2sv/components/field.py | 31 ++++-- srdl2sv/components/register.py | 124 +++++++++++++++------ srdl2sv/components/templates/register.yaml | 59 ++++++---- 4 files changed, 159 insertions(+), 67 deletions(-) diff --git a/srdl2sv/components/component.py b/srdl2sv/components/component.py index a731ba1..3e9b71a 100644 --- a/srdl2sv/components/component.py +++ b/srdl2sv/components/component.py @@ -40,8 +40,16 @@ class Component(): self.config = config.copy() # By default, registers and fields are not interrupt registers - self.intr = False - self.halt = False + self.properties = { + 'intr': False, + 'halt': False, + 'swmod': False, + 'swacc': False, + 'sw_rd': False, + 'sw_wr': False, + 'sw_rd_wire': False, + 'sw_wr_wire': False, + } # Create logger object self.create_logger("{}".format(self.full_path), config) diff --git a/srdl2sv/components/field.py b/srdl2sv/components/field.py index e3d1f10..3b0872b 100644 --- a/srdl2sv/components/field.py +++ b/srdl2sv/components/field.py @@ -76,6 +76,10 @@ class Field(Component): # Append to list of registers that can write self.writable_by.add(path_wo_field) + # This will need a wire to indicate that a write is taking place + self.properties['sw_wr_wire'] = True + self.properties['sw_wr'] = True + swwe = obj.get_property('swwe') swwel = obj.get_property('swwel') @@ -114,7 +118,7 @@ class Field(Component): if onwrite: if onwrite == OnWriteType.wuser: - self.logger.warning("The OnReadType.wuser is not yet supported!") + self.logger.warning("The OnWriteType.wuser is not yet supported!") elif onwrite in (OnWriteType.wclr, OnWriteType.wset): access_rtl['sw_write'][0].append( self.process_yaml( @@ -177,10 +181,14 @@ class Field(Component): # Append to list of registers that can read self.readable_by.add(path_wo_field) + self.properties['sw_wr'] = True + # Set onread properties if onread == OnReadType.ruser: self.logger.error("The OnReadType.ruser is not yet supported!") elif onread: + self.properties['sw_rd_wire'] = True + access_rtl['sw_read'][0].append( self.process_yaml( Field.templ_dict[str(onread)], @@ -636,7 +644,7 @@ class Field(Component): ) # Check if SW has write access to the field - if self.obj.get_property('sw') in (AccessType.rw, AccessType.w): + if self.properties['sw_wr']: swmod_assigns.append( self.process_yaml( Field.templ_dict['swmod_assign'], @@ -666,10 +674,13 @@ class Field(Component): swmod_props = '' if self.obj.get_property('swacc') and \ - self.obj.get_property('sw') in (AccessType.rw, AccessType.r): - + (self.properties['sw_rd'] or self.properties['sw_wr']): self.logger.debug("Field has swacc property") + self.properties['swacc'] = True + self.properties['sw_wr_wire'] = True + self.properties['sw_rd_wire'] = True + swacc_props = self.process_yaml( Field.templ_dict['swacc_assign'], {'path': self.path_underscored, @@ -691,7 +702,7 @@ class Field(Component): def __add_interrupt(self): if self.obj.get_property('intr'): - self.intr = True + self.properties['intr'] = True # Determine what causes the interrupt to get set, i.e., # is it a trigger that is passed to the module through an @@ -791,21 +802,21 @@ class Field(Component): self.get_signal_name(haltmask) ]) - self.halt = True + self.properties['halt'] = True elif haltenable := self.obj.get_property('haltenable'): self.itr_haltmasked = ' && '.join([ self.register_name, self.get_signal_name(haltenable) ]) - self.halt = True + self.properties['halt'] = True else: self.itr_haltmasked = self.register_name else: self.itr_masked = False self.itr_haltmasked = False - return self.intr + return self.properties['intr'] def __add_hw_access(self): # Mutually exclusive. systemrdl-compiler performs check for this @@ -957,7 +968,7 @@ class Field(Component): ) def create_external_rtl(self): - if self.obj.get_property('sw') in (AccessType.rw, AccessType.w): + if self.properties['sw_wr']: for i, alias in enumerate(self.path_underscored_vec): # Create bit-wise mask so that outside logic knows what # bits it may change @@ -989,7 +1000,7 @@ class Field(Component): } )) - if self.obj.get_property('sw') in (AccessType.rw, AccessType.r): + if self.properties['sw_rd']: for i, alias in enumerate(self.path_underscored_vec): self.rtl_footer.append(self.process_yaml( Field.templ_dict['external_rd_assignments'], diff --git a/srdl2sv/components/register.py b/srdl2sv/components/register.py index efd548c..b8c07ff 100644 --- a/srdl2sv/components/register.py +++ b/srdl2sv/components/register.py @@ -42,9 +42,9 @@ class Register(Component): self.config, glbl_settings) - # 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 + # Get properties from field that apply to whole register + for key in self.properties: + self.properties[key] |= self.children[field_range].properties[key] # Perform sanity check self.children[field_range].sanity_checks() @@ -111,7 +111,7 @@ class Register(Component): # 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: + if self.properties['intr']: self.rtl_footer.append(Register.templ_dict['interrupt_comment']['rtl']) self.rtl_footer.append( @@ -125,7 +125,7 @@ class Register(Component): ) ) - if self.halt: + if self.properties['halt']: self.rtl_footer.append( self.process_yaml( Register.templ_dict['interrupt_halt'], @@ -328,38 +328,100 @@ class Register(Component): self.obj.current_idx = [0] if self.total_dimensions: - rw_wire_assign_field = 'rw_wire_assign_multi_dim' + access_wire_assign_field = 'access_wire_assign_multi_dim' else: - rw_wire_assign_field = 'rw_wire_assign_1_dim' + access_wire_assign_field = 'access_wire_assign_1_dim' - [self.rtl_header.append( - self.process_yaml( - Register.templ_dict[rw_wire_assign_field], - {'path': x[0], - 'addr': x[1], - 'alias': '(alias)' if i > 0 else '', - 'genvars': self.genvars_str, - 'genvars_sum': self.genvars_sum_str, - 'depth': self.depth, - 'field_type': self.field_type} + for i, x in enumerate(self.name_addr_mappings): + self.rtl_header.append( + self.process_yaml( + Register.templ_dict['access_wire_comment'], + {'path': x[0], + 'alias': '(alias)' if i > 0 else '', + } + ) ) - ) for i, x in enumerate(self.name_addr_mappings)] + + self.rtl_header.append( + self.process_yaml( + Register.templ_dict[access_wire_assign_field], + {'path': x[0], + 'addr': x[1], + 'genvars': self.genvars_str, + 'genvars_sum': self.genvars_sum_str, + 'depth': self.depth, + } + ) + ) + + # A wire that indicates a read is required + if self.properties['sw_rd_wire']: + # Check if a read is actually possible. Otherwise provide a wire + # that is tied to 1'b0 + if self.properties['sw_rd']: + self.rtl_header.append( + self.process_yaml( + Register.templ_dict['read_wire_assign'], + {'path': x[0], + 'addr': x[1], + 'genvars': self.genvars_str, + 'genvars_sum': self.genvars_sum_str, + 'depth': self.depth, + } + ) + ) + else: + self.rtl_header.append( + self.process_yaml( + Register.templ_dict['read_wire_assign_0'], + {'path': x[0], + 'genvars': self.genvars_str, + } + ) + ) + + # A wire that indicates a write is required + if self.properties['sw_wr_wire']: + # Check if a write is actually possible. Otherwise provide a wire + # that is tied to 1'b0 + if self.properties['sw_wr']: + self.rtl_header.append( + self.process_yaml( + Register.templ_dict['write_wire_assign'], + {'path': x[0], + 'addr': x[1], + 'genvars': self.genvars_str, + 'genvars_sum': self.genvars_sum_str, + 'depth': self.depth, + } + ) + ) + else: + self.rtl_header.append( + self.process_yaml( + Register.templ_dict['write_wire_assign_0'], + {'path': x[0], + 'genvars': self.genvars_str, + } + ) + ) # Add combined signal to be used for general access of the register - self.rtl_header.append( - self.process_yaml( - Register.templ_dict['rw_wire_assign_any_alias'], - {'path': self.name_addr_mappings[0][0], - 'genvars': self.genvars_str, - 'sw_rds_w_genvars': ' || '.join( - [''.join([x[0], '_sw_rd', self.genvars_str]) - for x in self.name_addr_mappings]), - 'sw_wrs_w_genvars': ' || '.join( - [''.join([x[0], '_sw_wr', self.genvars_str]) - for x in self.name_addr_mappings]) - } + if self.properties['swacc']: + self.rtl_header.append( + self.process_yaml( + Register.templ_dict['rw_wire_assign_any_alias'], + {'path': self.name_addr_mappings[0][0], + 'genvars': self.genvars_str, + 'sw_rds_w_genvars': ' || '.join( + [''.join([x[0], '_sw_rd', self.genvars_str]) + for x in self.name_addr_mappings]), + 'sw_wrs_w_genvars': ' || '.join( + [''.join([x[0], '_sw_wr', self.genvars_str]) + for x in self.name_addr_mappings]) + } + ) ) - ) def __add_signal_instantiations(self): # Add wire/register instantiations diff --git a/srdl2sv/components/templates/register.yaml b/srdl2sv/components/templates/register.yaml index 1c6d39e..307f355 100644 --- a/srdl2sv/components/templates/register.yaml +++ b/srdl2sv/components/templates/register.yaml @@ -1,44 +1,55 @@ --- -rw_wire_assign_1_dim: - rtl: | - - // Register-activation for '{path}' {alias} - assign {path}_accss = b2r.addr == {addr}; - assign {path}_sw_wr = {path}_accss && b2r.w_vld; - assign {path}_sw_rd = {path}_accss && b2r.r_vld; - signals: - - name: '{path}_sw_wr' - signal_type: 'logic' - - name: '{path}_sw_rd' - signal_type: 'logic' - - name: '{path}_accss' - signal_type: 'logic' -rw_wire_assign_multi_dim: +access_wire_comment: rtl: |- // Register-activation for '{path}' {alias} +access_wire_assign_1_dim: + rtl: |- + assign {path}_accss = b2r.addr == {addr}; + signals: + - name: '{path}_accss' + signal_type: 'logic' +access_wire_assign_multi_dim: + rtl: |- assign {path}_accss{genvars} = b2r.addr == {addr}+({genvars_sum}); - assign {path}_sw_wr{genvars} = {path}_accss{genvars} && b2r.w_vld; + signals: + - name: '{path}_accss' + signal_type: 'logic' +read_wire_assign: + rtl: |- assign {path}_sw_rd{genvars} = {path}_accss{genvars} && b2r.r_vld; + signals: + - name: '{path}_sw_rd' + signal_type: 'logic' +read_wire_assign_0: + rtl: |- + assign {path}_sw_rd{genvars} = 0; + signals: + - name: '{path}_sw_rd' + signal_type: 'logic' +write_wire_assign: + rtl: |- + assign {path}_sw_wr{genvars} = {path}_accss{genvars} && b2r.w_vld; signals: - name: '{path}_sw_wr' signal_type: 'logic' - - name: '{path}_sw_rd' +write_wire_assign_0: + rtl: |- + assign {path}_sw_wr{genvars} = 0; + signals: + - name: '{path}_sw_wr' signal_type: 'logic' - - name: '{path}_accss' - signal_type: 'logic' -rw_wire_assign_any_alias: +rw_wire_assign_any_alias: rtl: |- // Combined register activation. These will become active - // _any_ alias accesses a certain register. - assign {path}__any_alias_sw_wr{genvars} = {sw_wrs_w_genvars}; assign {path}__any_alias_sw_rd{genvars} = {sw_rds_w_genvars}; + assign {path}__any_alias_sw_wr{genvars} = {sw_wrs_w_genvars}; signals: - - name: '{path}__any_alias_sw_wr' - signal_type: 'logic' - name: '{path}__any_alias_sw_rd' signal_type: 'logic' + - name: '{path}__any_alias_sw_wr' + signal_type: 'logic' reg_comment: |- /*******************************************************************