mirror of
https://github.com/Silicon1602/srdl2sv.git
synced 2024-12-22 15:08:39 +00:00
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:
parent
f50d65d2d2
commit
9385f59ac7
@ -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
|
||||||
|
@ -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})
|
||||||
|
Loading…
Reference in New Issue
Block a user