Add counters (w/o threshold property and w/o an overflow property)

Saturating and non-saturating counters are supported. Furthermore,
dynamic and static incrvalues and the incrwidth property is supported.
This commit is contained in:
Dennis Potter 2021-06-27 17:04:48 +02:00
parent f50d65d2d2
commit 9385f59ac7
Signed by: Dennis
GPG Key ID: 186A8AD440942BAF
2 changed files with 324 additions and 14 deletions

View File

@ -1,6 +1,7 @@
import math import math
import importlib.resources as pkg_resources import importlib.resources as pkg_resources
import sys
import yaml import yaml
from systemrdl.node import FieldNode, SignalNode from systemrdl.node import FieldNode, SignalNode
@ -47,6 +48,7 @@ class Field(Component):
self.__add_hw_access() self.__add_hw_access()
self.__add_combo() self.__add_combo()
self.__add_swmod_swacc() self.__add_swmod_swacc()
self.__add_counter()
self.add_sw_access(obj) self.add_sw_access(obj)
@ -206,6 +208,240 @@ class Field(Component):
self.access_rtl['sw_read'] = [access_rtl['sw_read']] self.access_rtl['sw_read'] = [access_rtl['sw_read']]
self.access_rtl['sw_write'] = [access_rtl['sw_write']] self.access_rtl['sw_write'] = [access_rtl['sw_write']]
def __add_counter(self):
if self.obj.get_property('counter'):
self.logger.debug("Detected counter property")
# Determine saturation values
if isinstance(self.obj.get_property('incrsaturate'), bool):
if self.obj.get_property('incrsaturate'):
incr_sat_value = 2**self.obj.width-1
else:
incr_sat_value = False
else:
incr_sat_value = self.obj.get_property('incrsaturate')
if isinstance(self.obj.get_property('decrsaturate'), bool):
if self.obj.get_property('decrsaturate'):
decr_sat_value = 2**self.obj.width-1
else:
decr_sat_value = False
else:
decr_sat_value = self.obj.get_property('decrsaturate')
# Determine with what value the counter is incremented
# According to the spec, the incrvalue/decrvalue default to '1'
obj_incr_value = self.obj.get_property('incrvalue')
obj_decr_value = self.obj.get_property('decrvalue')
obj_incr_width = self.obj.get_property('incrwidth')
obj_decr_width = self.obj.get_property('decrwidth')
if obj_incr_value == 0:
incr_value = None
incr_width = 0
elif obj_incr_value is None:
if obj_incr_width:
# Decrement value is not set. Check if incrwidth is set and use
# that is applicable
incr_value = False
incr_width = obj_incr_width
# Doesn't return RTL, only adds input port
self.process_yaml(
Field.templ_dict['counter_incr_input'],
{'path': self.path_underscored,
'genvars': self.genvars_str,
'incr_width': incr_width-1
}
)
else:
# Otherwise, use default value according to LRM
incr_value = '1'
incr_width = 1
elif isinstance(obj_incr_value, int):
incr_value = str(obj_incr_value)
incr_width = math.floor(math.log2(obj_incr_value)+1)
if obj_incr_width:
self.logger.error(
"The 'incrwidth' and 'incrvalue' properties are both "\
"defined. This is not legal and the incrwidth property "\
"will be ignored!")
else:
incr_value = self.get_signal_name(obj_incr_value)
incr_width = obj_incr_value.width
if obj_incr_value.width > self.obj.width:
self.logger.error(
"Width of 'incr_value' signal '{}' is wider than current "\
"counter field. This could potentially cause ugly errors.".format(
obj_incr_value.get_path()))
if obj_incr_width:
self.logger.error(
"The 'incrwidth' and 'incrvalue' properties are both "\
"defined. This is not legal and the incrwidth property "\
"will be ignored!")
if incr_value:
self.rtl_footer.append(
self.process_yaml(
Field.templ_dict['counter_internal_incr_signal'],
{'path': self.path_underscored,
'genvars': self.genvars_str,
'incr_width': incr_width-1,
'incr_value': incr_value,
}
)
)
if obj_decr_value == 0:
decr_value = None
decr_width = 0
elif obj_decr_value is None:
if obj_decr_width:
# Decrement value is not set. Check if decrwidth is set and use
# that is applicable
decr_value = False
decr_width = obj_decr_width
# Doesn't return RTL, only adds input port
self.process_yaml(
Field.templ_dict['counter_decr_input'],
{'path': self.path_underscored,
'genvars': self.genvars_str,
'decr_width': decr_width-1
}
)
else:
# Otherwise, use default value according to LRM
decr_value = '1'
decr_width = 1
elif isinstance(obj_decr_value, int):
decr_value = str(obj_decr_value)
decr_width = math.floor(math.log2(obj_decr_value)+1)
if obj_decr_width:
self.logger.error(
"The 'decrwidth' and 'decrvalue' properties are both "\
"defined. This is not legal and the decrwidth property "\
"will be ignored!")
else:
decr_value = self.get_signal_name(obj_decr_value)
decr_width = obj_decr_value.width
if obj_decr_value.width > self.obj.width:
self.logger.error(
"Width of 'decr_value' signal '{}' is wider than current "\
"counter field. This could potentially cause ugly errors.".format(
obj_decr_value.get_path()))
if obj_decr_width:
self.logger.error(
"The 'decrwidth' and 'decrvalue' properties are both "\
"defined. This is not legal and the decrwidth property "\
"will be ignored!")
if decr_value:
self.rtl_footer.append(
self.process_yaml(
Field.templ_dict['counter_internal_decr_signal'],
{'path': self.path_underscored,
'genvars': self.genvars_str,
'decr_width': decr_width-1,
'decr_value': decr_value,
}
)
)
if (incr_width or incr_value) and (decr_width or decr_value):
sat_condition = []
if incr_sat_value:
sat_condition.append(
self.process_yaml(
Field.templ_dict['incr_decr_sat_counter_condition'],
{'path': self.path_underscored,
'genvars': self.genvars_str,
'greater_smaller': '>',
'sat_value': incr_sat_value
}
)
)
if decr_sat_value:
if sat_condition:
sat_condition.append(' && ')
sat_condition.append(
self.process_yaml(
Field.templ_dict['incr_decr_sat_counter_condition'],
{'path': self.path_underscored,
'genvars': self.genvars_str,
'greater_smaller': '<',
'sat_value': decr_sat_value
}
)
)
counter_logic = self.process_yaml(
Field.templ_dict['incr_decr_counter'],
{'path': self.path_underscored,
'genvars': self.genvars_str,
'incr_decr_sat_counter_condition': ''.join(sat_condition),
}
)
elif incr_width or incr_value:
sat_condition = self.process_yaml(
Field.templ_dict['incr_sat_counter_condition'],
{'path': self.path_underscored,
'genvars': self.genvars_str,
'sat_value': incr_sat_value,
}
) if incr_sat_value else '1'
counter_logic = self.process_yaml(
Field.templ_dict['incr_counter'],
{'path': self.path_underscored,
'genvars': self.genvars_str,
'incr_sat_counter_condition': sat_condition,
}
)
elif decr_width or decr_value:
sat_condition = self.process_yaml(
Field.templ_dict['decr_sat_counter_condition'],
{'path': self.path_underscored,
'genvars': self.genvars_str,
'sat_value': decr_sat_value,
}
) if decr_sat_value else '1'
counter_logic = self.process_yaml(
Field.templ_dict['decr_counter'],
{'path': self.path_underscored,
'genvars': self.genvars_str,
'decr_sat_counter_condition': sat_condition,
}
)
else:
self.logger.fatal("Illegal counter configuration! Both 'incr_value' "\
"and 'decr_value' are forced to 0. If you intended "\
"to use 'incr_width' or 'decr_width', simply don't "\
"force 'incr_value' or 'decr_value' to any value.")
sys.exit(1)
self.rtl_footer.append(
self.process_yaml(
Field.templ_dict['counter'],
{'path': self.path_underscored,
'genvars': self.genvars_str,
'counter_logic': counter_logic,
'field_type': self.field_type,
}
)
)
def __add_swmod_swacc(self): def __add_swmod_swacc(self):
if self.obj.get_property('swmod'): if self.obj.get_property('swmod'):
self.logger.debug("Field has swmod property") self.logger.debug("Field has swmod property")
@ -284,7 +520,17 @@ class Field(Component):
def __add_hw_access(self): def __add_hw_access(self):
# Define hardware access (if applicable) # Define hardware access (if applicable)
if self.obj.get_property('hw') in (AccessType.rw, AccessType.w): if self.obj.get_property('counter'):
self.access_rtl['hw_write'] = ([
self.process_yaml(
Field.templ_dict['hw_access_counter'],
{'path': self.path_underscored,
'genvars': self.genvars_str,
'field_type': self.field_type}
)
],
False)
elif self.obj.get_property('hw') in (AccessType.rw, AccessType.w):
write_condition = 'hw_access_we_wel' if self.we_or_wel else 'hw_access_no_we_wel' write_condition = 'hw_access_we_wel' if self.we_or_wel else 'hw_access_no_we_wel'
# if-line of hw-access # if-line of hw-access

