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.fhdl import verilog
from migen.bus import wishbone from migen.bus import wishbone
m1 = wishbone.Master() m1 = wishbone.Interface()
m2 = wishbone.Master() m2 = wishbone.Interface()
s1 = wishbone.Slave() s1 = wishbone.Interface()
s2 = wishbone.Slave() s2 = wishbone.Interface()
wishbonecon0 = wishbone.InterconnectShared( wishbonecon0 = wishbone.InterconnectShared(
[m1, m2], [m1, m2],
[(0, s1), (1, s2)], [(0, s1), (1, s2)],
@ -12,8 +12,8 @@ wishbonecon0 = wishbone.InterconnectShared(
offset=1) offset=1)
frag = wishbonecon0.get_fragment() 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, 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_o, m2.stb_o, m2.we_o, m2.adr_o, m2.sel_o, m2.dat_o, m2.dat_i, m2.ack_i, m2.cyc, m2.stb, m2.we, m2.adr, m2.sel, m2.dat_r, m2.dat_w, m2.ack,
s1.cyc_i, s1.stb_i, s1.we_i, s1.adr_i, s1.sel_i, s1.dat_i, s1.dat_o, s1.ack_o, s1.cyc, s1.stb, s1.we, s1.adr, s1.sel, s1.dat_r, s1.dat_w, s1.ack,
s2.cyc_i, s2.stb_i, s2.we_i, s2.adr_i, s2.sel_i, s2.dat_i, s2.dat_o, s2.ack_o}) s2.cyc, s2.stb, s2.we, s2.adr, s2.sel, s2.dat_r, s2.dat_w, s2.ack})
print(v) print(v)

View file

@ -80,42 +80,42 @@ intercon dut(
.sys_rst(sys_rst), .sys_rst(sys_rst),
// Master 0 // Master 0
.m1_wishbone_dat_o(m1_wishbone_dat_w), .m1_wishbone_dat_w(m1_wishbone_dat_w),
.m1_wishbone_dat_i(m1_wishbone_dat_r), .m1_wishbone_dat_r(m1_wishbone_dat_r),
.m1_wishbone_adr_o(m1_wishbone_adr), .m1_wishbone_adr(m1_wishbone_adr),
.m1_wishbone_we_o(m1_wishbone_we), .m1_wishbone_we(m1_wishbone_we),
.m1_wishbone_sel_o(m1_wishbone_sel), .m1_wishbone_sel(m1_wishbone_sel),
.m1_wishbone_cyc_o(m1_wishbone_cyc), .m1_wishbone_cyc(m1_wishbone_cyc),
.m1_wishbone_stb_o(m1_wishbone_stb), .m1_wishbone_stb(m1_wishbone_stb),
.m1_wishbone_ack_i(m1_wishbone_ack), .m1_wishbone_ack(m1_wishbone_ack),
// Master 1 // Master 1
.m2_wishbone_dat_o(m2_wishbone_dat_w), .m2_wishbone_dat_w(m2_wishbone_dat_w),
.m2_wishbone_dat_i(m2_wishbone_dat_r), .m2_wishbone_dat_r(m2_wishbone_dat_r),
.m2_wishbone_adr_o(m2_wishbone_adr), .m2_wishbone_adr(m2_wishbone_adr),
.m2_wishbone_we_o(m2_wishbone_we), .m2_wishbone_we(m2_wishbone_we),
.m2_wishbone_sel_o(m2_wishbone_sel), .m2_wishbone_sel(m2_wishbone_sel),
.m2_wishbone_cyc_o(m2_wishbone_cyc), .m2_wishbone_cyc(m2_wishbone_cyc),
.m2_wishbone_stb_o(m2_wishbone_stb), .m2_wishbone_stb(m2_wishbone_stb),
.m2_wishbone_ack_i(m2_wishbone_ack), .m2_wishbone_ack(m2_wishbone_ack),
// Slave 0 // Slave 0
.s1_wishbone_dat_o(s1_wishbone_dat_r), .s1_wishbone_dat_r(s1_wishbone_dat_r),
.s1_wishbone_dat_i(s1_wishbone_dat_w), .s1_wishbone_dat_w(s1_wishbone_dat_w),
.s1_wishbone_adr_i(s1_wishbone_adr), .s1_wishbone_adr(s1_wishbone_adr),
.s1_wishbone_sel_i(s1_wishbone_sel), .s1_wishbone_sel(s1_wishbone_sel),
.s1_wishbone_we_i(s1_wishbone_we), .s1_wishbone_we(s1_wishbone_we),
.s1_wishbone_cyc_i(s1_wishbone_cyc), .s1_wishbone_cyc(s1_wishbone_cyc),
.s1_wishbone_stb_i(s1_wishbone_stb), .s1_wishbone_stb(s1_wishbone_stb),
.s1_wishbone_ack_o(s1_wishbone_ack), .s1_wishbone_ack(s1_wishbone_ack),
// Slave 1 // Slave 1
.s2_wishbone_dat_o(s2_wishbone_dat_r), .s2_wishbone_dat_r(s2_wishbone_dat_r),
.s2_wishbone_dat_i(s2_wishbone_dat_w), .s2_wishbone_dat_w(s2_wishbone_dat_w),
.s2_wishbone_adr_i(s2_wishbone_adr), .s2_wishbone_adr(s2_wishbone_adr),
.s2_wishbone_sel_i(s2_wishbone_sel), .s2_wishbone_sel(s2_wishbone_sel),
.s2_wishbone_we_i(s2_wishbone_we), .s2_wishbone_we(s2_wishbone_we),
.s2_wishbone_cyc_i(s2_wishbone_cyc), .s2_wishbone_cyc(s2_wishbone_cyc),
.s2_wishbone_stb_i(s2_wishbone_stb), .s2_wishbone_stb(s2_wishbone_stb),
.s2_wishbone_ack_o(s2_wishbone_ack) .s2_wishbone_ack(s2_wishbone_ack)
); );
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View file

