Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
  • 3 commits
  • 13 files changed
  • 0 commit comments
  • 1 contributor
View
24 examples/basic/record.py
@@ -0,0 +1,24 @@
+from migen.fhdl.structure import *
+from migen.fhdl.module import Module
+from migen.fhdl import verilog
+from migen.genlib.record import *
+
+L = [
+ ("position", [
+ ("x", 10, DIR_M_TO_S),
+ ("y", 10, DIR_M_TO_S),
+ ]),
+ ("color", 32, DIR_M_TO_S),
+ ("stb", 1, DIR_M_TO_S),
+ ("ack", 1, DIR_S_TO_M)
+]
+
+class Test(Module):
+ def __init__(self):
+ master = Record(L)
+ slave = Record(L)
+ self.comb += master.connect(slave)
+
+print(verilog.convert(Test()))
+print(layout_len(L))
+print(layout_partial(L, "position/x", "color"))
View
20 examples/basic/using_record.py
@@ -1,20 +0,0 @@
-from migen.fhdl.structure import *
-from migen.genlib.record import *
-
-L = [
- ("x", 10, 8),
- ("y", 10, 8),
- ("level2", [
- ("a", 5, 32),
- ("b", 5, 16)
- ])
-]
-
-myrec = Record(L)
-print(myrec.flatten())
-print(myrec.flatten(True))
-s = myrec.subrecord("level2/a", "x")
-print(s.flatten())
-print(s.level2.layout())
-myrec2 = myrec.copy()
-print(myrec2.flatten())
View
2  migen/actorlib/spi.py
@@ -108,7 +108,7 @@ def get_fragment(self):
self._r_wc.dat_w.eq(self._r_wc.storage - 1),
wp.adr.eq(self._r_wa.storage),
- wp.dat_w.eq(Cat(*self.token("sink").flatten())),
+ wp.dat_w.eq(self.token("sink").raw_bits()),
rp.adr.eq(self._r_ra.storage),
self._r_rd.status.eq(rp.dat_r)
View
6 migen/actorlib/structuring.py
@@ -29,7 +29,7 @@ def get_process_fragment(self):
])
def pack_layout(l, n):
- return [("chunk{0}".format(i), l) for i in range(n)]
+ return [("chunk"+str(i), l) for i in range(n)]
class Unpack(Actor):
def __init__(self, n, layout_to):
@@ -57,7 +57,7 @@ def get_fragment(self):
]
cases = {}
for i in range(self.n):
- cases[i] = [Cat(*self.token("source").flatten()).eq(Cat(*self.token("sink").subrecord("chunk{0}".format(i)).flatten()))]
+ cases[i] = [self.token("source").raw_bits().eq(getattr(self.token("sink"), "chunk"+str(i)).raw_bits())]
comb.append(Case(mux, cases).makedefault())
return Fragment(comb, sync)
@@ -75,7 +75,7 @@ def get_fragment(self):
strobe_all = Signal()
cases = {}
for i in range(self.n):
- cases[i] = [Cat(*self.token("source").subrecord("chunk{0}".format(i)).flatten()).eq(*self.token("sink").flatten())]
+ cases[i] = [getattr(self.token("source"), "chunk"+str(i)).raw_bits().eq(self.token("sink").raw_bits())]
comb = [
self.busy.eq(strobe_all),
self.endpoints["sink"].ack.eq(~strobe_all | self.endpoints["source"].ack),
View
103 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]
View
62 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 @@ def get_standard_names(self, m2s=True, s2m=True):
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
47 migen/bus/simple.py
@@ -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
154 migen/bus/wishbone.py
@@ -2,64 +2,59 @@
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 @@ def do_simulation(self, s):
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
11 migen/bus/wishbone2asmi.py
@@ -3,7 +3,7 @@
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 @@ def get_fragment(self):
]
# 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 += [
View
1  migen/flow/actor.py
@@ -163,7 +163,6 @@ def get_binary_control_fragment(self, stb_i, ack_o, stb_o, ack_i):
def get_conn_fragment(source, sink):
assert isinstance(source, Source)
assert isinstance(sink, Sink)
- assert sink.token.compatible(source.token)
sigs_source = source.token.flatten()
sigs_sink = sink.token.flatten()
comb = [
View
2  migen/flow/network.py
@@ -170,7 +170,7 @@ def _infer_plumbing_layout(self):
other_ep = other.single_sink()
else:
raise AssertionError
- layout = other.token(other_ep).layout()
+ layout = other.token(other_ep).layout
a.parameters["layout"] = layout
self.instantiate(a)
View
53 migen/flow/plumbing.py
@@ -1,4 +1,5 @@
from migen.fhdl.structure import *
+from migen.fhdl.module import Module
from migen.flow.actor import *
from migen.genlib.record import *
from migen.genlib.misc import optree
@@ -14,57 +15,45 @@ def get_process_fragment(self):
sync = [If(self.pipe_ce, Cat(*sigs_q).eq(Cat(*sigs_d)))]
return Fragment(sync=sync)
-class Combinator(Actor):
+class Combinator(Module, Actor):
def __init__(self, layout, subrecords):
- source = Record(layout)
- subrecords = [source.subrecord(*subr) for subr in subrecords]
- eps = [("sink{0}".format(n), Sink, r)
+ eps = [("source", Source, layout)]
+ eps += [("sink"+str(n), Sink, layout_partial(layout, r))
for n, r in enumerate(subrecords)]
- ep_source = ("source", Source, source)
- eps.append(ep_source)
Actor.__init__(self, *eps)
- def get_fragment(self):
+ ###
+
source = self.endpoints["source"]
- sinks = [self.endpoints["sink{0}".format(n)]
+ sinks = [self.endpoints["sink"+str(n)]
for n in range(len(self.endpoints)-1)]
- comb = [source.stb.eq(optree("&", [sink.stb for sink in sinks]))]
- comb += [sink.ack.eq(source.ack & source.stb) for sink in sinks]
- return Fragment(comb)
+ self.comb += [source.stb.eq(optree("&", [sink.stb for sink in sinks]))]
+ self.comb += [sink.ack.eq(source.ack & source.stb) for sink in sinks]
+ self.comb += [source.token.eq(sink.token) for sink in sinks]
-class Splitter(Actor):
+class Splitter(Module, Actor):
def __init__(self, layout, subrecords):
- sink = Record(layout)
- subr = []
- for s in subrecords:
- if s is None:
- subr.append(sink)
- else:
- subr.append(sink.subrecord(*s))
- eps = [("source{0}".format(n), Source, r)
- for n, r in enumerate(subr)]
- ep_sink = ("sink", Sink, sink)
- eps.append(ep_sink)
+ eps = [("sink", Sink, layout)]
+ eps += [("source"+str(n), Source, layout_partial(layout, *r))
+ for n, r in enumerate(subrecords)]
Actor.__init__(self, *eps)
- def get_fragment(self):
+ ###
+
sources = [self.endpoints[e] for e in self.sources()]
sink = self.endpoints[self.sinks()[0]]
+
+ self.comb += [source.token.eq(sink.token) for source in sources]
already_acked = Signal(len(sources))
- sync = [
- If(sink.stb,
+ self.sync += If(sink.stb,
already_acked.eq(already_acked | Cat(*[s.ack for s in sources])),
If(sink.ack, already_acked.eq(0))
)
- ]
- comb = [
- sink.ack.eq(optree("&",
+ self.comb += sink.ack.eq(optree("&",
[s.ack | already_acked[n] for n, s in enumerate(sources)]))
- ]
for n, s in enumerate(sources):
- comb.append(s.stb.eq(sink.stb & ~already_acked[n]))
- return Fragment(comb, sync)
+ self.comb += s.stb.eq(sink.stb & ~already_acked[n])
# Actors whose layout should be inferred from what their single sink is connected to.
layout_sink = {Buffer, Splitter}
View
197 migen/genlib/record.py
@@ -1,112 +1,121 @@
from migen.fhdl.structure import *
-from migen.fhdl.tools import value_bits_sign
+from migen.fhdl.tracer import get_obj_var_name
+from migen.genlib.misc import optree
+
+(DIR_NONE, DIR_S_TO_M, DIR_M_TO_S) = range(3)
+
+# Possible layout elements:
+# 1. (name, size)
+# 2. (name, size, direction)
+# 3. (name, sublayout)
+# size can be an int, or a (int, bool) tuple for signed numbers
+# sublayout must be a list
+
+def layout_len(layout):
+ r = 0
+ for f in layout:
+ if isinstance(f[1], (int, tuple)): # cases 1/2
+ if(len(f) == 3):
+ fname, fsize, fdirection = f
+ else:
+ fname, fsize = f
+ elif isinstance(f[1], list): # case 3
+ fname, fsublayout = f
+ fsize = layout_len(fsublayout)
+ else:
+ raise TypeError
+ if isinstance(fsize, tuple):
+ r += fsize[0]
+ else:
+ r += fsize
+ return r
+
+def layout_get(layout, name):
+ for f in layout:
+ if f[0] == name:
+ return f
+ raise KeyError
+
+def layout_partial(layout, *elements):
+ r = []
+ for path in elements:
+ path_s = path.split("/")
+ last = path_s.pop()
+ copy_ref = layout
+ insert_ref = r
+ for hop in path_s:
+ name, copy_ref = layout_get(copy_ref, hop)
+ try:
+ name, insert_ref = layout_get(insert_ref, hop)
+ except KeyError:
+ new_insert_ref = []
+ insert_ref.append((hop, new_insert_ref))
+ insert_ref = new_insert_ref
+ insert_ref.append(layout_get(copy_ref, last))
+ return r
class Record:
- def __init__(self, layout, name=""):
- self.name = name
- self.field_order = []
+ def __init__(self, layout, name=None):
+ self.name = get_obj_var_name(name, "")
+ self.layout = layout
+
if self.name:
prefix = self.name + "_"
else:
prefix = ""
- for f in layout:
- if isinstance(f, tuple):
- if isinstance(f[1], (int, tuple)):
- setattr(self, f[0], Signal(f[1], prefix + f[0]))
- elif isinstance(f[1], Signal) or isinstance(f[1], Record):
- setattr(self, f[0], f[1])
- elif isinstance(f[1], list):
- setattr(self, f[0], Record(f[1], prefix + f[0]))
- else:
- raise TypeError
- if len(f) == 3:
- self.field_order.append((f[0], f[2]))
+ for f in self.layout:
+ if isinstance(f[1], (int, tuple)): # cases 1/2
+ if(len(f) == 3):
+ fname, fsize, fdirection = f
else:
- self.field_order.append((f[0], 1))
+ fname, fsize = f
+ finst = Signal(fsize, name=prefix + fname)
+ elif isinstance(f[1], list): # case 3
+ fname, fsublayout = f
+ finst = Record(fsublayout, prefix + fname)
else:
- setattr(self, f, Signal(1, prefix + f))
- self.field_order.append((f, 1))
+ raise TypeError
+ setattr(self, fname, finst)
def eq(self, other):
- return [getattr(self, key).eq(getattr(other, key))
- for key, a in self.field_order]
-
- def layout(self):
- l = []
- for key, alignment in self.field_order:
- e = getattr(self, key)
- if isinstance(e, Signal):
- l.append((key, (e.nbits, e.signed), alignment))
- elif isinstance(e, Record):
- l.append((key, e.layout(), alignment))
- return l
-
- def copy(self, name=None):
- return Record(self.layout(), name)
-
- def get_alignment(self, name):
- return list(filter(lambda x: x[0] == name, self.field_order))[0][1]
-
- def subrecord(self, *descr):
- fields = []
- for item in descr:
- path = item.split("/")
- last = path.pop()
- pos_self = self
- pos_fields = fields
- for hop in path:
- pos_self = getattr(pos_self, hop)
- lu = list(filter(lambda x: x[0] == hop, pos_fields))
- try:
- pos_fields = lu[0][1]
- except IndexError:
- n = []
- pos_fields.append((hop, n))
- pos_fields = n
- if not isinstance(pos_fields, list):
- raise ValueError
- if len(list(filter(lambda x: x[0] == last, pos_fields))) > 0:
- raise ValueError
- pos_fields.append((last, getattr(pos_self, last), pos_self.get_alignment(last)))
- return Record(fields, "subrecord")
+ return [getattr(self, f[0]).eq(getattr(other, f[0]))
+ for f in self.layout if hasattr(other, f[0])]
- def compatible(self, other):
- tpl1 = self.flatten()
- tpl2 = other.flatten()
- return len(tpl1) == len(tpl2)
-
- def flatten(self, align=False, offset=0, return_offset=False):
- l = []
- for key, alignment in self.field_order:
- if align:
- pad_size = alignment - (offset % alignment)
- if pad_size < alignment:
- l.append(Replicate(0, pad_size))
- offset += pad_size
-
- e = getattr(self, key)
+ def flatten(self):
+ r = []
+ for f in self.layout:
+ e = getattr(self, f[0])
if isinstance(e, Signal):
- added = [e]
+ r.append(e)
elif isinstance(e, Record):
- added = e.flatten(align, offset)
+ r += e.flatten()
else:
raise TypeError
- for x in added:
- offset += value_bits_sign(x)[0]
- l += added
- if return_offset:
- return (l, offset)
- else:
- return l
-
- def to_signal(self, assignment_list, sig_out, align=False):
- flattened, length = self.flatten(align, return_offset=True)
- raw = Signal(length)
- if sig_out:
- assignment_list.append(raw.eq(Cat(*flattened)))
- else:
- assignment_list.append(Cat(*flattened).eq(raw))
- return raw
+ return r
+
+ def raw_bits(self):
+ return Cat(*self.flatten())
+ def connect(self, *slaves):
+ r = []
+ for f in self.layout:
+ field = f[0]
+ self_e = getattr(self, field)
+ if isinstance(self_e, Signal):
+ direction = f[2]
+ if direction == DIR_M_TO_S:
+ r += [getattr(slave, field).eq(self_e) for slave in slaves]
+ elif direction == DIR_S_TO_M:
+ r.append(self_e.eq(optree("|", [getattr(slave, field) for slave in slaves])))
+ else:
+ raise TypeError
+ else:
+ for slave in slaves:
+ r += self_e.connect(getattr(slave, field))
+ return r
+
+ def __len__(self):
+ return layout_len(self.layout)
+
def __repr__(self):
- return "<Record " + repr(self.layout()) + ">"
+ return "<Record " + ":".join(f[0] for f in self.layout) + " at " + hex(id(self)) + ">"

No commit comments for this range

Something went wrong with that request. Please try again.