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:
Sebastien Bourdeauducq 2012-02-15 16:30:16 +01:00
parent 46b1f74e98
commit 0493212124
7 changed files with 145 additions and 150 deletions

View File

@ -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)

View File

@ -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)
);
//---------------------------------------------------------------------------

View File

@ -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

View File

@ -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:
modules = self.__module__.split(".")
busname = modules[len(modules)-1]
signame = get_sig_name(signal, slave)
setattr(self, signame, Signal(BV(signal[2]), busname + "_" + signame))
class Description:
def __init__(self, *desc):
self.desc = desc
def signals(self):
return [self.__dict__[k]
for k in self.__dict__
if isinstance(self.__dict__[k], Signal)]
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]
for signal in self.desc.desc:
signame = signal[1]
setattr(self, signame, Signal(BV(signal[2]), busname + "_" + signame))
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)

View File

@ -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

View File

@ -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)
),

View File

@ -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()