Skip to content

Commit

Permalink
Add tests for stream registers + bugfixes
Browse files Browse the repository at this point in the history
  • Loading branch information
jvanstraten committed Aug 28, 2019
1 parent f7cc798 commit 20321ff
Show file tree
Hide file tree
Showing 6 changed files with 223 additions and 10 deletions.
4 changes: 2 additions & 2 deletions doc/md/internalcounter.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ Controls the existence of the `ctrl_increment` control input
signal. When this signal is asserted, the internal data register is
incremented.

The value must be a boolean (default `yes`).
The value must be a boolean (default `no`).

This key is optional unless required by context. If not specified, the default value (`yes`) is used.
This key is optional unless required by context. If not specified, the default value (`no`) is used.

## `ctrl-decrement`

Expand Down
4 changes: 2 additions & 2 deletions doc/md/volatileinternalcounter.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ Controls the existence of the `ctrl_increment` control input
signal. When this signal is asserted, the internal data register is
incremented.

The value must be a boolean (default `yes`).
The value must be a boolean (default `no`).

This key is optional unless required by context. If not specified, the default value (`yes`) is used.
This key is optional unless required by context. If not specified, the default value (`no`) is used.

## `ctrl-decrement`

Expand Down
209 changes: 209 additions & 0 deletions tests/integration/test_primitive_stream.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
"""Primitive stream field tests."""

from unittest import TestCase
from ..testbench import RegisterFileTestbench

class TestPrimitiveStreamFields(TestCase):
"""Primitive stream field tests"""

def test_stream_to_mmio(self):
"""test stream to MMIO field"""
rft = RegisterFileTestbench({
'metadata': {'name': 'test'},
'fields': [
{
'address': 0,
'name': 'a',
'behavior': 'stream-to-mmio',
'full-internal': 'a_full',
'empty-internal': 'a_empty',
'underrun-internal': 'a_under',
},
{
'address': 4,
'name': 'b',
'behavior': 'stream-to-mmio',
'bus-read': 'valid-only',
'full-internal': 'b_full',
'empty-internal': 'b_empty',
'reset': 33,
},
{
'address': 8,
'bitrange': 0,
'name': 'a_full',
'behavior': 'internal-status',
'internal': 'a_full',
},
{
'address': 8,
'bitrange': 1,
'name': 'a_empty',
'behavior': 'internal-status',
'internal': 'a_empty',
},
{
'address': 8,
'bitrange': 2,
'name': 'a_under',
'behavior': 'internal-flag',
'internal': 'a_under',
},
{
'address': 8,
'bitrange': 3,
'name': 'b_full',
'behavior': 'internal-status',
'internal': 'b_full',
},
{
'address': 8,
'bitrange': 4,
'name': 'b_empty',
'behavior': 'internal-status',
'internal': 'b_empty',
},
]})
with rft as objs:
rft.testbench.clock()
self.assertEqual(objs.bus.read(8), 0b01010)
self.assertEqual(objs.bus.read(0), 0)
self.assertEqual(objs.bus.read(8), 0b01110)
objs.bus.write(8, 0b00100)
objs.f_a_i.data.val = 33
objs.f_a_i.valid.val = 1
rft.testbench.clock() # needed because the test case runner is synchronous
objs.f_a_i.valid.val = 0
self.assertEqual(int(objs.f_a_o.ready), 1)
rft.testbench.clock()
self.assertEqual(int(objs.f_a_o.ready), 0)
self.assertEqual(objs.bus.read(8), 0b01001)
self.assertEqual(objs.bus.read(0), 33)
self.assertEqual(int(objs.f_a_o.ready), 1)
self.assertEqual(objs.bus.read(8), 0b01010)
self.assertEqual(objs.bus.read(0), 0)
self.assertEqual(objs.bus.read(8), 0b01110)
objs.bus.write(8, 0b00100)
with self.assertRaisesRegex(ValueError, 'decode'):
objs.bus.write(0, 0)

self.assertEqual(objs.bus.read(4), 33)
self.assertEqual(objs.bus.read(8), 0b10010)
with self.assertRaisesRegex(ValueError, 'slave'):
objs.bus.read(4)
self.assertEqual(objs.bus.read(8), 0b10010)
objs.f_b_i.data.val = 42
objs.f_b_i.valid.val = 1
rft.testbench.clock() # needed because the test case runner is synchronous
objs.f_b_i.valid.val = 0
self.assertEqual(int(objs.f_b_o.ready), 1)
rft.testbench.clock()
self.assertEqual(int(objs.f_b_o.ready), 0)
self.assertEqual(objs.bus.read(8), 0b01010)
self.assertEqual(objs.bus.read(4), 42)
self.assertEqual(objs.bus.read(8), 0b10010)
with self.assertRaisesRegex(ValueError, 'slave'):
objs.bus.read(4)
self.assertEqual(objs.bus.read(8), 0b10010)
with self.assertRaisesRegex(ValueError, 'decode'):
objs.bus.write(4, 0)

