bus: replace simple bus module with new bidirectional Record

This commit is contained in:
Sebastien Bourdeauducq 2013-04-01 21:54:21 +02:00
parent 6a3c413717
commit 29b468529f
5 changed files with 149 additions and 228 deletions

View File

@ -1,23 +1,24 @@
from migen.fhdl.structure import *
from migen.fhdl.specials import Memory
from migen.fhdl.module import Module
from migen.bus.simple import *
from migen.bus.transactions import *
from migen.bank.description import CSRStorage
from migen.genlib.record import *
from migen.genlib.misc import chooser
data_width = 8
class Interface(SimpleInterface):
class Interface(Record):
def __init__(self):
SimpleInterface.__init__(self, Description(
(M_TO_S, "adr", 14),
(M_TO_S, "we", 1),
(M_TO_S, "dat_w", data_width),
(S_TO_M, "dat_r", data_width)))
Record.__init__(self, [
("adr", 14, DIR_M_TO_S),
("we", 1, DIR_M_TO_S),
("dat_w", data_width, DIR_M_TO_S),
("dat_r", data_width, DIR_S_TO_M)])
class Interconnect(SimpleInterconnect):
pass
class Interconnect(Module):
def __init__(self, master, slaves):
self.comb += master.connect(*slaves)
class Initiator(Module):
def __init__(self, generator, bus=None):
@ -53,80 +54,74 @@ def _compute_page_bits(nwords):
else:
return 0
class SRAM:
class SRAM(Module):
def __init__(self, mem_or_size, address, read_only=None, bus=None):
if isinstance(mem_or_size, Memory):
self.mem = mem_or_size
mem = mem_or_size
else:
self.mem = Memory(data_width, mem_or_size//(data_width//8))
self.address = address
if self.mem.width > data_width:
self.csrw_per_memw = (self.mem.width + data_width - 1)//data_width
self.word_bits = bits_for(self.csrw_per_memw-1)
mem = Memory(data_width, mem_or_size//(data_width//8))
if mem.width > data_width:
csrw_per_memw = (self.mem.width + data_width - 1)//data_width
word_bits = bits_for(csrw_per_memw-1)
else:
self.csrw_per_memw = 1
self.word_bits = 0
page_bits = _compute_page_bits(self.mem.depth + self.word_bits)
csrw_per_memw = 1
word_bits = 0
page_bits = _compute_page_bits(mem.depth + word_bits)
if page_bits:
self._page = CSRStorage(page_bits, name=self.mem.name_override + "_page")
else:
self._page = None
if read_only is None:
if hasattr(self.mem, "bus_read_only"):
read_only = self.mem.bus_read_only
if hasattr(mem, "bus_read_only"):
read_only = mem.bus_read_only
else:
read_only = False
self.read_only = read_only
if bus is None:
bus = Interface()
self.bus = bus
def get_csrs(self):
if self._page is None:
return []
else:
return [self._page]
def get_fragment(self):
port = self.mem.get_port(write_capable=not self.read_only,
we_granularity=data_width if not self.read_only and self.word_bits else 0)
###
self.specials += mem
port = mem.get_port(write_capable=not read_only,
we_granularity=data_width if not read_only and word_bits else 0)
sel = Signal()
sel_r = Signal()
sync = [sel_r.eq(sel)]
comb = [sel.eq(self.bus.adr[9:] == self.address)]
self.sync += sel_r.eq(sel)
self.comb += sel.eq(self.bus.adr[9:] == address)
if self.word_bits:
word_index = Signal(self.word_bits)
word_expanded = Signal(self.csrw_per_memw*data_width)
sync.append(word_index.eq(self.bus.adr[:self.word_bits]))
comb += [
if word_bits:
word_index = Signal(word_bits)
word_expanded = Signal(csrw_per_memw*data_width)
sync.append(word_index.eq(self.bus.adr[:word_bits]))
self.comb += [
word_expanded.eq(port.dat_r),
If(sel_r,
chooser(word_expanded, word_index, self.bus.dat_r, n=self.csrw_per_memw, reverse=True)
chooser(word_expanded, word_index, self.bus.dat_r, n=csrw_per_memw, reverse=True)
)
]
if not self.read_only:
comb += [
If(sel & self.bus.we, port.we.eq((1 << self.word_bits) >> self.bus.adr[:self.word_bits])),
port.dat_w.eq(Replicate(self.bus.dat_w, self.csrw_per_memw))
if not read_only:
self.comb += [
If(sel & self.bus.we, port.we.eq((1 << word_bits) >> self.bus.adr[:self.word_bits])),
port.dat_w.eq(Replicate(self.bus.dat_w, csrw_per_memw))
]
else:
comb += [
If(sel_r,
self.bus.dat_r.eq(port.dat_r)
)
]
if not self.read_only:
comb += [
self.comb += If(sel_r, self.bus.dat_r.eq(port.dat_r))
if not read_only:
self.comb += [
port.we.eq(sel & self.bus.we),
port.dat_w.eq(self.bus.dat_w)
]
if self._page is None:
comb.append(port.adr.eq(self.bus.adr[self.word_bits:len(port.adr)]))
self.comb += port.adr.eq(self.bus.adr[word_bits:len(port.adr)])
else:
pv = self._page.storage
comb.append(port.adr.eq(Cat(self.bus.adr[self.word_bits:len(port.adr)-len(pv)], pv)))
return Fragment(comb, sync, specials={self.mem})
self.comb += port.adr.eq(Cat(self.bus.adr[word_bits:len(port.adr)-len(pv)], pv))
def get_csrs(self):
if self._page is None:
return []
else:
return [self._page]

View File

@ -1,29 +1,31 @@
from migen.fhdl.structure import *
from migen.bus.simple import *
from migen.fhdl.module import Module
from migen.genlib.record import *
def phase_description(a, ba, d):
return Description(
(M_TO_S, "address", a),
(M_TO_S, "bank", ba),
(M_TO_S, "cas_n", 1),
(M_TO_S, "cke", 1),
(M_TO_S, "cs_n", 1),
(M_TO_S, "ras_n", 1),
(M_TO_S, "we_n", 1),
return [
("address", a, DIR_M_TO_S),
("bank", ba, DIR_M_TO_S),
("cas_n", 1, DIR_M_TO_S),
("cke", 1, DIR_M_TO_S),
("cs_n", 1, DIR_M_TO_S),
("ras_n", 1, DIR_M_TO_S),
("we_n", 1, DIR_M_TO_S),
(M_TO_S, "wrdata", d),
(M_TO_S, "wrdata_en", 1),
(M_TO_S, "wrdata_mask", d//8),
("wrdata", d, DIR_M_TO_S),
("wrdata_en", 1, DIR_M_TO_S),
("wrdata_mask", d//8, DIR_M_TO_S),
(M_TO_S, "rddata_en", 1),
(S_TO_M, "rddata", d),
(S_TO_M, "rddata_valid", 1)
)
("rddata_en", 1, DIR_M_TO_S),
("rddata", d, DIR_S_TO_M),
("rddata_valid", 1, DIR_S_TO_M)
]
class Interface:
class Interface(Record):
def __init__(self, a, ba, d, nphases=1):
self.pdesc = phase_description(a, ba, d)
self.phases = [SimpleInterface(self.pdesc) for i in range(nphases)]
layout = [("p"+str(i), phase_description(a, ba, d)) for i in range(nphases)]
Record.__init__(self, layout)
self.phases = [getattr(self, "p"+str(i)) for i in range(nphases)]
for p in self.phases:
p.cas_n.reset = 1
p.cs_n.reset = 1
@ -35,28 +37,18 @@ class Interface:
r = []
add_suffix = len(self.phases) > 1
for n, phase in enumerate(self.phases):
for signal in self.pdesc.desc:
if (m2s and signal[0] == M_TO_S) or (s2m and signal[0] == S_TO_M):
for field, size, direction in phase.layout:
if (m2s and direction == DIR_M_TO_S) or (s2m and direction == DIR_S_TO_M):
if add_suffix:
if signal[0] == M_TO_S:
if direction == DIR_M_TO_S:
suffix = "_p" + str(n)
else:
suffix = "_w" + str(n)
else:
suffix = ""
r.append(("dfi_" + signal[1] + suffix, getattr(phase, signal[1])))
r.append(("dfi_" + field + suffix, getattr(phase, field)))
return r
def interconnect_stmts(master, slave):
r = []
for pm, ps in zip(master.phases, slave.phases):
r += simple_interconnect_stmts(master.pdesc, pm, [ps])
return r
class Interconnect:
class Interconnect(Module):
def __init__(self, master, slave):
self.master = master
self.slave = slave
def get_fragment(self):
return Fragment(interconnect_stmts(self.master, self.slave))
self.comb += master.connect(slave)

View File

@ -1,47 +0,0 @@
from migen.fhdl.structure import *
from migen.genlib.misc import optree
(S_TO_M, M_TO_S) = range(2)
# desc is a list of tuples, each made up of:
# 0) S_TO_M/M_TO_S: data direction
# 1) string: name
# 2) int: width
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]
for signal in self.desc.desc:
signame = signal[1]
setattr(self, signame, Signal(signal[2], busname + "_" + signame))
def simple_interconnect_stmts(desc, master, slaves):
s2m = desc.get_names(S_TO_M)
m2s = desc.get_names(M_TO_S)
sl = [getattr(slave, name).eq(getattr(master, name))
for name in m2s for slave in slaves]
sl += [getattr(master, name).eq(
optree("|", [getattr(slave, name) for slave in slaves])
)
for name in s2m]
return sl
class SimpleInterconnect:
def __init__(self, master, slaves):
self.master = master
self.slaves = slaves
def get_fragment(self):
return Fragment(simple_interconnect_stmts(self.master.desc, self.master, self.slaves))

View File

@ -2,64 +2,59 @@ from migen.fhdl.structure import *
from migen.fhdl.specials import Memory
from migen.fhdl.module import Module
from migen.genlib import roundrobin
from migen.genlib.record import *
from migen.genlib.misc import optree
from migen.bus.simple import *
from migen.bus.transactions import *
from migen.sim.generic import Proxy
_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)
)
_layout = [
("adr", 30, DIR_M_TO_S),
("dat_w", 32, DIR_M_TO_S),
("dat_r", 32, DIR_S_TO_M),
("sel", 4, DIR_M_TO_S),
("cyc", 1, DIR_M_TO_S),
("stb", 1, DIR_M_TO_S),
("ack", 1, DIR_S_TO_M),
("we", 1, DIR_M_TO_S),
("cti", 3, DIR_M_TO_S),
("bte", 2, DIR_M_TO_S),
("err", 1, DIR_S_TO_M)
]
class Interface(SimpleInterface):
class Interface(Record):
def __init__(self):
SimpleInterface.__init__(self, _desc)
Record.__init__(self, _layout)
class InterconnectPointToPoint(SimpleInterconnect):
class InterconnectPointToPoint(Module):
def __init__(self, master, slave):
SimpleInterconnect.__init__(self, master, [slave])
self.comb += master.connect(slave)
class Arbiter:
class Arbiter(Module):
def __init__(self, masters, target):
self.masters = masters
self.target = target
self.rr = roundrobin.RoundRobin(len(self.masters))
def get_fragment(self):
comb = []
self.submodules.rr = roundrobin.RoundRobin(len(masters))
# mux master->slave signals
for name in _desc.get_names(M_TO_S):
choices = Array(getattr(m, name) for m in self.masters)
comb.append(getattr(self.target, name).eq(choices[self.rr.grant]))
for name, size, direction in _layout:
if direction == DIR_M_TO_S:
choices = Array(getattr(m, name) for m in masters)
self.comb += getattr(target, name).eq(choices[self.rr.grant])
# connect slave->master signals
for name in _desc.get_names(S_TO_M):
source = getattr(self.target, name)
for i, m in enumerate(self.masters):
dest = getattr(m, name)
if name == "ack" or name == "err":
comb.append(dest.eq(source & (self.rr.grant == i)))
else:
comb.append(dest.eq(source))
for name, size, direction in _layout:
if direction == DIR_S_TO_M:
source = getattr(target, name)
for i, m in enumerate(masters):
dest = getattr(m, name)
if name == "ack" or name == "err":
self.comb += dest.eq(source & (self.rr.grant == i))
else:
self.comb += dest.eq(source)
# connect bus requests to round-robin selector
reqs = [m.cyc for m in self.masters]
comb.append(self.rr.request.eq(Cat(*reqs)))
return Fragment(comb) + self.rr.get_fragment()
reqs = [m.cyc for m in masters]
self.comb += self.rr.request.eq(Cat(*reqs))
class Decoder:
class Decoder(Module):
# slaves is a list of pairs:
# 0) function that takes the address signal and returns a FHDL expression
# that evaluates to 1 when the slave is selected and 0 otherwise.
@ -67,55 +62,43 @@ class Decoder:
# register adds flip-flops after the address comparators. Improves timing,
# but breaks Wishbone combinatorial feedback.
def __init__(self, master, slaves, register=False):
self.master = master
self.slaves = slaves
self.register = register
def get_fragment(self):
comb = []
sync = []
ns = len(self.slaves)
ns = len(slaves)
slave_sel = Signal(ns)
slave_sel_r = Signal(ns)
# decode slave addresses
comb += [slave_sel[i].eq(fun(self.master.adr))
for i, (fun, bus) in enumerate(self.slaves)]
if self.register:
sync.append(slave_sel_r.eq(slave_sel))
self.comb += [slave_sel[i].eq(fun(master.adr))
for i, (fun, bus) in enumerate(slaves)]
if register:
self.sync += slave_sel_r.eq(slave_sel)
else:
comb.append(slave_sel_r.eq(slave_sel))
self.comb += slave_sel_r.eq(slave_sel)
# connect master->slaves signals except cyc
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]
for slave in slaves:
for name, size, direction in _layout:
if direction == DIR_M_TO_S and name != "cyc":
self.comb += getattr(slave[1], name).eq(getattr(master, name))
# combine cyc with slave selection signals
comb += [slave[1].cyc.eq(self.master.cyc & slave_sel[i])
for i, slave in enumerate(self.slaves)]
self.comb += [slave[1].cyc.eq(master.cyc & slave_sel[i])
for i, slave in enumerate(slaves)]
# generate master ack (resp. err) by ORing all slave acks (resp. errs)
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]))
self.comb += [
master.ack.eq(optree("|", [slave[1].ack for slave in slaves])),
master.err.eq(optree("|", [slave[1].err for slave in slaves]))
]
# mux (1-hot) slave data return
masked = [Replicate(slave_sel_r[i], len(self.master.dat_r)) & 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)
masked = [Replicate(slave_sel_r[i], len(master.dat_r)) & slaves[i][1].dat_r for i in range(ns)]
self.comb += master.dat_r.eq(optree("|", masked))
class InterconnectShared:
class InterconnectShared(Module):
def __init__(self, masters, slaves, register=False):
self._shared = Interface()
self._arbiter = Arbiter(masters, self._shared)
self._decoder = Decoder(self._shared, slaves, register)
def get_fragment(self):
return self._arbiter.get_fragment() + self._decoder.get_fragment()
shared = Interface()
self.submodules += Arbiter(masters, shared)
self.submodules += Decoder(shared, slaves, register)
class Tap(Module):
def __init__(self, bus, handler=print):
@ -200,34 +183,33 @@ class Target(Module):
else:
bus.ack = 0
class SRAM:
class SRAM(Module):
def __init__(self, mem_or_size, bus=None):
if isinstance(mem_or_size, Memory):
assert(mem_or_size.width <= 32)
self.mem = mem_or_size
mem = mem_or_size
else:
self.mem = Memory(32, mem_or_size//4)
mem = Memory(32, mem_or_size//4)
if bus is None:
bus = Interface()
self.bus = bus
def get_fragment(self):
###
# memory
port = self.mem.get_port(write_capable=True, we_granularity=8)
self.specials += mem
port = mem.get_port(write_capable=True, we_granularity=8)
# generate write enable signal
comb = [port.we[i].eq(self.bus.cyc & self.bus.stb & self.bus.we & self.bus.sel[i])
self.comb += [port.we[i].eq(self.bus.cyc & self.bus.stb & self.bus.we & self.bus.sel[i])
for i in range(4)]
# address and data
comb += [
self.comb += [
port.adr.eq(self.bus.adr[:len(port.adr)]),
port.dat_w.eq(self.bus.dat_w),
self.bus.dat_r.eq(port.dat_r)
]
# generate ack
sync = [
self.sync += [
self.bus.ack.eq(0),
If(self.bus.cyc & self.bus.stb & ~self.bus.ack,
self.bus.ack.eq(1)
)
If(self.bus.cyc & self.bus.stb & ~self.bus.ack, self.bus.ack.eq(1))
]
return Fragment(comb, sync, specials={self.mem})

View File

@ -3,7 +3,7 @@ from migen.fhdl.specials import Memory
from migen.bus import wishbone
from migen.genlib.fsm import FSM
from migen.genlib.misc import split, displacer, chooser
from migen.genlib.record import Record
from migen.genlib.record import Record, layout_len
# cachesize (in 32-bit words) is the size of the data store, must be a power of 2
class WB2ASMI:
@ -60,15 +60,14 @@ class WB2ASMI:
]
# Tag memory
tag_mem = Memory(tagbits+1, 2**linebits)
tag_port = tag_mem.get_port(write_capable=True)
tag_layout = [("tag", tagbits), ("dirty", 1)]
tag_mem = Memory(layout_len(tag_layout), 2**linebits)
tag_port = tag_mem.get_port(write_capable=True)
tag_do = Record(tag_layout)
tag_di = Record(tag_layout)
comb += [
Cat(*tag_do.flatten()).eq(tag_port.dat_r),
tag_port.dat_w.eq(Cat(*tag_di.flatten()))
tag_do.raw_bits().eq(tag_port.dat_r),
tag_port.dat_w.eq(tag_di.raw_bits())
]
comb += [