return f.Fragment(comb) + self.rr.GetFragment()
+
+class Decoder:
+ # slaves is a list of pairs:
+ # 0) structure.Constant defining address (always decoded on the upper bits)
+ # Slaves can have differing numbers of address bits, but addresses
+ # must not conflict.
+ # 1) wishbone.Slave reference
+ # Addresses are decoded from bit 31-offset and downwards.
+ # register adds flip-flops after the address comparators. Improves timing,
+ # but breaks Wishbone combinatorial feedback.
+ def __init__(self, master, slaves, offset=0, register=False):
+ self.master = master
+ self.slaves = slaves
+ self.offset = offset
+ self.register = register
+
+ addresses = [slave[0] for slave in self.slaves]
+ maxbits = max([f.BitsFor(addr) for addr in addresses])
+ def mkconst(x):
+ if isinstance(x, int):
+ return f.Constant(x, f.BV(maxbits))
+ else:
+ return x
+ self.addresses = list(map(mkconst, addresses))
+
+ ns = len(self.slaves)
+ d = partial(f.Declare, self)
+ d("_slave_sel", f.BV(ns))
+ d("_slave_sel_r", f.BV(ns))
+
+ def GetFragment(self):
+ comb = []
+ sync = []
+
+ # decode slave addresses
+ i = 0
+ hi = self.master.adr_o.bv.width - self.offset
+ for addr in self.addresses:
+ comb.append(f.Assign(self._slave_sel[i],
+ self.master.adr_o[hi-addr.bv.width:hi] == addr))
+ i += 1
+ if self.register:
+ sync.append(f.Assign(self._slave_sel_r, self._slave_sel))
+ else:
+ comb.append(f.Assign(self._slave_sel_r, self._slave_sel))
+
+ # connect master->slaves signals except cyc
+ m2s_names = [(GetSigName(x, False), GetSigName(x, True))
+ for x in _desc if x[0] and x[1] != "cyc"]
+ comb += [f.Assign(getattr(slave[1], name[1]), getattr(self.master, name[0]))
+ for name in m2s_names for slave in self.slaves]
+
+ # combine cyc with slave selection signals
+ i = 0
+ for slave in self.slaves:
+ comb.append(f.Assign(slave[1].cyc_i, self.master.cyc_o & self._slave_sel_r[i]))
+ i += 1
+
+ # generate master ack (resp. err) by ORing all slave acks (resp. errs)
+ ackv = f.Constant(0)
+ errv = f.Constant(0)
+ for slave in self.slaves:
+ ackv = ackv | slave[1].ack_o
+ errv = errv | slave[1].err_o
+ comb.append(f.Assign(self.master.ack_i, ackv))
+ comb.append(f.Assign(self.master.err_i, errv))
+
+ # mux (1-hot) slave data return
+ i = 0
+ datav = f.Constant(0, self.master.dat_i.bv)
+ for slave in self.slaves:
+ datav = datav | (f.Replicate(self._slave_sel_r[i], self.master.dat_i.bv.width) & slave[1].dat_o)
+ i += 1
+ comb.append(f.Assign(self.master.dat_i, datav))
+
+ return f.Fragment(comb, sync)
+
+class InterconnectShared:
+ def __init__(self, masters, slaves, offset=0, register=False):
+ self._shared = Master("shr")
+ self._arbiter = Arbiter(masters, self._shared)
+ self._decoder = Decoder(self._shared, slaves, offset, register)
+ self.addresses = self._decoder.addresses
+
+ def GetFragment(self):
+ return self._arbiter.GetFragment() + self._decoder.GetFragment()