def test_mmio_to_stream(self):
"""test MMIO to stream field"""
rft = RegisterFileTestbench({
'metadata': {'name': 'test'},
'fields': [
{
'address': 0,
'name': 'a',
'behavior': 'mmio-to-stream',
'full-internal': 'a_full',
'empty-internal': 'a_empty',
'overrun-internal': 'a_over',
},
{
'address': 4,
'name': 'b',
'behavior': 'mmio-to-stream',
'bus-write': 'invalid-only',
'full-internal': 'b_full',
'empty-internal': 'b_empty',
'reset': 33,
},
{
'address': 8,
'bitrange': 0,
'name': 'a_full',
'behavior': 'internal-status',
'internal': 'a_full',
},
{
'address': 8,
'bitrange': 1,
'name': 'a_empty',
'behavior': 'internal-status',
'internal': 'a_empty',
},
{
'address': 8,
'bitrange': 2,
'name': 'a_over',
'behavior': 'internal-flag',
'internal': 'a_over',
},
{
'address': 8,
'bitrange': 3,
'name': 'b_full',
'behavior': 'internal-status',
'internal': 'b_full',
},
{
'address': 8,
'bitrange': 4,
'name': 'b_empty',
'behavior': 'internal-status',
'internal': 'b_empty',
},
]})
with rft as objs:
rft.testbench.clock()
self.assertEqual(objs.bus.read(8), 0b01010)
self.assertEqual(int(objs.f_a_o.data), 0)
self.assertEqual(int(objs.f_a_o.valid), 0)
objs.bus.write(0, 33)
self.assertEqual(objs.bus.read(8), 0b01001)
self.assertEqual(int(objs.f_a_o.data), 33)
self.assertEqual(int(objs.f_a_o.valid), 1)
objs.bus.write(0, 42) # ignored!
self.assertEqual(objs.bus.read(8), 0b01101)
objs.bus.write(8, 0b00100)
self.assertEqual(int(objs.f_a_o.data), 33)
self.assertEqual(int(objs.f_a_o.valid), 1)
objs.f_a_i.ready.val = 1
rft.testbench.clock()
objs.f_a_i.ready.val = 0
rft.testbench.clock() # needed because the test case runner is synchronous
self.assertEqual(int(objs.f_a_o.valid), 0)
self.assertEqual(objs.bus.read(8), 0b01010)
with self.assertRaisesRegex(ValueError, 'decode'):
objs.bus.read(0)

self.assertEqual(int(objs.f_b_o.data), 33)
self.assertEqual(int(objs.f_b_o.valid), 1)
objs.f_b_i.ready.val = 1
rft.testbench.clock()
objs.f_b_i.ready.val = 0
rft.testbench.clock() # needed because the test case runner is synchronous
self.assertEqual(int(objs.f_b_o.valid), 0)
self.assertEqual(objs.bus.read(8), 0b10010)
objs.bus.write(4, 42)
self.assertEqual(objs.bus.read(8), 0b01010)
self.assertEqual(int(objs.f_b_o.data), 42)
self.assertEqual(int(objs.f_b_o.valid), 1)
with self.assertRaisesRegex(ValueError, 'slave'):
objs.bus.write(4, 33)
self.assertEqual(int(objs.f_b_o.data), 42)
self.assertEqual(int(objs.f_b_o.valid), 1)
with self.assertRaisesRegex(ValueError, 'decode'):
objs.bus.read(4)
6 changes: 4 additions & 2 deletions vhdmmio/config/behavior/counter.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ class VolatileCounter(Counter):
@behavior(
'internal-counter', 'internal event counter, reset explicitly by a write.', 2)
@derive(
name='`internal-counter` behavior')
name='`internal-counter` behavior',
ctrl_increment=[False])
class InternalCounter(Counter):
"""This field behaves like `counter`, but instead of the counter being
incremented by an external signal, it is incremented by an internal
Expand All @@ -93,7 +94,8 @@ def internal(self, value):
'volatile-internal-counter', 'internal event counter, reset implicitly by the '
'read.', 2)
@derive(
name='`volatile-internal-counter` behavior')
name='`volatile-internal-counter` behavior',
ctrl_increment=[False])
class VolatileInternalCounter(VolatileCounter):
"""This field behaves like `volatile-counter`, but instead of the counter
being incremented by an external signal, it is incremented by an internal
Expand Down
2 changes: 2 additions & 0 deletions vhdmmio/config/behavior/flag.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ class VolatileFlag(Flag):
'internal-flag', 'like `flag`, but set by an internal signal.', 2)
@derive(
name='`internal-flag` behavior',
ctrl_bit_set=False,
monitor_mode='bit-set')
class InternalFlag(Flag):
"""`internal-flag` fields behave like `flag` fields, but instead of the
Expand All @@ -103,6 +104,7 @@ def internal(self, value):
'`internal-flag`.', 2)
@derive(
name='`volatile-internal-flag` behavior',
ctrl_bit_set=False,
monitor_mode='bit-set')
class VolatileInternalFlag(VolatileFlag):
"""`volatile-internal-flag` fields behave like `volatile-flag` fields, but
Expand Down
8 changes: 4 additions & 4 deletions vhdmmio/vhdl/behavior/primitive.template.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -280,13 +280,13 @@
|$endblock

|$block HANDLE_WRITE
|$if b.underrun_internal is not None
|$if b.overrun_internal is not None
|@ If the field is already valid, assert the overrun flag.
|if $state[i].v$ = '1' then
|$if b.underrun_internal.is_vector()
| $b.underrun_internal.drive_name$($i$) := '1';
|$if b.overrun_internal.is_vector()
| $b.overrun_internal.drive_name$($i$) := '1';
|$else
| $b.underrun_internal.drive_name$ := '1';
| $b.overrun_internal.drive_name$ := '1';
|$endif
|end if;
|
Expand Down

0 comments on commit 20321ff

Please # to comment.