View File

@ -56,6 +56,17 @@ hw_access_field:
input_ports: input_ports:
- name: '{path}_in' - name: '{path}_in'
signal_type: '{field_type}' signal_type: '{field_type}'
hw_access_counter:
rtl: |-
if ({path}_update_cnt{genvars})
begin
{path}_q{genvars} <= {path}_next{genvars};
end
signals:
- name: '{path}_update_cnt'
signal_type: 'logic'
- name: '{path}_next'
signal_type: '{field_type}'
end_field_ff: end_field_ff:
rtl: |- rtl: |-
end // of {path}'s always_ff end // of {path}'s always_ff
@ -181,38 +192,91 @@ swmod_assign:
signal_type: 'logic' signal_type: 'logic'
counter: counter:
rtl: |- rtl: |-
// Combinational logic that implements counter
always_comb always_comb
begin begin
{path}_next{genvars} = {path}_q{genvars}; {path}_next{genvars} = {path}_q{genvars};
{path}_update_cnt{genvars} = 0; {path}_update_cnt{genvars} = 0;
{incr_counter} {counter_logic}
{decr_counter}
end end
signals:
- name: '{path}_update_cnt'
signal_type: 'logic'
- name: '{path}_next'
signal_type: '{field_type}'
counter_internal_incr_signal:
rtl: |-
assign {path}_incr_val{genvars} = {incr_value};
signals:
- name: '{path}_incr_val'
signal_type: 'logic [{incr_width}:0]'
counter_internal_decr_signal:
rtl: |-
assign {path}_decr_val{genvars} = {decr_value};
signals:
- name: '{path}_decr_val'
signal_type: 'logic [{decr_width}:0]'
counter_incr_input:
rtl: ''
input_ports:
- name: '{path}_incr_val'
signal_type: 'logic [{incr_width}:0]'
counter_decr_input:
rtl: ''
input_ports:
- name: '{path}_decr_val'
signal_type: 'logic [{decr_width}:0]'
incr_counter: incr_counter:
rtl: |- rtl: |-
{incr_counter_condition} if ({path}_incr{genvars})
begin begin
{path}_next{genvars} += {path}_{operation_str}_val{genvars}; if ({incr_sat_counter_condition})
begin
{path}_next{genvars} += {path}_incr_val{genvars};
{path}_update_cnt{genvars} = 1; {path}_update_cnt{genvars} = 1;
end end
end
input_ports:
- name: '{path}_incr'
signal_type: 'logic'
decr_counter: decr_counter:
rtl: |- rtl: |-
{incr_counter_condition} if ({path}_decr{genvars})
begin begin
{path}_next{genvars} += {path}_{operation_str}_val{genvars}; if ({decr_sat_counter_condition})
begin
{path}_next{genvars} -= {path}_decr_val{genvars};
{path}_update_cnt{genvars} = 1; {path}_update_cnt{genvars} = 1;
end end
incr_counter_condition: end
input_ports:
- name: '{path}_decr'
signal_type: 'logic'
incr_decr_counter:
rtl: |- rtl: |-
if ({path}_incr{genvars}) if ({path}_incr{genvars} || {path}_decr{genvars})
begin
if ({incr_decr_sat_counter_condition})
begin
{path}_next{genvars} += {path}_incr_val{genvars};
{path}_next{genvars} -= {path}_decr_val{genvars};
{path}_update_cnt{genvars} = 1;
end
end
input_ports:
- name: '{path}_incr'
signal_type: 'logic'
- name: '{path}_decr'
signal_type: 'logic'
incr_sat_counter_condition: incr_sat_counter_condition:
rtl: |- rtl: |-
if ({path}_incr{genvars} && {path}_next{genvars} + {path}_incr_val{genvars} <= {sat_value}) {path}_next{genvars} + {path}_incr_val{genvars} <= {sat_value}
decr_counter_condition:
rtl: |-
if ({path}_decr{genvars})
decr_sat_counter_condition: decr_sat_counter_condition:
rtl: |- rtl: |-
if ({path}_decr{genvars} && {path}_next{genvars} - {path}_decr_val{genvars} >= {sat_value}) {path}_next{genvars} - {path}_decr_val{genvars} >= {sat_value}
incr_decr_sat_counter_condition:
rtl: |-
({path}_next{genvars} + {path}_incr_val{genvars} - {path}_decr_val{genvars} {greater_smaller}= {sat_value})