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()
# 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)

View File

@ -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'],

View File

@ -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

View File

@ -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'
signal_type: 'logic'
- name: '{path}_accss'
write_wire_assign_0:
rtl: |-
assign {path}_sw_wr{genvars} = 0;
signals:
- name: '{path}_sw_wr'
signal_type: 'logic'
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: |-
/*******************************************************************