[go: up one dir, main page]

Skip to content

Commit

Permalink
Add more tests for deferring fields + bugfixes
Browse files Browse the repository at this point in the history
  • Loading branch information
jvanstraten committed Sep 3, 2019
1 parent 2b228d5 commit ce81878
Show file tree
Hide file tree
Showing 4 changed files with 283 additions and 8 deletions.
4 changes: 0 additions & 4 deletions tests/integration/TODO

This file was deleted.

275 changes: 275 additions & 0 deletions tests/integration/test_defer.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,278 @@ def callback(data, _):
expected.append(15)
self.assertEqual(responses, expected)
self.assertEqual(rft.testbench.cycle - start, 89)

def test_wide_read_defer(self):
"""test multi-word read-deferring field"""
rft = RegisterFileTestbench({
'metadata': {'name': 'test'},
'fields': [
{
'address': 0,
'bitrange': '63..0',
'repeat': 2,
'field-repeat': 1,
'stride': 2,
'name': 'a',
'behavior': 'custom',
'interfaces': [{'state': 'count:3'}, {'state': 'busy'}],
'read-can-block': True,
'read-request': (
'if $s.busy$ = \'1\' then\n'
' if $resp_ready$ then\n'
' $block$ := true;\n'
' end if;\n'
'else\n'
' $s.busy$ := \'1\';\n'
' $defer$ := true;\n'
'end if;\n'
),
'read-response': (
'if $s.count$ = "111" then\n'
' $ack$ := true;\n'
' if $i$ = 0 then\n'
' $data$ := X"1122334455667788";\n'
' else\n'
' $data$ := X"8877665544332211";\n'
' end if;\n'
' $s.busy$ := \'0\';\n'
'else\n'
' $block$ := true;\n'
'end if;\n'
),
'post-access': (
'if $s.busy$ = \'1\' then\n'
' if $s.count$ /= "111" then\n'
' $s.count$ := std_logic_vector(unsigned($s.count$) + 1);\n'
' end if;\n'
'else\n'
' $s.count$ := "000";\n'
'end if;\n'
),
},
{
'address': 16,
'bitrange': '63..0',
'name': 'b',
'behavior': 'constant',
'value': 0xDEADBEEFC0DE,
}
]})
self.assertEqual(rft.ports, ('bus',))
with rft as objs:
start = rft.testbench.cycle
responses = []
def callback(data, _):
responses.append(int(data))
objs.bus.async_read(callback, 0)
objs.bus.async_read(callback, 4)
objs.bus.async_read(callback, 8)
objs.bus.async_read(callback, 12)
objs.bus.async_read(callback, 16)
objs.bus.async_read(callback, 20)
objs.bus.async_read(callback, 0)
objs.bus.async_read(callback, 4)
objs.bus.async_read(callback, 8)
objs.bus.async_read(callback, 12)
objs.bus.async_read(callback, 16)
responses.append(objs.bus.read(20))
self.assertEqual(responses, [
0x55667788, 0x11223344,
0x44332211, 0x88776655,
0xBEEFC0DE, 0x0000DEAD,
0x55667788, 0x11223344,
0x44332211, 0x88776655,
0xBEEFC0DE, 0x0000DEAD])
self.assertEqual(rft.testbench.cycle - start, 41)

def test_write_defer(self):
"""test write-deferring fields"""
rft = RegisterFileTestbench({
'metadata': {'name': 'test'},
'fields': [
{
'address': 0,
'repeat': 4,
'field-repeat': 1,
'name': 'a',
'behavior': 'custom',
'interfaces': [{'state': 'count:3'}, {'state': 'data:32'}, {'state': 'busy'}],
'write-can-block': True,
'write-request': (
'if $s.busy$ = \'1\' then\n'
' if $resp_ready$ then\n'
' $block$ := true;\n'
' end if;\n'
'else\n'
' $s.data$ := $data$;\n'
' $s.busy$ := \'1\';\n'
' $defer$ := true;\n'
'end if;\n'
),
'write-response': (
'if $s.count$ = "111" then\n'
' case $s.data$(1 downto 0) is\n'
' when "00" => $ack$ := true;\n'
' when "01" => $nack$ := true;\n'
' when others => null;\n'
' end case;\n'
' $s.busy$ := \'0\';\n'
'else\n'
' $block$ := true;\n'
'end if;\n'
),
'post-access': (
'if $s.busy$ = \'1\' then\n'
' if $s.count$ /= "111" then\n'
' $s.count$ := std_logic_vector(unsigned($s.count$) + 1);\n'
' end if;\n'
'else\n'
' $s.count$ := "000";\n'
'end if;\n'
),
},
]})
self.assertEqual(rft.ports, ('bus',))
with rft as objs:
start = rft.testbench.cycle
objs.bus.write(0, 0)
self.assertEqual(rft.testbench.cycle - start, 9)

