diff --git a/migen/bus/wishbone.py b/migen/bus/wishbone.py index 1e7f1e8e6..ee579fb1f 100644 --- a/migen/bus/wishbone.py +++ b/migen/bus/wishbone.py @@ -54,3 +54,89 @@ class Arbiter: 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()