@ -1,33 +1,16 @@
from migen.fhdl.structure import * from migen.fhdl.structure import *
from migen.corelogic.misc import optree from migen.bus.simple import *
from migen.bus.simple import Simple
_desc = [ _desc = Description(
(True, "adr", 14), (M_TO_S, "adr", 14),
(True, "we", 1), (M_TO_S, "we", 1),
(True, "dat", 8), (M_TO_S, "dat_w", 8),
(False, "dat", 8) (S_TO_M, "dat_r", 8)
] )
class Master(Simple): class Interface(SimpleInterface):
def __init__(self): def __init__(self):
Simple.__init__(self, _desc, False) SimpleInterface.__init__(self, _desc)
class Slave(Simple): class Interconnect(SimpleInterconnect):
def __init__(self): pass
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)

View file

@ -1,25 +1,44 @@
from migen.fhdl.structure import * from migen.fhdl.structure import *
from migen.corelogic.misc import optree
def get_sig_name(signal, slave): (S_TO_M, M_TO_S) = range(2)
if signal[0] ^ slave:
suffix = "_o"
else:
suffix = "_i"
return signal[1] + suffix
# desc is a list of tuples, each made up of: # 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 # 1) string: name
# 2) int: width # 2) int: width
class Simple():
def __init__(self, desc, slave): class Description:
for signal in desc: def __init__(self, *desc):
modules = self.__module__.split(".") self.desc = desc
busname = modules[len(modules)-1]
signame = get_sig_name(signal, slave)
setattr(self, signame, Signal(BV(signal[2]), busname + "_" + signame))
def signals(self): def get_names(self, direction, *exclude_list):
return [self.__dict__[k] exclude = set(exclude_list)
for k in self.__dict__ return [signal[1]
if isinstance(self.__dict__[k], Signal)] 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.fhdl.structure import *
from migen.corelogic import roundrobin from migen.corelogic import roundrobin
from migen.corelogic.misc import multimux, optree from migen.corelogic.misc import multimux, optree
from migen.bus.simple import Simple, get_sig_name from migen.bus.simple import *
_desc = [ _desc = Description(
(True, "adr", 30), (M_TO_S, "adr", 30),
(True, "dat", 32), (M_TO_S, "dat_w", 32),
(False, "dat", 32), (S_TO_M, "dat_r", 32),
(True, "sel", 4), (M_TO_S, "sel", 4),
(True, "cyc", 1), (M_TO_S, "cyc", 1),
(True, "stb", 1), (M_TO_S, "stb", 1),
(False, "ack", 1), (S_TO_M, "ack", 1),
(True, "we", 1), (M_TO_S, "we", 1),
(True, "cti", 3), (M_TO_S, "cti", 3),
(True, "bte", 2), (M_TO_S, "bte", 2),
(False, "err", 1) (S_TO_M, "err", 1)
] )
class Master(Simple): class Interface(SimpleInterface):
def __init__(self): def __init__(self):
Simple.__init__(self, _desc, False) SimpleInterface.__init__(self, _desc)
class Slave(Simple): class InterconnectPointToPoint(SimpleInterconnect):
def __init__(self): def __init__(self, master, slave):
Simple.__init__(self, _desc, True) SimpleInterconnect.__init__(self, master, [slave])
class Arbiter: class Arbiter:
def __init__(self, masters, target): def __init__(self, masters, target):
@ -35,26 +35,23 @@ class Arbiter:
comb = [] comb = []
# mux master->slave signals # 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_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] m2s_target = [getattr(self.target, name) for name in m2s_names]
comb += multimux(self.rr.grant, m2s_masters, m2s_target) comb += multimux(self.rr.grant, m2s_masters, m2s_target)
# connect slave->master signals # connect slave->master signals
s2m_names = [get_sig_name(x, False) for x in _desc if not x[0]] for name in _desc.get_names(S_TO_M):
for name in s2m_names:
source = getattr(self.target, name) source = getattr(self.target, name)
i = 0 for i, m in enumerate(self.masters):
for m in self.masters:
dest = getattr(m, name) 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)))) comb.append(dest.eq(source & (self.rr.grant == Constant(i, self.rr.grant.bv))))
else: else:
comb.append(dest.eq(source)) comb.append(dest.eq(source))
i += 1
# connect bus requests to round-robin selector # 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))) comb.append(self.rr.request.eq(Cat(*reqs)))
return Fragment(comb) + self.rr.get_fragment() return Fragment(comb) + self.rr.get_fragment()
@ -92,42 +89,38 @@ class Decoder:
slave_sel_r = Signal(BV(ns)) slave_sel_r = Signal(BV(ns))
# decode slave addresses # decode slave addresses
i = 0 hi = self.master.adr.bv.width - self.offset
hi = self.master.adr_o.bv.width - self.offset comb += [slave_sel[i].eq(self.master.adr[hi-addr.bv.width:hi] == addr)
for addr in self.addresses: for i, addr in enumerate(self.addresses)]
comb.append(slave_sel[i].eq(
self.master.adr_o[hi-addr.bv.width:hi] == addr))
i += 1
if self.register: if self.register:
sync.append(slave_sel_r.eq(slave_sel)) sync.append(slave_sel_r.eq(slave_sel))
else: else:
comb.append(slave_sel_r.eq(slave_sel)) comb.append(slave_sel_r.eq(slave_sel))
# connect master->slaves signals except cyc # connect master->slaves signals except cyc
m2s_names = [(get_sig_name(x, False), get_sig_name(x, True)) m2s_names = _desc.get_names(M_TO_S, "cyc")
for x in _desc if x[0] and x[1] != "cyc"] comb += [getattr(slave[1], name).eq(getattr(self.master, name))
comb += [getattr(slave[1], name[1]).eq(getattr(self.master, name[0]))
for name in m2s_names for slave in self.slaves] for name in m2s_names for slave in self.slaves]
# combine cyc with slave selection signals # combine cyc with slave selection signals
i = 0 comb += [slave[1].cyc.eq(self.master.cyc & slave_sel[i])
for slave in self.slaves: for i, slave in enumerate(self.slaves)]
comb.append(slave[1].cyc_i.eq(self.master.cyc_o & slave_sel[i]))
i += 1
# generate master ack (resp. err) by ORing all slave acks (resp. errs) # 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 += [
comb.append(self.master.err_i.eq(optree("|", [slave[1].err_o for slave in self.slaves]))) 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 # 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))] 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_i.eq(optree("|", masked))) comb.append(self.master.dat_r.eq(optree("|", masked)))
return Fragment(comb, sync) return Fragment(comb, sync)
class InterconnectShared: class InterconnectShared:
def __init__(self, masters, slaves, offset=0, register=False): def __init__(self, masters, slaves, offset=0, register=False):
self._shared = Master() self._shared = Interface()
self._arbiter = Arbiter(masters, self._shared) self._arbiter = Arbiter(masters, self._shared)
self._decoder = Decoder(self._shared, slaves, offset, register) self._decoder = Decoder(self._shared, slaves, offset, register)
self.addresses = self._decoder.addresses 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 # cachesize (in 32-bit words) is the size of the data store, must be a power of 2
class WB2ASMI: class WB2ASMI:
def __init__(self, cachesize, asmiport): def __init__(self, cachesize, asmiport):
self.wishbone = wishbone.Slave() self.wishbone = wishbone.Interface()
self.cachesize = cachesize self.cachesize = cachesize
self.asmiport = asmiport self.asmiport = asmiport
if len(self.asmiport.slots) != 1: if len(self.asmiport.slots) != 1:
@ -41,7 +41,7 @@ class WB2ASMI:
addressbits = aaw + offsetbits addressbits = aaw + offsetbits
linebits = _log2_int(self.cachesize) - offsetbits linebits = _log2_int(self.cachesize) - offsetbits
tagbits = aaw - linebits 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 memory
data_adr = Signal(BV(linebits)) data_adr = Signal(BV(linebits))
@ -60,16 +60,16 @@ class WB2ASMI:
data_di.eq(self.asmiport.dat_r), data_di.eq(self.asmiport.dat_r),
data_we.eq(Replicate(1, adw//8)) data_we.eq(Replicate(1, adw//8))
).Else( ).Else(
data_di.eq(Replicate(self.wishbone.dat_i, adw//32)), data_di.eq(Replicate(self.wishbone.dat_w, adw//32)),
If(self.wishbone.cyc_i & self.wishbone.stb_i & self.wishbone.we_i & self.wishbone.ack_o, If(self.wishbone.cyc & self.wishbone.stb & self.wishbone.we & self.wishbone.ack,
displacer(self.wishbone.sel_i, adr_offset, data_we, 2**offsetbits, reverse=True) displacer(self.wishbone.sel, adr_offset, data_we, 2**offsetbits, reverse=True)
) )
), ),
If(write_to_asmi, If(write_to_asmi,
self.asmiport.dat_w.eq(data_do), self.asmiport.dat_w.eq(data_do),
self.asmiport.dat_wm.eq(Replicate(1, adw//8)) 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 += [ sync += [
adr_offset_r.eq(adr_offset) adr_offset_r.eq(adr_offset)
@ -102,12 +102,12 @@ class WB2ASMI:
"REFILL_WRTAG", "REFILL_ISSUE", "REFILL_WAIT", "REFILL_COMPLETE") "REFILL_WRTAG", "REFILL_ISSUE", "REFILL_WAIT", "REFILL_COMPLETE")
fsm.act(fsm.IDLE, 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, fsm.act(fsm.TEST_HIT,
If(tag_do.tag == adr_tag, If(tag_do.tag == adr_tag,
self.wishbone.ack_o.eq(1), self.wishbone.ack.eq(1),
If(self.wishbone.we_i, If(self.wishbone.we,
tag_di.dirty.eq(1), tag_di.dirty.eq(1),
tag_we.eq(1) tag_we.eq(1)
), ),

View file

@ -5,18 +5,18 @@ from migen.corelogic import timeline
class WB2CSR: class WB2CSR:
def __init__(self): def __init__(self):
self.wishbone = wishbone.Slave() self.wishbone = wishbone.Interface()
self.csr = csr.Master() self.csr = csr.Interface()
self.timeline = timeline.Timeline(self.wishbone.cyc_i & self.wishbone.stb_i, self.timeline = timeline.Timeline(self.wishbone.cyc & self.wishbone.stb,
[(1, [self.csr.we_o.eq(self.wishbone.we_i)]), [(1, [self.csr.we.eq(self.wishbone.we)]),
(2, [self.wishbone.ack_o.eq(1)]), (2, [self.wishbone.ack.eq(1)]),
(3, [self.wishbone.ack_o.eq(0)])]) (3, [self.wishbone.ack.eq(0)])])
def get_fragment(self): def get_fragment(self):
sync = [ sync = [
self.csr.we_o.eq(0), self.csr.we.eq(0),
self.csr.dat_o.eq(self.wishbone.dat_i[:8]), self.csr.dat_w.eq(self.wishbone.dat_w[:8]),
self.csr.adr_o.eq(self.wishbone.adr_i[:14]), self.csr.adr.eq(self.wishbone.adr[:14]),
self.wishbone.dat_o.eq(self.csr.dat_i) self.wishbone.dat_r.eq(self.csr.dat_r)
] ]
return Fragment(sync=sync) + self.timeline.get_fragment() return Fragment(sync=sync) + self.timeline.get_fragment()