start = rft.testbench.cycle
responses = []
def callback(resp):
responses.append(int(resp))
objs.bus.async_write(callback, 4, 0)
objs.bus.async_write(callback, 8, 1)
objs.bus.async_write(callback, 12, 2)
objs.bus.write(0, 0)
self.assertEqual(responses, [0, 2, 3])
self.assertEqual(rft.testbench.cycle - start, 12)

def test_wide_write_defer(self):
"""test multi-word write-deferring fields"""
rft = RegisterFileTestbench({
'metadata': {'name': 'test'},
'fields': [
{
'address': 0,
'bitrange': '63..0',
'repeat': 4,
'field-repeat': 1,
'stride': 2,
'name': 'a',
'behavior': 'custom',
'interfaces': [{'state': 'count:3'}, {'state': 'data:64'}, {'state': 'busy'}],
'write-can-block': True,
'write-request': (
'if $s.busy$ = \'1\' then\n'
' if $resp_ready$ then\n'
' $block$ := true;\n'
' end if;\n'
'else\n'
' $s.data$ := $data$;\n'
' $s.busy$ := \'1\';\n'
' $defer$ := true;\n'
'end if;\n'
),
'write-response': (
'if $s.count$ = "111" then\n'
' case $s.data$(1 downto 0) is\n'
' when "00" => $ack$ := true;\n'
' when "01" => $nack$ := true;\n'
' when others => null;\n'
' end case;\n'
' $s.busy$ := \'0\';\n'
'else\n'
' $block$ := true;\n'
'end if;\n'
),
'post-access': (
'if $s.busy$ = \'1\' then\n'
' if $s.count$ /= "111" then\n'
' $s.count$ := std_logic_vector(unsigned($s.count$) + 1);\n'
' end if;\n'
'else\n'
' $s.count$ := "000";\n'
'end if;\n'
),
},
]})
self.assertEqual(rft.ports, ('bus',))
with rft as objs:
start = rft.testbench.cycle
objs.bus.write(0, 0)
self.assertEqual(rft.testbench.cycle - start, 2)
objs.bus.write(4, 0)
self.assertEqual(rft.testbench.cycle - start, 11)

start = rft.testbench.cycle
responses = []
def callback(resp):
responses.append(int(resp))
objs.bus.async_write(callback, 8, 0)
objs.bus.async_write(callback, 12, 0)
objs.bus.async_write(callback, 16, 1)
objs.bus.async_write(callback, 20, 0)
objs.bus.async_write(callback, 24, 2)
objs.bus.async_write(callback, 28, 0)
objs.bus.async_write(callback, 0, 0)
objs.bus.write(4, 0)
self.assertEqual(responses, [0, 0, 0, 2, 0, 3, 0])
self.assertEqual(rft.testbench.cycle - start, 37)

@staticmethod
def test_mixed():
"""test register with write-defer and read field"""
# Just check that constructing this doesn't raise an exception; this
# was a problem at some point.
RegisterFileTestbench({
'metadata': {'name': 'test'},
'fields': [
{
'address': 0,
'bitrange': '3..0',
'name': 'a',
'behavior': 'custom',
'write-request': (
'$defer$ := true;\n'
),
'write-response': (
'$ack$ := true;\n'
),
},
{
'address': 0,
'bitrange': '7..4',
'name': 'b',
'behavior': 'constant',
'value': 0,
},
]})

def test_error(self):
"""test defer-related errors"""
msg = r'deferring fields cannot share a register with other fields \(`A`\)'
with self.assertRaisesRegex(Exception, msg):
RegisterFileTestbench({
'metadata': {'name': 'test'},
'fields': [
{
'address': 0,
'bitrange': '3..0',
'name': 'a',
'behavior': 'custom',
'write-request': (
'$defer$ := true;\n'
),
'write-response': (
'$ack$ := true;\n'
),
},
{
'address': 0,
'bitrange': '7..4',
'name': 'b',
'behavior': 'control',
},
]})
8 changes: 5 additions & 3 deletions vhdmmio/core/block.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,13 @@ def __init__(self, resources, register, index, count):
# accesses after the deferred access is performed.
self._read_tag = None
self._write_tag = None
if len(register.fields) == 1:
if self.can_read() and register.fields[0].behavior.bus.read.deferring:
for field in register.fields:
if field.behavior.bus.read is not None and field.behavior.bus.read.deferring:
assert self._read_tag is None
self._read_tag = resources.read_tags.get_next()
if self.can_write() and register.fields[0].behavior.bus.write.deferring:
if field.behavior.bus.write is not None and field.behavior.bus.write.deferring:
if index == count - 1:
assert self._write_tag is None
self._write_tag = resources.write_tags.get_next()

# If there are multiple blocks, register each block in the register
Expand Down
4 changes: 3 additions & 1 deletion vhdmmio/vhdl/entity.template.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,9 @@ $ FIELD_LOGIC_WRITE

|$if di.write_count
-- Handle deferred writes.
$ FIELD_LOGIC_WRITE_TAG
if w_rreq then
$ FIELD_LOGIC_WRITE_TAG
end if;
|$endif
$endif

Expand Down

0 comments on commit ce81878

Please sign in to comment.