+++ /dev/null
-from migen.fhdl.std import *
-from migen.genlib.complex import *
-from migen.fhdl import verilog
-
-
-class Example(Module):
- def __init__(self):
- w = Complex(32, 42)
- A = SignalC(16)
- B = SignalC(16)
- Bw = SignalC(16)
- C = SignalC(16)
- D = SignalC(16)
- self.comb += Bw.eq(B*w)
- self.sync += [
- C.eq(A + Bw),
- D.eq(A - Bw)
- ]
-
-print(verilog.convert(Example()))
+++ /dev/null
-from migen.fhdl import verilog
-from migen.fhdl.std import *
-from migen.genlib.mhamgen import HammingGenerator, HammingChecker
-
-
-# Instantiates Hamming code generator and checker modules back
-# to back. Also creates an intermediate bus between generator
-# and checker and injects a single-bit error on the bus, to
-# demonstrate the correction.
-class gen_check(Module):
- def __init__(self, width=8):
- # Save module parameters and instantiate generator and checker
- self.width = width
- hg = HammingGenerator(self.width)
- hc = HammingChecker(self.width, correct=True)
- self.submodules += hg
- self.submodules += hc
-
- # Create the intermediate bus and inject a single-bit error on
- # the bus. Position of the error bit is controllable by the
- # error_bit input.
- data = Signal(width)
- error_bit = Signal(bits_for(width))
- self.comb += data.eq(hg.data_in ^ (1 << error_bit))
- self.comb += hc.code_in.eq(hg.code_out)
- self.comb += hc.data_in.eq(data)
-
- # Call out I/O necessary for testing the generator/checker
- self.io = set()
- self.io.add(hg.data_in)
- self.io.add(hc.enable)
- self.io.add(error_bit)
- self.io.add(hc.code_out)
- self.io.add(hc.data_out)
-
-gc = gen_check()
-print(verilog.convert(gc, gc.io, name="gen_check"))
+++ /dev/null
-from migen.fhdl.std import *
-from migen.fhdl import verilog
-from migen.genlib.cdc import MultiReg
-from migen.bank import description, csrgen
-
-
-class Example(Module):
- def __init__(self, ninputs=32, noutputs=32):
- r_o = description.CSRStorage(noutputs, atomic_write=True)
- r_i = description.CSRStatus(ninputs)
-
- self.submodules.bank = csrgen.Bank([r_o, r_i])
- self.gpio_in = Signal(ninputs)
- self.gpio_out = Signal(ninputs)
-
- ###
-
- gpio_in_s = Signal(ninputs)
- self.specials += MultiReg(self.gpio_in, gpio_in_s)
- self.comb += [
- self.gpio_out.eq(r_o.storage),
- r_i.status.eq(gpio_in_s)
- ]
-
-example = Example()
-i = example.bank.bus
-v = verilog.convert(example, {i.dat_r, i.adr, i.we, i.dat_w,
- example.gpio_in, example.gpio_out})
-print(v)
+++ /dev/null
-from random import Random
-
-from migen.fhdl.std import *
-from migen.flow.network import *
-from migen.flow.transactions import *
-from migen.actorlib import dma_wishbone
-from migen.actorlib.sim import *
-from migen.bus import wishbone
-from migen.sim.generic import run_simulation
-
-
-class MyModel:
- def read(self, address):
- return address + 4
-
-
-class MyModelWB(MyModel, wishbone.TargetModel):
- def __init__(self):
- self.prng = Random(763627)
-
- def can_ack(self, bus):
- return self.prng.randrange(0, 2)
-
-
-def adrgen_gen():
- for i in range(10):
- print("Address: " + hex(i))
- yield Token("address", {"a": i})
-
-
-class SimAdrGen(SimActor):
- def __init__(self, nbits):
- self.address = Source([("a", nbits)])
- SimActor.__init__(self, adrgen_gen())
-
-
-def dumper_gen():
- while True:
- t = Token("data", idle_wait=True)
- yield t
- print("Received: " + hex(t.value["d"]))
-
-
-class SimDumper(SimActor):
- def __init__(self):
- self.data = Sink([("d", 32)])
- SimActor.__init__(self, dumper_gen())
-
-
-def trgen_gen():
- for i in range(10):
- a = i
- d = i+10
- print("Address: " + hex(a) + " Data: " + hex(d))
- yield Token("address_data", {"a": a, "d": d})
-
-
-class SimTrGen(SimActor):
- def __init__(self, a_nbits):
- self.address_data = Source([("a", a_nbits), ("d", 32)])
- SimActor.__init__(self, trgen_gen())
-
-
-class TBWishbone(Module):
- def __init__(self, master):
- self.submodules.peripheral = wishbone.Target(MyModelWB())
- self.submodules.tap = wishbone.Tap(self.peripheral.bus)
- self.submodules.interconnect = wishbone.InterconnectPointToPoint(master.bus,
- self.peripheral.bus)
-
-
-class TBWishboneReader(TBWishbone):
- def __init__(self):
- self.adrgen = SimAdrGen(30)
- self.reader = dma_wishbone.Reader()
- self.dumper = SimDumper()
- g = DataFlowGraph()
- g.add_connection(self.adrgen, self.reader)
- g.add_connection(self.reader, self.dumper)
- self.submodules.comp = CompositeActor(g)
- TBWishbone.__init__(self, self.reader)
-
-
-class TBWishboneWriter(TBWishbone):
- def __init__(self):
- self.trgen = SimTrGen(30)
- self.writer = dma_wishbone.Writer()
- g = DataFlowGraph()
- g.add_connection(self.trgen, self.writer)
- self.submodules.comp = CompositeActor(g)
- TBWishbone.__init__(self, self.writer)
-
-
-def test_wb_reader():
- print("*** Testing Wishbone reader")
- run_simulation(TBWishboneReader(), 100)
-
-
-def test_wb_writer():
- print("*** Testing Wishbone writer")
- run_simulation(TBWishboneWriter(), 100)
-
-if __name__ == "__main__":
- test_wb_reader()
- test_wb_writer()
+++ /dev/null
-from migen.flow.network import *
-from migen.flow.transactions import *
-from migen.actorlib import misc
-from migen.actorlib.sim import *
-from migen.sim.generic import run_simulation
-
-
-def source_gen():
- for i in range(10):
- v = i + 5
- print("==> " + str(v))
- yield Token("source", {"maximum": v})
-
-
-class SimSource(SimActor):
- def __init__(self):
- self.source = Source([("maximum", 32)])
- SimActor.__init__(self, source_gen())
-
-
-def sink_gen():
- while True:
- t = Token("sink")
- yield t
- print(t.value["value"])
-
-
-class SimSink(SimActor):
- def __init__(self):
- self.sink = Sink([("value", 32)])
- SimActor.__init__(self, sink_gen())
-
-if __name__ == "__main__":
- source = SimSource()
- loop = misc.IntSequence(32)
- sink = SimSink()
- g = DataFlowGraph()
- g.add_connection(source, loop)
- g.add_connection(loop, sink)
- comp = CompositeActor(g)
- run_simulation(comp, ncycles=500)
+++ /dev/null
-from itertools import count
-
-import networkx as nx
-import matplotlib.pyplot as plt
-
-from migen.flow.network import *
-from migen.flow.transactions import *
-from migen.actorlib import structuring
-from migen.actorlib.sim import *
-from migen.flow import perftools
-from migen.sim.generic import run_simulation
-
-pack_factor = 5
-base_layout = [("value", 32)]
-packed_layout = structuring.pack_layout(base_layout, pack_factor)
-rawbits_layout = [("value", 32*pack_factor)]
-
-
-def source_gen():
- for i in count(0):
- yield Token("source", {"value": i})
-
-
-class SimSource(SimActor):
- def __init__(self):
- self.source = Source(base_layout)
- SimActor.__init__(self, source_gen())
-
-
-def sink_gen():
- while True:
- t = Token("sink")
- yield t
- print(t.value["value"])
-
-
-class SimSink(SimActor):
- def __init__(self):
- self.sink = Sink(base_layout)
- SimActor.__init__(self, sink_gen())
-
-
-class TB(Module):
- def __init__(self):
- source = SimSource()
- sink = SimSink()
-
- # A tortuous way of passing integer tokens.
- packer = structuring.Pack(base_layout, pack_factor)
- to_raw = structuring.Cast(packed_layout, rawbits_layout)
- from_raw = structuring.Cast(rawbits_layout, packed_layout)
- unpacker = structuring.Unpack(pack_factor, base_layout)
-
- self.g = DataFlowGraph()
- self.g.add_connection(source, packer)
- self.g.add_connection(packer, to_raw)
- self.g.add_connection(to_raw, from_raw)
- self.g.add_connection(from_raw, unpacker)
- self.g.add_connection(unpacker, sink)
- self.submodules.comp = CompositeActor(self.g)
- self.submodules.reporter = perftools.DFGReporter(self.g)
-
-if __name__ == "__main__":
- tb = TB()
- run_simulation(tb, ncycles=1000)
-
- g = nx.MultiDiGraph()
- for u, v, edge in tb.g.edges_iter():
- g.add_edge(u, v, **edge)
- g_layout = nx.spectral_layout(g)
- nx.draw(g, g_layout)
- nx.draw_networkx_edge_labels(g, g_layout, tb.reporter.get_edge_labels())
- plt.show()
+++ /dev/null
-from migen.fhdl.std import *
-from migen.bus import wishbone
-from migen.flow.actor import *
-
-
-class Reader(Module):
- def __init__(self):
- self.bus = wishbone.Interface()
- self.address = Sink([("a", 30)])
- self.data = Source([("d", 32)])
- self.busy = Signal()
-
- ###
-
- bus_stb = Signal()
- data_reg_loaded = Signal()
- data_reg = Signal(32)
-
- self.comb += [
- self.busy.eq(data_reg_loaded),
- self.bus.we.eq(0),
- bus_stb.eq(self.address.stb & (~data_reg_loaded | self.data.ack)),
- self.bus.cyc.eq(bus_stb),
- self.bus.stb.eq(bus_stb),
- self.bus.adr.eq(self.address.a),
- self.address.ack.eq(self.bus.ack),
- self.data.stb.eq(data_reg_loaded),
- self.data.d.eq(data_reg)
- ]
- self.sync += [
- If(self.data.ack, data_reg_loaded.eq(0)),
- If(self.bus.ack,
- data_reg_loaded.eq(1),
- data_reg.eq(self.bus.dat_r)
- )
- ]
-
-
-class Writer(Module):
- def __init__(self):
- self.bus = wishbone.Interface()
- self.address_data = Sink([("a", 30), ("d", 32)])
- self.busy = Signal()
-
- ###
-
- self.comb += [
- self.busy.eq(0),
- self.bus.we.eq(1),
- self.bus.cyc.eq(self.address_data.stb),
- self.bus.stb.eq(self.address_data.stb),
- self.bus.adr.eq(self.address_data.a),
- self.bus.sel.eq(0xf),
- self.bus.dat_w.eq(self.address_data.d),
- self.address_data.ack.eq(self.bus.ack)
- ]
+++ /dev/null
-from migen.fhdl.std import *
-from migen.flow.actor import *
-from migen.genlib import fifo
-
-
-class _FIFOActor(Module):
- def __init__(self, fifo_class, layout, depth):
- self.sink = Sink(layout)
- self.source = Source(layout)
- self.busy = Signal()
-
- ###
-
- description = self.sink.description
- fifo_layout = [
- ("payload", description.payload_layout),
- # Note : Can be optimized by passing parameters
- # in another fifo. We will only have one
- # data per packet.
- ("param", description.param_layout)
- ]
- if description.packetized:
- fifo_layout += [("sop", 1), ("eop", 1)]
-
- self.submodules.fifo = fifo_class(fifo_layout, depth)
-
- self.comb += [
- self.sink.ack.eq(self.fifo.writable),
- self.fifo.we.eq(self.sink.stb),
- self.fifo.din.payload.eq(self.sink.payload),
- self.fifo.din.param.eq(self.sink.param),
-
- self.source.stb.eq(self.fifo.readable),
- self.source.payload.eq(self.fifo.dout.payload),
- self.source.param.eq(self.fifo.dout.param),
- self.fifo.re.eq(self.source.ack)
- ]
- if description.packetized:
- self.comb += [
- self.fifo.din.sop.eq(self.sink.sop),
- self.fifo.din.eop.eq(self.sink.eop),
- self.source.sop.eq(self.fifo.dout.sop),
- self.source.eop.eq(self.fifo.dout.eop)
- ]
-
-
-class SyncFIFO(_FIFOActor):
- def __init__(self, layout, depth, buffered=False):
- _FIFOActor.__init__(
- self,
- fifo.SyncFIFOBuffered if buffered else fifo.SyncFIFO,
- layout, depth)
-
-
-class AsyncFIFO(_FIFOActor):
- def __init__(self, layout, depth):
- _FIFOActor.__init__(self, fifo.AsyncFIFO, layout, depth)
+++ /dev/null
-from migen.fhdl.std import *
-from migen.genlib.record import *
-from migen.genlib.fsm import *
-from migen.flow.actor import *
-from migen.flow.plumbing import Buffer
-
-
-# Generates integers from start to maximum-1
-class IntSequence(Module):
- def __init__(self, nbits, offsetbits=0, step=1):
- parameters_layout = [("maximum", nbits)]
- if offsetbits:
- parameters_layout.append(("offset", offsetbits))
-
- self.parameters = Sink(parameters_layout)
- self.source = Source([("value", max(nbits, offsetbits))])
- self.busy = Signal()
-
- ###
-
- load = Signal()
- ce = Signal()
- last = Signal()
-
- maximum = Signal(nbits)
- if offsetbits:
- offset = Signal(offsetbits)
- counter = Signal(nbits)
-
- if step > 1:
- self.comb += last.eq(counter + step >= maximum)
- else:
- self.comb += last.eq(counter + 1 == maximum)
- self.sync += [
- If(load,
- counter.eq(0),
- maximum.eq(self.parameters.maximum),
- offset.eq(self.parameters.offset) if offsetbits else None
- ).Elif(ce,
- If(last,
- counter.eq(0)
- ).Else(
- counter.eq(counter + step)
- )
- )
- ]
- if offsetbits:
- self.comb += self.source.value.eq(counter + offset)
- else:
- self.comb += self.source.value.eq(counter)
-
- fsm = FSM()
- self.submodules += fsm
- fsm.act("IDLE",
- load.eq(1),
- self.parameters.ack.eq(1),
- If(self.parameters.stb, NextState("ACTIVE"))
- )
- fsm.act("ACTIVE",
- self.busy.eq(1),
- self.source.stb.eq(1),
- If(self.source.ack,
- ce.eq(1),
- If(last, NextState("IDLE"))
- )
- )
-
-# Add buffers on Endpoints (can be used to improve timings)
-class BufferizeEndpoints(ModuleTransformer):
- def __init__(self, *names):
- self.names = names
-
- def transform_instance(self, submodule):
- endpoints = get_endpoints(submodule)
- sinks = {}
- sources = {}
- for name, endpoint in endpoints.items():
- if not self.names or name in self.names:
- if isinstance(endpoint, Sink):
- sinks.update({name: endpoint})
- elif isinstance(endpoint, Source):
- sources.update({name: endpoint})
-
- # add buffer on sinks
- for name, sink in sinks.items():
- buf = Buffer(sink.description)
- submodule.submodules += buf
- setattr(submodule, name, buf.d)
- submodule.comb += Record.connect(buf.q, sink)
-
- # add buffer on sources
- for name, source in sources.items():
- buf = Buffer(source.description)
- submodule.submodules += buf
- submodule.comb += Record.connect(source, buf.d)
- setattr(submodule, name, buf.q)
+++ /dev/null
-from migen.fhdl.std import *
-from migen.genlib.roundrobin import *
-from migen.genlib.record import *
-from migen.flow.actor import *
-from migen.actorlib.fifo import SyncFIFO
-from migen.genlib.fsm import FSM, NextState
-from migen.genlib.misc import reverse_bytes, Counter
-
-
-class Status(Module):
- def __init__(self, endpoint):
- self.sop = sop = Signal()
- self.eop = eop =Signal()
- self.ongoing = Signal()
-
- ongoing = Signal()
- self.comb += \
- If(endpoint.stb,
- sop.eq(endpoint.sop),
- eop.eq(endpoint.eop & endpoint.ack)
- )
- self.sync += ongoing.eq((sop | ongoing) & ~eop)
- self.comb += self.ongoing.eq((sop | ongoing) & ~eop)
-
-
-class Arbiter(Module):
- def __init__(self, masters, slave):
- if len(masters) == 0:
- pass
- elif len(masters) == 1:
- self.grant = Signal()
- self.comb += Record.connect(masters.pop(), slave)
- else:
- self.submodules.rr = RoundRobin(len(masters))
- self.grant = self.rr.grant
- cases = {}
- for i, master in enumerate(masters):
- status = Status(master)
- self.submodules += status
- self.comb += self.rr.request[i].eq(status.ongoing)
- cases[i] = [Record.connect(master, slave)]
- self.comb += Case(self.grant, cases)
-
-
-class Dispatcher(Module):
- def __init__(self, master, slaves, one_hot=False):
- if len(slaves) == 0:
- self.sel = Signal()
- elif len(slaves) == 1:
- self.comb += Record.connect(master, slaves.pop())
- self.sel = Signal()
- else:
- if one_hot:
- self.sel = Signal(len(slaves))
- else:
- self.sel = Signal(max=len(slaves))
-
- # # #
-
- status = Status(master)
- self.submodules += status
-
- sel = Signal.like(self.sel)
- sel_ongoing = Signal.like(self.sel)
- self.sync += \
- If(status.sop,
- sel_ongoing.eq(self.sel)
- )
- self.comb += \
- If(status.sop,
- sel.eq(self.sel)
- ).Else(
- sel.eq(sel_ongoing)
- )
- cases = {}
- for i, slave in enumerate(slaves):
- if one_hot:
- idx = 2**i
- else:
- idx = i
- cases[idx] = [Record.connect(master, slave)]
- cases["default"] = [master.ack.eq(1)]
- self.comb += Case(sel, cases)
-
-
-class HeaderField:
- def __init__(self, byte, offset, width):
- self.byte = byte
- self.offset = offset
- self.width = width
-
-
-class Header:
- def __init__(self, fields, length, swap_field_bytes=True):
- self.fields = fields
- self.length = length
- self.swap_field_bytes = swap_field_bytes
-
- def get_layout(self):
- layout = []
- for k, v in sorted(self.fields.items()):
- layout.append((k, v.width))
- return layout
-
- def get_field(self, obj, name, width):
- if "_lsb" in name:
- field = getattr(obj, name.replace("_lsb", ""))[:width]
- elif "_msb" in name:
- field = getattr(obj, name.replace("_msb", ""))[width:2*width]
- else:
- field = getattr(obj, name)
- return field
-
- def encode(self, obj, signal):
- r = []
- for k, v in sorted(self.fields.items()):
- start = v.byte*8+v.offset
- end = start+v.width
- field = self.get_field(obj, k, v.width)
- if self.swap_field_bytes:
- field = reverse_bytes(field)
- r.append(signal[start:end].eq(field))
- return r
-
- def decode(self, signal, obj):
- r = []
- for k, v in sorted(self.fields.items()):
- start = v.byte*8+v.offset
- end = start+v.width
- field = self.get_field(obj, k, v.width)
- if self.swap_field_bytes:
- r.append(field.eq(reverse_bytes(signal[start:end])))
- else:
- r.append(field.eq(signal[start:end]))
- return r
-
-
-class Packetizer(Module):
- def __init__(self, sink_description, source_description, header):
- self.sink = sink = Sink(sink_description)
- self.source = source = Source(source_description)
- self.header = Signal(header.length*8)
-
- # # #
-
- dw = flen(self.sink.data)
-
- header_reg = Signal(header.length*8)
- header_words = (header.length*8)//dw
- load = Signal()
- shift = Signal()
- counter = Counter(max=max(header_words, 2))
- self.submodules += counter
-
- self.comb += header.encode(sink, self.header)
- if header_words == 1:
- self.sync += [
- If(load,
- header_reg.eq(self.header)
- )
- ]
- else:
- self.sync += [
- If(load,
- header_reg.eq(self.header)
- ).Elif(shift,
- header_reg.eq(Cat(header_reg[dw:], Signal(dw)))
- )
- ]
-
- fsm = FSM(reset_state="IDLE")
- self.submodules += fsm
-
- if header_words == 1:
- idle_next_state = "COPY"
- else:
- idle_next_state = "SEND_HEADER"
-
- fsm.act("IDLE",
- sink.ack.eq(1),
- counter.reset.eq(1),
- If(sink.stb & sink.sop,
- sink.ack.eq(0),
- source.stb.eq(1),
- source.sop.eq(1),
- source.eop.eq(0),
- source.data.eq(self.header[:dw]),
- If(source.stb & source.ack,
- load.eq(1),
- NextState(idle_next_state)
- )
- )
- )
- if header_words != 1:
- fsm.act("SEND_HEADER",
- source.stb.eq(1),
- source.sop.eq(0),
- source.eop.eq(0),
- source.data.eq(header_reg[dw:2*dw]),
- If(source.stb & source.ack,
- shift.eq(1),
- counter.ce.eq(1),
- If(counter.value == header_words-2,
- NextState("COPY")
- )
- )
- )
- fsm.act("COPY",
- source.stb.eq(sink.stb),
- source.sop.eq(0),
- source.eop.eq(sink.eop),
- source.data.eq(sink.data),
- source.error.eq(sink.error),
- If(source.stb & source.ack,
- sink.ack.eq(1),
- If(source.eop,
- NextState("IDLE")
- )
- )
- )
-
-
-class Depacketizer(Module):
- def __init__(self, sink_description, source_description, header):
- self.sink = sink = Sink(sink_description)
- self.source = source = Source(source_description)
- self.header = Signal(header.length*8)
-
- # # #
-
- dw = flen(sink.data)
-
- header_words = (header.length*8)//dw
-
- shift = Signal()
- counter = Counter(max=max(header_words, 2))
- self.submodules += counter
-
- if header_words == 1:
- self.sync += \
- If(shift,
- self.header.eq(sink.data)
- )
- else:
- self.sync += \
- If(shift,
- self.header.eq(Cat(self.header[dw:], sink.data))
- )
-
- fsm = FSM(reset_state="IDLE")
- self.submodules += fsm
-
- if header_words == 1:
- idle_next_state = "COPY"
- else:
- idle_next_state = "RECEIVE_HEADER"
-
- fsm.act("IDLE",
- sink.ack.eq(1),
- counter.reset.eq(1),
- If(sink.stb,
- shift.eq(1),
- NextState(idle_next_state)
- )
- )
- if header_words != 1:
- fsm.act("RECEIVE_HEADER",
- sink.ack.eq(1),
- If(sink.stb,
- counter.ce.eq(1),
- shift.eq(1),
- If(counter.value == header_words-2,
- NextState("COPY")
- )
- )
- )
- no_payload = Signal()
- self.sync += \
- If(fsm.before_entering("COPY"),
- source.sop.eq(1),
- no_payload.eq(sink.eop)
- ).Elif(source.stb & source.ack,
- source.sop.eq(0)
- )
-
- if hasattr(sink, "error"):
- self.comb += source.error.eq(sink.error)
- self.comb += [
- source.eop.eq(sink.eop | no_payload),
- source.data.eq(sink.data),
- header.decode(self.header, source)
- ]
- fsm.act("COPY",
- sink.ack.eq(source.ack),
- source.stb.eq(sink.stb | no_payload),
- If(source.stb & source.ack & source.eop,
- NextState("IDLE")
- )
- )
-
-
-class Buffer(Module):
- def __init__(self, description, data_depth, cmd_depth=4, almost_full=None):
- self.sink = sink = Sink(description)
- self.source = source = Source(description)
-
- # # #
-
- sink_status = Status(self.sink)
- source_status = Status(self.source)
- self.submodules += sink_status, source_status
-
- # store incoming packets
- # cmds
- def cmd_description():
- layout = [("error", 1)]
- return EndpointDescription(layout)
- cmd_fifo = SyncFIFO(cmd_description(), cmd_depth)
- self.submodules += cmd_fifo
- self.comb += cmd_fifo.sink.stb.eq(sink_status.eop)
- if hasattr(sink, "error"):
- self.comb += cmd_fifo.sink.error.eq(sink.error)
-
- # data
- data_fifo = SyncFIFO(description, data_depth, buffered=True)
- self.submodules += data_fifo
- self.comb += [
- Record.connect(self.sink, data_fifo.sink),
- data_fifo.sink.stb.eq(self.sink.stb & cmd_fifo.sink.ack),
- self.sink.ack.eq(data_fifo.sink.ack & cmd_fifo.sink.ack),
- ]
-
- # output packets
- self.fsm = fsm = FSM(reset_state="IDLE")
- self.submodules += fsm
- fsm.act("IDLE",
- If(cmd_fifo.source.stb,
- NextState("SEEK_SOP")
- )
- )
- fsm.act("SEEK_SOP",
- If(~data_fifo.source.sop,
- data_fifo.source.ack.eq(1)
- ).Else(
- NextState("OUTPUT")
- )
- )
- if hasattr(source, "error"):
- source_error = self.source.error
- else:
- source_error = Signal()
-
- fsm.act("OUTPUT",
- Record.connect(data_fifo.source, self.source),
- source_error.eq(cmd_fifo.source.error),
- If(source_status.eop,
- cmd_fifo.source.ack.eq(1),
- NextState("IDLE")
- )
- )
-
- # compute almost full
- if almost_full is not None:
- self.almost_full = Signal()
- self.comb += self.almost_full.eq(data_fifo.fifo.level > almost_full)
+++ /dev/null
-from migen.fhdl.std import *
-from migen.flow.actor import *
-from migen.flow.transactions import *
-from migen.util.misc import xdir
-
-
-def _sim_multiread(sim, obj):
- if isinstance(obj, Signal):
- return sim.rd(obj)
- else:
- r = {}
- for k, v in xdir(obj, True):
- rd = _sim_multiread(sim, v)
- if isinstance(rd, int) or rd:
- r[k] = rd
- return r
-
-
-def _sim_multiwrite(sim, obj, value):
- if isinstance(obj, Signal):
- sim.wr(obj, value)
- else:
- for k, v in value.items():
- _sim_multiwrite(sim, getattr(obj, k), v)
-
-
-# Generators yield None or a tuple of Tokens.
-# Tokens for Sink endpoints are pulled and the "value" field filled in.
-# Tokens for Source endpoints are pushed according to their "value" field.
-#
-# NB: the possibility to push several tokens at once is important to interact
-# with actors that only accept a group of tokens when all of them are available.
-class TokenExchanger(Module):
- def __init__(self, generator, actor):
- self.generator = generator
- self.actor = actor
- self.active = set()
- self.busy = True
- self.done = False
-
- def _process_transactions(self, selfp):
- completed = set()
- for token in self.active:
- ep = getattr(self.actor, token.endpoint)
- if isinstance(ep, Sink):
- if selfp.simulator.rd(ep.ack) and selfp.simulator.rd(ep.stb):
- token.value = _sim_multiread(selfp.simulator, ep.payload)
- completed.add(token)
- selfp.simulator.wr(ep.ack, 0)
- elif isinstance(ep, Source):
- if selfp.simulator.rd(ep.ack) and selfp.simulator.rd(ep.stb):
- completed.add(token)
- selfp.simulator.wr(ep.stb, 0)
- else:
- raise TypeError
- self.active -= completed
- if not self.active:
- self.busy = True
-
- def _update_control_signals(self, selfp):
- for token in self.active:
- ep = getattr(self.actor, token.endpoint)
- if isinstance(ep, Sink):
- selfp.simulator.wr(ep.ack, 1)
- elif isinstance(ep, Source):
- _sim_multiwrite(selfp.simulator, ep.payload, token.value)
- selfp.simulator.wr(ep.stb, 1)
- else:
- raise TypeError
-
- def _next_transactions(self):
- try:
- transactions = next(self.generator)
- except StopIteration:
- self.busy = False
- self.done = True
- raise StopSimulation
- if isinstance(transactions, Token):
- self.active = {transactions}
- elif isinstance(transactions, (tuple, list, set)):
- self.active = set(transactions)
- elif transactions is None:
- self.active = set()
- else:
- raise TypeError
- if self.active and all(transaction.idle_wait for transaction in self.active):
- self.busy = False
-
- def do_simulation(self, selfp):
- if self.active:
- self._process_transactions(selfp)
- if not self.active:
- self._next_transactions()
- self._update_control_signals(selfp)
- do_simulation.passive = True
-
-
-class SimActor(Module):
- def __init__(self, generator):
- self.busy = Signal()
- self.submodules.token_exchanger = TokenExchanger(generator, self)
-
- def do_simulation(self, selfp):
- selfp.busy = self.token_exchanger.busy
- do_simulation.passive = True
-
-
-def _dumper_gen(prefix):
- while True:
- t = Token("result")
- yield t
- if len(t.value) > 1:
- s = str(t.value)
- else:
- s = str(list(t.value.values())[0])
- print(prefix + s)
-
-
-class Dumper(SimActor):
- def __init__(self, layout, prefix=""):
- self.result = Sink(layout)
- SimActor.__init__(self, _dumper_gen(prefix))
+++ /dev/null
-# Simple Processor Interface
-
-from migen.fhdl.std import *
-from migen.bank.description import *
-from migen.flow.actor import *
-from migen.flow.network import *
-from migen.flow import plumbing
-from migen.actorlib import misc
-
-
-# layout is a list of tuples, either:
-# - (name, nbits, [reset value], [alignment bits])
-# - (name, sublayout)
-
-def _convert_layout(layout):
- r = []
- for element in layout:
- if isinstance(element[1], list):
- r.append((element[0], _convert_layout(element[1])))
- else:
- r.append((element[0], element[1]))
- return r
-
-(MODE_EXTERNAL, MODE_SINGLE_SHOT, MODE_CONTINUOUS) = range(3)
-
-
-class SingleGenerator(Module, AutoCSR):
- def __init__(self, layout, mode):
- self.source = Source(_convert_layout(layout))
- self.busy = Signal()
-
- self.comb += self.busy.eq(self.source.stb)
-
- if mode == MODE_EXTERNAL:
- self.trigger = Signal()
- trigger = self.trigger
- elif mode == MODE_SINGLE_SHOT:
- self._shoot = CSR()
- trigger = self._shoot.re
- elif mode == MODE_CONTINUOUS:
- self._enable = CSRStorage()
- trigger = self._enable.storage
- else:
- raise ValueError
- self.sync += If(self.source.ack | ~self.source.stb, self.source.stb.eq(trigger))
-
- self._create_csrs(layout, self.source.payload, mode != MODE_SINGLE_SHOT)
-
- def _create_csrs(self, layout, target, atomic, prefix=""):
- for element in layout:
- if isinstance(element[1], list):
- self._create_csrs(element[1], atomic,
- getattr(target, element[0]),
- element[0] + "_")
- else:
- name = element[0]
- nbits = element[1]
- if len(element) > 2:
- reset = element[2]
- else:
- reset = 0
- if len(element) > 3:
- alignment = element[3]
- else:
- alignment = 0
- regname = prefix + name
- reg = CSRStorage(nbits + alignment, reset=reset, atomic_write=atomic,
- alignment_bits=alignment, name=regname)
- setattr(self, "_"+regname, reg)
- self.sync += If(self.source.ack | ~self.source.stb,
- getattr(target, name).eq(reg.storage))
-
-
-class Collector(Module, AutoCSR):
- def __init__(self, layout, depth=1024):
- self.sink = Sink(layout)
- self.busy = Signal()
- dw = sum(len(s) for s in self.sink.payload.flatten())
-
- self._wa = CSRStorage(bits_for(depth-1), write_from_dev=True)
- self._wc = CSRStorage(bits_for(depth), write_from_dev=True, atomic_write=True)
- self._ra = CSRStorage(bits_for(depth-1))
- self._rd = CSRStatus(dw)
-
- ###
-
- mem = Memory(dw, depth)
- self.specials += mem
- wp = mem.get_port(write_capable=True)
- rp = mem.get_port()
- self.specials += wp, rp
-
- self.comb += [
- self.busy.eq(0),
-
- If(self._wc.r != 0,
- self.sink.ack.eq(1),
- If(self.sink.stb,
- self._wa.we.eq(1),
- self._wc.we.eq(1),
- wp.we.eq(1)
- )
- ),
- self._wa.dat_w.eq(self._wa.storage + 1),
- self._wc.dat_w.eq(self._wc.storage - 1),
-
- wp.adr.eq(self._wa.storage),
- wp.dat_w.eq(self.sink.payload.raw_bits()),
-
- rp.adr.eq(self._ra.storage),
- self._rd.status.eq(rp.dat_r)
- ]
-
-
-class _DMAController(Module):
- def __init__(self, bus_accessor, bus_aw, bus_dw, mode, base_reset=0, length_reset=0):
- self.alignment_bits = bits_for(bus_dw//8) - 1
- layout = [
- ("length", bus_aw + self.alignment_bits, length_reset, self.alignment_bits),
- ("base", bus_aw + self.alignment_bits, base_reset, self.alignment_bits)
- ]
- self.generator = SingleGenerator(layout, mode)
- self._busy = CSRStatus()
-
- self.length = self.generator._length.storage
- self.base = self.generator._base.storage
- if hasattr(self.generator, "trigger"):
- self.trigger = self.generator.trigger
-
- def get_csrs(self):
- return self.generator.get_csrs() + [self._busy]
-
-
-class DMAReadController(_DMAController):
- def __init__(self, bus_accessor, *args, **kwargs):
- bus_aw = flen(bus_accessor.address.a)
- bus_dw = flen(bus_accessor.data.d)
- _DMAController.__init__(self, bus_accessor, bus_aw, bus_dw, *args, **kwargs)
-
- g = DataFlowGraph()
- g.add_pipeline(self.generator,
- misc.IntSequence(bus_aw, bus_aw),
- AbstractActor(plumbing.Buffer),
- bus_accessor,
- AbstractActor(plumbing.Buffer))
- comp_actor = CompositeActor(g)
- self.submodules += comp_actor
-
- self.data = comp_actor.q
- self.busy = comp_actor.busy
- self.comb += self._busy.status.eq(self.busy)
-
-
-class DMAWriteController(_DMAController):
- def __init__(self, bus_accessor, *args, ack_when_inactive=False, **kwargs):
- bus_aw = flen(bus_accessor.address_data.a)
- bus_dw = flen(bus_accessor.address_data.d)
- _DMAController.__init__(self, bus_accessor, bus_aw, bus_dw, *args, **kwargs)
-
- g = DataFlowGraph()
- adr_buffer = AbstractActor(plumbing.Buffer)
- int_sequence = misc.IntSequence(bus_aw, bus_aw)
- g.add_pipeline(self.generator,
- int_sequence,
- adr_buffer)
- g.add_connection(adr_buffer, bus_accessor, sink_subr=["a"])
- g.add_connection(AbstractActor(plumbing.Buffer), bus_accessor, sink_subr=["d"])
- comp_actor = CompositeActor(g)
- self.submodules += comp_actor
-
- if ack_when_inactive:
- demultiplexer = plumbing.Demultiplexer([("d", bus_dw)], 2)
- self.comb += [
- demultiplexer.sel.eq(~adr_buffer.busy),
- demultiplexer.source0.connect(comp_actor.d),
- demultiplexer.source1.ack.eq(1),
- ]
- self.submodules += demultiplexer
- self.data = demultiplexer.sink
- else:
- self.data = comp_actor.d
-
- self.busy = comp_actor.busy
- self.comb += self._busy.status.eq(self.busy)
+++ /dev/null
-from copy import copy
-
-from migen.fhdl.std import *
-from migen.genlib.record import *
-from migen.flow.actor import *
-
-
-def _rawbits_layout(l):
- if isinstance(l, int):
- return [("rawbits", l)]
- else:
- return l
-
-
-class Cast(CombinatorialActor):
- def __init__(self, layout_from, layout_to, reverse_from=False, reverse_to=False):
- self.sink = Sink(_rawbits_layout(layout_from))
- self.source = Source(_rawbits_layout(layout_to))
- CombinatorialActor.__init__(self)
-
- ###
-
- sigs_from = self.sink.payload.flatten()
- if reverse_from:
- sigs_from = list(reversed(sigs_from))
- sigs_to = self.source.payload.flatten()
- if reverse_to:
- sigs_to = list(reversed(sigs_to))
- if sum(flen(s) for s in sigs_from) != sum(flen(s) for s in sigs_to):
- raise TypeError
- self.comb += Cat(*sigs_to).eq(Cat(*sigs_from))
-
-
-def pack_layout(l, n):
- return [("chunk"+str(i), l) for i in range(n)]
-
-
-class Unpack(Module):
- def __init__(self, n, layout_to, reverse=False):
- self.source = source = Source(layout_to)
- description_from = copy(source.description)
- description_from.payload_layout = pack_layout(description_from.payload_layout, n)
- self.sink = sink = Sink(description_from)
-
- self.busy = Signal()
-
- ###
-
- mux = Signal(max=n)
- first = Signal()
- last = Signal()
- self.comb += [
- first.eq(mux == 0),
- last.eq(mux == (n-1)),
- source.stb.eq(sink.stb),
- sink.ack.eq(last & source.ack)
- ]
- self.sync += [
- If(source.stb & source.ack,
- If(last,
- mux.eq(0)
- ).Else(
- mux.eq(mux + 1)
- )
- )
- ]
- cases = {}
- for i in range(n):
- chunk = n-i-1 if reverse else i
- cases[i] = [source.payload.raw_bits().eq(getattr(sink.payload, "chunk"+str(chunk)).raw_bits())]
- self.comb += Case(mux, cases).makedefault()
-
- for f in description_from.param_layout:
- src = getattr(self.sink, f[0])
- dst = getattr(self.source, f[0])
- self.comb += dst.eq(src)
-
- if description_from.packetized:
- self.comb += [
- source.sop.eq(sink.sop & first),
- source.eop.eq(sink.eop & last)
- ]
-
-
-class Pack(Module):
- def __init__(self, layout_from, n, reverse=False):
- self.sink = sink = Sink(layout_from)
- description_to = copy(sink.description)
- description_to.payload_layout = pack_layout(description_to.payload_layout, n)
- self.source = source = Source(description_to)
- self.busy = Signal()
-
- ###
-
- demux = Signal(max=n)
-
- load_part = Signal()
- strobe_all = Signal()
- cases = {}
- for i in range(n):
- chunk = n-i-1 if reverse else i
- cases[i] = [getattr(source.payload, "chunk"+str(chunk)).raw_bits().eq(sink.payload.raw_bits())]
- self.comb += [
- self.busy.eq(strobe_all),
- sink.ack.eq(~strobe_all | source.ack),
- source.stb.eq(strobe_all),
- load_part.eq(sink.stb & sink.ack)
- ]
-
- for f in description_to.param_layout:
- src = getattr(self.sink, f[0])
- dst = getattr(self.source, f[0])
- self.comb += dst.eq(src)
-
- if description_to.packetized:
- demux_last = ((demux == (n - 1)) | sink.eop)
- else:
- demux_last = (demux == (n - 1))
-
- self.sync += [
- If(source.ack, strobe_all.eq(0)),
- If(load_part,
- Case(demux, cases),
- If(demux_last,
- demux.eq(0),
- strobe_all.eq(1)
- ).Else(
- demux.eq(demux + 1)
- )
- )
- ]
-
- if description_to.packetized:
- self.sync += [
- If(source.stb & source.ack,
- source.sop.eq(sink.sop),
- source.eop.eq(sink.eop),
- ).Elif(sink.stb & sink.ack,
- source.sop.eq(sink.sop | source.sop),
- source.eop.eq(sink.eop | source.eop)
- )
- ]
-
-
-class Chunkerize(CombinatorialActor):
- def __init__(self, layout_from, layout_to, n, reverse=False):
- self.sink = Sink(layout_from)
- if isinstance(layout_to, EndpointDescription):
- layout_to = copy(layout_to)
- layout_to.payload_layout = pack_layout(layout_to.payload_layout, n)
- else:
- layout_to = pack_layout(layout_to, n)
- self.source = Source(layout_to)
- CombinatorialActor.__init__(self)
-
- ###
-
- for i in range(n):
- chunk = n-i-1 if reverse else i
- for f in self.sink.description.payload_layout:
- src = getattr(self.sink, f[0])
- dst = getattr(getattr(self.source, "chunk"+str(chunk)), f[0])
- self.comb += dst.eq(src[i*flen(src)//n:(i+1)*flen(src)//n])
-
- for f in self.sink.description.param_layout:
- src = getattr(self.sink, f[0])
- dst = getattr(self.source, f[0])
- self.comb += dst.eq(src)
-
-
-class Unchunkerize(CombinatorialActor):
- def __init__(self, layout_from, n, layout_to, reverse=False):
- if isinstance(layout_from, EndpointDescription):
- fields = layout_from.payload_layout
- layout_from = copy(layout_from)
- layout_from.payload_layout = pack_layout(layout_from.payload_layout, n)
- else:
- fields = layout_from
- layout_from = pack_layout(layout_from, n)
- self.sink = Sink(layout_from)
- self.source = Source(layout_to)
- CombinatorialActor.__init__(self)
-
- ###
-
- for i in range(n):
- chunk = n-i-1 if reverse else i
- for f in fields:
- src = getattr(getattr(self.sink, "chunk"+str(chunk)), f[0])
- dst = getattr(self.source, f[0])
- self.comb += dst[i*flen(dst)//n:(i+1)*flen(dst)//n].eq(src)
-
- for f in self.sink.description.param_layout:
- src = getattr(self.sink, f[0])
- dst = getattr(self.source, f[0])
- self.comb += dst.eq(src)
-
-
-class Converter(Module):
- def __init__(self, layout_from, layout_to, reverse=False):
- self.sink = Sink(layout_from)
- self.source = Source(layout_to)
- self.busy = Signal()
-
- ###
-
- width_from = flen(self.sink.payload.raw_bits())
- width_to = flen(self.source.payload.raw_bits())
-
- # downconverter
- if width_from > width_to:
- if width_from % width_to:
- raise ValueError
- ratio = width_from//width_to
- self.submodules.chunkerize = Chunkerize(layout_from, layout_to, ratio, reverse)
- self.submodules.unpack = Unpack(ratio, layout_to)
-
- self.comb += [
- Record.connect(self.sink, self.chunkerize.sink),
- Record.connect(self.chunkerize.source, self.unpack.sink),
- Record.connect(self.unpack.source, self.source),
- self.busy.eq(self.unpack.busy)
- ]
- # upconverter
- elif width_to > width_from:
- if width_to % width_from:
- raise ValueError
- ratio = width_to//width_from
- self.submodules.pack = Pack(layout_from, ratio)
- self.submodules.unchunkerize = Unchunkerize(layout_from, ratio, layout_to, reverse)
-
- self.comb += [
- Record.connect(self.sink, self.pack.sink),
- Record.connect(self.pack.source, self.unchunkerize.sink),
- Record.connect(self.unchunkerize.source, self.source),
- self.busy.eq(self.pack.busy)
- ]
- # direct connection
- else:
- self.comb += Record.connect(self.sink, self.source)
-
-
-class Pipeline(Module):
- def __init__(self, *modules):
- self.busy = Signal()
- n = len(modules)
- m = modules[0]
- # expose sink of first module
- # if available
- if hasattr(m, "sink"):
- self.sink = m.sink
- if hasattr(m, "busy"):
- busy = m.busy
- else:
- busy = 0
- for i in range(1, n):
- m_n = modules[i]
- if hasattr(m_n, "busy"):
- busy_n = m_n.busy
- else:
- busy_n = 0
- self.comb += m.source.connect(m_n.sink)
- m = m_n
- busy = busy | busy_n
- # expose source of last module
- # if available
- if hasattr(m, "source"):
- self.source = m.source
- self.comb += self.busy.eq(busy)
+++ /dev/null
-from migen.fhdl.std import Module, bits_for
-from migen.bank.description import CSR
-
-
-class GenericBank(Module):
- def __init__(self, description, busword):
- # Turn description into simple CSRs and claim ownership of compound CSR modules
- self.simple_csrs = []
- for c in description:
- if isinstance(c, CSR):
- self.simple_csrs.append(c)
- else:
- c.finalize(busword)
- self.simple_csrs += c.get_simple_csrs()
- self.submodules += c
- self.decode_bits = bits_for(len(self.simple_csrs)-1)
-
-
-def get_offset(description, name, busword):
- offset = 0
- for c in description:
- if c.name == name:
- return offset
- offset += (c.size + busword - 1)//busword
- raise KeyError("CSR not found: "+name)
+++ /dev/null
-from migen.util.misc import xdir
-from migen.fhdl.std import *
-from migen.bus import csr
-from migen.bank.bank import GenericBank
-
-
-class Bank(GenericBank):
- def __init__(self, description, address=0, bus=None):
- if bus is None:
- bus = csr.Interface()
- self.bus = bus
-
- ###
-
- GenericBank.__init__(self, description, flen(self.bus.dat_w))
-
- sel = Signal()
- self.comb += sel.eq(self.bus.adr[9:] == address)
-
- for i, c in enumerate(self.simple_csrs):
- self.comb += [
- c.r.eq(self.bus.dat_w[:c.size]),
- c.re.eq(sel & \
- self.bus.we & \
- (self.bus.adr[:self.decode_bits] == i))
- ]
-
- brcases = dict((i, self.bus.dat_r.eq(c.w)) for i, c in enumerate(self.simple_csrs))
- self.sync += [
- self.bus.dat_r.eq(0),
- If(sel, Case(self.bus.adr[:self.decode_bits], brcases))
- ]
-
-
-# address_map(name, memory) returns the CSR offset at which to map
-# the CSR object (register bank or memory).
-# If memory=None, the object is the register bank of object source.name.
-# Otherwise, it is a memory object belonging to source.name.
-# address_map is called exactly once for each object at each call to
-# scan(), so it can have side effects.
-class BankArray(Module):
- def __init__(self, source, address_map, *ifargs, **ifkwargs):
- self.source = source
- self.address_map = address_map
- self.scan(ifargs, ifkwargs)
-
- def scan(self, ifargs, ifkwargs):
- self.banks = []
- self.srams = []
- for name, obj in xdir(self.source, True):
- if hasattr(obj, "get_csrs"):
- csrs = obj.get_csrs()
- else:
- csrs = []
- if hasattr(obj, "get_memories"):
- memories = obj.get_memories()
- for memory in memories:
- mapaddr = self.address_map(name, memory)
- if mapaddr is None:
- continue
- sram_bus = csr.Interface(*ifargs, **ifkwargs)
- mmap = csr.SRAM(memory, mapaddr, bus=sram_bus)
- self.submodules += mmap
- csrs += mmap.get_csrs()
- self.srams.append((name, memory, mapaddr, mmap))
- if csrs:
- mapaddr = self.address_map(name, None)
- if mapaddr is None:
- continue
- bank_bus = csr.Interface(*ifargs, **ifkwargs)
- rmap = Bank(csrs, mapaddr, bus=bank_bus)
- self.submodules += rmap
- self.banks.append((name, csrs, mapaddr, rmap))
-
- def get_rmaps(self):
- return [rmap for name, csrs, mapaddr, rmap in self.banks]
-
- def get_mmaps(self):
- return [mmap for name, memory, mapaddr, mmap in self.srams]
-
- def get_buses(self):
- return [i.bus for i in self.get_rmaps() + self.get_mmaps()]
+++ /dev/null
-from migen.util.misc import xdir
-from migen.fhdl.std import *
-from migen.fhdl.tracer import get_obj_var_name
-
-
-class _CSRBase(HUID):
- def __init__(self, size, name):
- HUID.__init__(self)
- self.name = get_obj_var_name(name)
- if self.name is None:
- raise ValueError("Cannot extract CSR name from code, need to specify.")
- self.size = size
-
-
-class CSR(_CSRBase):
- def __init__(self, size=1, name=None):
- _CSRBase.__init__(self, size, name)
- self.re = Signal(name=self.name + "_re")
- self.r = Signal(self.size, name=self.name + "_r")
- self.w = Signal(self.size, name=self.name + "_w")
-
-
-class _CompoundCSR(_CSRBase, Module):
- def __init__(self, size, name):
- _CSRBase.__init__(self, size, name)
- self.simple_csrs = []
-
- def get_simple_csrs(self):
- if not self.finalized:
- raise FinalizeError
- return self.simple_csrs
-
- def do_finalize(self, busword):
- raise NotImplementedError
-
-
-class CSRStatus(_CompoundCSR):
- def __init__(self, size=1, reset=0, name=None):
- _CompoundCSR.__init__(self, size, name)
- self.status = Signal(self.size, reset=reset)
-
- def do_finalize(self, busword):
- nwords = (self.size + busword - 1)//busword
- for i in reversed(range(nwords)):
- nbits = min(self.size - i*busword, busword)
- sc = CSR(nbits, self.name + str(i) if nwords > 1 else self.name)
- self.comb += sc.w.eq(self.status[i*busword:i*busword+nbits])
- self.simple_csrs.append(sc)
-
-
-class CSRStorage(_CompoundCSR):
- def __init__(self, size=1, reset=0, atomic_write=False, write_from_dev=False, alignment_bits=0, name=None):
- _CompoundCSR.__init__(self, size, name)
- self.alignment_bits = alignment_bits
- self.storage_full = Signal(self.size, reset=reset)
- self.storage = Signal(self.size - self.alignment_bits, reset=reset >> alignment_bits)
- self.comb += self.storage.eq(self.storage_full[self.alignment_bits:])
- self.atomic_write = atomic_write
- self.re = Signal()
- if write_from_dev:
- self.we = Signal()
- self.dat_w = Signal(self.size - self.alignment_bits)
- self.sync += If(self.we, self.storage_full.eq(self.dat_w << self.alignment_bits))
-
- def do_finalize(self, busword):
- nwords = (self.size + busword - 1)//busword
- if nwords > 1 and self.atomic_write:
- backstore = Signal(self.size - busword, name=self.name + "_backstore")
- for i in reversed(range(nwords)):
- nbits = min(self.size - i*busword, busword)
- sc = CSR(nbits, self.name + str(i) if nwords else self.name)
- self.simple_csrs.append(sc)
- lo = i*busword
- hi = lo+nbits
- # read
- if lo >= self.alignment_bits:
- self.comb += sc.w.eq(self.storage_full[lo:hi])
- elif hi > self.alignment_bits:
- self.comb += sc.w.eq(Cat(Replicate(0, hi - self.alignment_bits),
- self.storage_full[self.alignment_bits:hi]))
- else:
- self.comb += sc.w.eq(0)
- # write
- if nwords > 1 and self.atomic_write:
- if i:
- self.sync += If(sc.re, backstore[lo-busword:hi-busword].eq(sc.r))
- else:
- self.sync += If(sc.re, self.storage_full.eq(Cat(sc.r, backstore)))
- else:
- self.sync += If(sc.re, self.storage_full[lo:hi].eq(sc.r))
- self.sync += self.re.eq(sc.re)
-
-
-def csrprefix(prefix, csrs, done):
- for csr in csrs:
- if csr.huid not in done:
- csr.name = prefix + csr.name
- done.add(csr.huid)
-
-
-def memprefix(prefix, memories, done):
- for memory in memories:
- if memory.huid not in done:
- memory.name_override = prefix + memory.name_override
- done.add(memory.huid)
-
-
-class AutoCSR:
- def get_memories(self):
- try:
- exclude = self.autocsr_exclude
- except AttributeError:
- exclude = {}
- try:
- prefixed = self.__prefixed
- except AttributeError:
- prefixed = self.__prefixed = set()
- r = []
- for k, v in xdir(self, True):
- if k not in exclude:
- if isinstance(v, Memory):
- r.append(v)
- elif hasattr(v, "get_memories") and callable(v.get_memories):
- memories = v.get_memories()
- memprefix(k + "_", memories, prefixed)
- r += memories
- return sorted(r, key=lambda x: x.huid)
-
- def get_csrs(self):
- try:
- exclude = self.autocsr_exclude
- except AttributeError:
- exclude = {}
- try:
- prefixed = self.__prefixed
- except AttributeError:
- prefixed = self.__prefixed = set()
- r = []
- for k, v in xdir(self, True):
- if k not in exclude:
- if isinstance(v, _CSRBase):
- r.append(v)
- elif hasattr(v, "get_csrs") and callable(v.get_csrs):
- csrs = v.get_csrs()
- csrprefix(k + "_", csrs, prefixed)
- r += csrs
- return sorted(r, key=lambda x: x.huid)
+++ /dev/null
-from migen.util.misc import xdir
-from migen.fhdl.std import *
-from migen.bank.description import *
-from migen.genlib.misc import optree
-
-
-class _EventSource(HUID):
- def __init__(self):
- HUID.__init__(self)
- self.status = Signal() # value in the status register
- self.pending = Signal() # value in the pending register + assert irq if unmasked
- self.trigger = Signal() # trigger signal interface to the user design
- self.clear = Signal() # clearing attempt by W1C to pending register, ignored by some event sources
-
-
-# set on a positive trigger pulse
-class EventSourcePulse(Module, _EventSource):
- def __init__(self):
- _EventSource.__init__(self)
- self.comb += self.status.eq(0)
- self.sync += [
- If(self.clear, self.pending.eq(0)),
- If(self.trigger, self.pending.eq(1))
- ]
-
-
-# set on the falling edge of the trigger, status = trigger
-class EventSourceProcess(Module, _EventSource):
- def __init__(self):
- _EventSource.__init__(self)
- self.comb += self.status.eq(self.trigger)
- old_trigger = Signal()
- self.sync += [
- If(self.clear, self.pending.eq(0)),
- old_trigger.eq(self.trigger),
- If(~self.trigger & old_trigger, self.pending.eq(1))
- ]
-
-
-# all status set by external trigger
-class EventSourceLevel(Module, _EventSource):
- def __init__(self):
- _EventSource.__init__(self)
- self.comb += [
- self.status.eq(self.trigger),
- self.pending.eq(self.trigger)
- ]
-
-
-class EventManager(Module, AutoCSR):
- def __init__(self):
- self.irq = Signal()
-
- def do_finalize(self):
- sources_u = [v for k, v in xdir(self, True) if isinstance(v, _EventSource)]
- sources = sorted(sources_u, key=lambda x: x.huid)
- n = len(sources)
- self.status = CSR(n)
- self.pending = CSR(n)
- self.enable = CSRStorage(n)
-
- for i, source in enumerate(sources):
- self.comb += [
- self.status.w[i].eq(source.status),
- If(self.pending.re & self.pending.r[i], source.clear.eq(1)),
- self.pending.w[i].eq(source.pending)
- ]
-
- irqs = [self.pending.w[i] & self.enable.storage[i] for i in range(n)]
- self.comb += self.irq.eq(optree("|", irqs))
-
- def __setattr__(self, name, value):
- object.__setattr__(self, name, value)
- if isinstance(value, _EventSource):
- if self.finalized:
- raise FinalizeError
- self.submodules += value
-
-
-class SharedIRQ(Module):
- def __init__(self, *event_managers):
- self.irq = Signal()
- self.comb += self.irq.eq(optree("|", [ev.irq for ev in event_managers]))
+++ /dev/null
-from migen.fhdl.std import *
-from migen.bus import wishbone
-from migen.bank.bank import GenericBank
-
-
-class Bank(GenericBank):
- def __init__(self, description, bus=None):
- if bus is None:
- bus = wishbone.Interface()
- self.bus = bus
-
- ###
-
- GenericBank.__init__(self, description, flen(self.bus.dat_w))
-
- for i, c in enumerate(self.simple_csrs):
- self.comb += [
- c.r.eq(self.bus.dat_w[:c.size]),
- c.re.eq(self.bus.cyc & self.bus.stb & ~self.bus.ack & self.bus.we & \
- (self.bus.adr[:self.decode_bits] == i))
- ]
-
- brcases = dict((i, self.bus.dat_r.eq(c.w)) for i, c in enumerate(self.simple_csrs))
- self.sync += [
- Case(self.bus.adr[:self.decode_bits], brcases),
- If(bus.ack, bus.ack.eq(0)).Elif(bus.cyc & bus.stb, bus.ack.eq(1))
- ]
+++ /dev/null
-from migen.fhdl.std import *
-from migen.bus.transactions import *
-from migen.bank.description import CSRStorage
-from migen.genlib.record import *
-from migen.genlib.misc import chooser
-
-_layout = [
- ("adr", "address_width", 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 Interface(Record):
- def __init__(self, data_width=8, address_width=14):
- Record.__init__(self, set_layout_parameters(_layout,
- data_width=data_width, address_width=address_width))
-
-
-class Interconnect(Module):
- def __init__(self, master, slaves):
- self.comb += master.connect(*slaves)
-
-
-class Initiator(Module):
- def __init__(self, generator, bus=None):
- self.generator = generator
- if bus is None:
- bus = Interface()
- self.bus = bus
- self.transaction = None
- self.read_data_ready = False
- self.done = False
-
- def do_simulation(self, selfp):
- if not self.done:
- if self.transaction is not None:
- if isinstance(self.transaction, TRead):
- if self.read_data_ready:
- self.transaction.data = selfp.bus.dat_r
- self.transaction = None
- self.read_data_ready = False
- else:
- self.read_data_ready = True
- else:
- selfp.bus.we = 0
- self.transaction = None
- if self.transaction is None:
- try:
- self.transaction = next(self.generator)
- except StopIteration:
- self.transaction = None
- raise StopSimulation
- if self.transaction is not None:
- selfp.bus.adr = self.transaction.address
- if isinstance(self.transaction, TWrite):
- selfp.bus.we = 1
- selfp.bus.dat_w = self.transaction.data
-
-
-class SRAM(Module):
- def __init__(self, mem_or_size, address, read_only=None, init=None, bus=None):
- if bus is None:
- bus = Interface()
- self.bus = bus
- data_width = flen(self.bus.dat_w)
- if isinstance(mem_or_size, Memory):
- mem = mem_or_size
- else:
- mem = Memory(data_width, mem_or_size//(data_width//8), init=init)
- csrw_per_memw = (mem.width + data_width - 1)//data_width
- word_bits = log2_int(csrw_per_memw)
- page_bits = log2_int((mem.depth*csrw_per_memw + 511)//512, False)
- if page_bits:
- self._page = CSRStorage(page_bits, name=mem.name_override + "_page")
- else:
- self._page = None
- if read_only is None:
- if hasattr(mem, "bus_read_only"):
- read_only = mem.bus_read_only
- else:
- read_only = False
-
- ###
-
- port = mem.get_port(write_capable=not read_only)
- self.specials += mem, port
-
- sel = Signal()
- sel_r = Signal()
- self.sync += sel_r.eq(sel)
- self.comb += sel.eq(self.bus.adr[9:] == address)
-
- if word_bits:
- word_index = Signal(word_bits)
- word_expanded = Signal(csrw_per_memw*data_width)
- self.sync += 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=csrw_per_memw, reverse=True)
- )
- ]
- if not read_only:
- wregs = []
- for i in range(csrw_per_memw-1):
- wreg = Signal(data_width)
- self.sync += If(sel & self.bus.we & (self.bus.adr[:word_bits] == i), wreg.eq(self.bus.dat_w))
- wregs.append(wreg)
- memword_chunks = [self.bus.dat_w] + list(reversed(wregs))
- self.comb += [
- port.we.eq(sel & self.bus.we & (self.bus.adr[:word_bits] == csrw_per_memw - 1)),
- port.dat_w.eq(Cat(*memword_chunks))
- ]
- else:
- 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:
- self.comb += port.adr.eq(self.bus.adr[word_bits:word_bits+flen(port.adr)])
- else:
- pv = self._page.storage
- self.comb += port.adr.eq(Cat(self.bus.adr[word_bits:word_bits+flen(port.adr)-flen(pv)], pv))
-
- def get_csrs(self):
- if self._page is None:
- return []
- else:
- return [self._page]
+++ /dev/null
-from migen.fhdl.std import *
-from migen.bus.transactions import *
-
-
-def _byte_mask(orig, dat_w, sel):
- r = 0
- shift = 0
- while sel:
- if sel & 1:
- r |= (dat_w & 0xff) << shift
- else:
- r |= (orig & 0xff) << shift
- orig >>= 8
- dat_w >>= 8
- sel >>= 1
- shift += 8
- return r
-
-
-class Initiator(Module):
- def __init__(self, generator, mem):
- self.generator = generator
- self.mem = mem
-
- def do_simulation(self, selfp):
- try:
- transaction = next(self.generator)
- except StopIteration:
- transaction = None
- raise StopSimulation
- if isinstance(transaction, TRead):
- transaction.data = selfp.mem[transaction.address]
- elif isinstance(transaction, TWrite):
- d = selfp.mem[transaction.address]
- d_mask = _byte_mask(d, transaction.data, transaction.sel)
- selfp.mem[transaction.address] = d_mask
+++ /dev/null
-from migen.fhdl.std import *
-
-
-class Transaction:
- def __init__(self, address, data=0, sel=None, busname=None):
- self.address = address
- self.data = data
- if sel is None:
- bytes = (bits_for(data) + 7)//8
- sel = 2**bytes - 1
- self.sel = sel
- self.busname = busname
- self.latency = 0
-
- def __str__(self):
- return "<" + self.__class__.__name__ + " adr:" + hex(self.address) + " dat:" + hex(self.data) + ">"
-
-
-class TRead(Transaction):
- pass
-
-
-class TWrite(Transaction):
- pass
+++ /dev/null
-from migen.fhdl.std import *
-from migen.genlib import roundrobin
-from migen.genlib.record import *
-from migen.genlib.misc import split, displacer, optree, chooser
-from migen.genlib.misc import FlipFlop, Counter
-from migen.genlib.fsm import FSM, NextState
-from migen.bus.transactions import *
-
-_layout = [
- ("adr", 30, DIR_M_TO_S),
- ("dat_w", "data_width", DIR_M_TO_S),
- ("dat_r", "data_width", DIR_S_TO_M),
- ("sel", "sel_width", 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(Record):
- def __init__(self, data_width=32):
- Record.__init__(self, set_layout_parameters(_layout,
- data_width=data_width,
- sel_width=data_width//8))
-
-
-class InterconnectPointToPoint(Module):
- def __init__(self, master, slave):
- self.comb += master.connect(slave)
-
-
-class Arbiter(Module):
- def __init__(self, masters, target):
- self.submodules.rr = roundrobin.RoundRobin(len(masters))
-
- # mux master->slave signals
- 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, 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 masters]
- self.comb += self.rr.request.eq(Cat(*reqs))
-
-
-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.
- # 1) wishbone.Slave reference.
- # register adds flip-flops after the address comparators. Improves timing,
- # but breaks Wishbone combinatorial feedback.
- def __init__(self, master, slaves, register=False):
- ns = len(slaves)
- slave_sel = Signal(ns)
- slave_sel_r = Signal(ns)
-
- # decode slave addresses
- 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:
- self.comb += slave_sel_r.eq(slave_sel)
-
- # connect master->slaves signals except cyc
- 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
- 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)
- 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], flen(master.dat_r)) & slaves[i][1].dat_r for i in range(ns)]
- self.comb += master.dat_r.eq(optree("|", masked))
-
-
-class InterconnectShared(Module):
- def __init__(self, masters, slaves, register=False):
- shared = Interface()
- self.submodules += Arbiter(masters, shared)
- self.submodules += Decoder(shared, slaves, register)
-
-
-class Crossbar(Module):
- def __init__(self, masters, slaves, register=False):
- matches, busses = zip(*slaves)
- access = [[Interface() for j in slaves] for i in masters]
- # decode each master into its access row
- for row, master in zip(access, masters):
- row = list(zip(matches, row))
- self.submodules += Decoder(master, row, register)
- # arbitrate each access column onto its slave
- for column, bus in zip(zip(*access), busses):
- self.submodules += Arbiter(column, bus)
-
-
-class DownConverter(Module):
- """DownConverter
-
- This module splits Wishbone accesses from a master interface to a smaller
- slave interface.
-
- Writes:
- Writes from master are splitted N writes to the slave. Access is acked when the last
- access is acked by the slave.
-
- Reads:
- Read from master are splitted in N reads to the the slave. Read datas from
- the slave are cached before being presented concatenated on the last access.
-
- TODO:
- Manage err signal? (Not implemented since we generally don't use it on Migen/MiSoC modules)
- """
- def __init__(self, master, slave):
- dw_from = flen(master.dat_r)
- dw_to = flen(slave.dat_w)
- ratio = dw_from//dw_to
-
- # # #
-
- read = Signal()
- write = Signal()
-
- counter = Counter(max=ratio)
- self.submodules += counter
- counter_done = Signal()
- self.comb += counter_done.eq(counter.value == ratio-1)
-
- # Main FSM
- self.submodules.fsm = fsm = FSM(reset_state="IDLE")
- fsm.act("IDLE",
- counter.reset.eq(1),
- If(master.stb & master.cyc,
- If(master.we,
- NextState("WRITE")
- ).Else(
- NextState("READ")
- )
- )
- )
- fsm.act("WRITE",
- write.eq(1),
- slave.we.eq(1),
- slave.cyc.eq(1),
- If(master.stb & master.cyc,
- slave.stb.eq(1),
- If(slave.ack,
- counter.ce.eq(1),
- If(counter_done,
- master.ack.eq(1),
- NextState("IDLE")
- )
- )
- ).Elif(~master.cyc,
- NextState("IDLE")
- )
- )
- fsm.act("READ",
- read.eq(1),
- slave.cyc.eq(1),
- If(master.stb & master.cyc,
- slave.stb.eq(1),
- If(slave.ack,
- counter.ce.eq(1),
- If(counter_done,
- master.ack.eq(1),
- NextState("IDLE")
- )
- )
- ).Elif(~master.cyc,
- NextState("IDLE")
- )
- )
-
- # Address
- self.comb += [
- If(counter_done,
- slave.cti.eq(7) # indicate end of burst
- ).Else(
- slave.cti.eq(2)
- ),
- slave.adr.eq(Cat(counter.value, master.adr))
- ]
-
- # Datapath
- cases = {}
- for i in range(ratio):
- cases[i] = [
- slave.sel.eq(master.sel[i*dw_to//8:(i+1)*dw_to]),
- slave.dat_w.eq(master.dat_w[i*dw_to:(i+1)*dw_to])
- ]
- self.comb += Case(counter.value, cases)
-
-
- cached_data = Signal(dw_from)
- self.comb += master.dat_r.eq(Cat(cached_data[dw_to:], slave.dat_r))
- self.sync += \
- If(read & counter.ce,
- cached_data.eq(master.dat_r)
- )
-
-
-class UpConverter(Module):
- """UpConverter
-
- This module up-converts wishbone accesses and bursts from a master interface
- to a wider slave interface. This allows efficient use wishbone bursts.
-
- Writes:
- Wishbone writes are cached before being written to the slave. Access to
- the slave is done at the end of a burst or when address reach end of burst
- addressing.
-
- Reads:
- Cache is refilled only at the beginning of each burst, the subsequent
- reads of a burst use the cached data.
-
- TODO:
- Manage err signal? (Not implemented since we generally don't use it on Migen/MiSoC modules)
- """
- def __init__(self, master, slave):
- dw_from = flen(master.dat_r)
- dw_to = flen(slave.dat_w)
- ratio = dw_to//dw_from
- ratiobits = log2_int(ratio)
-
- # # #
-
- write = Signal()
- evict = Signal()
- refill = Signal()
- read = Signal()
-
- address = FlipFlop(30)
- self.submodules += address
- self.comb += address.d.eq(master.adr)
-
- counter = Counter(max=ratio)
- self.submodules += counter
- counter_offset = Signal(max=ratio)
- counter_done = Signal()
- self.comb += [
- counter_offset.eq(address.q),
- counter_done.eq((counter.value + counter_offset) == ratio-1)
- ]
-
- cached_data = Signal(dw_to)
- cached_sel = Signal(dw_to//8)
-
- end_of_burst = Signal()
- self.comb += end_of_burst.eq(~master.cyc |
- (master.stb & master.cyc & master.ack & ((master.cti == 7) | counter_done)))
-
-
- need_refill = FlipFlop(reset=1)
- self.submodules += need_refill
- self.comb += [
- need_refill.reset.eq(end_of_burst),
- need_refill.d.eq(0)
- ]
-
- # Main FSM
- self.submodules.fsm = fsm = FSM()
- fsm.act("IDLE",
- counter.reset.eq(1),
- If(master.stb & master.cyc,
- address.ce.eq(1),
- If(master.we,
- NextState("WRITE")
- ).Else(
- If(need_refill.q,
- NextState("REFILL")
- ).Else(
- NextState("READ")
- )
- )
- )
- )
- fsm.act("WRITE",
- If(master.stb & master.cyc,
- write.eq(1),
- counter.ce.eq(1),
- master.ack.eq(1),
- If(counter_done,
- NextState("EVICT")
- )
- ).Elif(~master.cyc,
- NextState("EVICT")
- )
- )
- fsm.act("EVICT",
- evict.eq(1),
- slave.stb.eq(1),
- slave.we.eq(1),
- slave.cyc.eq(1),
- slave.dat_w.eq(cached_data),
- slave.sel.eq(cached_sel),
- If(slave.ack,
- NextState("IDLE")
- )
- )
- fsm.act("REFILL",
- refill.eq(1),
- slave.stb.eq(1),
- slave.cyc.eq(1),
- If(slave.ack,
- need_refill.ce.eq(1),
- NextState("READ")
- )
- )
- fsm.act("READ",
- read.eq(1),
- If(master.stb & master.cyc,
- master.ack.eq(1)
- ),
- NextState("IDLE")
- )
-
- # Address
- self.comb += [
- slave.cti.eq(7), # we are not able to generate bursts since up-converting
- slave.adr.eq(address.q[ratiobits:])
- ]
-
- # Datapath
- cached_datas = [FlipFlop(dw_from) for i in range(ratio)]
- cached_sels = [FlipFlop(dw_from//8) for i in range(ratio)]
- self.submodules += cached_datas, cached_sels
-
- cases = {}
- for i in range(ratio):
- write_sel = Signal()
- cases[i] = write_sel.eq(1)
- self.comb += [
- cached_sels[i].reset.eq(counter.reset),
- If(write,
- cached_datas[i].d.eq(master.dat_w),
- ).Else(
- cached_datas[i].d.eq(slave.dat_r[dw_from*i:dw_from*(i+1)])
- ),
- cached_sels[i].d.eq(master.sel),
- If((write & write_sel) | refill,
- cached_datas[i].ce.eq(1),
- cached_sels[i].ce.eq(1)
- )
- ]
- self.comb += Case(counter.value + counter_offset, cases)
-
- cases = {}
- for i in range(ratio):
- cases[i] = master.dat_r.eq(cached_datas[i].q)
- self.comb += Case(address.q[:ratiobits], cases)
-
- self.comb += [
- cached_data.eq(Cat([cached_data.q for cached_data in cached_datas])),
- cached_sel.eq(Cat([cached_sel.q for cached_sel in cached_sels]))
- ]
-
-
-class Converter(Module):
- """Converter
-
- This module is a wrapper for DownConverter and UpConverter.
- It should preferably be used rather than direct instantiations
- of specific converters.
- """
- def __init__(self, master, slave):
- self.master = master
- self.slave = slave
-
- # # #
-
- dw_from = flen(master.dat_r)
- dw_to = flen(slave.dat_r)
- if dw_from > dw_to:
- downconverter = DownConverter(master, slave)
- self.submodules += downconverter
- elif dw_from < dw_to:
- upconverter = UpConverter(master, slave)
- self.submodules += upconverter
- else:
- Record.connect(master, slave)
-
-
-class Cache(Module):
- """Cache
-
- This module is a write-back wishbone cache that can be used as a L2 cache.
- Cachesize (in 32-bit words) is the size of the data store and must be a power of 2
- """
- def __init__(self, cachesize, master, slave):
- self.master = master
- self.slave = slave
-
- ###
-
- dw_from = flen(master.dat_r)
- dw_to = flen(slave.dat_r)
- if dw_to > dw_from and (dw_to % dw_from) != 0:
- raise ValueError("Slave data width must be a multiple of {dw}".format(dw=dw_from))
- if dw_to < dw_from and (dw_from % dw_to) != 0:
- raise ValueError("Master data width must be a multiple of {dw}".format(dw=dw_to))
-
- # Split address:
- # TAG | LINE NUMBER | LINE OFFSET
- offsetbits = log2_int(max(dw_to//dw_from, 1))
- addressbits = flen(slave.adr) + offsetbits
- linebits = log2_int(cachesize) - offsetbits
- tagbits = addressbits - linebits
- wordbits = log2_int(max(dw_from//dw_to, 1))
- adr_offset, adr_line, adr_tag = split(master.adr, offsetbits, linebits, tagbits)
- word = Signal(wordbits) if wordbits else None
-
- # Data memory
- data_mem = Memory(dw_to*2**wordbits, 2**linebits)
- data_port = data_mem.get_port(write_capable=True, we_granularity=8)
- self.specials += data_mem, data_port
-
- write_from_slave = Signal()
- if adr_offset is None:
- adr_offset_r = None
- else:
- adr_offset_r = Signal(offsetbits)
- self.sync += adr_offset_r.eq(adr_offset)
-
- self.comb += [
- data_port.adr.eq(adr_line),
- If(write_from_slave,
- displacer(slave.dat_r, word, data_port.dat_w),
- displacer(Replicate(1, dw_to//8), word, data_port.we)
- ).Else(
- data_port.dat_w.eq(Replicate(master.dat_w, max(dw_to//dw_from, 1))),
- If(master.cyc & master.stb & master.we & master.ack,
- displacer(master.sel, adr_offset, data_port.we, 2**offsetbits, reverse=True)
- )
- ),
- chooser(data_port.dat_r, word, slave.dat_w),
- slave.sel.eq(2**(dw_to//8)-1),
- chooser(data_port.dat_r, adr_offset_r, master.dat_r, reverse=True)
- ]
-
-
- # Tag memory
- tag_layout = [("tag", tagbits), ("dirty", 1)]
- tag_mem = Memory(layout_len(tag_layout), 2**linebits)
- tag_port = tag_mem.get_port(write_capable=True)
- self.specials += tag_mem, tag_port
- tag_do = Record(tag_layout)
- tag_di = Record(tag_layout)
- self.comb += [
- tag_do.raw_bits().eq(tag_port.dat_r),
- tag_port.dat_w.eq(tag_di.raw_bits())
- ]
-
- self.comb += [
- tag_port.adr.eq(adr_line),
- tag_di.tag.eq(adr_tag)
- ]
- if word is not None:
- self.comb += slave.adr.eq(Cat(word, adr_line, tag_do.tag))
- else:
- self.comb += slave.adr.eq(Cat(adr_line, tag_do.tag))
-
- # slave word computation, word_clr and word_inc will be simplified
- # at synthesis when wordbits=0
- word_clr = Signal()
- word_inc = Signal()
- if word is not None:
- self.sync += \
- If(word_clr,
- word.eq(0),
- ).Elif(word_inc,
- word.eq(word+1)
- )
-
- def word_is_last(word):
- if word is not None:
- return word == 2**wordbits-1
- else:
- return 1
-
- # Control FSM
- self.submodules.fsm = fsm = FSM(reset_state="IDLE")
- fsm.act("IDLE",
- If(master.cyc & master.stb,
- NextState("TEST_HIT")
- )
- )
- fsm.act("TEST_HIT",
- word_clr.eq(1),
- If(tag_do.tag == adr_tag,
- master.ack.eq(1),
- If(master.we,
- tag_di.dirty.eq(1),
- tag_port.we.eq(1)
- ),
- NextState("IDLE")
- ).Else(
- If(tag_do.dirty,
- NextState("EVICT")
- ).Else(
- NextState("REFILL_WRTAG")
- )
- )
- )
-
- fsm.act("EVICT",
- slave.stb.eq(1),
- slave.cyc.eq(1),
- slave.we.eq(1),
- If(slave.ack,
- word_inc.eq(1),
- If(word_is_last(word),
- NextState("REFILL_WRTAG")
- )
- )
- )
- fsm.act("REFILL_WRTAG",
- # Write the tag first to set the slave address
- tag_port.we.eq(1),
- word_clr.eq(1),
- NextState("REFILL")
- )
- fsm.act("REFILL",
- slave.stb.eq(1),
- slave.cyc.eq(1),
- slave.we.eq(0),
- If(slave.ack,
- write_from_slave.eq(1),
- word_inc.eq(1),
- If(word_is_last(word),
- NextState("TEST_HIT"),
- ).Else(
- NextState("REFILL")
- )
- )
- )
-
-
-class Tap(Module):
- def __init__(self, bus, handler=print):
- self.bus = bus
- self.handler = handler
-
- def do_simulation(self, selfp):
- if selfp.bus.ack:
- assert(selfp.bus.cyc and selfp.bus.stb)
- if selfp.bus.we:
- transaction = TWrite(selfp.bus.adr,
- selfp.bus.dat_w,
- selfp.bus.sel)
- else:
- transaction = TRead(selfp.bus.adr,
- selfp.bus.dat_r)
- self.handler(transaction)
- do_simulation.passive = True
-
-
-class Initiator(Module):
- def __init__(self, generator, bus=None):
- self.generator = generator
- if bus is None:
- bus = Interface()
- self.bus = bus
- self.transaction_start = 0
- self.transaction = None
-
- def do_simulation(self, selfp):
- if self.transaction is None or selfp.bus.ack:
- if self.transaction is not None:
- self.transaction.latency = selfp.simulator.cycle_counter - self.transaction_start - 1
- if isinstance(self.transaction, TRead):
- self.transaction.data = selfp.bus.dat_r
- try:
- self.transaction = next(self.generator)
- except StopIteration:
- selfp.bus.cyc = 0
- selfp.bus.stb = 0
- raise StopSimulation
- if self.transaction is not None:
- self.transaction_start = selfp.simulator.cycle_counter
- selfp.bus.cyc = 1
- selfp.bus.stb = 1
- selfp.bus.adr = self.transaction.address
- if isinstance(self.transaction, TWrite):
- selfp.bus.we = 1
- selfp.bus.sel = self.transaction.sel
- selfp.bus.dat_w = self.transaction.data
- else:
- selfp.bus.we = 0
- else:
- selfp.bus.cyc = 0
- selfp.bus.stb = 0
-
-
-class TargetModel:
- def read(self, address):
- return 0
-
- def write(self, address, data, sel):
- pass
-
- def can_ack(self, bus):
- return True
-
-
-class Target(Module):
- def __init__(self, model, bus=None):
- if bus is None:
- bus = Interface()
- self.bus = bus
- self.model = model
-
- def do_simulation(self, selfp):
- bus = selfp.bus
- if not bus.ack:
- if self.model.can_ack(bus) and bus.cyc and bus.stb:
- if bus.we:
- self.model.write(bus.adr, bus.dat_w, bus.sel)
- else:
- bus.dat_r = self.model.read(bus.adr)
- bus.ack = 1
- else:
- bus.ack = 0
- do_simulation.passive = True
-
-
-class SRAM(Module):
- def __init__(self, mem_or_size, read_only=None, init=None, bus=None):
- if bus is None:
- bus = Interface()
- self.bus = bus
- bus_data_width = flen(self.bus.dat_r)
- if isinstance(mem_or_size, Memory):
- assert(mem_or_size.width <= bus_data_width)
- self.mem = mem_or_size
- else:
- self.mem = Memory(bus_data_width, mem_or_size//(bus_data_width//8), init=init)
- if read_only is None:
- if hasattr(self.mem, "bus_read_only"):
- read_only = self.mem.bus_read_only
- else:
- read_only = False
-
- ###
-
- # memory
- port = self.mem.get_port(write_capable=not read_only, we_granularity=8)
- self.specials += self.mem, port
- # generate write enable signal
- if not read_only:
- 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
- self.comb += [
- port.adr.eq(self.bus.adr[:flen(port.adr)]),
- self.bus.dat_r.eq(port.dat_r)
- ]
- if not read_only:
- self.comb += port.dat_w.eq(self.bus.dat_w),
- # generate ack
- self.sync += [
- self.bus.ack.eq(0),
- If(self.bus.cyc & self.bus.stb & ~self.bus.ack, self.bus.ack.eq(1))
- ]
+++ /dev/null
-from migen.fhdl.std import *
-from migen.bus import wishbone
-from migen.bus import csr
-from migen.genlib.misc import timeline
-
-
-class WB2CSR(Module):
- def __init__(self, bus_wishbone=None, bus_csr=None):
- if bus_wishbone is None:
- bus_wishbone = wishbone.Interface()
- self.wishbone = bus_wishbone
- if bus_csr is None:
- bus_csr = csr.Interface()
- self.csr = bus_csr
-
- ###
-
- self.sync += [
- self.csr.we.eq(0),
- self.csr.dat_w.eq(self.wishbone.dat_w),
- self.csr.adr.eq(self.wishbone.adr),
- self.wishbone.dat_r.eq(self.csr.dat_r)
- ]
- self.sync += timeline(self.wishbone.cyc & self.wishbone.stb, [
- (1, [self.csr.we.eq(self.wishbone.we)]),
- (2, [self.wishbone.ack.eq(1)]),
- (3, [self.wishbone.ack.eq(0)])
- ])
+++ /dev/null
-from migen.util.misc import xdir
-from migen.fhdl.std import *
-from migen.genlib.misc import optree
-from migen.genlib.record import *
-
-
-def _make_m2s(layout):
- r = []
- for f in layout:
- if isinstance(f[1], (int, tuple)):
- r.append((f[0], f[1], DIR_M_TO_S))
- else:
- r.append((f[0], _make_m2s(f[1])))
- return r
-
-
-class EndpointDescription:
- def __init__(self, payload_layout, param_layout=[], packetized=False):
- self.payload_layout = payload_layout
- self.param_layout = param_layout
- self.packetized = packetized
-
- def get_full_layout(self):
- reserved = {"stb", "ack", "payload", "param", "sop", "eop", "description"}
- attributed = set()
- for f in self.payload_layout + self.param_layout:
- if f[0] in attributed:
- raise ValueError(f[0] + " already attributed in payload or param layout")
- if f[0] in reserved:
- raise ValueError(f[0] + " cannot be used in endpoint layout")
- attributed.add(f[0])
-
- full_layout = [
- ("payload", _make_m2s(self.payload_layout)),
- ("param", _make_m2s(self.param_layout)),
- ("stb", 1, DIR_M_TO_S),
- ("ack", 1, DIR_S_TO_M)
- ]
- if self.packetized:
- full_layout += [
- ("sop", 1, DIR_M_TO_S),
- ("eop", 1, DIR_M_TO_S)
- ]
- return full_layout
-
-
-class _Endpoint(Record):
- def __init__(self, description_or_layout):
- if isinstance(description_or_layout, EndpointDescription):
- self.description = description_or_layout
- else:
- self.description = EndpointDescription(description_or_layout)
- Record.__init__(self, self.description.get_full_layout())
-
- def __getattr__(self, name):
- try:
- return getattr(object.__getattribute__(self, "payload"), name)
- except:
- return getattr(object.__getattribute__(self, "param"), name)
-
-
-class Source(_Endpoint):
- def connect(self, sink):
- return Record.connect(self, sink)
-
-
-class Sink(_Endpoint):
- def connect(self, source):
- return source.connect(self)
-
-
-def get_endpoints(obj, filt=_Endpoint):
- if hasattr(obj, "get_endpoints") and callable(obj.get_endpoints):
- return obj.get_endpoints(filt)
- r = dict()
- for k, v in xdir(obj, True):
- if isinstance(v, filt):
- r[k] = v
- return r
-
-
-def get_single_ep(obj, filt):
- eps = get_endpoints(obj, filt)
- if len(eps) != 1:
- raise ValueError("More than one endpoint")
- return list(eps.items())[0]
-
-
-class BinaryActor(Module):
- def __init__(self, *args, **kwargs):
- self.busy = Signal()
- sink = get_single_ep(self, Sink)[1]
- source = get_single_ep(self, Source)[1]
- self.build_binary_control(sink, source, *args, **kwargs)
-
- def build_binary_control(self, sink, source):
- raise NotImplementedError("Binary actor classes must overload build_binary_control_fragment")
-
-
-class CombinatorialActor(BinaryActor):
- def build_binary_control(self, sink, source):
- self.comb += [
- source.stb.eq(sink.stb),
- sink.ack.eq(source.ack),
- self.busy.eq(0)
- ]
- if sink.description.packetized:
- self.comb += [
- source.sop.eq(sink.sop),
- source.eop.eq(sink.eop)
- ]
-
-
-class SequentialActor(BinaryActor):
- def __init__(self, delay):
- self.trigger = Signal()
- BinaryActor.__init__(self, delay)
-
- def build_binary_control(self, sink, source, delay):
- ready = Signal()
- timer = Signal(max=delay+1)
- self.comb += ready.eq(timer == 0)
- self.sync += If(self.trigger,
- timer.eq(delay)
- ).Elif(~ready,
- timer.eq(timer - 1)
- )
-
- mask = Signal()
- self.comb += [
- source.stb.eq(ready & mask),
- self.trigger.eq(sink.stb & (source.ack | ~mask) & ready),
- sink.ack.eq(self.trigger),
- self.busy.eq(~ready)
- ]
- self.sync += [
- If(self.trigger, mask.eq(1)),
- If(source.stb & source.ack, mask.eq(0))
- ]
- if sink.packetized:
- self.comb += [
- source.sop.eq(sink.sop),
- source.eop.eq(sink.eop)
- ]
-
-
-class PipelinedActor(BinaryActor):
- def __init__(self, latency):
- self.pipe_ce = Signal()
- BinaryActor.__init__(self, latency)
-
- def build_binary_control(self, sink, source, latency):
- busy = 0
- valid = sink.stb
- for i in range(latency):
- valid_n = Signal()
- self.sync += If(self.pipe_ce, valid_n.eq(valid))
- valid = valid_n
- busy = busy | valid
-
- self.comb += [
- self.pipe_ce.eq(source.ack | ~valid),
- sink.ack.eq(self.pipe_ce),
- source.stb.eq(valid),
- self.busy.eq(busy)
- ]
- if sink.description.packetized:
- sop = sink.stb & sink.sop
- eop = sink.stb & sink.eop
- for i in range(latency):
- sop_n = Signal()
- eop_n = Signal()
- self.sync += \
- If(self.pipe_ce,
- sop_n.eq(sop),
- eop_n.eq(eop)
- )
- sop = sop_n
- eop = eop_n
-
- self.comb += [
- source.eop.eq(eop),
- source.sop.eq(sop)
- ]
+++ /dev/null
-from collections import defaultdict
-
-from migen.fhdl.std import *
-from migen.flow.actor import *
-
-
-class EndpointSimHook(Module):
- def __init__(self, endpoint):
- self.endpoint = endpoint
-
- def on_ack(self):
- pass
-
- def on_nack(self):
- pass
-
- def on_inactive(self):
- pass
-
- def do_simulation(self, selfp):
- if selfp.endpoint.stb:
- if selfp.endpoint.ack:
- self.on_ack()
- else:
- self.on_nack()
- else:
- self.on_inactive()
-
-
-class DFGHook(Module):
- def __init__(self, dfg, create):
- assert(not dfg.is_abstract())
- self.nodepair_to_ep = defaultdict(dict)
- for hookn, (u, v, data) in enumerate(dfg.edges_iter(data=True)):
- ep_to_hook = self.nodepair_to_ep[(u, v)]
- ep = data["source"]
- h = create(u, ep, v)
- ep_to_hook[ep] = h
- setattr(self.submodules, "hook"+str(hookn), h)
-
- def hooks_iter(self):
- for v1 in self.nodepair_to_ep.values():
- for v2 in v1.values():
- yield v2
+++ /dev/null
-from migen.fhdl.std import *
-from migen.bank.description import *
-from migen.flow.hooks import DFGHook
-
-ISD_MAGIC = 0x6ab4
-
-
-class EndpointReporter(Module, AutoCSR):
- def __init__(self, endpoint, nbits):
- self.reset = Signal()
- self.freeze = Signal()
-
- self._ack_count = CSRStatus(nbits)
- self._nack_count = CSRStatus(nbits)
- self._cur_status = CSRStatus(2)
-
- ###
-
- stb = Signal()
- ack = Signal()
- self.comb += self._cur_status.status.eq(Cat(stb, ack))
- ack_count = Signal(nbits)
- nack_count = Signal(nbits)
- self.sync += [
- # register monitored signals
- stb.eq(endpoint.stb),
- ack.eq(endpoint.ack),
- # count operations
- If(self.reset,
- ack_count.eq(0),
- nack_count.eq(0)
- ).Else(
- If(stb,
- If(ack,
- ack_count.eq(ack_count + 1)
- ).Else(
- nack_count.eq(nack_count + 1)
- )
- )
- ),
- If(~self.freeze,
- self._ack_count.status.eq(ack_count),
- self._nack_count.status.eq(nack_count)
- )
- ]
-
-
-class DFGReporter(DFGHook, AutoCSR):
- def __init__(self, dfg, nbits):
- self._magic = CSRStatus(16)
- self._neps = CSRStatus(8)
- self._nbits = CSRStatus(8)
- self._freeze = CSRStorage()
- self._reset = CSR()
-
- ###
-
- DFGHook.__init__(self, dfg,
- lambda u, ep, v: EndpointReporter(getattr(u, ep), nbits))
- hooks = list(self.hooks_iter())
-
- self.comb += [
- self._magic.status.eq(ISD_MAGIC),
- self._neps.status.eq(len(hooks)),
- self._nbits.status.eq(nbits)
- ]
- for h in hooks:
- self.comb += [
- h.freeze.eq(self._freeze.storage),
- h.reset.eq(self._reset.re)
- ]
+++ /dev/null
-from collections import defaultdict
-
-from migen.fhdl.std import *
-from migen.genlib.misc import optree
-from migen.flow.actor import *
-from migen.flow import plumbing
-
-# Abstract actors mean that the actor class should be instantiated with the parameters
-# from the dictionary. They are needed to enable actor duplication or sharing during
-# elaboration, and automatic parametrization of plumbing actors.
-
-
-class AbstractActor:
- def __init__(self, actor_class, parameters=dict(), name=None):
- self.actor_class = actor_class
- self.parameters = parameters
- self.name = name
- self.busy = Signal()
-
- def create_instance(self):
- return self.actor_class(**self.parameters)
-
- def __repr__(self):
- r = "<abstract " + self.actor_class.__name__
- if self.name is not None:
- r += ": " + self.name
- r += ">"
- return r
-
-
-class MultiDiGraph:
- def __init__(self):
- self.edges = defaultdict(list)
- self.incoming = defaultdict(set)
- self.outgoing = defaultdict(set)
- self.nodes = set()
-
- def add_edge(self, a, b, **edge):
- self.edges[(a, b)].append(edge)
- self.incoming[b].add(a)
- self.outgoing[a].add(b)
- self.nodes |= {a, b}
-
- def __iter__(self):
- return iter(self.nodes)
-
- def __len__(self):
- return len(self.nodes)
-
- def edges_iter(self, data=True):
- assert data
- for (a, b), edges in self.edges.items():
- for edge in edges:
- yield a, b, edge
-
- def get_edge_data(self, a, b):
- return dict(enumerate(self.edges[(a, b)]))
-
- def add_node(self, node):
- self.nodes.add(node)
-
- def remove_node(self, node):
- for i in self.incoming.pop(node):
- del self.edges[(i, node)]
- self.outgoing[i].remove(node)
- for i in self.outgoing.pop(node):
- del self.edges[(node, i)]
- self.incoming[i].remove(node)
- self.nodes.remove(node)
-
- def remove_edge(self, a, b, key):
- e = self.edges[(a, b)]
- del e[key]
- if not e:
- self.incoming[b].remove(a)
- self.outgoing[a].remove(b)
-
- def in_edges(self, sink, data=True):
- assert data
- e = []
- for source in self.incoming[sink]:
- for edge in self.edges[(source, sink)]:
- e.append((source, sink, edge))
- return e
-
- def out_edges(self, source, data=True):
- assert data
- e = []
- for sink in self.outgoing[source]:
- for edge in self.edges[(source, sink)]:
- e.append((source, sink, edge))
- return e
-
-
-# TODO: rewrite this without non-determinism
-class DataFlowGraph(MultiDiGraph):
- def __init__(self):
- MultiDiGraph.__init__(self)
- self.elaborated = False
- self.abstract_busy_signals = dict()
-
- def add_connection(self, source_node, sink_node,
- source_ep=None, sink_ep=None, # default: assume nodes have 1 source/sink and use that one
- source_subr=None, sink_subr=None): # default: use whole record
- self.add_edge(source_node, sink_node,
- source=source_ep, sink=sink_ep,
- source_subr=source_subr, sink_subr=sink_subr)
-
- def add_buffered_connection(self, source_node, sink_node,
- source_ep=None, sink_ep=None,
- source_subr=None, sink_subr=None):
- buf = AbstractActor(plumbing.Buffer)
- self.add_connection(source_node, buf, source_ep=source_ep, source_subr=source_subr)
- self.add_connection(buf, sink_node, sink_ep=sink_ep, sink_subr=sink_subr)
-
- def add_pipeline(self, *nodes):
- for n1, n2 in zip(nodes, nodes[1:]):
- self.add_connection(n1, n2)
-
- def del_connections(self, source_node, sink_node, data_requirements):
- edges_to_delete = []
- edge_data = self.get_edge_data(source_node, sink_node)
- if edge_data is None:
- # the two nodes are already completely disconnected
- return
- for key, data in edge_data.items():
- if all(k not in data_requirements or data_requirements[k] == v
- for k, v in data.items()):
- edges_to_delete.append(key)
- for key in edges_to_delete:
- self.remove_edge(source_node, sink_node, key)
-
- def replace_actor(self, old, new):
- self.add_node(new)
- for xold, v, data in self.out_edges(old, data=True):
- self.add_edge(new, v, **data)
- for u, xold, data in self.in_edges(old, data=True):
- self.add_edge(u, new, **data)
- self.remove_node(old)
-
- def instantiate(self, actor):
- inst = actor.create_instance()
- self.abstract_busy_signals[id(inst)] = actor.busy
- self.replace_actor(actor, inst)
-
- # Returns a dictionary
- # source -> [sink1, ..., sinkn]
- # source element is a (node, endpoint) pair.
- # sink elements are (node, endpoint, source subrecord, sink subrecord) triples.
- def _source_to_sinks(self):
- d = dict()
- for u, v, data in self.edges_iter(data=True):
- el_src = (u, data["source"])
- el_dst = (v, data["sink"], data["source_subr"], data["sink_subr"])
- if el_src in d:
- d[el_src].append(el_dst)
- else:
- d[el_src] = [el_dst]
- return d
-
- # Returns a dictionary
- # sink -> [source1, ... sourcen]
- # sink element is a (node, endpoint) pair.
- # source elements are (node, endpoint, sink subrecord, source subrecord) triples.
- def _sink_to_sources(self):
- d = dict()
- for u, v, data in self.edges_iter(data=True):
- el_src = (u, data["source"], data["sink_subr"], data["source_subr"])
- el_dst = (v, data["sink"])
- if el_dst in d:
- d[el_dst].append(el_src)
- else:
- d[el_dst] = [el_src]
- return d
-
- # List sources that feed more than one sink.
- def _list_divergences(self):
- d = self._source_to_sinks()
- return dict((k, v) for k, v in d.items() if len(v) > 1)
-
- # A graph is abstract if any of these conditions is met:
- # (1) A node is an abstract actor.
- # (2) A subrecord is used.
- # (3) A single source feeds more than one sink.
- # NB: It is not allowed for a single sink to be fed by more than one source
- # (except with subrecords, i.e. when a combinator is used)
- def is_abstract(self):
- return any(isinstance(x, AbstractActor) for x in self) \
- or any(d["source_subr"] is not None or d["sink_subr"] is not None
- for u, v, d in self.edges_iter(data=True)) \
- or bool(self._list_divergences())
-
- def _eliminate_subrecords_and_divergences(self):
- # Insert combinators.
- for (dst_node, dst_endpoint), sources in self._sink_to_sources().items():
- if len(sources) > 1 or sources[0][2] is not None:
- # build combinator
- # "layout" is filled in during instantiation
- subrecords = [dst_subrecord for src_node, src_endpoint, dst_subrecord, src_subrecord in sources]
- combinator = AbstractActor(plumbing.Combinator, {"subrecords": subrecords})
- # disconnect source1 -> sink ... sourcen -> sink
- # connect source1 -> combinator_sink1 ... sourcen -> combinator_sinkn
- for n, (src_node, src_endpoint, dst_subrecord, src_subrecord) in enumerate(sources):
- self.del_connections(src_node, dst_node,
- {"source": src_endpoint, "sink": dst_endpoint})
- self.add_connection(src_node, combinator,
- src_endpoint, "sink{0}".format(n), source_subr=src_subrecord)
- # connect combinator_source -> sink
- self.add_connection(combinator, dst_node, "source", dst_endpoint)
- # Insert splitters.
- for (src_node, src_endpoint), sinks in self._source_to_sinks().items():
- if len(sinks) > 1 or sinks[0][2] is not None:
- subrecords = [src_subrecord for dst_node, dst_endpoint, src_subrecord, dst_subrecord in sinks]
- splitter = AbstractActor(plumbing.Splitter, {"subrecords": subrecords})
- # disconnect source -> sink1 ... source -> sinkn
- # connect splitter_source1 -> sink1 ... splitter_sourcen -> sinkn
- for n, (dst_node, dst_endpoint, src_subrecord, dst_subrecord) in enumerate(sinks):
- self.del_connections(src_node, dst_node,
- {"source": src_endpoint, "sink": dst_endpoint})
- self.add_connection(splitter, dst_node,
- "source{0}".format(n), dst_endpoint)
- # connect source -> splitter_sink
- self.add_connection(src_node, splitter, src_endpoint, "sink")
-
- def _infer_plumbing_layout(self):
- while True:
- ap = [a for a in self if isinstance(a, AbstractActor) and a.actor_class in plumbing.actors]
- if not ap:
- break
- for a in ap:
- in_edges = self.in_edges(a, data=True)
- out_edges = self.out_edges(a, data=True)
- if a.actor_class in plumbing.layout_sink and len(in_edges) == 1:
- other, me, data = in_edges[0]
- if isinstance(other, AbstractActor):
- continue
- other_ep = data["source"]
- if other_ep is None:
- other_ep = get_single_ep(other, Source)[1]
- else:
- other_ep = getattr(other, other_ep)
- elif a.actor_class in plumbing.layout_source and len(out_edges) == 1:
- me, other, data = out_edges[0]
- if isinstance(other, AbstractActor):
- continue
- other_ep = data["sink"]
- if other_ep is None:
- other_ep = get_single_ep(other, Sink)[1]
- else:
- other_ep = getattr(other, other_ep)
- else:
- raise AssertionError
- layout = other_ep.payload.layout
- a.parameters["layout"] = layout
- self.instantiate(a)
-
- def _instantiate_actors(self):
- # 1. instantiate all abstract non-plumbing actors
- for actor in list(self):
- if isinstance(actor, AbstractActor) and actor.actor_class not in plumbing.actors:
- self.instantiate(actor)
- # 2. infer plumbing layout and instantiate plumbing
- self._infer_plumbing_layout()
- # 3. resolve default eps
- for u, v, d in self.edges_iter(data=True):
- if d["source"] is None:
- d["source"] = get_single_ep(u, Source)[0]
- if d["sink"] is None:
- d["sink"] = get_single_ep(v, Sink)[0]
-
- # Elaboration turns an abstract DFG into a physical one.
- # Pass 1: eliminate subrecords and divergences
- # by inserting Combinator/Splitter actors
- # Pass 2: run optimizer (e.g. share and duplicate actors)
- # Pass 3: instantiate all abstract actors and explicit "None" endpoints
- def elaborate(self, optimizer=None):
- if self.elaborated:
- return
- self.elaborated = True
-
- self._eliminate_subrecords_and_divergences()
- if optimizer is not None:
- optimizer(self)
- self._instantiate_actors()
-
-
-class CompositeActor(Module):
- def __init__(self, dfg):
- dfg.elaborate()
-
- # expose unconnected endpoints
- uc_eps_by_node = dict((node, get_endpoints(node)) for node in dfg)
- for u, v, d in dfg.edges_iter(data=True):
- uc_eps_u = uc_eps_by_node[u]
- source = d["source"]
- try:
- del uc_eps_u[source]
- except KeyError:
- pass
- uc_eps_v = uc_eps_by_node[v]
- sink = d["sink"]
- try:
- del uc_eps_v[sink]
- except KeyError:
- pass
- for node, uc_eps in uc_eps_by_node.items():
- for k, v in uc_eps.items():
- assert(not hasattr(self, k))
- setattr(self, k, v)
-
- # connect abstract busy signals
- for node in dfg:
- try:
- abstract_busy_signal = dfg.abstract_busy_signals[id(node)]
- except KeyError:
- pass
- else:
- self.comb += abstract_busy_signal.eq(node.busy)
-
- # generate busy signal
- self.busy = Signal()
- self.comb += self.busy.eq(optree("|", [node.busy for node in dfg]))
-
- # claim ownership of sub-actors and establish connections
- for node in dfg:
- self.submodules += node
- for u, v, d in dfg.edges_iter(data=True):
- ep_src = getattr(u, d["source"])
- ep_dst = getattr(v, d["sink"])
- self.comb += ep_src.connect_flat(ep_dst)
+++ /dev/null
-from migen.flow.hooks import *
-
-
-class EndpointReporter(EndpointSimHook):
- def __init__(self, endpoint):
- EndpointSimHook.__init__(self, endpoint)
- self.reset()
-
- def reset(self):
- self.inactive = 0
- self.ack = 0
- self.nack = 0
-
- # Total number of cycles per token (inverse token rate)
- def cpt(self):
- return (self.inactive + self.nack + self.ack)/self.ack
-
- # Inactivity cycles per token (slack)
- def ipt(self):
- return self.inactive/self.ack
-
- # NAK cycles per token (backpressure)
- def npt(self):
- return self.nack/self.ack
-
- def report_str(self):
- if self.ack:
- return "C/T={:.2f}\nI/T={:.2f}\nN/T={:.2f}".format(self.cpt(), self.ipt(), self.npt())
- else:
- return "N/A"
-
- def on_ack(self):
- self.ack += 1
-
- def on_nack(self):
- self.nack += 1
-
- def on_inactive(self):
- self.inactive += 1
-
-
-class DFGReporter(DFGHook):
- def __init__(self, dfg):
- DFGHook.__init__(self, dfg, lambda u, ep, v: EndpointReporter(getattr(u, ep)))
-
- def get_edge_labels(self):
- d = dict()
- for (u, v), eps in self.nodepair_to_ep.items():
- if len(eps) == 1:
- d[(u, v)] = list(eps.values())[0].report_str()
- else:
- d[(u, v)] = "\n".join(ep + ":\n" + reporter.report_str()
- for ep, reporter in eps)
- return d
+++ /dev/null
-from migen.fhdl.std import *
-from migen.flow.actor import *
-from migen.genlib.record import *
-from migen.genlib.misc import optree
-
-
-class Buffer(PipelinedActor):
- def __init__(self, layout):
- self.d = Sink(layout)
- self.q = Source(layout)
- PipelinedActor.__init__(self, 1)
- self.sync += \
- If(self.pipe_ce,
- self.q.payload.eq(self.d.payload),
- self.q.param.eq(self.d.param)
- )
-
-
-class Combinator(Module):
- def __init__(self, layout, subrecords):
- self.source = Source(layout)
- sinks = []
- for n, r in enumerate(subrecords):
- s = Sink(layout_partial(layout, *r))
- setattr(self, "sink"+str(n), s)
- sinks.append(s)
- self.busy = Signal()
-
- ###
-
- self.comb += [
- self.busy.eq(0),
- self.source.stb.eq(optree("&", [sink.stb for sink in sinks]))
- ]
- self.comb += [sink.ack.eq(self.source.ack & self.source.stb) for sink in sinks]
- self.comb += [self.source.payload.eq(sink.payload) for sink in sinks]
- self.comb += [self.source.param.eq(sink.param) for sink in sinks]
-
-
-class Splitter(Module):
- def __init__(self, layout, subrecords):
- self.sink = Sink(layout)
- sources = []
- for n, r in enumerate(subrecords):
- s = Source(layout_partial(layout, *r))
- setattr(self, "source"+str(n), s)
- sources.append(s)
- self.busy = Signal()
-
- ###
-
- self.comb += [source.payload.eq(self.sink.payload) for source in sources]
- self.comb += [source.param.eq(self.sink.param) for source in sources]
- already_acked = Signal(len(sources))
- self.sync += If(self.sink.stb,
- already_acked.eq(already_acked | Cat(*[s.ack for s in sources])),
- If(self.sink.ack, already_acked.eq(0))
- )
- self.comb += self.sink.ack.eq(optree("&",
- [s.ack | already_acked[n] for n, s in enumerate(sources)]))
- for n, s in enumerate(sources):
- self.comb += s.stb.eq(self.sink.stb & ~already_acked[n])
-
-
-class Multiplexer(Module):
- def __init__(self, layout, n):
- self.source = Source(layout)
- sinks = []
- for i in range(n):
- sink = Sink(layout)
- setattr(self, "sink"+str(i), sink)
- sinks.append(sink)
- self.busy = Signal()
- self.sel = Signal(max=n)
-
- ###
-
- cases = {}
- for i, sink in enumerate(sinks):
- cases[i] = Record.connect(sink, self.source)
- self.comb += Case(self.sel, cases)
-
-
-class Demultiplexer(Module):
- def __init__(self, layout, n):
- self.sink = Sink(layout)
- sources = []
- for i in range(n):
- source = Source(layout)
- setattr(self, "source"+str(i), source)
- sources.append(source)
- self.busy = Signal()
- self.sel = Signal(max=n)
-
- ###
-
- cases = {}
- for i, source in enumerate(sources):
- cases[i] = Record.connect(self.sink, source)
- self.comb += Case(self.sel, cases)
-
-# Actors whose layout should be inferred from what their single sink is connected to.
-layout_sink = {Buffer, Splitter}
-# Actors whose layout should be inferred from what their single source is connected to.
-layout_source = {Buffer, Combinator}
-# All actors.
-actors = layout_sink | layout_source
+++ /dev/null
-class Token:
- def __init__(self, endpoint, value=None, idle_wait=False):
- self.endpoint = endpoint
- self.value = value
- self.idle_wait = idle_wait
+++ /dev/null
-from migen.fhdl.std import *
-
-
-class Complex:
- def __init__(self, real, imag):
- self.real = real
- self.imag = imag
-
- def __neg__(self):
- return Complex(-self.real, -self.imag)
-
- def __add__(self, other):
- if isinstance(other, Complex):
- return Complex(self.real + other.real, self.imag + other.imag)
- else:
- return Complex(self.real + other, self.imag)
- __radd__ = __add__
- def __sub__(self, other):
- if isinstance(other, Complex):
- return Complex(self.real - other.real, self.imag - other.imag)
- else:
- return Complex(self.real - other, self.imag)
- def __rsub__(self, other):
- if isinstance(other, Complex):
- return Complex(other.real - self.real, other.imag - self.imag)
- else:
- return Complex(other - self.real, -self.imag)
- def __mul__(self, other):
- if isinstance(other, Complex):
- return Complex(self.real*other.real - self.imag*other.imag,
- self.real*other.imag + self.imag*other.real)
- else:
- return Complex(self.real*other, self.imag*other)
- __rmul__ = __mul__
-
- def __lshift__(self, other):
- return Complex(self.real << other, self.imag << other)
- def __rshift__(self, other):
- return Complex(self.real >> other, self.imag >> other)
-
- def __repr__(self):
- return repr(self.real) + " + " + repr(self.imag) + "j"
-
- def eq(self, r):
- if isinstance(r, Complex):
- return self.real.eq(r.real), self.imag.eq(r.imag)
- else:
- return self.real.eq(r), self.imag.eq(0)
-
-
-def SignalC(*args, **kwargs):
- real = Signal(*args, **kwargs)
- imag = Signal(*args, **kwargs)
- return Complex(real, imag)
+++ /dev/null
-#!/usr/bin/env python3
-
-# Copyright (c) 2014 Guy Hutchison
-
-# Redistribution and use in source and binary forms, with or without modification,
-# are permitted provided that the following conditions are met:
-
-# 1. Redistributions of source code must retain the above copyright notice, this
-# list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
-# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import migen
-import operator
-from migen.fhdl.std import *
-from migen.fhdl.verilog import convert
-
-
-# Join two lists a and b, such that redundant terms are removed
-def join_lists(a, b):
- z = []
- for x in a+b:
- if x not in z:
- z.append(x)
- else:
- z.remove(x)
- return z
-
-
-def join_operator(list, op):
- if len(list) == 0:
- return []
- elif len(list) == 1:
- return list[0]
- elif len(list) == 2:
- return op(list[0], list[1])
- else:
- return op(list[0], join_operator(list[1:], op))
-
-
-def calc_code_bits(data_bits):
- m = 1
- c = 0
-
- while c < data_bits:
- m += 1
- c = 2**m - m - 1
- return m
-
-
-# build_seq() is used to create the selection of bits which need
-# to be checked for a particular data parity bit.
-def build_seq(bnum, out_width):
- tmp = []
-
- ptr = 0
- cur = 0
- skip = 2**bnum-1
- if skip == 0:
- check = 2**bnum
- else:
- check = 0
- while cur < out_width:
- if check > 0:
- if (cur != 2**bnum-1):
- tmp.append(cur)
- ptr += 1
- check -= 1
- if check == 0:
- skip = 2**bnum
- else:
- skip -= 1
- if skip == 0:
- check = 2**bnum
- cur += 1
-
- return tmp
-
-
-# build_bits() is used for the generator portion, it combines the
-# bit sequences for all input and parity bits which are used and
-# removes redundant terms.
-def build_bits(in_width, gen_parity=True):
- pnum = 1
- innum = 0
- blist = []
- num_code_bits = calc_code_bits(in_width)
- out_width = in_width + num_code_bits
- v = [list()] * out_width
- code_bit_list = []
-
- for b in range(out_width):
- if (b+1) == pnum:
- pnum = 2*pnum
- else:
- v[b] = [innum]
- innum += 1
-
- for b in range(num_code_bits):
- vindex = 2**b-1
- blist = build_seq(b, out_width)
- for bli in blist:
- v[vindex] = join_lists(v[vindex], v[bli])
- code_bit_list.append(v[vindex])
-
- # Calculate parity bit
- if gen_parity:
- pbit = []
- for b in v:
- pbit = join_lists(pbit, b)
- code_bit_list.append(pbit)
- return code_bit_list
-
-
-# xor_tree() takes a signal and a list of bits to be applied from
-# the signal and generates a balanced xor tree as output.
-def xor_tree(in_signal, in_bits):
- if len(in_bits) == 0:
- print ("ERROR: in_bits must be > 0")
- elif len(in_bits) == 1:
- return in_signal[in_bits[0]]
- elif len(in_bits) == 2:
- return in_signal[in_bits[0]] ^ in_signal[in_bits[1]]
- elif len(in_bits) == 3:
- return in_signal[in_bits[0]] ^ in_signal[in_bits[1]] ^ in_signal[in_bits[2]]
- else:
- split = int(len(in_bits)/2)
- return xor_tree(in_signal, in_bits[0:split]) ^ xor_tree(in_signal, in_bits[split:])
-
-
-# Base class for Hamming code generator/checker.
-
-
-# Hamming code generator class
-
-# The class constructor takes a single required input, which is the number of
-# bits of the input data. The module creates a single output, which is a set
-# of code check bits and a parity bit.
-
-# This generator and its corresponding checker will only generate a single-
-# error correct, double-error detect code. If double-error detection is
-# not desired, the most-significant code_out bit can be left unconnected.
-
-# If generated as a top-level module, contains its suggested module name
-# in self.name and list of ports in self.ports
-class HammingGenerator(Module):
- def __init__(self, input_size):
- self.input_size = input_size
- self.data_in = Signal(input_size)
- self.code_out = Signal(calc_code_bits(input_size)+1)
-
- xor_bits = build_bits(self.input_size)
- for b in range(len(xor_bits)):
- self.comb += self.code_out[b].eq(xor_tree(self.data_in, xor_bits[b]))
-
-
-# Hamming code checker class
-
-# Constructor takes two parameters:
-# input_size (bits of data bus, not counting check bits)
-# correct (boolean, True if output data should be corrected)
-
-# If used as a check/correct module, the module creates an
-# enable input which can dynamically turn off error correction
-# for debug.
-
-# If double-bit detection is not desired, the most-significant
-# code_in bit can be tied to 0, and the dberr output port left
-# unconnected.
-
-# If generated as a top-level module, contains its suggested module name
-# in self.name and list of ports in self.ports
-class HammingChecker(Module):
- def __init__(self, input_size, correct=True, gen_parity=True):
- self.input_size = input_size
- self.correct = correct
- self.data_in = Signal(input_size)
- self.code_bits = calc_code_bits(input_size)
- self.code_in = Signal(self.code_bits+1)
- self.code_out = Signal(self.code_bits)
- self.sberr = Signal()
- if gen_parity:
- self.dberr = Signal()
-
- # vector of which interleaved bit position represents a particular
- # data bit, used for error correction
- dbits = []
-
- # Create interleaved vector of code bits and data bits with code bits
- # in power-of-two positions
- pnum = 0
- dnum = 0
- self.par_vec = Signal(input_size+self.code_bits)
- for b in range(input_size+calc_code_bits(input_size)):
- if b+1 == 2**pnum:
- self.comb += self.par_vec[b].eq(self.code_in[pnum])
- pnum += 1
- else:
- self.comb += self.par_vec[b].eq(self.data_in[dnum])
- dbits.append(b)
- dnum += 1
-
- if correct:
- self.enable = Signal()
- self.correct_out = Signal(input_size)
- self.data_out = Signal(input_size, name='data_out')
- for b in range(input_size):
- self.comb += self.correct_out[b].eq((self.code_out == (dbits[b]+1)) ^ self.data_in[b])
- self.comb += If(self.enable, self.data_out.eq(self.correct_out)).Else(self.data_out.eq(self.data_in))
-
- self.comb += self.sberr.eq(self.code_out != 0)
- if gen_parity:
- parity = Signal()
- self.comb += parity.eq(xor_tree(self.data_in, range(input_size)) ^ xor_tree(self.code_in, range(self.code_bits+1)))
- self.comb += self.dberr.eq(~parity)
-
- for b in range(calc_code_bits(self.input_size)):
- bits = [2**b-1]
- bits += build_seq(b, self.input_size+calc_code_bits(self.input_size))
- self.comb += self.code_out[b].eq(xor_tree(self.par_vec, bits))
+++ /dev/null
-from migen.fhdl.std import *
-
-
-class ReorderSlot:
- def __init__(self, tag_width, data_width):
- self.wait_data = Signal()
- self.has_data = Signal()
- self.tag = Signal(tag_width)
- self.data = Signal(data_width)
-
-
-class ReorderBuffer(Module):
- def __init__(self, tag_width, data_width, depth):
- # issue
- self.can_issue = Signal()
- self.issue = Signal()
- self.tag_issue = Signal(tag_width)
-
- # call
- self.call = Signal()
- self.tag_call = Signal(tag_width)
- self.data_call = Signal(data_width)
-
- # readback
- self.can_read = Signal()
- self.read = Signal()
- self.data_read = Signal(data_width)
-
- ###
-
- empty_count = Signal(max=depth+1, reset=depth)
- produce = Signal(max=depth)
- consume = Signal(max=depth)
- slots = Array(ReorderSlot(tag_width, data_width)
- for n in range(depth))
-
- # issue
- self.comb += self.can_issue.eq(empty_count != 0)
- self.sync += If(self.issue & self.can_issue,
- empty_count.eq(empty_count - 1),
- If(produce == depth - 1,
- produce.eq(0)
- ).Else(
- produce.eq(produce + 1)
- ),
- slots[produce].wait_data.eq(1),
- slots[produce].tag.eq(self.tag_issue)
- )
-
- # call
- for n, slot in enumerate(slots):
- self.sync += If(self.call & slot.wait_data & (self.tag_call == slot.tag),
- slot.wait_data.eq(0),
- slot.has_data.eq(1),
- slot.data.eq(self.data_call)
- )
-
- # readback
- self.comb += [
- self.can_read.eq(slots[consume].has_data),
- self.data_read.eq(slots[consume].data)
- ]
- self.sync += [
- If(self.read & self.can_read,
- empty_count.eq(empty_count + 1),
- If(consume == depth - 1,
- consume.eq(0)
- ).Else(
- consume.eq(consume + 1)
- ),
- slots[consume].has_data.eq(0)
- )
- ]
-
- # do not touch empty count when issuing and reading at the same time
- self.sync += If(self.issue & self.can_issue & self.read & self.can_read,
- empty_count.eq(empty_count)
- )
+++ /dev/null
-import unittest
-
-from migen.fhdl.std import *
-from migen.flow.actor import *
-from migen.flow.transactions import *
-from migen.flow.network import *
-from migen.actorlib.sim import *
-
-from migen.test.support import SimCase, SimBench
-
-
-def source_gen(sent):
- for i in range(10):
- yield Token("source", {"value": i})
- sent.append(i)
-
-
-class SimSource(SimActor):
- def __init__(self):
- self.source = Source([("value", 32)])
- self.sent = []
- SimActor.__init__(self, source_gen(self.sent))
-
-
-def sink_gen(received):
- while True:
- t = Token("sink")
- yield t
- received.append(t.value["value"])
-
-
-class SimSink(SimActor):
- def __init__(self):
- self.sink = Sink([("value", 32)])
- self.received = []
- SimActor.__init__(self, sink_gen(self.received))
-
-
-class SourceSinkCase(SimCase, unittest.TestCase):
- class TestBench(SimBench):
- def __init__(self):
- self.source = SimSource()
- self.sink = SimSink()
- g = DataFlowGraph()
- g.add_connection(self.source, self.sink)
- self.submodules.comp = CompositeActor(g)
-
- def do_simulation(self, selfp):
- if self.source.token_exchanger.done:
- raise StopSimulation
-
- def test_equal(self):
- self.run_with(lambda tb, tbp: None)
- self.assertEqual(self.tb.source.sent, self.tb.sink.received)
-
-
-class SourceSinkDirectCase(SimCase, unittest.TestCase):
- class TestBench(SimBench):
- def __init__(self):
- self.source = SimSource()
- self.sink = SimSink()
- self.submodules += self.source, self.sink
- self.comb += self.sink.sink.connect(self.source.source)
-
- def do_simulation(self, selfp):
- if self.source.token_exchanger.done:
- raise StopSimulation
-
- def test_equal(self):
- self.run_with(lambda tb, tbp: None)
- self.assertEqual(self.tb.source.sent, self.tb.sink.received)