-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ce81878
commit 29151b9
Showing
11 changed files
with
418 additions
and
131 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
"""Primitive constant field tests.""" | ||
|
||
from unittest import TestCase | ||
from ..testbench import RegisterFileTestbench | ||
|
||
class TestPrimitiveConstantFields(TestCase): | ||
"""Primitive constant field tests""" | ||
|
||
def test_fields(self): | ||
"""test constant fields""" | ||
rft = RegisterFileTestbench({ | ||
'metadata': {'name': 'test'}, | ||
'fields': [ | ||
{ | ||
'address': '0x--', | ||
'name': 'a', | ||
'behavior': 'axi', | ||
'flatten': True | ||
}, | ||
]}) | ||
self.assertEqual(rft.ports, ('bus', 'f_a')) | ||
with rft as objs: | ||
|
||
# Test blocking. | ||
read_resp = [] | ||
def read_cb(_, resp): | ||
read_resp.append(int(resp)) | ||
objs.bus.async_read(read_cb, 0) | ||
|
||
write_resp = [] | ||
def write_cb(resp): | ||
write_resp.append(int(resp)) | ||
objs.bus.async_write(write_cb, 0, 0) | ||
|
||
rft.testbench.clock(20) | ||
self.assertEqual(read_resp, []) | ||
self.assertEqual(write_resp, []) | ||
|
||
objs.f_a.start() | ||
|
||
rft.testbench.clock(10) | ||
self.assertEqual(read_resp, [0]) | ||
self.assertEqual(write_resp, [0]) | ||
|
||
# Test data passthrough. | ||
for i in range(16): | ||
objs.bus.write(i * 4, hash(str(i)) & 0xFFFFFFFF) | ||
for i in range(16): | ||
self.assertEqual(objs.f_a.read(i * 4), hash(str(i)) & 0xFFFFFFFF) | ||
self.assertEqual(objs.bus.read(i * 4), hash(str(i)) & 0xFFFFFFFF) | ||
|
||
# Test error passthrough. | ||
objs.f_a.handle_read = lambda *_: 'error' | ||
objs.f_a.handle_write = lambda *_: 'error' | ||
with self.assertRaisesRegex(ValueError, 'slave'): | ||
objs.bus.read(0) | ||
with self.assertRaisesRegex(ValueError, 'slave'): | ||
objs.bus.write(0, 0) | ||
|
||
objs.f_a.handle_read = lambda *_: 'decode' | ||
objs.f_a.handle_write = lambda *_: 'decode' | ||
with self.assertRaisesRegex(ValueError, 'decode'): | ||
objs.bus.read(0) | ||
with self.assertRaisesRegex(ValueError, 'decode'): | ||
objs.bus.write(0, 0) | ||
|
||
def test_errors(self): | ||
"""test constant field config errors""" | ||
msg = ('AXI fields must be 32 or 64 bits wide') | ||
with self.assertRaisesRegex(Exception, msg): | ||
RegisterFileTestbench({ | ||
'metadata': {'name': 'test'}, | ||
'fields': [ | ||
{ | ||
'address': 0, | ||
'bitrange': '15..0', | ||
'name': 'a', | ||
'behavior': 'axi', | ||
}, | ||
]}) | ||
|
||
msg = ('subaddress is too wide for 30-bit word address') | ||
with self.assertRaisesRegex(Exception, msg): | ||
RegisterFileTestbench({ | ||
'metadata': {'name': 'test'}, | ||
'fields': [ | ||
{ | ||
'address': 0, | ||
'subaddress': [{'blank': 40}], | ||
'name': 'a', | ||
'behavior': 'axi', | ||
}, | ||
]}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
"""Submodule for AXI behavior.""" | ||
|
||
from .base import Behavior, behavior, BusAccessNoOpMethod, BusAccessBehavior, BusBehavior | ||
from ...config.behavior import Axi | ||
|
||
@behavior(Axi) | ||
class AxiBehavior(Behavior): | ||
"""Behavior class for AXI fields.""" | ||
|
||
def __init__(self, resources, field_descriptor, | ||
behavior_cfg, read_allow_cfg, write_allow_cfg): | ||
|
||
# Figure out the bus width. | ||
bus_width = field_descriptor.base_bitrange.width | ||
if bus_width not in [32, 64]: | ||
raise ValueError('AXI fields must be 32 or 64 bits wide') | ||
|
||
# Figure out the slice of the bus address that is controlled by the | ||
# subaddress. | ||
sub_low = {32: 2, 64: 3}[bus_width] | ||
sub_high = sub_low + field_descriptor.subaddress.width - 1 | ||
if sub_high > 31: | ||
raise ValueError( | ||
'subaddress is too wide for %d-bit word address' | ||
% (32 - sub_low)) | ||
self._subaddress_range = '%s downto %d' % (sub_high, sub_low) | ||
|
||
# Connect the internal signal for the interrupt. | ||
self._interrupt_internal = None | ||
if behavior_cfg.interrupt_internal is not None: | ||
self._interrupt_internal = resources.internals.drive( | ||
field_descriptor, | ||
behavior_cfg.interrupt_internal, | ||
field_descriptor.shape) | ||
|
||
# Decode the bus access behavior. | ||
if behavior_cfg.mode in ['read-only', 'read-write']: | ||
read_behavior = BusAccessBehavior( | ||
read_allow_cfg, | ||
blocking=True, volatile=True, deferring=True, | ||
no_op_method=BusAccessNoOpMethod.NEVER) | ||
else: | ||
read_behavior = None | ||
|
||
if behavior_cfg.mode in ['write-only', 'read-write']: | ||
write_behavior = BusAccessBehavior( | ||
write_allow_cfg, | ||
blocking=True, volatile=True, deferring=True, | ||
no_op_method=BusAccessNoOpMethod.NEVER) | ||
else: | ||
write_behavior = None | ||
|
||
bus_behavior = BusBehavior( | ||
read=read_behavior, write=write_behavior, | ||
can_read_for_rmw=False) | ||
|
||
super().__init__(field_descriptor, behavior_cfg, bus_behavior) | ||
|
||
@property | ||
def interrupt_internal(self): | ||
"""The internal signal used for the interrupt signal that `vhdmmio` | ||
passes along with AXI4L busses, or `None` if this signal is not | ||
used.""" | ||
return self._interrupt_internal | ||
|
||
@property | ||
def subaddress_range(self): | ||
"""The slice of the child bus address in VHDL range notation that the | ||
subaddress maps to.""" | ||
return self._subaddress_range | ||
|
||
@property | ||
def doc_reset(self): | ||
"""The reset value as printed in the documentation as an integer, or | ||
`None` if the field is driven by a signal and thus does not have a | ||
register to reset.""" | ||
return None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.