bus: replace simple bus module with new bidirectional Record
authorSebastien Bourdeauducq <sebastien@milkymist.org>
Mon, 1 Apr 2013 19:54:21 +0000 (21:54 +0200)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Mon, 1 Apr 2013 19:54:21 +0000 (21:54 +0200)
migen/bus/csr.py
migen/bus/dfi.py
migen/bus/simple.py [deleted file]
migen/bus/wishbone.py
migen/bus/wishbone2asmi.py

index a320ae864cc262bd0cb50fa299768abfa720e53d..1a2b497232a2b1fe257e7c8c01c49d1aec8bf427 100644 (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]
index d1c2cf7202f66834895a80d46f1888f4722766dc..d8c2f90fef6d350cd6f2c5091bfe5ebfea414a1a 100644 (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)
diff --git a/migen/bus/simple.py b/migen/bus/simple.py
deleted file mode 100644 (file)
index 8c6e0d6..0000000
+++ /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))
index 89ef3dda668c2bc412b1d13c4faafece98187274..25b1dc510b76db7428239144e11b7b247754c05b 100644 (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})
index c68999cb606a50df499800547c0d83411ea75937..45882078883dc91b15fda57a3526f2962167be8d 100644 (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 += [