From 5168470ca0dac333b6d84b3750c89f81486037dd Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 18 Dec 2018 20:04:22 +0000 Subject: [PATCH] compat: import genlib.record from Migen. --- nmigen/compat/__init__.py | 2 +- nmigen/compat/genlib/record.py | 195 +++++++++++++++++++++++++++++++++ nmigen/hdl/xfrm.py | 3 +- nmigen/tracer.py | 3 + 4 files changed, 201 insertions(+), 2 deletions(-) create mode 100644 nmigen/compat/genlib/record.py diff --git a/nmigen/compat/__init__.py b/nmigen/compat/__init__.py index a22f559..b8f412d 100644 --- a/nmigen/compat/__init__.py +++ b/nmigen/compat/__init__.py @@ -7,5 +7,5 @@ from .fhdl.bitcontainer import * from .sim import * -# from .genlib.record import * +from .genlib.record import * from .genlib.fsm import * diff --git a/nmigen/compat/genlib/record.py b/nmigen/compat/genlib/record.py new file mode 100644 index 0000000..69ce0e2 --- /dev/null +++ b/nmigen/compat/genlib/record.py @@ -0,0 +1,195 @@ +from ...tracer import * +from ..fhdl.structure import * + +from functools import reduce +from operator import or_ + + +(DIR_NONE, DIR_S_TO_M, DIR_M_TO_S) = range(3) + +# Possible layout elements: +# 1. (name, size) +# 2. (name, size, direction) +# 3. (name, sublayout) +# size can be an int, or a (int, bool) tuple for signed numbers +# sublayout must be a list + + +def set_layout_parameters(layout, **layout_dict): + def resolve(p): + if isinstance(p, str): + try: + return layout_dict[p] + except KeyError: + return p + else: + return p + + r = [] + for f in layout: + if isinstance(f[1], (int, tuple, str)): # cases 1/2 + if len(f) == 3: + r.append((f[0], resolve(f[1]), f[2])) + else: + r.append((f[0], resolve(f[1]))) + elif isinstance(f[1], list): # case 3 + r.append((f[0], set_layout_parameters(f[1], **layout_dict))) + else: + raise TypeError + return r + + +def layout_len(layout): + r = 0 + for f in layout: + if isinstance(f[1], (int, tuple)): # cases 1/2 + if len(f) == 3: + fname, fsize, fdirection = f + else: + fname, fsize = f + elif isinstance(f[1], list): # case 3 + fname, fsublayout = f + fsize = layout_len(fsublayout) + else: + raise TypeError + if isinstance(fsize, tuple): + r += fsize[0] + else: + r += fsize + return r + + +def layout_get(layout, name): + for f in layout: + if f[0] == name: + return f + raise KeyError(name) + + +def layout_partial(layout, *elements): + r = [] + for path in elements: + path_s = path.split("/") + last = path_s.pop() + copy_ref = layout + insert_ref = r + for hop in path_s: + name, copy_ref = layout_get(copy_ref, hop) + try: + name, insert_ref = layout_get(insert_ref, hop) + except KeyError: + new_insert_ref = [] + insert_ref.append((hop, new_insert_ref)) + insert_ref = new_insert_ref + insert_ref.append(layout_get(copy_ref, last)) + return r + + +class Record: + def __init__(self, layout, name=None, **kwargs): + try: + self.name = get_var_name() + except NameNotFound: + self.name = "" + self.layout = layout + + if self.name: + prefix = self.name + "_" + else: + prefix = "" + for f in self.layout: + if isinstance(f[1], (int, tuple)): # cases 1/2 + if(len(f) == 3): + fname, fsize, fdirection = f + else: + fname, fsize = f + finst = Signal(fsize, name=prefix + fname, **kwargs) + elif isinstance(f[1], list): # case 3 + fname, fsublayout = f + finst = Record(fsublayout, prefix + fname, **kwargs) + else: + raise TypeError + setattr(self, fname, finst) + + def eq(self, other): + return [getattr(self, f[0]).eq(getattr(other, f[0])) + for f in self.layout if hasattr(other, f[0])] + + def iter_flat(self): + for f in self.layout: + e = getattr(self, f[0]) + if isinstance(e, Signal): + if len(f) == 3: + yield e, f[2] + else: + yield e, DIR_NONE + elif isinstance(e, Record): + yield from e.iter_flat() + else: + raise TypeError + + def flatten(self): + return [signal for signal, direction in self.iter_flat()] + + def raw_bits(self): + return Cat(*self.flatten()) + + def connect(self, *slaves, keep=None, omit=None): + if keep is None: + _keep = set([f[0] for f in self.layout]) + elif isinstance(keep, list): + _keep = set(keep) + else: + _keep = keep + if omit is None: + _omit = set() + elif isinstance(omit, list): + _omit = set(omit) + else: + _omit = omit + + _keep = _keep - _omit + + r = [] + for f in self.layout: + field = f[0] + self_e = getattr(self, field) + if isinstance(self_e, Signal): + if field in _keep: + direction = f[2] + if direction == DIR_M_TO_S: + r += [getattr(slave, field).eq(self_e) for slave in slaves] + elif direction == DIR_S_TO_M: + r.append(self_e.eq(reduce(or_, [getattr(slave, field) for slave in slaves]))) + else: + raise TypeError + else: + for slave in slaves: + r += self_e.connect(getattr(slave, field), keep=keep, omit=omit) + return r + + def connect_flat(self, *slaves): + r = [] + iter_slaves = [slave.iter_flat() for slave in slaves] + for m_signal, m_direction in self.iter_flat(): + if m_direction == DIR_M_TO_S: + for iter_slave in iter_slaves: + s_signal, s_direction = next(iter_slave) + assert(s_direction == DIR_M_TO_S) + r.append(s_signal.eq(m_signal)) + elif m_direction == DIR_S_TO_M: + s_signals = [] + for iter_slave in iter_slaves: + s_signal, s_direction = next(iter_slave) + assert(s_direction == DIR_S_TO_M) + s_signals.append(s_signal) + r.append(m_signal.eq(reduce(or_, s_signals))) + else: + raise TypeError + return r + + def __len__(self): + return layout_len(self.layout) + + def __repr__(self): + return "" diff --git a/nmigen/hdl/xfrm.py b/nmigen/hdl/xfrm.py index 4c7f2b3..9dc0e06 100644 --- a/nmigen/hdl/xfrm.py +++ b/nmigen/hdl/xfrm.py @@ -74,7 +74,8 @@ class AbstractValueTransformer(metaclass=ABCMeta): new_value = self.on_Slice(value) elif type(value) is Part: new_value = self.on_Part(value) - elif type(value) is Cat: + elif isinstance(value, Cat): + # Uses `isinstance()` and not `type() is` because nmigen.compat requires it. new_value = self.on_Cat(value) elif type(value) is Repl: new_value = self.on_Repl(value) diff --git a/nmigen/tracer.py b/nmigen/tracer.py index c4c83d1..e018c8f 100644 --- a/nmigen/tracer.py +++ b/nmigen/tracer.py @@ -2,6 +2,9 @@ import inspect from opcode import opname +__all__ = ["NameNotFound", "get_var_name"] + + class NameNotFound(Exception): pass -- 2.30.2