Emit error if field that is asynchronously reset uses a dynamic reset value. #129
This commit is contained in:
@@ -19,6 +19,7 @@ class DesignValidator(RDLListener):
|
|||||||
"""
|
"""
|
||||||
def __init__(self, exp:'RegblockExporter') -> None:
|
def __init__(self, exp:'RegblockExporter') -> None:
|
||||||
self.exp = exp
|
self.exp = exp
|
||||||
|
self.ds = exp.ds
|
||||||
self.msg = self.top_node.env.msg
|
self.msg = self.top_node.env.msg
|
||||||
|
|
||||||
self._contains_external_block_stack = [] # type: List[bool]
|
self._contains_external_block_stack = [] # type: List[bool]
|
||||||
@@ -152,6 +153,23 @@ class DesignValidator(RDLListener):
|
|||||||
node.inst.inst_src_ref
|
node.inst.inst_src_ref
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Check for unsynthesizable reset
|
||||||
|
reset = node.get_property("reset")
|
||||||
|
if not (reset is None or isinstance(reset, int)):
|
||||||
|
# Has reset that is not a constant value
|
||||||
|
resetsignal = node.get_property("resetsignal")
|
||||||
|
if resetsignal:
|
||||||
|
is_async_reset = resetsignal.get_property("async")
|
||||||
|
else:
|
||||||
|
is_async_reset = self.ds.default_reset_async
|
||||||
|
|
||||||
|
if is_async_reset:
|
||||||
|
self.msg.error(
|
||||||
|
"A field that uses an asynchronous reset cannot use a dynamic reset value. This is not synthesizable.",
|
||||||
|
node.inst.inst_src_ref
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def exit_AddressableComponent(self, node: AddressableNode) -> None:
|
def exit_AddressableComponent(self, node: AddressableNode) -> None:
|
||||||
if not isinstance(node, RegNode):
|
if not isinstance(node, RegNode):
|
||||||
# Exiting block-like node
|
# Exiting block-like node
|
||||||
|
|||||||
@@ -76,3 +76,16 @@ class TestValidationErrors(BaseTestCase):
|
|||||||
"multiple_unconditional_assigns.rdl",
|
"multiple_unconditional_assigns.rdl",
|
||||||
"Field has multiple conflicting properties that unconditionally set its state",
|
"Field has multiple conflicting properties that unconditionally set its state",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_unsynth_reset1(self) -> None:
|
||||||
|
self.assert_validate_error(
|
||||||
|
"unsynth_reset1.rdl",
|
||||||
|
"A field that uses an asynchronous reset cannot use a dynamic reset value. This is not synthesizable.",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_unsynth_reset2(self) -> None:
|
||||||
|
self.default_reset_async = True
|
||||||
|
self.assert_validate_error(
|
||||||
|
"unsynth_reset2.rdl",
|
||||||
|
"A field that uses an asynchronous reset cannot use a dynamic reset value. This is not synthesizable.",
|
||||||
|
)
|
||||||
|
|||||||
19
tests/test_validation_errors/unsynth_reset1.rdl
Normal file
19
tests/test_validation_errors/unsynth_reset1.rdl
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
signal {
|
||||||
|
field_reset;
|
||||||
|
async;
|
||||||
|
activehigh;
|
||||||
|
} foo;
|
||||||
|
|
||||||
|
addrmap top {
|
||||||
|
reg {
|
||||||
|
field {
|
||||||
|
sw=rw; hw=na;
|
||||||
|
} f1;
|
||||||
|
|
||||||
|
field {
|
||||||
|
sw=rw; hw=na;
|
||||||
|
} f2;
|
||||||
|
|
||||||
|
f1->reset = f2;
|
||||||
|
} x;
|
||||||
|
};
|
||||||
13
tests/test_validation_errors/unsynth_reset2.rdl
Normal file
13
tests/test_validation_errors/unsynth_reset2.rdl
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
addrmap top {
|
||||||
|
reg {
|
||||||
|
field {
|
||||||
|
sw=rw; hw=na;
|
||||||
|
} f1;
|
||||||
|
|
||||||
|
field {
|
||||||
|
sw=rw; hw=na;
|
||||||
|
} f2;
|
||||||
|
|
||||||
|
f1->reset = f2;
|
||||||
|
} x;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user