-"""
-
-from nmigen import Signal, Cat, Const, Mux, Module, Value
-from nmigen.cli import verilog, rtlil
-from nmigen.hdl.ast import ArrayProxy
-from nmigen.hdl.rec import Record, Layout
-
-from abc import ABCMeta, abstractmethod
-from collections.abc import Sequence
-
-
-class PrevControl:
- """ contains signals that come *from* the previous stage (both in and out)
- * i_valid: previous stage indicating all incoming data is valid.
- may be a multi-bit signal, where all bits are required
- to be asserted to indicate "valid".
- * o_ready: output to next stage indicating readiness to accept data
- * i_data : an input - added by the user of this class
- """
-
- def __init__(self, i_width=1, stage_ctl=False):
- self.stage_ctl = stage_ctl
- self.i_valid = Signal(i_width, name="p_i_valid") # prev >>in self
- self._o_ready = Signal(name="p_o_ready") # prev <<out self
- self.i_data = None # XXX MUST BE ADDED BY USER
- if stage_ctl:
- self.s_o_ready = Signal(name="p_s_o_rdy") # prev <<out self
-
- @property
- def o_ready(self):
- """ public-facing API: indicates (externally) that stage is ready
- """
- if self.stage_ctl:
- return self.s_o_ready # set dynamically by stage
- return self._o_ready # return this when not under dynamic control
-
- def _connect_in(self, prev):
- """ internal helper function to connect stage to an input source.
- do not use to connect stage-to-stage!
- """
- return [self.i_valid.eq(prev.i_valid_test),
- prev.o_ready.eq(self.o_ready),
- eq(self.i_data, prev.i_data),
- ]
-
- @property
- def i_valid_test(self):
- vlen = len(self.i_valid)
- if vlen > 1:
- # multi-bit case: valid only when i_valid is all 1s
- all1s = Const(-1, (len(self.i_valid), False))
- i_valid = (self.i_valid == all1s)
- else:
- # single-bit i_valid case
- i_valid = self.i_valid
-
- # when stage indicates not ready, incoming data
- # must "appear" to be not ready too
- if self.stage_ctl:
- i_valid = i_valid & self.s_o_ready
-
- return i_valid
-
-
-class NextControl:
- """ contains the signals that go *to* the next stage (both in and out)
- * o_valid: output indicating to next stage that data is valid
- * i_ready: input from next stage indicating that it can accept data
- * o_data : an output - added by the user of this class
- """
- def __init__(self, stage_ctl=False):
- self.stage_ctl = stage_ctl
- self.o_valid = Signal(name="n_o_valid") # self out>> next
- self.i_ready = Signal(name="n_i_ready") # self <<in next
- self.o_data = None # XXX MUST BE ADDED BY USER
- #if self.stage_ctl:
- self.d_valid = Signal(reset=1) # INTERNAL (data valid)
-
- @property
- def i_ready_test(self):
- if self.stage_ctl:
- return self.i_ready & self.d_valid
- return self.i_ready
-
- def connect_to_next(self, nxt):
- """ helper function to connect to the next stage data/valid/ready.
- data/valid is passed *TO* nxt, and ready comes *IN* from nxt.
- use this when connecting stage-to-stage
- """
- return [nxt.i_valid.eq(self.o_valid),
- self.i_ready.eq(nxt.o_ready),
- eq(nxt.i_data, self.o_data),
- ]
-
- def _connect_out(self, nxt):
- """ internal helper function to connect stage to an output source.
- do not use to connect stage-to-stage!
- """
- return [nxt.o_valid.eq(self.o_valid),
- self.i_ready.eq(nxt.i_ready_test),
- eq(nxt.o_data, self.o_data),
- ]
-
-
-def eq(o, i):
- """ makes signals equal: a helper routine which identifies if it is being
- passed a list (or tuple) of objects, or signals, or Records, and calls
- the objects' eq function.
-
- complex objects (classes) can be used: they must follow the
- convention of having an eq member function, which takes the
- responsibility of further calling eq and returning a list of
- eq assignments
-
- Record is a special (unusual, recursive) case, where the input may be
- specified as a dictionary (which may contain further dictionaries,
- recursively), where the field names of the dictionary must match
- the Record's field spec. Alternatively, an object with the same
- member names as the Record may be assigned: it does not have to
- *be* a Record.
-
- ArrayProxy is also special-cased, it's a bit messy: whilst ArrayProxy
- has an eq function, the object being assigned to it (e.g. a python
- object) might not. despite the *input* having an eq function,
- that doesn't help us, because it's the *ArrayProxy* that's being
- assigned to. so.... we cheat. use the ports() function of the
- python object, enumerate them, find out the list of Signals that way,
- and assign them.
- """
- res = []
- if isinstance(o, dict):
- for (k, v) in o.items():
- print ("d-eq", v, i[k])
- res.append(v.eq(i[k]))
- return res
-
- if not isinstance(o, Sequence):
- o, i = [o], [i]
- for (ao, ai) in zip(o, i):
- #print ("eq", ao, ai)
- if isinstance(ao, Record):
- for idx, (field_name, field_shape, _) in enumerate(ao.layout):
- if isinstance(field_shape, Layout):
- val = ai.fields
- else:
- val = ai
- if hasattr(val, field_name): # check for attribute
- val = getattr(val, field_name)
- else:
- val = val[field_name] # dictionary-style specification
- rres = eq(ao.fields[field_name], val)
- res += rres
- elif isinstance(ao, ArrayProxy) and not isinstance(ai, Value):
- for p in ai.ports():
- op = getattr(ao, p.name)
- #print (op, p, p.name)
- rres = op.eq(p)
- if not isinstance(rres, Sequence):
- rres = [rres]
- res += rres
- else:
- rres = ao.eq(ai)
- if not isinstance(rres, Sequence):
- rres = [rres]
- res += rres
- return res
-