Add counter support
This commit is contained in:
@@ -60,8 +60,12 @@ class Dereferencer:
|
||||
return self.get_value(reset_value)
|
||||
else:
|
||||
# No reset value defined!
|
||||
# Callers shall ensure this is impossible
|
||||
raise RuntimeError
|
||||
obj.env.msg.warning(
|
||||
"Field '%s' is a constant but does not have a known value (missing reset). Assigning it a value of X."
|
||||
% obj.inst_name,
|
||||
obj.inst.inst_src_ref
|
||||
)
|
||||
return "'X"
|
||||
|
||||
if isinstance(obj, SignalNode):
|
||||
# Signals are always inputs from the hwif
|
||||
@@ -106,28 +110,12 @@ class Dereferencer:
|
||||
}:
|
||||
return self.get_value(field.get_property(prop_name))
|
||||
|
||||
# Counter properties
|
||||
if prop_name == 'incr':
|
||||
prop_value = field.get_property(prop_name)
|
||||
if prop_value is None:
|
||||
# unset by the user, points to the implied internal signal
|
||||
return self.field_logic.get_counter_incr_identifier(field)
|
||||
else:
|
||||
return self.get_value(prop_value)
|
||||
elif prop_name == 'decr':
|
||||
prop_value = field.get_property(prop_name)
|
||||
if prop_value is None:
|
||||
# unset by the user, points to the implied internal signal
|
||||
return self.field_logic.get_counter_decr_identifier(field)
|
||||
else:
|
||||
return self.get_value(prop_value)
|
||||
|
||||
# Field Next
|
||||
if prop_name == "next":
|
||||
prop_value = field.get_property(prop_name)
|
||||
if prop_value is None:
|
||||
# unset by the user, points to the implied internal signal
|
||||
return self.field_logic.get_field_next_identifier(field)
|
||||
return self.field_logic.get_field_combo_identifier(field, "next")
|
||||
else:
|
||||
return self.get_value(prop_value)
|
||||
|
||||
@@ -175,19 +163,31 @@ class Dereferencer:
|
||||
if prop_name == "swmod":
|
||||
return self.field_logic.get_swmod_identifier(field)
|
||||
|
||||
raise RuntimeError("Unhandled reference to: %s->%s" % (field, prop_name))
|
||||
|
||||
"""
|
||||
TODO:
|
||||
Resolves to an internal signal used in the field's logic
|
||||
decrsaturate
|
||||
decrthreshold
|
||||
incrsaturate
|
||||
incrthreshold
|
||||
overflow
|
||||
saturate
|
||||
threshold
|
||||
"""
|
||||
# translate aliases
|
||||
aliases = {
|
||||
"saturate": "incrsaturate",
|
||||
"threshold": "incrthreshold",
|
||||
}
|
||||
prop_name = aliases.get(prop_name, prop_name)
|
||||
|
||||
# Counter properties
|
||||
if prop_name == 'incr':
|
||||
return self.field_logic.get_counter_incr_strobe(field)
|
||||
if prop_name == 'decr':
|
||||
return self.field_logic.get_counter_decr_strobe(field)
|
||||
|
||||
if prop_name in {
|
||||
'decrsaturate',
|
||||
'decrthreshold',
|
||||
'incrsaturate',
|
||||
'incrthreshold',
|
||||
'overflow',
|
||||
'underflow',
|
||||
}:
|
||||
return self.field_logic.get_field_combo_identifier(field, prop_name)
|
||||
|
||||
raise RuntimeError("Unhandled reference to: %s->%s" % (field, prop_name))
|
||||
|
||||
|
||||
def get_reg_propref_value(self, reg: RegNode, prop_name: str) -> str:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from systemrdl.rdltypes import PropertyReference, PrecedenceType
|
||||
from systemrdl.node import Node
|
||||
|
||||
from .bases import AssignmentPrecedence, NextStateConditional
|
||||
from . import sw_onread
|
||||
@@ -61,41 +62,105 @@ class FieldLogic:
|
||||
#---------------------------------------------------------------------------
|
||||
# Field utility functions
|
||||
#---------------------------------------------------------------------------
|
||||
def get_storage_identifier(self, node: 'FieldNode') -> str:
|
||||
def get_storage_identifier(self, field: 'FieldNode') -> str:
|
||||
"""
|
||||
Returns the Verilog string that represents the storage register element
|
||||
for the referenced field
|
||||
"""
|
||||
assert node.implements_storage
|
||||
path = get_indexed_path(self.top_node, node)
|
||||
assert field.implements_storage
|
||||
path = get_indexed_path(self.top_node, field)
|
||||
return f"field_storage.{path}"
|
||||
|
||||
def get_field_next_identifier(self, node: 'FieldNode') -> str:
|
||||
def get_field_combo_identifier(self, field: 'FieldNode', name: str) -> str:
|
||||
"""
|
||||
Returns a Verilog string that represents the field's next-state.
|
||||
This is specifically for use in Field->next property references.
|
||||
Returns a Verilog string that represents a field's internal combinational
|
||||
signal.
|
||||
"""
|
||||
assert node.implements_storage
|
||||
path = get_indexed_path(self.top_node, node)
|
||||
return f"field_combo.{path}.next"
|
||||
assert field.implements_storage
|
||||
path = get_indexed_path(self.top_node, field)
|
||||
return f"field_combo.{path}.{name}"
|
||||
|
||||
def get_counter_incr_identifier(self, field: 'FieldNode') -> str:
|
||||
def get_counter_incr_strobe(self, field: 'FieldNode') -> str:
|
||||
"""
|
||||
Return the Veriog string that represents the field's inferred incr/decr strobe signal.
|
||||
prop_ref will be either an incr or decr property reference, and it is already known that
|
||||
the incr/decr properties are not explicitly set by the user and are therefore inferred.
|
||||
Return the Verilog string that represents the field's incr strobe signal.
|
||||
"""
|
||||
# TODO: Implement this
|
||||
raise NotImplementedError
|
||||
prop_value = field.get_property('incr')
|
||||
if prop_value:
|
||||
return self.exp.dereferencer.get_value(prop_value)
|
||||
|
||||
def get_counter_decr_identifier(self, field: 'FieldNode') -> str:
|
||||
# unset by the user, points to the implied input signal
|
||||
return self.exp.hwif.get_implied_prop_input_identifier(field, "incr")
|
||||
|
||||
def get_counter_incrvalue(self, field: 'FieldNode') -> str:
|
||||
"""
|
||||
Return the Veriog string that represents the field's inferred incr/decr strobe signal.
|
||||
prop_ref will be either an incr or decr property reference, and it is already known that
|
||||
the incr/decr properties are not explicitly set by the user and are therefore inferred.
|
||||
Return the string that represents the field's increment value
|
||||
"""
|
||||
# TODO: Implement this
|
||||
raise NotImplementedError
|
||||
incrvalue = field.get_property('incrvalue')
|
||||
if incrvalue is not None:
|
||||
return self.exp.dereferencer.get_value(incrvalue)
|
||||
if field.get_property('incrwidth'):
|
||||
return self.exp.hwif.get_implied_prop_input_identifier(field, "incrvalue")
|
||||
return "1'b1"
|
||||
|
||||
def get_counter_incrsaturate_value(self, field: 'FieldNode') -> str:
|
||||
prop_value = field.get_property('incrsaturate')
|
||||
if prop_value is True:
|
||||
return self.exp.dereferencer.get_value(2**field.width - 1)
|
||||
return self.exp.dereferencer.get_value(prop_value)
|
||||
|
||||
def counter_incrsaturates(self, field: 'FieldNode') -> bool:
|
||||
"""
|
||||
Returns True if the counter saturates
|
||||
"""
|
||||
return field.get_property('incrsaturate') is not False
|
||||
|
||||
def get_counter_incrthreshold_value(self, field: 'FieldNode') -> str:
|
||||
prop_value = field.get_property('incrthreshold')
|
||||
if isinstance(prop_value, bool):
|
||||
# No explicit value set. use max
|
||||
return self.exp.dereferencer.get_value(2**field.width - 1)
|
||||
return self.exp.dereferencer.get_value(prop_value)
|
||||
|
||||
def get_counter_decr_strobe(self, field: 'FieldNode') -> str:
|
||||
"""
|
||||
Return the Verilog string that represents the field's incr strobe signal.
|
||||
"""
|
||||
prop_value = field.get_property('decr')
|
||||
if prop_value:
|
||||
return self.exp.dereferencer.get_value(prop_value)
|
||||
|
||||
# unset by the user, points to the implied input signal
|
||||
return self.exp.hwif.get_implied_prop_input_identifier(field, "decr")
|
||||
|
||||
def get_counter_decrvalue(self, field: 'FieldNode') -> str:
|
||||
"""
|
||||
Return the string that represents the field's decrement value
|
||||
"""
|
||||
decrvalue = field.get_property('decrvalue')
|
||||
if decrvalue is not None:
|
||||
return self.exp.dereferencer.get_value(decrvalue)
|
||||
if field.get_property('decrwidth'):
|
||||
return self.exp.hwif.get_implied_prop_input_identifier(field, "decrvalue")
|
||||
return "1'b1"
|
||||
|
||||
def get_counter_decrsaturate_value(self, field: 'FieldNode') -> str:
|
||||
prop_value = field.get_property('decrsaturate')
|
||||
if prop_value is True:
|
||||
return "'d0"
|
||||
return self.exp.dereferencer.get_value(prop_value)
|
||||
|
||||
def counter_decrsaturates(self, field: 'FieldNode') -> bool:
|
||||
"""
|
||||
Returns True if the counter saturates
|
||||
"""
|
||||
return field.get_property('decrsaturate') is not False
|
||||
|
||||
def get_counter_decrthreshold_value(self, field: 'FieldNode') -> str:
|
||||
prop_value = field.get_property('decrthreshold')
|
||||
if isinstance(prop_value, bool):
|
||||
# No explicit value set. use min
|
||||
return "'d0"
|
||||
return self.exp.dereferencer.get_value(prop_value)
|
||||
|
||||
def get_swacc_identifier(self, field: 'FieldNode') -> str:
|
||||
"""
|
||||
|
||||
@@ -39,8 +39,26 @@ class CombinationalStructGenerator(RDLStructGenerator):
|
||||
self.add_member("load_next")
|
||||
for signal in extra_combo_signals.values():
|
||||
self.add_member(signal.name, signal.width)
|
||||
if node.is_up_counter:
|
||||
self.add_up_counter_members(node)
|
||||
if node.is_down_counter:
|
||||
self.add_down_counter_members(node)
|
||||
self.pop_struct()
|
||||
|
||||
def add_up_counter_members(self, node: 'FieldNode') -> None:
|
||||
self.add_member('incrthreshold')
|
||||
if self.field_logic.counter_incrsaturates(node):
|
||||
self.add_member('incrsaturate')
|
||||
else:
|
||||
self.add_member('overflow')
|
||||
|
||||
def add_down_counter_members(self, node: 'FieldNode') -> None:
|
||||
self.add_member('decrthreshold')
|
||||
if self.field_logic.counter_decrsaturates(node):
|
||||
self.add_member('decrsaturate')
|
||||
else:
|
||||
self.add_member('underflow')
|
||||
|
||||
|
||||
class FieldStorageStructGenerator(RDLStructGenerator):
|
||||
|
||||
@@ -92,10 +110,12 @@ class FieldLogicGenerator(RDLForLoopGenerator):
|
||||
'node': node,
|
||||
'reset': reset_value_str,
|
||||
'field_path': get_indexed_path(self.exp.top_node, node),
|
||||
'field_logic': self.field_logic,
|
||||
'extra_combo_signals': extra_combo_signals,
|
||||
'conditionals': conditionals,
|
||||
'resetsignal': resetsignal,
|
||||
'get_always_ff_event': get_always_ff_event,
|
||||
'get_value': self.exp.dereferencer.get_value,
|
||||
}
|
||||
self.add_content(self.field_storage_template.render(context))
|
||||
|
||||
@@ -144,3 +164,16 @@ class FieldLogicGenerator(RDLForLoopGenerator):
|
||||
self.add_content(
|
||||
f"assign {output_identifier} = {value};"
|
||||
)
|
||||
|
||||
if node.get_property('incrthreshold') is not False: # (explicitly not False. Not 0)
|
||||
output_identifier = self.exp.hwif.get_implied_prop_output_identifier(node, "incrthreshold")
|
||||
value = self.field_logic.get_field_combo_identifier(node, 'incrthreshold')
|
||||
self.add_content(
|
||||
f"assign {output_identifier} = {value};"
|
||||
)
|
||||
if node.get_property('decrthreshold') is not False: # (explicitly not False. Not 0)
|
||||
output_identifier = self.exp.hwif.get_implied_prop_output_identifier(node, "decrthreshold")
|
||||
value = self.field_logic.get_field_combo_identifier(node, 'decrthreshold')
|
||||
self.add_content(
|
||||
f"assign {output_identifier} = {value};"
|
||||
)
|
||||
|
||||
@@ -36,8 +36,8 @@ class HWSet(NextStateConditional):
|
||||
next_val = "'1"
|
||||
|
||||
return [
|
||||
f"field_combo.{field_path}.next = {next_val};",
|
||||
f"field_combo.{field_path}.load_next = '1;",
|
||||
f"next_c = {next_val};",
|
||||
f"load_next_c = '1;",
|
||||
]
|
||||
|
||||
|
||||
@@ -71,6 +71,6 @@ class HWClear(NextStateConditional):
|
||||
next_val = "'0"
|
||||
|
||||
return [
|
||||
f"field_combo.{field_path}.next = {next_val};",
|
||||
f"field_combo.{field_path}.load_next = '1;",
|
||||
f"next_c = {next_val};",
|
||||
f"load_next_c = '1;",
|
||||
]
|
||||
|
||||
@@ -39,8 +39,8 @@ class AlwaysWrite(NextStateConditional):
|
||||
next_val = self.exp.hwif.get_input_identifier(field)
|
||||
|
||||
return [
|
||||
f"field_combo.{field_path}.next = {next_val};",
|
||||
f"field_combo.{field_path}.load_next = '1;",
|
||||
f"next_c = {next_val};",
|
||||
f"load_next_c = '1;",
|
||||
]
|
||||
|
||||
class WEWrite(AlwaysWrite):
|
||||
|
||||
@@ -24,8 +24,8 @@ class ClearOnRead(_OnRead):
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
field_path = self.get_field_path(field)
|
||||
return [
|
||||
f"field_combo.{field_path}.next = '0;",
|
||||
f"field_combo.{field_path}.load_next = '1;",
|
||||
f"next_c = '0;",
|
||||
f"load_next_c = '1;",
|
||||
]
|
||||
|
||||
|
||||
@@ -36,6 +36,6 @@ class SetOnRead(_OnRead):
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
field_path = self.get_field_path(field)
|
||||
return [
|
||||
f"field_combo.{field_path}.next = '1;",
|
||||
f"field_combo.{field_path}.load_next = '1;",
|
||||
f"next_c = '1;",
|
||||
f"load_next_c = '1;",
|
||||
]
|
||||
|
||||
@@ -40,8 +40,8 @@ class WriteOneSet(_OnWrite):
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
field_path = self.get_field_path(field)
|
||||
return [
|
||||
f"field_combo.{field_path}.next = field_storage.{field_path} | {self._wr_data(field)};",
|
||||
f"field_combo.{field_path}.load_next = '1;",
|
||||
f"next_c = field_storage.{field_path} | {self._wr_data(field)};",
|
||||
f"load_next_c = '1;",
|
||||
]
|
||||
|
||||
class WriteOneClear(_OnWrite):
|
||||
@@ -51,8 +51,8 @@ class WriteOneClear(_OnWrite):
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
field_path = self.get_field_path(field)
|
||||
return [
|
||||
f"field_combo.{field_path}.next = field_storage.{field_path} & ~{self._wr_data(field)};",
|
||||
f"field_combo.{field_path}.load_next = '1;",
|
||||
f"next_c = field_storage.{field_path} & ~{self._wr_data(field)};",
|
||||
f"load_next_c = '1;",
|
||||
]
|
||||
|
||||
class WriteOneToggle(_OnWrite):
|
||||
@@ -62,8 +62,8 @@ class WriteOneToggle(_OnWrite):
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
field_path = self.get_field_path(field)
|
||||
return [
|
||||
f"field_combo.{field_path}.next = field_storage.{field_path} ^ {self._wr_data(field)};",
|
||||
f"field_combo.{field_path}.load_next = '1;",
|
||||
f"next_c = field_storage.{field_path} ^ {self._wr_data(field)};",
|
||||
f"load_next_c = '1;",
|
||||
]
|
||||
|
||||
class WriteZeroSet(_OnWrite):
|
||||
@@ -73,8 +73,8 @@ class WriteZeroSet(_OnWrite):
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
field_path = self.get_field_path(field)
|
||||
return [
|
||||
f"field_combo.{field_path}.next = field_storage.{field_path} | ~{self._wr_data(field)};",
|
||||
f"field_combo.{field_path}.load_next = '1;",
|
||||
f"next_c = field_storage.{field_path} | ~{self._wr_data(field)};",
|
||||
f"load_next_c = '1;",
|
||||
]
|
||||
|
||||
class WriteZeroClear(_OnWrite):
|
||||
@@ -84,8 +84,8 @@ class WriteZeroClear(_OnWrite):
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
field_path = self.get_field_path(field)
|
||||
return [
|
||||
f"field_combo.{field_path}.next = field_storage.{field_path} & {self._wr_data(field)};",
|
||||
f"field_combo.{field_path}.load_next = '1;",
|
||||
f"next_c = field_storage.{field_path} & {self._wr_data(field)};",
|
||||
f"load_next_c = '1;",
|
||||
]
|
||||
|
||||
class WriteZeroToggle(_OnWrite):
|
||||
@@ -95,8 +95,8 @@ class WriteZeroToggle(_OnWrite):
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
field_path = self.get_field_path(field)
|
||||
return [
|
||||
f"field_combo.{field_path}.next = field_storage.{field_path} ^ ~{self._wr_data(field)};",
|
||||
f"field_combo.{field_path}.load_next = '1;",
|
||||
f"next_c = field_storage.{field_path} ^ ~{self._wr_data(field)};",
|
||||
f"load_next_c = '1;",
|
||||
]
|
||||
|
||||
class WriteClear(_OnWrite):
|
||||
@@ -106,8 +106,8 @@ class WriteClear(_OnWrite):
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
field_path = self.get_field_path(field)
|
||||
return [
|
||||
f"field_combo.{field_path}.next = '0;",
|
||||
f"field_combo.{field_path}.load_next = '1;",
|
||||
f"next_c = '0;",
|
||||
f"load_next_c = '1;",
|
||||
]
|
||||
|
||||
class WriteSet(_OnWrite):
|
||||
@@ -117,8 +117,8 @@ class WriteSet(_OnWrite):
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
field_path = self.get_field_path(field)
|
||||
return [
|
||||
f"field_combo.{field_path}.next = '1;",
|
||||
f"field_combo.{field_path}.load_next = '1;",
|
||||
f"next_c = '1;",
|
||||
f"load_next_c = '1;",
|
||||
]
|
||||
|
||||
class Write(_OnWrite):
|
||||
@@ -128,6 +128,6 @@ class Write(_OnWrite):
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
field_path = self.get_field_path(field)
|
||||
return [
|
||||
f"field_combo.{field_path}.next = {self._wr_data(field)};",
|
||||
f"field_combo.{field_path}.load_next = '1;",
|
||||
f"next_c = {self._wr_data(field)};",
|
||||
f"load_next_c = '1;",
|
||||
]
|
||||
|
||||
@@ -18,6 +18,6 @@ class Singlepulse(NextStateConditional):
|
||||
def get_assignments(self, field: 'FieldNode') -> List[str]:
|
||||
field_path = self.get_field_path(field)
|
||||
return [
|
||||
f"field_combo.{field_path}.next = '0;",
|
||||
f"field_combo.{field_path}.load_next = '1;",
|
||||
f"next_c = '0;",
|
||||
f"load_next_c = '1;",
|
||||
]
|
||||
|
||||
56
peakrdl/regblock/field_logic/templates/counter_macros.sv
Normal file
56
peakrdl/regblock/field_logic/templates/counter_macros.sv
Normal file
@@ -0,0 +1,56 @@
|
||||
{% macro up_counter(field) -%}
|
||||
if({{field_logic.get_counter_incr_strobe(node)}}) begin // increment
|
||||
{%- if field_logic.counter_incrsaturates(node) %}
|
||||
if((({{node.width+1}})'(next_c) + {{field_logic.get_counter_incrvalue(node)}}) > {{field_logic.get_counter_incrsaturate_value(node)}}) begin // up-counter saturated
|
||||
next_c = {{field_logic.get_counter_incrsaturate_value(node)}};
|
||||
end else begin
|
||||
next_c = next_c + {{field_logic.get_counter_incrvalue(node)}};
|
||||
end
|
||||
{%- else %}
|
||||
field_combo.{{field_path}}.overflow = ((({{node.width+1}})'(next_c) + {{field_logic.get_counter_incrvalue(node)}}) > {{get_value(2**node.width - 1)}});
|
||||
next_c = next_c + {{field_logic.get_counter_incrvalue(node)}};
|
||||
{%- endif %}
|
||||
load_next_c = '1;
|
||||
{%- if not field_logic.counter_incrsaturates(node) %}
|
||||
end else begin
|
||||
field_combo.{{field_path}}.overflow = '0;
|
||||
{%- endif %}
|
||||
end
|
||||
field_combo.{{field_path}}.incrthreshold = (field_storage.{{field_path}} >= {{field_logic.get_counter_incrthreshold_value(node)}});
|
||||
{%- if field_logic.counter_incrsaturates(node) %}
|
||||
field_combo.{{field_path}}.incrsaturate = (field_storage.{{field_path}} >= {{field_logic.get_counter_incrsaturate_value(node)}});
|
||||
if(next_c > {{field_logic.get_counter_incrsaturate_value(node)}}) begin
|
||||
next_c = {{field_logic.get_counter_incrsaturate_value(node)}};
|
||||
load_next_c = '1;
|
||||
end
|
||||
{%- endif %}
|
||||
{%- endmacro %}
|
||||
|
||||
|
||||
{% macro down_counter(field) -%}
|
||||
if({{field_logic.get_counter_decr_strobe(node)}}) begin // decrement
|
||||
{%- if field_logic.counter_decrsaturates(node) %}
|
||||
if(({{node.width+1}})'(next_c) < ({{field_logic.get_counter_decrvalue(node)}} + {{field_logic.get_counter_decrsaturate_value(node)}})) begin // down-counter saturated
|
||||
next_c = {{field_logic.get_counter_decrsaturate_value(node)}};
|
||||
end else begin
|
||||
next_c = next_c - {{field_logic.get_counter_decrvalue(node)}};
|
||||
end
|
||||
{%- else %}
|
||||
field_combo.{{field_path}}.underflow = (next_c < ({{field_logic.get_counter_decrvalue(node)}}));
|
||||
next_c = next_c - {{field_logic.get_counter_decrvalue(node)}};
|
||||
{%- endif %}
|
||||
load_next_c = '1;
|
||||
{%- if not field_logic.counter_decrsaturates(node) %}
|
||||
end else begin
|
||||
field_combo.{{field_path}}.underflow = '0;
|
||||
{%- endif %}
|
||||
end
|
||||
field_combo.{{field_path}}.decrthreshold = (field_storage.{{field_path}} <= {{field_logic.get_counter_decrthreshold_value(node)}});
|
||||
{%- if field_logic.counter_decrsaturates(node) %}
|
||||
field_combo.{{field_path}}.decrsaturate = (field_storage.{{field_path}} <= {{field_logic.get_counter_decrsaturate_value(node)}});
|
||||
if(next_c < {{field_logic.get_counter_decrsaturate_value(node)}}) begin
|
||||
next_c = {{field_logic.get_counter_decrsaturate_value(node)}};
|
||||
load_next_c = '1;
|
||||
end
|
||||
{%- endif %}
|
||||
{%- endmacro %}
|
||||
@@ -1,7 +1,8 @@
|
||||
{%- import 'field_logic/templates/counter_macros.sv' as counter_macros with context -%}
|
||||
// Field: {{node.get_path()}}
|
||||
always_comb begin
|
||||
field_combo.{{field_path}}.next = field_storage.{{field_path}};
|
||||
field_combo.{{field_path}}.load_next = '0;
|
||||
automatic logic [{{node.width-1}}:0] next_c = field_storage.{{field_path}};
|
||||
automatic logic load_next_c = '0;
|
||||
{%- for signal in extra_combo_signals %}
|
||||
field_combo.{{field_path}}.{{signal.name}} = {{signal.default_assignment}};
|
||||
{%- endfor %}
|
||||
@@ -12,6 +13,14 @@ always_comb begin
|
||||
{%- endfor %}
|
||||
end
|
||||
{%- endfor %}
|
||||
{%- if node.is_up_counter %}
|
||||
{{counter_macros.up_counter(node)}}
|
||||
{%- endif %}
|
||||
{%- if node.is_down_counter %}
|
||||
{{counter_macros.down_counter(node)}}
|
||||
{%- endif %}
|
||||
field_combo.{{field_path}}.next = next_c;
|
||||
field_combo.{{field_path}}.load_next = load_next_c;
|
||||
end
|
||||
always_ff {{get_always_ff_event(resetsignal)}} begin
|
||||
{% if resetsignal is not none -%}
|
||||
|
||||
@@ -159,21 +159,23 @@ class Hwif:
|
||||
contents.append(f"logic {prop_name};")
|
||||
|
||||
# Generate any implied counter inputs
|
||||
if node.get_property('counter'):
|
||||
if node.is_up_counter:
|
||||
if not node.get_property('incr'):
|
||||
# User did not provide their own incr component reference.
|
||||
# Imply an input
|
||||
contents.append("logic incr;")
|
||||
if not node.get_property('decr'):
|
||||
# User did not provide their own decr component reference.
|
||||
# Imply an input
|
||||
contents.append("logic decr;")
|
||||
|
||||
width = node.get_property('incrwidth')
|
||||
if width:
|
||||
# Implies a corresponding incrvalue input
|
||||
contents.append(f"logic [{width-1}:0] incrvalue;")
|
||||
|
||||
if node.is_down_counter:
|
||||
if not node.get_property('decr'):
|
||||
# User did not provide their own decr component reference.
|
||||
# Imply an input
|
||||
contents.append("logic decr;")
|
||||
|
||||
width = node.get_property('decrwidth')
|
||||
if width:
|
||||
# Implies a corresponding decrvalue input
|
||||
@@ -198,10 +200,15 @@ class Hwif:
|
||||
contents.append(f"logic [{node.width-1}:0] value;")
|
||||
|
||||
# Generate output bit signals enabled via property
|
||||
for prop_name in ["anded", "ored", "xored", "swmod", "swacc"]:
|
||||
for prop_name in ["anded", "ored", "xored", "swmod", "swacc", "overflow", "underflow"]:
|
||||
if node.get_property(prop_name):
|
||||
contents.append(f"logic {prop_name};")
|
||||
|
||||
if node.get_property('incrthreshold') is not False: # (explicitly not False. Not 0)
|
||||
contents.append("logic incrthreshold;")
|
||||
if node.get_property('decrthreshold') is not False: # (explicitly not False. Not 0)
|
||||
contents.append("logic decrthreshold;")
|
||||
|
||||
return contents
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
@@ -252,7 +259,10 @@ class Hwif:
|
||||
|
||||
|
||||
def get_implied_prop_input_identifier(self, field: FieldNode, prop: str) -> str:
|
||||
assert prop in {'hwclr', 'hwset', 'swwe', 'swwel', 'we', 'wel'}
|
||||
assert prop in {
|
||||
'hwclr', 'hwset', 'swwe', 'swwel', 'we', 'wel',
|
||||
'incr', 'decr', 'incrvalue', 'decrvalue'
|
||||
}
|
||||
path = get_indexed_path(self.top_node, field)
|
||||
return "hwif_in." + path + "." + prop
|
||||
|
||||
|
||||
Reference in New Issue
Block a user