Ensure that sw_rd/sw_wr wires are only generated if they are required

This commit is contained in:
Dennis Potter 2021-10-02 00:32:04 -07:00
parent 8756945a6d
commit dc37c87944
Signed by: Dennis
GPG Key ID: 186A8AD440942BAF
4 changed files with 159 additions and 67 deletions

View File

@ -40,8 +40,16 @@ class Component():
self.config = config.copy() self.config = config.copy()
# By default, registers and fields are not interrupt registers # By default, registers and fields are not interrupt registers
self.intr = False self.properties = {
self.halt = False '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 # Create logger object
self.create_logger("{}".format(self.full_path), config) self.create_logger("{}".format(self.full_path), config)

View File

@ -76,6 +76,10 @@ class Field(Component):
# Append to list of registers that can write # Append to list of registers that can write
self.writable_by.add(path_wo_field) 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') swwe = obj.get_property('swwe')
swwel = obj.get_property('swwel') swwel = obj.get_property('swwel')
@ -114,7 +118,7 @@ class Field(Component):
if onwrite: if onwrite:
if onwrite == OnWriteType.wuser: 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): elif onwrite in (OnWriteType.wclr, OnWriteType.wset):
access_rtl['sw_write'][0].append( access_rtl['sw_write'][0].append(
self.process_yaml( self.process_yaml(
@ -177,10 +181,14 @@ class Field(Component):
# Append to list of registers that can read # Append to list of registers that can read
self.readable_by.add(path_wo_field) self.readable_by.add(path_wo_field)
self.properties['sw_wr'] = True
# Set onread properties # Set onread properties
if onread == OnReadType.ruser: if onread == OnReadType.ruser:
self.logger.error("The OnReadType.ruser is not yet supported!") self.logger.error("The OnReadType.ruser is not yet supported!")
elif onread: elif onread:
self.properties['sw_rd_wire'] = True
access_rtl['sw_read'][0].append( access_rtl['sw_read'][0].append(
self.process_yaml( self.process_yaml(
Field.templ_dict[str(onread)], Field.templ_dict[str(onread)],
@ -636,7 +644,7 @@ class Field(Component):
) )
# Check if SW has write access to the field # 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( swmod_assigns.append(
self.process_yaml( self.process_yaml(
Field.templ_dict['swmod_assign'], Field.templ_dict['swmod_assign'],
@ -666,10 +674,13 @@ class Field(Component):
swmod_props = '' swmod_props = ''
if self.obj.get_property('swacc') and \ 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.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( swacc_props = self.process_yaml(
Field.templ_dict['swacc_assign'], Field.templ_dict['swacc_assign'],
{'path': self.path_underscored, {'path': self.path_underscored,
@ -691,7 +702,7 @@ class Field(Component):
def __add_interrupt(self): def __add_interrupt(self):
if self.obj.get_property('intr'): if self.obj.get_property('intr'):
self.intr = True self.properties['intr'] = True
# Determine what causes the interrupt to get set, i.e., # Determine what causes the interrupt to get set, i.e.,
# is it a trigger that is passed to the module through an # 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.get_signal_name(haltmask)
]) ])
self.halt = True self.properties['halt'] = True
elif haltenable := self.obj.get_property('haltenable'): elif haltenable := self.obj.get_property('haltenable'):
self.itr_haltmasked = ' && '.join([ self.itr_haltmasked = ' && '.join([
self.register_name, self.register_name,
self.get_signal_name(haltenable) self.get_signal_name(haltenable)
]) ])
self.halt = True self.properties['halt'] = True
else: else:
self.itr_haltmasked = self.register_name self.itr_haltmasked = self.register_name
else: else:
self.itr_masked = False self.itr_masked = False
self.itr_haltmasked = False self.itr_haltmasked = False
return self.intr return self.properties['intr']
def __add_hw_access(self): def __add_hw_access(self):
# Mutually exclusive. systemrdl-compiler performs check for this # Mutually exclusive. systemrdl-compiler performs check for this
@ -957,7 +968,7 @@ class Field(Component):
) )
def create_external_rtl(self): 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): for i, alias in enumerate(self.path_underscored_vec):
# Create bit-wise mask so that outside logic knows what # Create bit-wise mask so that outside logic knows what
# bits it may change # 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): for i, alias in enumerate(self.path_underscored_vec):
self.rtl_footer.append(self.process_yaml( self.rtl_footer.append(self.process_yaml(
Field.templ_dict['external_rd_assignments'], Field.templ_dict['external_rd_assignments'],

View File

@ -42,9 +42,9 @@ class Register(Component):
self.config, self.config,
glbl_settings) glbl_settings)
# Get certain properties from field that apply to whole register # Get properties from field that apply to whole register
self.intr = self.intr or self.children[field_range].intr for key in self.properties:
self.halt = self.halt or self.children[field_range].halt self.properties[key] |= self.children[field_range].properties[key]
# Perform sanity check # Perform sanity check
self.children[field_range].sanity_checks() self.children[field_range].sanity_checks()
@ -111,7 +111,7 @@ class Register(Component):
# no mask or enables are specified. # no mask or enables are specified.
# c) The halt property shall only be present if haltmask or haltenable is # c) The halt property shall only be present if haltmask or haltenable is
# specified on at least one field in the register. # 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(Register.templ_dict['interrupt_comment']['rtl'])
self.rtl_footer.append( self.rtl_footer.append(
@ -125,7 +125,7 @@ class Register(Component):
) )
) )
if self.halt: if self.properties['halt']:
self.rtl_footer.append( self.rtl_footer.append(
self.process_yaml( self.process_yaml(
Register.templ_dict['interrupt_halt'], Register.templ_dict['interrupt_halt'],
@ -328,38 +328,100 @@ class Register(Component):
self.obj.current_idx = [0] self.obj.current_idx = [0]
if self.total_dimensions: if self.total_dimensions:
rw_wire_assign_field = 'rw_wire_assign_multi_dim' access_wire_assign_field = 'access_wire_assign_multi_dim'
else: else:
rw_wire_assign_field = 'rw_wire_assign_1_dim' access_wire_assign_field = 'access_wire_assign_1_dim'
[self.rtl_header.append( for i, x in enumerate(self.name_addr_mappings):
self.process_yaml( self.rtl_header.append(
Register.templ_dict[rw_wire_assign_field], self.process_yaml(
{'path': x[0], Register.templ_dict['access_wire_comment'],
'addr': x[1], {'path': x[0],
'alias': '(alias)' if i > 0 else '', '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_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 # Add combined signal to be used for general access of the register
self.rtl_header.append( if self.properties['swacc']:
self.process_yaml( self.rtl_header.append(
Register.templ_dict['rw_wire_assign_any_alias'], self.process_yaml(
{'path': self.name_addr_mappings[0][0], Register.templ_dict['rw_wire_assign_any_alias'],
'genvars': self.genvars_str, {'path': self.name_addr_mappings[0][0],
'sw_rds_w_genvars': ' || '.join( 'genvars': self.genvars_str,
[''.join([x[0], '_sw_rd', self.genvars_str]) 'sw_rds_w_genvars': ' || '.join(
for x in self.name_addr_mappings]), [''.join([x[0], '_sw_rd', self.genvars_str])
'sw_wrs_w_genvars': ' || '.join( for x in self.name_addr_mappings]),
[''.join([x[0], '_sw_wr', self.genvars_str]) 'sw_wrs_w_genvars': ' || '.join(
for x in self.name_addr_mappings]) [''.join([x[0], '_sw_wr', self.genvars_str])
} for x in self.name_addr_mappings])
}
)
) )
)
def __add_signal_instantiations(self): def __add_signal_instantiations(self):
# Add wire/register instantiations # Add wire/register instantiations

View File

@ -1,44 +1,55 @@
--- ---
rw_wire_assign_1_dim: access_wire_comment:
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:
rtl: |- rtl: |-
// Register-activation for '{path}' {alias} // 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}_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; 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: signals:
- name: '{path}_sw_wr' - name: '{path}_sw_wr'
signal_type: 'logic' 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' signal_type: 'logic'
- name: '{path}_accss' rw_wire_assign_any_alias:
signal_type: 'logic'
rw_wire_assign_any_alias:
rtl: |- rtl: |-
// Combined register activation. These will become active // 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_rd{genvars} = {sw_rds_w_genvars};
assign {path}__any_alias_sw_wr{genvars} = {sw_wrs_w_genvars};
signals: signals:
- name: '{path}__any_alias_sw_wr'
signal_type: 'logic'
- name: '{path}__any_alias_sw_rd' - name: '{path}__any_alias_sw_rd'
signal_type: 'logic' signal_type: 'logic'
- name: '{path}__any_alias_sw_wr'
signal_type: 'logic'
reg_comment: |- reg_comment: |-
/******************************************************************* /*******************************************************************