bus: simplify and cleanup
Unify slave and master interfaces Remove signal direction suffixes Generic simple interconnect Wishbone point-to-point interconnect Description filter (get_name) Misc cleanups
This commit is contained in:
parent
46b1f74e98
commit
0493212124
|
@ -1,10 +1,10 @@
|
|||
from migen.fhdl import verilog
|
||||
from migen.bus import wishbone
|
||||
|
||||
m1 = wishbone.Master()
|
||||
m2 = wishbone.Master()
|
||||
s1 = wishbone.Slave()
|
||||
s2 = wishbone.Slave()
|
||||
m1 = wishbone.Interface()
|
||||
m2 = wishbone.Interface()
|
||||
s1 = wishbone.Interface()
|
||||
s2 = wishbone.Interface()
|
||||
wishbonecon0 = wishbone.InterconnectShared(
|
||||
[m1, m2],
|
||||
[(0, s1), (1, s2)],
|
||||
|
@ -12,8 +12,8 @@ wishbonecon0 = wishbone.InterconnectShared(
|
|||
offset=1)
|
||||
|
||||
frag = wishbonecon0.get_fragment()
|
||||
v = verilog.convert(frag, name="intercon", ios={m1.cyc_o, m1.stb_o, m1.we_o, m1.adr_o, m1.sel_o, m1.dat_o, m1.dat_i, m1.ack_i,
|
||||
m2.cyc_o, m2.stb_o, m2.we_o, m2.adr_o, m2.sel_o, m2.dat_o, m2.dat_i, m2.ack_i,
|
||||
s1.cyc_i, s1.stb_i, s1.we_i, s1.adr_i, s1.sel_i, s1.dat_i, s1.dat_o, s1.ack_o,
|
||||
s2.cyc_i, s2.stb_i, s2.we_i, s2.adr_i, s2.sel_i, s2.dat_i, s2.dat_o, s2.ack_o})
|
||||
v = verilog.convert(frag, name="intercon", ios={m1.cyc, m1.stb, m1.we, m1.adr, m1.sel, m1.dat_w, m1.dat_r, m1.ack,
|
||||
m2.cyc, m2.stb, m2.we, m2.adr, m2.sel, m2.dat_r, m2.dat_w, m2.ack,
|
||||
s1.cyc, s1.stb, s1.we, s1.adr, s1.sel, s1.dat_r, s1.dat_w, s1.ack,
|
||||
s2.cyc, s2.stb, s2.we, s2.adr, s2.sel, s2.dat_r, s2.dat_w, s2.ack})
|
||||
print(v)
|
||||
|
|
|
@ -80,42 +80,42 @@ intercon dut(
|
|||
.sys_rst(sys_rst),
|
||||
|
||||
// Master 0
|
||||
.m1_wishbone_dat_o(m1_wishbone_dat_w),
|
||||
.m1_wishbone_dat_i(m1_wishbone_dat_r),
|
||||
.m1_wishbone_adr_o(m1_wishbone_adr),
|
||||
.m1_wishbone_we_o(m1_wishbone_we),
|
||||
.m1_wishbone_sel_o(m1_wishbone_sel),
|
||||
.m1_wishbone_cyc_o(m1_wishbone_cyc),
|
||||
.m1_wishbone_stb_o(m1_wishbone_stb),
|
||||
.m1_wishbone_ack_i(m1_wishbone_ack),
|
||||
.m1_wishbone_dat_w(m1_wishbone_dat_w),
|
||||
.m1_wishbone_dat_r(m1_wishbone_dat_r),
|
||||
.m1_wishbone_adr(m1_wishbone_adr),
|
||||
.m1_wishbone_we(m1_wishbone_we),
|
||||
.m1_wishbone_sel(m1_wishbone_sel),
|
||||
.m1_wishbone_cyc(m1_wishbone_cyc),
|
||||
.m1_wishbone_stb(m1_wishbone_stb),
|
||||
.m1_wishbone_ack(m1_wishbone_ack),
|
||||
// Master 1
|
||||
.m2_wishbone_dat_o(m2_wishbone_dat_w),
|
||||
.m2_wishbone_dat_i(m2_wishbone_dat_r),
|
||||
.m2_wishbone_adr_o(m2_wishbone_adr),
|
||||
.m2_wishbone_we_o(m2_wishbone_we),
|
||||
.m2_wishbone_sel_o(m2_wishbone_sel),
|
||||
.m2_wishbone_cyc_o(m2_wishbone_cyc),
|
||||
.m2_wishbone_stb_o(m2_wishbone_stb),
|
||||
.m2_wishbone_ack_i(m2_wishbone_ack),
|
||||
.m2_wishbone_dat_w(m2_wishbone_dat_w),
|
||||
.m2_wishbone_dat_r(m2_wishbone_dat_r),
|
||||
.m2_wishbone_adr(m2_wishbone_adr),
|
||||
.m2_wishbone_we(m2_wishbone_we),
|
||||
.m2_wishbone_sel(m2_wishbone_sel),
|
||||
.m2_wishbone_cyc(m2_wishbone_cyc),
|
||||
.m2_wishbone_stb(m2_wishbone_stb),
|
||||
.m2_wishbone_ack(m2_wishbone_ack),
|
||||
|
||||
// Slave 0
|
||||
.s1_wishbone_dat_o(s1_wishbone_dat_r),
|
||||
.s1_wishbone_dat_i(s1_wishbone_dat_w),
|
||||
.s1_wishbone_adr_i(s1_wishbone_adr),
|
||||
.s1_wishbone_sel_i(s1_wishbone_sel),
|
||||
.s1_wishbone_we_i(s1_wishbone_we),
|
||||
.s1_wishbone_cyc_i(s1_wishbone_cyc),
|
||||
.s1_wishbone_stb_i(s1_wishbone_stb),
|
||||
.s1_wishbone_ack_o(s1_wishbone_ack),
|
||||
.s1_wishbone_dat_r(s1_wishbone_dat_r),
|
||||
.s1_wishbone_dat_w(s1_wishbone_dat_w),
|
||||
.s1_wishbone_adr(s1_wishbone_adr),
|
||||
.s1_wishbone_sel(s1_wishbone_sel),
|
||||
.s1_wishbone_we(s1_wishbone_we),
|
||||
.s1_wishbone_cyc(s1_wishbone_cyc),
|
||||
.s1_wishbone_stb(s1_wishbone_stb),
|
||||
.s1_wishbone_ack(s1_wishbone_ack),
|
||||
// Slave 1
|
||||
.s2_wishbone_dat_o(s2_wishbone_dat_r),
|
||||
.s2_wishbone_dat_i(s2_wishbone_dat_w),
|
||||
.s2_wishbone_adr_i(s2_wishbone_adr),
|
||||
.s2_wishbone_sel_i(s2_wishbone_sel),
|
||||
.s2_wishbone_we_i(s2_wishbone_we),
|
||||
.s2_wishbone_cyc_i(s2_wishbone_cyc),
|
||||
.s2_wishbone_stb_i(s2_wishbone_stb),
|
||||
.s2_wishbone_ack_o(s2_wishbone_ack)
|
||||
.s2_wishbone_dat_r(s2_wishbone_dat_r),
|
||||
.s2_wishbone_dat_w(s2_wishbone_dat_w),
|
||||
.s2_wishbone_adr(s2_wishbone_adr),
|
||||
.s2_wishbone_sel(s2_wishbone_sel),
|
||||
.s2_wishbone_we(s2_wishbone_we),
|
||||
.s2_wishbone_cyc(s2_wishbone_cyc),
|
||||
.s2_wishbone_stb(s2_wishbone_stb),
|
||||
.s2_wishbone_ack(s2_wishbone_ack)
|
||||
);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
|
|
@ -1,33 +1,16 @@
|
|||
from migen.fhdl.structure import *
|
||||
from migen.corelogic.misc import optree
|
||||
from migen.bus.simple import Simple
|
||||
from migen.bus.simple import *
|
||||
|
||||
_desc = [
|
||||
(True, "adr", 14),
|
||||
(True, "we", 1),
|
||||
(True, "dat", 8),
|
||||
(False, "dat", 8)
|
||||
]
|
||||
_desc = Description(
|
||||
(M_TO_S, "adr", 14),
|
||||
(M_TO_S, "we", 1),
|
||||
(M_TO_S, "dat_w", 8),
|
||||
(S_TO_M, "dat_r", 8)
|
||||
)
|
||||
|
||||
class Master(Simple):
|
||||
class Interface(SimpleInterface):
|
||||
def __init__(self):
|
||||
Simple.__init__(self, _desc, False)
|
||||
SimpleInterface.__init__(self, _desc)
|
||||
|
||||
class Slave(Simple):
|
||||
def __init__(self):
|
||||
Simple.__init__(self, _desc, True)
|
||||
|
||||
class Interconnect:
|
||||
def __init__(self, master, slaves):
|
||||
self.master = master
|
||||
self.slaves = slaves
|
||||
|
||||
def get_fragment(self):
|
||||
comb = []
|
||||
for slave in self.slaves:
|
||||
comb.append(slave.adr_i.eq(self.master.adr_o))
|
||||
comb.append(slave.we_i.eq(self.master.we_o))
|
||||
comb.append(slave.dat_i.eq(self.master.dat_o))
|
||||
rb = optree("|", [slave.dat_o for slave in self.slaves])
|
||||
comb.append(self.master.dat_i.eq(rb))
|
||||
return Fragment(comb)
|
||||
class Interconnect(SimpleInterconnect):
|
||||
pass
|
||||
|
|
|
@ -1,25 +1,44 @@
|
|||
from migen.fhdl.structure import *
|
||||
from migen.corelogic.misc import optree
|
||||
|
||||
def get_sig_name(signal, slave):
|
||||
if signal[0] ^ slave:
|
||||
suffix = "_o"
|
||||
else:
|
||||
suffix = "_i"
|
||||
return signal[1] + suffix
|
||||
(S_TO_M, M_TO_S) = range(2)
|
||||
|
||||
# desc is a list of tuples, each made up of:
|
||||
# 0) boolean: "master to slave"
|
||||
# 0) S_TO_M/M_TO_S: data direction
|
||||
# 1) string: name
|
||||
# 2) int: width
|
||||
class Simple():
|
||||
def __init__(self, desc, slave):
|
||||
for signal in desc:
|
||||
|
||||
class Description:
|
||||
def __init__(self, *desc):
|
||||
self.desc = desc
|
||||
|
||||
def get_names(self, direction, *exclude_list):
|
||||
exclude = set(exclude_list)
|
||||
return [signal[1]
|
||||
for signal in self.desc
|
||||
if signal[0] == direction and signal[1] not in exclude]
|
||||
|
||||
class SimpleInterface:
|
||||
def __init__(self, desc):
|
||||
self.desc = desc
|
||||
modules = self.__module__.split(".")
|
||||
busname = modules[len(modules)-1]
|
||||
signame = get_sig_name(signal, slave)
|
||||
for signal in self.desc.desc:
|
||||
signame = signal[1]
|
||||
setattr(self, signame, Signal(BV(signal[2]), busname + "_" + signame))
|
||||
|
||||
def signals(self):
|
||||
return [self.__dict__[k]
|
||||
for k in self.__dict__
|
||||
if isinstance(self.__dict__[k], Signal)]
|
||||
class SimpleInterconnect:
|
||||
def __init__(self, master, slaves):
|
||||
self.master = master
|
||||
self.slaves = slaves
|
||||
|
||||
def get_fragment(self):
|
||||
s2m = master.desc.get_names(S_TO_M)
|
||||
m2s = master.desc.get_names(M_TO_S)
|
||||
comb = [getattr(slave, name).eq(getattr(master, name))
|
||||
for name in m2s for slave in self.slave]
|
||||
comb += [getattr(master, name).eq(
|
||||
optree("|", [getattr(slave, name) for slave in self.slaves])
|
||||
)
|
||||
for name in s2m]
|
||||
return Fragment(comb)
|
||||
|
|
|
@ -1,29 +1,29 @@
|
|||
from migen.fhdl.structure import *
|
||||
from migen.corelogic import roundrobin
|
||||
from migen.corelogic.misc import multimux, optree
|
||||
from migen.bus.simple import Simple, get_sig_name
|
||||
from migen.bus.simple import *
|
||||
|
||||
_desc = [
|
||||
(True, "adr", 30),
|
||||
(True, "dat", 32),
|
||||
(False, "dat", 32),
|
||||
(True, "sel", 4),
|
||||
(True, "cyc", 1),
|
||||
(True, "stb", 1),
|
||||
(False, "ack", 1),
|
||||
(True, "we", 1),
|
||||
(True, "cti", 3),
|
||||
(True, "bte", 2),
|
||||
(False, "err", 1)
|
||||
]
|
||||
_desc = Description(
|
||||
(M_TO_S, "adr", 30),
|
||||
(M_TO_S, "dat_w", 32),
|
||||
(S_TO_M, "dat_r", 32),
|
||||
(M_TO_S, "sel", 4),
|
||||
(M_TO_S, "cyc", 1),
|
||||
(M_TO_S, "stb", 1),
|
||||
(S_TO_M, "ack", 1),
|
||||
(M_TO_S, "we", 1),
|
||||
(M_TO_S, "cti", 3),
|
||||
(M_TO_S, "bte", 2),
|
||||
(S_TO_M, "err", 1)
|
||||
)
|
||||
|
||||
class Master(Simple):
|
||||
class Interface(SimpleInterface):
|
||||
def __init__(self):
|
||||
Simple.__init__(self, _desc, False)
|
||||
SimpleInterface.__init__(self, _desc)
|
||||
|
||||
class Slave(Simple):
|
||||
def __init__(self):
|
||||
Simple.__init__(self, _desc, True)
|
||||
class InterconnectPointToPoint(SimpleInterconnect):
|
||||
def __init__(self, master, slave):
|
||||
SimpleInterconnect.__init__(self, master, [slave])
|
||||
|
||||
class Arbiter:
|
||||
def __init__(self, masters, target):
|
||||
|
@ -35,26 +35,23 @@ class Arbiter:
|
|||
comb = []
|
||||
|
||||
# mux master->slave signals
|
||||
m2s_names = [get_sig_name(x, False) for x in _desc if x[0]]
|
||||
m2s_names = _desc.get_names(M_TO_S)
|
||||
m2s_masters = [[getattr(m, name) for name in m2s_names] for m in self.masters]
|
||||
m2s_target = [getattr(self.target, name) for name in m2s_names]
|
||||
comb += multimux(self.rr.grant, m2s_masters, m2s_target)
|
||||
|
||||
# connect slave->master signals
|
||||
s2m_names = [get_sig_name(x, False) for x in _desc if not x[0]]
|
||||
for name in s2m_names:
|
||||
for name in _desc.get_names(S_TO_M):
|
||||
source = getattr(self.target, name)
|
||||
i = 0
|
||||
for m in self.masters:
|
||||
for i, m in enumerate(self.masters):
|
||||
dest = getattr(m, name)
|
||||
if name == "ack_i" or name == "err_i":
|
||||
if name == "ack" or name == "err":
|
||||
comb.append(dest.eq(source & (self.rr.grant == Constant(i, self.rr.grant.bv))))
|
||||
else:
|
||||
comb.append(dest.eq(source))
|
||||
i += 1
|
||||
|
||||
# connect bus requests to round-robin selector
|
||||
reqs = [m.cyc_o for m in self.masters]
|
||||
reqs = [m.cyc for m in self.masters]
|
||||
comb.append(self.rr.request.eq(Cat(*reqs)))
|
||||
|
||||
return Fragment(comb) + self.rr.get_fragment()
|
||||
|
@ -92,42 +89,38 @@ class Decoder:
|
|||
slave_sel_r = Signal(BV(ns))
|
||||
|
||||
# decode slave addresses
|
||||
i = 0
|
||||
hi = self.master.adr_o.bv.width - self.offset
|
||||
for addr in self.addresses:
|
||||
comb.append(slave_sel[i].eq(
|
||||
self.master.adr_o[hi-addr.bv.width:hi] == addr))
|
||||
i += 1
|
||||
hi = self.master.adr.bv.width - self.offset
|
||||
comb += [slave_sel[i].eq(self.master.adr[hi-addr.bv.width:hi] == addr)
|
||||
for i, addr in enumerate(self.addresses)]
|
||||
if self.register:
|
||||
sync.append(slave_sel_r.eq(slave_sel))
|
||||
else:
|
||||
comb.append(slave_sel_r.eq(slave_sel))
|
||||
|
||||
# connect master->slaves signals except cyc
|
||||
m2s_names = [(get_sig_name(x, False), get_sig_name(x, True))
|
||||
for x in _desc if x[0] and x[1] != "cyc"]
|
||||
comb += [getattr(slave[1], name[1]).eq(getattr(self.master, name[0]))
|
||||
m2s_names = _desc.get_names(M_TO_S, "cyc")
|
||||
comb += [getattr(slave[1], name).eq(getattr(self.master, name))
|
||||
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(slave[1].cyc_i.eq(self.master.cyc_o & slave_sel[i]))
|
||||
i += 1
|
||||
comb += [slave[1].cyc.eq(self.master.cyc & slave_sel[i])
|
||||
for i, slave in enumerate(self.slaves)]
|
||||
|
||||
# generate master ack (resp. err) by ORing all slave acks (resp. errs)
|
||||
comb.append(self.master.ack_i.eq(optree("|", [slave[1].ack_o for slave in self.slaves])))
|
||||
comb.append(self.master.err_i.eq(optree("|", [slave[1].err_o for slave in self.slaves])))
|
||||
comb += [
|
||||
self.master.ack.eq(optree("|", [slave[1].ack for slave in self.slaves])),
|
||||
self.master.err.eq(optree("|", [slave[1].err for slave in self.slaves]))
|
||||
]
|
||||
|
||||
# mux (1-hot) slave data return
|
||||
masked = [Replicate(slave_sel_r[i], self.master.dat_i.bv.width) & self.slaves[i][1].dat_o for i in range(len(self.slaves))]
|
||||
comb.append(self.master.dat_i.eq(optree("|", masked)))
|
||||
masked = [Replicate(slave_sel_r[i], self.master.dat_r.bv.width) & self.slaves[i][1].dat_r for i in range(len(self.slaves))]
|
||||
comb.append(self.master.dat_r.eq(optree("|", masked)))
|
||||
|
||||
return Fragment(comb, sync)
|
||||
|
||||
class InterconnectShared:
|
||||
def __init__(self, masters, slaves, offset=0, register=False):
|
||||
self._shared = Master()
|
||||
self._shared = Interface()
|
||||
self._arbiter = Arbiter(masters, self._shared)
|
||||
self._decoder = Decoder(self._shared, slaves, offset, register)
|
||||
self.addresses = self._decoder.addresses
|
||||
|
|
|
@ -18,7 +18,7 @@ def _log2_int(n):
|
|||
# cachesize (in 32-bit words) is the size of the data store, must be a power of 2
|
||||
class WB2ASMI:
|
||||
def __init__(self, cachesize, asmiport):
|
||||
self.wishbone = wishbone.Slave()
|
||||
self.wishbone = wishbone.Interface()
|
||||
self.cachesize = cachesize
|
||||
self.asmiport = asmiport
|
||||
if len(self.asmiport.slots) != 1:
|
||||
|
@ -41,7 +41,7 @@ class WB2ASMI:
|
|||
addressbits = aaw + offsetbits
|
||||
linebits = _log2_int(self.cachesize) - offsetbits
|
||||
tagbits = aaw - linebits
|
||||
adr_offset, adr_line, adr_tag = split(self.wishbone.adr_i, offsetbits, linebits, tagbits)
|
||||
adr_offset, adr_line, adr_tag = split(self.wishbone.adr, offsetbits, linebits, tagbits)
|
||||
|
||||
# Data memory
|
||||
data_adr = Signal(BV(linebits))
|
||||
|
@ -60,16 +60,16 @@ class WB2ASMI:
|
|||
data_di.eq(self.asmiport.dat_r),
|
||||
data_we.eq(Replicate(1, adw//8))
|
||||
).Else(
|
||||
data_di.eq(Replicate(self.wishbone.dat_i, adw//32)),
|
||||
If(self.wishbone.cyc_i & self.wishbone.stb_i & self.wishbone.we_i & self.wishbone.ack_o,
|
||||
displacer(self.wishbone.sel_i, adr_offset, data_we, 2**offsetbits, reverse=True)
|
||||
data_di.eq(Replicate(self.wishbone.dat_w, adw//32)),
|
||||
If(self.wishbone.cyc & self.wishbone.stb & self.wishbone.we & self.wishbone.ack,
|
||||
displacer(self.wishbone.sel, adr_offset, data_we, 2**offsetbits, reverse=True)
|
||||
)
|
||||
),
|
||||
If(write_to_asmi,
|
||||
self.asmiport.dat_w.eq(data_do),
|
||||
self.asmiport.dat_wm.eq(Replicate(1, adw//8))
|
||||
),
|
||||
chooser(data_do, adr_offset_r, self.wishbone.dat_o, reverse=True)
|
||||
chooser(data_do, adr_offset_r, self.wishbone.dat_r, reverse=True)
|
||||
]
|
||||
sync += [
|
||||
adr_offset_r.eq(adr_offset)
|
||||
|
@ -102,12 +102,12 @@ class WB2ASMI:
|
|||
"REFILL_WRTAG", "REFILL_ISSUE", "REFILL_WAIT", "REFILL_COMPLETE")
|
||||
|
||||
fsm.act(fsm.IDLE,
|
||||
If(self.wishbone.cyc_i & self.wishbone.stb_i, fsm.next_state(fsm.TEST_HIT))
|
||||
If(self.wishbone.cyc & self.wishbone.stb, fsm.next_state(fsm.TEST_HIT))
|
||||
)
|
||||
fsm.act(fsm.TEST_HIT,
|
||||
If(tag_do.tag == adr_tag,
|
||||
self.wishbone.ack_o.eq(1),
|
||||
If(self.wishbone.we_i,
|
||||
self.wishbone.ack.eq(1),
|
||||
If(self.wishbone.we,
|
||||
tag_di.dirty.eq(1),
|
||||
tag_we.eq(1)
|
||||
),
|
||||
|
|
|
@ -5,18 +5,18 @@ from migen.corelogic import timeline
|
|||
|
||||
class WB2CSR:
|
||||
def __init__(self):
|
||||
self.wishbone = wishbone.Slave()
|
||||
self.csr = csr.Master()
|
||||
self.timeline = timeline.Timeline(self.wishbone.cyc_i & self.wishbone.stb_i,
|
||||
[(1, [self.csr.we_o.eq(self.wishbone.we_i)]),
|
||||
(2, [self.wishbone.ack_o.eq(1)]),
|
||||
(3, [self.wishbone.ack_o.eq(0)])])
|
||||
self.wishbone = wishbone.Interface()
|
||||
self.csr = csr.Interface()
|
||||
self.timeline = timeline.Timeline(self.wishbone.cyc & self.wishbone.stb,
|
||||
[(1, [self.csr.we.eq(self.wishbone.we)]),
|
||||
(2, [self.wishbone.ack.eq(1)]),
|
||||
(3, [self.wishbone.ack.eq(0)])])
|
||||
|
||||
def get_fragment(self):
|
||||
sync = [
|
||||
self.csr.we_o.eq(0),
|
||||
self.csr.dat_o.eq(self.wishbone.dat_i[:8]),
|
||||
self.csr.adr_o.eq(self.wishbone.adr_i[:14]),
|
||||
self.wishbone.dat_o.eq(self.csr.dat_i)
|
||||
self.csr.we.eq(0),
|
||||
self.csr.dat_w.eq(self.wishbone.dat_w[:8]),
|
||||
self.csr.adr.eq(self.wishbone.adr[:14]),
|
||||
self.wishbone.dat_r.eq(self.csr.dat_r)
|
||||
]
|
||||
return Fragment(sync=sync) + self.timeline.get_fragment()
|
||||
|
|
Loading…
Reference in New Issue