Skip to content

Commit

Permalink
hdl.rec: make Record inherit from UserValue.
Browse files Browse the repository at this point in the history
Closes #354.
  • Loading branch information
anuejn committed Apr 16, 2020
1 parent b4af217 commit ff6c032
Show file tree
Hide file tree
Showing 7 changed files with 32 additions and 24 deletions.
3 changes: 0 additions & 3 deletions nmigen/back/pysim.py
Expand Up @@ -374,9 +374,6 @@ def on_ClockSignal(self, value):
def on_ResetSignal(self, value):
raise NotImplementedError # :nocov:

def on_Record(self, value):
return self(Cat(value.fields.values()))

def on_AnyConst(self, value):
raise NotImplementedError # :nocov:

Expand Down
11 changes: 6 additions & 5 deletions nmigen/back/rtlil.py
Expand Up @@ -365,9 +365,6 @@ def on_Sample(self, value):
def on_Initial(self, value):
raise NotImplementedError # :nocov:

def on_Record(self, value):
return self(ast.Cat(value.fields.values()))

def on_Cat(self, value):
return "{{ {} }}".format(" ".join(reversed([self(o) for o in value.parts])))

Expand All @@ -378,7 +375,11 @@ def on_Slice(self, value):
if value.start == 0 and value.stop == len(value.value):
return self(value.value)

sigspec = self._prepare_value_for_Slice(value.value)
if isinstance(value.value, ast.UserValue):
sigspec = self._prepare_value_for_Slice(value.value._lazy_lower())
else:
sigspec = self._prepare_value_for_Slice(value.value)

if value.start == value.stop:
return "{}"
elif value.start + 1 == value.stop:
Expand Down Expand Up @@ -644,7 +645,7 @@ def on_Signal(self, value):
return wire_next or wire_curr

def _prepare_value_for_Slice(self, value):
assert isinstance(value, (ast.Signal, ast.Slice, ast.Cat, rec.Record))
assert isinstance(value, (ast.Signal, ast.Slice, ast.Cat))
return self(value)

def on_Part(self, value):
Expand Down
5 changes: 4 additions & 1 deletion nmigen/hdl/ast.py
Expand Up @@ -1188,7 +1188,10 @@ def lower(self):

def _lazy_lower(self):
if self.__lowered is None:
self.__lowered = Value.cast(self.lower())
lowered = self.lower()
if isinstance(lowered, UserValue):
lowered = lowered._lazy_lower()
self.__lowered = Value.cast(lowered)
return self.__lowered

def shape(self):
Expand Down
8 changes: 5 additions & 3 deletions nmigen/hdl/rec.py
Expand Up @@ -85,7 +85,7 @@ def __repr__(self):


# Unlike most Values, Record *can* be subclassed.
class Record(Value):
class Record(UserValue):
@staticmethod
def like(other, *, name=None, name_suffix=None, src_loc_at=0):
if name is not None:
Expand Down Expand Up @@ -113,6 +113,8 @@ def concat(a, b):
return Record(other.layout, name=new_name, fields=fields, src_loc_at=1)

def __init__(self, layout, *, name=None, fields=None, src_loc_at=0):
super().__init__(src_loc_at=src_loc_at)

if name is None:
name = tracer.get_var_name(depth=2 + src_loc_at, default=None)

Expand Down Expand Up @@ -165,8 +167,8 @@ def __getitem__(self, item):
else:
return super().__getitem__(item)

def shape(self):
return Shape(sum(len(f) for f in self.fields.values()))
def lower(self):
return Cat(self.fields.values())

def _lhs_signals(self):
return union((f._lhs_signals() for f in self.fields.values()), start=SignalSet())
Expand Down
12 changes: 0 additions & 12 deletions nmigen/hdl/xfrm.py
Expand Up @@ -38,10 +38,6 @@ def on_AnySeq(self, value):
def on_Signal(self, value):
pass # :nocov:

@abstractmethod
def on_Record(self, value):
pass # :nocov:

@abstractmethod
def on_ClockSignal(self, value):
pass # :nocov:
Expand Down Expand Up @@ -98,9 +94,6 @@ def on_value(self, value):
elif isinstance(value, Signal):
# Uses `isinstance()` and not `type() is` because nmigen.compat requires it.
new_value = self.on_Signal(value)
elif isinstance(value, Record):
# Uses `isinstance()` and not `type() is` to allow inheriting from Record.
new_value = self.on_Record(value)
elif type(value) is ClockSignal:
new_value = self.on_ClockSignal(value)
elif type(value) is ResetSignal:
Expand Down Expand Up @@ -147,9 +140,6 @@ def on_AnySeq(self, value):
def on_Signal(self, value):
return value

def on_Record(self, value):
return value

def on_ClockSignal(self, value):
return value

Expand Down Expand Up @@ -372,8 +362,6 @@ def on_ClockSignal(self, value):
def on_ResetSignal(self, value):
self._add_used_domain(value.domain)

on_Record = on_ignore

def on_Operator(self, value):
for o in value.operands:
self.on_value(o)
Expand Down
8 changes: 8 additions & 0 deletions nmigen/test/test_hdl_ast.py
Expand Up @@ -916,6 +916,14 @@ def test_shape(self):
self.assertEqual(uv.shape(), unsigned(1))
self.assertEqual(uv.lower_count, 1)

def test_lower_to_user_value(self):
uv = MockUserValue(MockUserValue(1))
self.assertEqual(uv.shape(), unsigned(1))
self.assertIsInstance(uv.shape(), Shape)
uv.lowered = MockUserValue(2)
self.assertEqual(uv.shape(), unsigned(1))
self.assertEqual(uv.lower_count, 1)


class SampleTestCase(FHDLTestCase):
def test_const(self):
Expand Down
9 changes: 9 additions & 0 deletions nmigen/test/test_hdl_xfrm.py
Expand Up @@ -620,3 +620,12 @@ def test_lower(self):
)
)
""")


class UserValueRecursiveTestCase(UserValueTestCase):
def setUp(self):
self.s = Signal()
self.c = Signal()
self.uv = MockUserValue(MockUserValue(self.s))

# inherit the test_lower method from UserValueTestCase because the checks are the same

0 comments on commit ff6c032

Please sign in to comment.