diff --git a/examples/basic/arrays.py b/examples/basic/arrays.py new file mode 100644 index 000000000..4081f8513 --- /dev/null +++ b/examples/basic/arrays.py @@ -0,0 +1,25 @@ +from migen.fhdl.structure import * +from migen.fhdl import verilog + +dx = 5 +dy = 5 + +x = Signal(BV(bits_for(dx))) +y = Signal(BV(bits_for(dy))) +out = Signal() + +my_2d_array = Array(Array(Signal() for a in range(dx)) for b in range(dy)) +comb = [ + out.eq(my_2d_array[x][y]) +] + +we = Signal() +inp = Signal() +sync = [ + If(we, + my_2d_array[x][y].eq(inp) + ) +] + +f = Fragment(comb) +print(verilog.convert(f)) diff --git a/migen/corelogic/misc.py b/migen/corelogic/misc.py index 746433209..5c8bae4cb 100644 --- a/migen/corelogic/misc.py +++ b/migen/corelogic/misc.py @@ -1,6 +1,8 @@ from migen.fhdl.structure import * from migen.fhdl.structure import _Operator +# multimux is deprecated - use Array instead +# TODO: remove uses of multimux def multimux(sel, inputs, output): n = len(inputs) i = 0 diff --git a/migen/fhdl/structure.py b/migen/fhdl/structure.py index b4fb44afd..ebb88fbb9 100644 --- a/migen/fhdl/structure.py +++ b/migen/fhdl/structure.py @@ -223,7 +223,29 @@ class Case: if self.default is None: self.default = _StatementList() -# +# arrays + +class _ArrayProxy(Value): + def __init__(self, choices, key): + self.choices = choices + self.key = key + + def __getattr__(self, attr): + return _ArrayProxy([getattr(choice, attr) for choice in self.choices], + self.key) + + def __getitem__(self, key): + return _ArrayProxy([choice.__getitem__(key) for choice in self.choices], + self.key) + +class Array(list): + def __getitem__(self, key): + if isinstance(key, Value): + return _ArrayProxy(self, key) + else: + return super().__getitem__(key) + +# extras class Instance: def __init__(self, of, outs=[], ins=[], inouts=[], parameters=[], clkport="", rstport="", name=""): @@ -270,6 +292,8 @@ class Memory: self.ports = ports self.init = init +# + class Fragment: def __init__(self, comb=None, sync=None, instances=None, memories=None, sim=None): if comb is None: comb = [] diff --git a/migen/fhdl/tools.py b/migen/fhdl/tools.py index bd8393d52..f79002966 100644 --- a/migen/fhdl/tools.py +++ b/migen/fhdl/tools.py @@ -1,5 +1,7 @@ +from copy import copy + from migen.fhdl.structure import * -from migen.fhdl.structure import _Operator, _Slice, _Assign, _StatementList +from migen.fhdl.structure import _Operator, _Slice, _Assign, _StatementList, _ArrayProxy def list_signals(node): if node is None: @@ -123,3 +125,98 @@ def insert_reset(rst, sl): targets = list_targets(sl) resetcode = [t.eq(t.reset) for t in targets] return If(rst, *resetcode).Else(*sl.l) + +def _lower_arrays_values(vl): + r = [] + extra_comb = [] + for v in vl: + v2, e = _lower_arrays_value(v) + extra_comb += e + r.append(v2) + return r, extra_comb + +def _lower_arrays_value(v): + if isinstance(v, _Operator): + op2, e = _lower_arrays_values(v.operands) + return _Operator(v.op, op2), e + elif isinstance(v, _Slice): + v2, e = _lower_arrays_value(v.value) + return _Slice(v2, v.start, v.stop), e + elif isinstance(v, Cat): + l2, e = _lower_arrays_values(v.l) + return Cat(*l2), e + elif isinstance(v, Replicate): + v2, e = _lower_arrays_value(v.v) + return Replicate(v2, v.n), e + elif isinstance(v, Constant): + return v, [] + elif isinstance(v, Signal): + return v, [] + elif isinstance(v, _ArrayProxy): + choices2, e = _lower_arrays_values(v.choices) + array_muxed = Signal(BV(32)) # TODO: use the correct BV + cases = [[Constant(n), _Assign(array_muxed, choice)] + for n, choice in enumerate(choices2)] + cases[-1][0] = Default() + e.append(Case(v.key, *cases)) + return array_muxed, e + +def _lower_arrays_assign(l, r): + extra_comb = [] + if isinstance(l, _ArrayProxy): + k, e = _lower_arrays_value(l.key) + extra_comb += e + cases = [] + for n, choice in enumerate(l.choices): + assign, e = _lower_arrays_assign(choice, r) + extra_comb += e + cases.append([Constant(n), assign]) + cases[-1][0] = Default() + return Case(k, *cases), extra_comb + else: + return _Assign(l, r), extra_comb + +def _lower_arrays_sl(sl): + result = _StatementList() + rs = result.l + extra_comb = [] + for statement in sl.l: + if isinstance(statement, _Assign): + r, e = _lower_arrays_value(statement.r) + extra_comb += e + r, e = _lower_arrays_assign(statement.l, r) + extra_comb += e + rs.append(r) + elif isinstance(statement, If): + cond, e = _lower_arrays_value(statement.cond) + extra_comb += e + t, e = _lower_arrays_sl(statement.t) + extra_comb += e + f, e = _lower_arrays_sl(statement.f) + extra_comb += e + i = If(cond) + i.t = t + i.f = f + rs.append(i) + elif isinstance(statement, Case): + test, e = _lower_arrays_value(statement.test) + extra_comb += e + c = Case(test) + for cond, csl in statement.cases: + stmts, e = _lower_arrays_sl(csl) + extra_comb += e + c.cases.append((cond, stmts)) + if statement.default is not None: + c.default, e = _lower_arrays_sl(statement.default) + extra_comb += e + rs.append(c) + elif statement is not None: + raise TypeError + return result, extra_comb + +def lower_arrays(f): + f = copy(f) + f.comb, ec1 = _lower_arrays_sl(f.comb) + f.sync, ec2 = _lower_arrays_sl(f.sync) + f.comb.l += ec1 + ec2 + return f diff --git a/migen/fhdl/verilog.py b/migen/fhdl/verilog.py index 81a02ac5e..e06dee662 100644 --- a/migen/fhdl/verilog.py +++ b/migen/fhdl/verilog.py @@ -247,6 +247,8 @@ def convert(f, ios=set(), name="top", if rst_signal is None: rst_signal = Signal(name_override="sys_rst") ios.add(rst_signal) + + f = lower_arrays(f) ns = build_namespace(list_signals(f) \ | list_inst_ios(f, True, True, True) \