From 29b468529f7d26173e74a3b7aae42cbd93ac2813 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 1 Apr 2013 21:54:21 +0200 Subject: [PATCH] bus: replace simple bus module with new bidirectional Record --- migen/bus/csr.py | 103 ++++++++++++------------- migen/bus/dfi.py | 62 +++++++-------- migen/bus/simple.py | 47 ----------- migen/bus/wishbone.py | 154 ++++++++++++++++--------------------- migen/bus/wishbone2asmi.py | 11 ++- 5 files changed, 149 insertions(+), 228 deletions(-) delete mode 100644 migen/bus/simple.py diff --git a/migen/bus/csr.py b/migen/bus/csr.py index a320ae86..1a2b4972 100644 --- a/migen/bus/csr.py +++ b/migen/bus/csr.py @@ -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] diff --git a/migen/bus/dfi.py b/migen/bus/dfi.py index d1c2cf72..d8c2f90f 100644 --- a/migen/bus/dfi.py +++ b/migen/bus/dfi.py @@ -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) diff --git a/migen/bus/simple.py b/migen/bus/simple.py deleted file mode 100644 index 8c6e0d68..00000000 --- a/migen/bus/simple.py +++ /dev/null @@ -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)) diff --git a/migen/bus/wishbone.py b/migen/bus/wishbone.py index 89ef3dda..25b1dc51 100644 --- a/migen/bus/wishbone.py +++ b/migen/bus/wishbone.py @@ -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}) diff --git a/migen/bus/wishbone2asmi.py b/migen/bus/wishbone2asmi.py index c68999cb..45882078 100644 --- a/migen/bus/wishbone2asmi.py +++ b/migen/bus/wishbone2asmi.py @@ -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 += [ -- 2.30.2