Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 3 commits
  • 20 files changed
  • 0 comments
  • 1 contributor
134  examples/dataflow/dma.py
... ...
@@ -1,5 +1,6 @@
1 1
 from random import Random
2 2
 
  3
+from migen.fhdl.module import Module
3 4
 from migen.flow.network import *
4 5
 from migen.flow.transactions import *
5 6
 from migen.actorlib import dma_wishbone, dma_asmi
@@ -26,12 +27,22 @@ def adrgen_gen():
26 27
 		print("Address:  " + str(i))
27 28
 		yield Token("address", {"a": i})
28 29
 
  30
+class SimAdrGen(SimActor):
  31
+	def __init__(self, nbits):
  32
+		self.address = Source([("a", nbits)])
  33
+		SimActor.__init__(self, adrgen_gen())
  34
+
29 35
 def dumper_gen():
30 36
 	while True:
31 37
 		t = Token("data", idle_wait=True)
32 38
 		yield t
33 39
 		print("Received: " + str(t.value["d"]))
34 40
 
  41
+class SimDumper(SimActor):
  42
+	def __init__(self):
  43
+		self.data = Sink([("d", 32)])
  44
+		SimActor.__init__(self, dumper_gen())		
  45
+
35 46
 def trgen_gen():
36 47
 	for i in range(10):
37 48
 		a = i
@@ -39,75 +50,78 @@ def trgen_gen():
39 50
 		print("Address: " + str(a) + " Data: " + str(d))
40 51
 		yield Token("address_data", {"a": a, "d": d})
41 52
 
42  
-def wishbone_sim(efragment, master, end_simulation):
43  
-	peripheral = wishbone.Target(MyModelWB())
44  
-	tap = wishbone.Tap(peripheral.bus)
45  
-	interconnect = wishbone.InterconnectPointToPoint(master.bus, peripheral.bus)
46  
-	def _end_simulation(s):
47  
-		s.interrupt = end_simulation(s)
48  
-	fragment = efragment \
49  
-		+ peripheral.get_fragment() \
50  
-		+ tap.get_fragment() \
51  
-		+ interconnect.get_fragment() \
52  
-		+ Fragment(sim=[_end_simulation])
53  
-	sim = Simulator(fragment)
54  
-	sim.run()
55  
-
56  
-def asmi_sim(efragment, hub, end_simulation):
57  
-	def _end_simulation(s):
58  
-		s.interrupt = end_simulation(s)
59  
-	peripheral = asmibus.Target(MyModelASMI(), hub)
60  
-	tap = asmibus.Tap(hub)
61  
-	def _end_simulation(s):
62  
-		s.interrupt = end_simulation(s)
63  
-	fragment = efragment \
64  
-		+ peripheral.get_fragment() \
65  
-		+ tap.get_fragment() \
66  
-		+ Fragment(sim=[_end_simulation])
67  
-	sim = Simulator(fragment)
68  
-	sim.run()
  53
+class SimTrGen(SimActor):
  54
+	def __init__(self):
  55
+		self.address_data = Source([("a", 30), ("d", 32)])
  56
+		SimActor.__init__(self, trgen_gen())
  57
+
  58
+class TBWishbone(Module):
  59
+	def __init__(self, master):
  60
+		self.submodules.peripheral = wishbone.Target(MyModelWB())
  61
+		self.submodules.tap = wishbone.Tap(self.peripheral.bus)
  62
+		self.submodules.interconnect = wishbone.InterconnectPointToPoint(master.bus,
  63
+		  self.peripheral.bus)
  64
+
  65
+class TBWishboneReader(TBWishbone):
  66
+	def __init__(self):
  67
+		self.adrgen = SimAdrGen(30)
  68
+		self.reader = dma_wishbone.Reader()
  69
+		self.dumper = SimDumper()
  70
+		g = DataFlowGraph()
  71
+		g.add_connection(self.adrgen, self.reader)
  72
+		g.add_connection(self.reader, self.dumper)
  73
+		self.submodules.comp = CompositeActor(g)
  74
+		TBWishbone.__init__(self, self.reader)
  75
+
  76
+	def do_simulation(self, s):
  77
+		s.interrupt = self.adrgen.token_exchanger.done and not s.rd(self.comp.busy)
  78
+
  79
+class TBWishboneWriter(TBWishbone):
  80
+	def __init__(self):
  81
+		self.trgen = SimTrGen()
  82
+		self.writer = dma_wishbone.Writer()
  83
+		g = DataFlowGraph()
  84
+		g.add_connection(self.trgen, self.writer)
  85
+		self.submodules.comp = CompositeActor(g)
  86
+		TBWishbone.__init__(self, self.writer)
  87
+
  88
+	def do_simulation(self, s):
  89
+		s.interrupt = self.trgen.token_exchanger.done and not s.rd(self.comp.busy)
  90
+
  91
+class TBAsmi(Module):
  92
+	def __init__(self, hub):
  93
+		self.submodules.peripheral = asmibus.Target(MyModelASMI(), hub)
  94
+		self.submodules.tap = asmibus.Tap(hub)
  95
+
  96
+class TBAsmiReader(TBAsmi):
  97
+	def __init__(self, nslots):
  98
+		self.submodules.hub = asmibus.Hub(32, 32)
  99
+		port = self.hub.get_port(nslots)
  100
+		self.hub.finalize()
  101
+		
  102
+		self.adrgen = SimAdrGen(32)
  103
+		self.reader = dma_asmi.Reader(port)
  104
+		self.dumper = SimDumper()
  105
+		g = DataFlowGraph()
  106
+		g.add_connection(self.adrgen, self.reader)
  107
+		g.add_connection(self.reader, self.dumper)
  108
+		self.submodules.comp = CompositeActor(g)
  109
+		TBAsmi.__init__(self, self.hub)
  110
+
  111
+	def do_simulation(self, s):
  112
+		s.interrupt = self.adrgen.token_exchanger.done and not s.rd(self.comp.busy)
69 113
 
70 114
 def test_wb_reader():
71 115
 	print("*** Testing Wishbone reader")
72  
-	adrgen = SimActor(adrgen_gen(), ("address", Source, [("a", 30)]))
73  
-	reader = dma_wishbone.Reader()
74  
-	dumper = SimActor(dumper_gen(), ("data", Sink, [("d", 32)]))
75  
-	g = DataFlowGraph()
76  
-	g.add_connection(adrgen, reader)
77  
-	g.add_connection(reader, dumper)
78  
-	comp = CompositeActor(g)
79  
-	
80  
-	wishbone_sim(comp.get_fragment(), reader,
81  
-		lambda s: adrgen.token_exchanger.done and not s.rd(comp.busy))
  116
+	Simulator(TBWishboneReader()).run()
82 117
 
83 118
 def test_wb_writer():
84 119
 	print("*** Testing Wishbone writer")
85  
-	trgen = SimActor(trgen_gen(), ("address_data", Source, [("a", 30), ("d", 32)]))
86  
-	writer = dma_wishbone.Writer()
87  
-	g = DataFlowGraph()
88  
-	g.add_connection(trgen, writer)
89  
-	comp = CompositeActor(g)
90  
-	
91  
-	wishbone_sim(comp.get_fragment(), writer,
92  
-		lambda s: trgen.token_exchanger.done and not s.rd(comp.busy))
  120
+	Simulator(TBWishboneWriter()).run()
93 121
 
94 122
 def test_asmi_reader(nslots):
95 123
 	print("*** Testing ASMI reader (nslots={})".format(nslots))
96  
-	
97  
-	hub = asmibus.Hub(32, 32)
98  
-	port = hub.get_port(nslots)
99  
-	hub.finalize()
100  
-	
101  
-	adrgen = SimActor(adrgen_gen(), ("address", Source, [("a", 32)]))
102  
-	reader = dma_asmi.Reader(port)
103  
-	dumper = SimActor(dumper_gen(), ("data", Sink, [("d", 32)]))
104  
-	g = DataFlowGraph()
105  
-	g.add_connection(adrgen, reader)
106  
-	g.add_connection(reader, dumper)
107  
-	comp = CompositeActor(g)
108  
-	
109  
-	asmi_sim(hub.get_fragment() + comp.get_fragment(), hub,
110  
-		lambda s: adrgen.token_exchanger.done and not s.rd(comp.busy))
  124
+	Simulator(TBAsmiReader(nslots)).run()
111 125
 
112 126
 test_wb_reader()
113 127
 test_wb_writer()
19  examples/dataflow/misc.py
@@ -8,7 +8,12 @@ def source_gen():
8 8
 	for i in range(10):
9 9
 		v = i + 5
10 10
 		print("==> " + str(v))
11  
-		yield Token("source", {"value": v})
  11
+		yield Token("source", {"maximum": v})
  12
+
  13
+class SimSource(SimActor):
  14
+	def __init__(self):
  15
+		self.source = Source([("maximum", 32)])
  16
+		SimActor.__init__(self, source_gen())
12 17
 
13 18
 def sink_gen():
14 19
 	while True:
@@ -16,16 +21,20 @@ def sink_gen():
16 21
 		yield t
17 22
 		print(t.value["value"])
18 23
 
  24
+class SimSink(SimActor):
  25
+	def __init__(self):
  26
+		self.sink = Sink([("value", 32)])
  27
+		SimActor.__init__(self, sink_gen())
  28
+
19 29
 def main():
20  
-	source = SimActor(source_gen(), ("source", Source, [("value", 32)]))
  30
+	source = SimSource()
21 31
 	loop = misc.IntSequence(32)
22  
-	sink = SimActor(sink_gen(), ("sink", Sink, [("value", 32)]))
  32
+	sink = SimSink()
23 33
 	g = DataFlowGraph()
24 34
 	g.add_connection(source, loop)
25 35
 	g.add_connection(loop, sink)
26 36
 	comp = CompositeActor(g)
27  
-	fragment = comp.get_fragment()
28  
-	sim = Simulator(fragment)
  37
+	sim = Simulator(comp)
29 38
 	sim.run(500)
30 39
 
31 40
 main()
67  examples/dataflow/structuring.py
@@ -11,48 +11,57 @@
11 11
 from migen.flow import perftools
12 12
 
13 13
 pack_factor = 5
  14
+base_layout = [("value", 32)]
  15
+packed_layout = structuring.pack_layout(base_layout, pack_factor)
  16
+rawbits_layout = [("value", 32*pack_factor)]
14 17
 
15 18
 def source_gen():
16 19
 	for i in count(0):
17 20
 		yield Token("source", {"value": i})
18 21
 
  22
+class SimSource(SimActor):
  23
+	def __init__(self):
  24
+		self.source = Source(base_layout)
  25
+		SimActor.__init__(self, source_gen())
  26
+
19 27
 def sink_gen():
20 28
 	while True:
21 29
 		t = Token("sink")
22 30
 		yield t
23 31
 		print(t.value["value"])
24 32
 
  33
+class SimSink(SimActor):
  34
+	def __init__(self):
  35
+		self.sink = Sink(base_layout)
  36
+		SimActor.__init__(self, sink_gen())
  37
+
  38
+class TB(Module):
  39
+	def __init__(self):
  40
+		source = SimSource()
  41
+		sink = SimSink()
  42
+		
  43
+		# A tortuous way of passing integer tokens.
  44
+		packer = structuring.Pack(base_layout, pack_factor)
  45
+		to_raw = structuring.Cast(packed_layout, rawbits_layout)
  46
+		from_raw = structuring.Cast(rawbits_layout, packed_layout)
  47
+		unpacker = structuring.Unpack(pack_factor, base_layout)
  48
+		
  49
+		self.g = DataFlowGraph()
  50
+		self.g.add_connection(source, packer)
  51
+		self.g.add_connection(packer, to_raw)
  52
+		self.g.add_connection(to_raw, from_raw)
  53
+		self.g.add_connection(from_raw, unpacker)
  54
+		self.g.add_connection(unpacker, sink)
  55
+		self.submodules.comp = CompositeActor(self.g)
  56
+		self.submodules.reporter = perftools.DFGReporter(self.g)
  57
+
25 58
 def main():
26  
-	base_layout = [("value", 32)]
27  
-	packed_layout = structuring.pack_layout(base_layout, pack_factor)
28  
-	rawbits_layout = [("value", 32*pack_factor)]
29  
-	
30  
-	source = SimActor(source_gen(), ("source", Source, base_layout))
31  
-	sink = SimActor(sink_gen(), ("sink", Sink, base_layout))
  59
+	tb = TB()
  60
+	sim = Simulator(tb).run(1000)
32 61
 	
33  
-	# A tortuous way of passing integer tokens.
34  
-	packer = structuring.Pack(base_layout, pack_factor)
35  
-	to_raw = structuring.Cast(packed_layout, rawbits_layout)
36  
-	from_raw = structuring.Cast(rawbits_layout, packed_layout)
37  
-	unpacker = structuring.Unpack(pack_factor, base_layout)
38  
-	
39  
-	g = DataFlowGraph()
40  
-	g.add_connection(source, packer)
41  
-	g.add_connection(packer, to_raw)
42  
-	g.add_connection(to_raw, from_raw)
43  
-	g.add_connection(from_raw, unpacker)
44  
-	g.add_connection(unpacker, sink)
45  
-	comp = CompositeActor(g)
46  
-	reporter = perftools.DFGReporter(g)
47  
-	
48  
-	fragment = comp.get_fragment() + reporter.get_fragment()
49  
-	sim = Simulator(fragment)
50  
-	sim.run(1000)
51  
-	
52  
-	g_layout = nx.spectral_layout(g)
53  
-	nx.draw(g, g_layout)
54  
-	nx.draw_networkx_edge_labels(g, g_layout, reporter.get_edge_labels())
  62
+	g_layout = nx.spectral_layout(tb.g)
  63
+	nx.draw(tb.g, g_layout)
  64
+	nx.draw_networkx_edge_labels(tb.g, g_layout, tb.reporter.get_edge_labels())
55 65
 	plt.show()
56 66
 
57  
-
58 67
 main()
8  examples/pytholite/basic.py
@@ -11,6 +11,11 @@ def number_gen():
11 11
 	for i in range(10):
12 12
 		yield Token("result", {"r": i})
13 13
 
  14
+class SimNumberGen(SimActor):
  15
+	def __init__(self):
  16
+		self.result = Source(layout)
  17
+		SimActor.__init__(self, number_gen())
  18
+
14 19
 def run_sim(ng):
15 20
 	g = DataFlowGraph()
16 21
 	d = Dumper(layout)
@@ -23,7 +28,7 @@ def run_sim(ng):
23 28
 
24 29
 def main():
25 30
 	print("Simulating native Python:")
26  
-	ng_native = SimActor(number_gen(), ("result", Source, layout))
  31
+	ng_native = SimNumberGen()
27 32
 	run_sim(ng_native)
28 33
 	
29 34
 	print("Simulating Pytholite:")
@@ -31,6 +36,7 @@ def main():
31 36
 	run_sim(ng_pytholite)
32 37
 	
33 38
 	print("Converting Pytholite to Verilog:")
  39
+	ng_pytholite = make_pytholite(number_gen, dataflow=[("result", Source, layout)])
34 40
 	print(verilog.convert(ng_pytholite))
35 41
 
36 42
 main()
3  examples/pytholite/uio.py
@@ -66,6 +66,9 @@ def main():
66 66
 	run_sim(ng_pytholite)
67 67
 	
68 68
 	print("Converting Pytholite to Verilog:")
  69
+	ng_pytholite = make_pytholite(gen,
  70
+		dataflow=dataflow,
  71
+		buses=buses)
69 72
 	print(verilog.convert(ng_pytholite.get_fragment()))
70 73
 
71 74
 main()
33  examples/sim/dataflow.py
@@ -10,22 +10,31 @@ def source_gen():
10 10
 		print("Sending:  " + str(i))
11 11
 		yield Token("source", {"value": i})
12 12
 
  13
+class SimSource(SimActor):
  14
+	def __init__(self):
  15
+		self.source = Source([("value", 32)])
  16
+		SimActor.__init__(self, source_gen())
  17
+
13 18
 def sink_gen():
14 19
 	while True:
15 20
 		t = Token("sink")
16 21
 		yield t
17 22
 		print("Received: " + str(t.value["value"]))
18 23
 
19  
-def main():
20  
-	source = SimActor(source_gen(), ("source", Source, [("value", 32)]))
21  
-	sink = SimActor(sink_gen(), ("sink", Sink, [("value", 32)]))
22  
-	g = DataFlowGraph()
23  
-	g.add_connection(source, sink)
24  
-	comp = CompositeActor(g)
25  
-	def end_simulation(s):
26  
-		s.interrupt = source.token_exchanger.done
27  
-	fragment = comp.get_fragment() + Fragment(sim=[end_simulation])
28  
-	sim = Simulator(fragment)
29  
-	sim.run()
  24
+class SimSink(SimActor):
  25
+	def __init__(self):
  26
+		self.sink = Sink([("value", 32)])
  27
+		SimActor.__init__(self, sink_gen())
  28
+
  29
+class TB(Module):
  30
+	def __init__(self):
  31
+		self.source = SimSource()
  32
+		self.sink = SimSink()
  33
+		g = DataFlowGraph()
  34
+		g.add_connection(self.source, self.sink)
  35
+		self.submodules.comp = CompositeActor(g)
  36
+
  37
+	def do_simulation(self, s):
  38
+		s.interrupt = self.source.token_exchanger.done
30 39
 
31  
-main()
  40
+Simulator(TB()).run()
116  migen/actorlib/dma_asmi.py
... ...
@@ -1,91 +1,83 @@
1 1
 from migen.fhdl.structure import *
  2
+from migen.fhdl.module import Module
2 3
 from migen.flow.actor import *
3 4
 from migen.genlib.buffers import ReorderBuffer
4 5
 
5  
-class SequentialReader(Actor):
  6
+class SequentialReader(Module):
6 7
 	def __init__(self, port):
7  
-		self.port = port
8  
-		assert(len(self.port.slots) == 1)
9  
-		Actor.__init__(self,
10  
-			("address", Sink, [("a", self.port.hub.aw)]),
11  
-			("data", Source, [("d", self.port.hub.dw)]))
  8
+		assert(len(port.slots) == 1)
  9
+		self.address = Sink([("a", port.hub.aw)])
  10
+		self.data = Source([("d", port.hub.dw)])
  11
+		self.busy = Signal()
12 12
 	
13  
-	def get_fragment(self):
  13
+		###
  14
+
14 15
 		sample = Signal()
15 16
 		data_reg_loaded = Signal()
16  
-		data_reg = Signal(self.port.hub.dw)
17  
-		
  17
+		data_reg = Signal(port.hub.dw)
18 18
 		accept_new = Signal()
19 19
 		
20  
-		# We check that len(self.port.slots) == 1
21  
-		# and therefore we can assume that self.port.ack
  20
+		# We check that len(port.slots) == 1
  21
+		# and therefore we can assume that port.ack
22 22
 		# goes low until the data phase.
23 23
 		
24  
-		comb = [
25  
-			self.busy.eq(~data_reg_loaded | ~self.port.ack),
26  
-			self.port.adr.eq(self.token("address").a),
27  
-			self.port.we.eq(0),
28  
-			accept_new.eq(~data_reg_loaded | self.endpoints["data"].ack),
29  
-			self.port.stb.eq(self.endpoints["address"].stb & accept_new),
30  
-			self.endpoints["address"].ack.eq(self.port.ack & accept_new),
31  
-			self.endpoints["data"].stb.eq(data_reg_loaded),
32  
-			self.token("data").d.eq(data_reg)
  24
+		self.comb += [
  25
+			self.busy.eq(~data_reg_loaded | ~port.ack),
  26
+			port.adr.eq(self.address.payload.a),
  27
+			port.we.eq(0),
  28
+			accept_new.eq(~data_reg_loaded | self.data.ack),
  29
+			port.stb.eq(self.address.stb & accept_new),
  30
+			self.address.ack.eq(port.ack & accept_new),
  31
+			self.data.stb.eq(data_reg_loaded),
  32
+			self.data.payload.d.eq(data_reg)
33 33
 		]
34  
-		sync = [
35  
-			If(self.endpoints["data"].ack,
36  
-				data_reg_loaded.eq(0)
37  
-			),
  34
+		self.sync += [
  35
+			If(self.data.ack, data_reg_loaded.eq(0)),
38 36
 			If(sample,
39 37
 				data_reg_loaded.eq(1),
40  
-				data_reg.eq(self.port.dat_r)
  38
+				data_reg.eq(port.dat_r)
41 39
 			),
42  
-			sample.eq(self.port.get_call_expression())
  40
+			sample.eq(port.get_call_expression())
43 41
 		]
44  
-		
45  
-		return Fragment(comb, sync)
46 42
 
47  
-class OOOReader(Actor):
  43
+class OOOReader(Module):
48 44
 	def __init__(self, port):
49  
-		self.port = port
50  
-		assert(len(self.port.slots) > 1)
51  
-		Actor.__init__(self,
52  
-			("address", Sink, [("a", self.port.hub.aw)]),
53  
-			("data", Source, [("d", self.port.hub.dw)]))
  45
+		assert(len(port.slots) > 1)
  46
+		self.address = Sink([("a", port.hub.aw)])
  47
+		self.data = Source([("d", port.hub.dw)])
  48
+		self.busy = Signal() # TODO: drive busy
54 49
 	
55  
-	def get_fragment(self):
56  
-		tag_width = len(self.port.tag_call)
57  
-		data_width = self.port.hub.dw
58  
-		depth = len(self.port.slots)
  50
+		###
  51
+
  52
+		tag_width = len(port.tag_call)
  53
+		data_width = port.hub.dw
  54
+		depth = len(port.slots)
59 55
 		rob = ReorderBuffer(tag_width, data_width, depth)
  56
+		self.submodules += rob
60 57
 		
61  
-		comb = [
62  
-			self.port.adr.eq(self.token("address").a),
63  
-			self.port.we.eq(0),
64  
-			self.port.stb.eq(self.endpoints["address"].stb & rob.can_issue),
65  
-			self.endpoints["address"].ack.eq(self.port.ack & rob.can_issue),
66  
-			rob.issue.eq(self.endpoints["address"].stb & self.port.ack),
67  
-			rob.tag_issue.eq(self.port.base + self.port.tag_issue),
  58
+		self.comb += [
  59
+			port.adr.eq(self.address.payload.a),
  60
+			port.we.eq(0),
  61
+			port.stb.eq(self.address.stb & rob.can_issue),
  62
+			self.address.ack.eq(port.ack & rob.can_issue),
  63
+			rob.issue.eq(self.address.stb & port.ack),
  64
+			rob.tag_issue.eq(port.base + port.tag_issue),
68 65
 			
69  
-			rob.data_call.eq(self.port.dat_r),
  66
+			rob.data_call.eq(port.dat_r),
70 67
 			
71  
-			self.endpoints["data"].stb.eq(rob.can_read),
72  
-			rob.read.eq(self.endpoints["data"].ack),
73  
-			self.token("data").d.eq(rob.data_read)
  68
+			self.data.stb.eq(rob.can_read),
  69
+			rob.read.eq(self.data.ack),
  70
+			self.data.payload.d.eq(rob.data_read)
74 71
 		]
75  
-		sync = [
  72
+		self.sync += [
76 73
 			# Data is announced one cycle in advance.
77 74
 			# Register the call to synchronize it with the data signal.
78  
-			rob.call.eq(self.port.call),
79  
-			rob.tag_call.eq(self.port.tag_call)
  75
+			rob.call.eq(port.call),
  76
+			rob.tag_call.eq(port.tag_call)
80 77
 		]
81  
-		
82  
-		return Fragment(comb, sync) + rob.get_fragment()
83 78
 
84  
-class Reader:
85  
-	def __init__(self, port):
86  
-		if len(port.slots) == 1:
87  
-			self.__class__ = SequentialReader
88  
-			SequentialReader.__init__(self, port)
89  
-		else:
90  
-			self.__class__ = OOOReader
91  
-			OOOReader.__init__(self, port)
  79
+def Reader(port):
  80
+	if len(port.slots) == 1:
  81
+		return SequentialReader(port)
  82
+	else:
  83
+		return OOOReader(port)
55  migen/actorlib/dma_wishbone.py
... ...
@@ -1,58 +1,55 @@
1 1
 from migen.fhdl.structure import *
  2
+from migen.fhdl.module import Module
2 3
 from migen.bus import wishbone
3 4
 from migen.flow.actor import *
4 5
 
5  
-class Reader(Actor):
  6
+class Reader(Module):
6 7
 	def __init__(self):
7 8
 		self.bus = wishbone.Interface()
8  
-		Actor.__init__(self,
9  
-			("address", Sink, [("a", 30)]),
10  
-			("data", Source, [("d", 32)]))
  9
+		self.address = Sink([("a", 30)])
  10
+		self.data = Source([("d", 32)])
  11
+		self.busy = Signal()
  12
+	
  13
+		###
11 14
 	
12  
-	def get_fragment(self):
13 15
 		bus_stb = Signal()
14  
-		
15 16
 		data_reg_loaded = Signal()
16 17
 		data_reg = Signal(32)
17 18
 		
18  
-		comb = [
  19
+		self.comb += [
19 20
 			self.busy.eq(data_reg_loaded),
20 21
 			self.bus.we.eq(0),
21  
-			bus_stb.eq(self.endpoints["address"].stb & (~data_reg_loaded | self.endpoints["data"].ack)),
  22
+			bus_stb.eq(self.address.stb & (~data_reg_loaded | self.data.ack)),
22 23
 			self.bus.cyc.eq(bus_stb),
23 24
 			self.bus.stb.eq(bus_stb),
24  
-			self.bus.adr.eq(self.token("address").a),
25  
-			self.endpoints["address"].ack.eq(self.bus.ack),
26  
-			self.endpoints["data"].stb.eq(data_reg_loaded),
27  
-			self.token("data").d.eq(data_reg)
  25
+			self.bus.adr.eq(self.address.payload.a),
  26
+			self.address.ack.eq(self.bus.ack),
  27
+			self.data.stb.eq(data_reg_loaded),
  28
+			self.data.payload.d.eq(data_reg)
28 29
 		]
29  
-		sync = [
30  
-			If(self.endpoints["data"].ack,
31  
-				data_reg_loaded.eq(0)
32  
-			),
  30
+		self.sync += [
  31
+			If(self.data.ack, data_reg_loaded.eq(0)),
33 32
 			If(self.bus.ack,
34 33
 				data_reg_loaded.eq(1),
35 34
 				data_reg.eq(self.bus.dat_r)
36 35
 			)
37 36
 		]
38 37
 
39  
-		return Fragment(comb, sync)
40  
-
41  
-class Writer(Actor):
  38
+class Writer(Module):
42 39
 	def __init__(self):
43 40
 		self.bus = wishbone.Interface()
44  
-		Actor.__init__(self,
45  
-			("address_data", Sink, [("a", 30), ("d", 32)]))
  41
+		self.address_data = Sink([("a", 30), ("d", 32)])
  42
+		self.busy = Signal()
  43
+
  44
+		###
46 45
 
47  
-	def get_fragment(self):
48  
-		comb = [
  46
+		self.comb += [
49 47
 			self.busy.eq(0),
50 48
 			self.bus.we.eq(1),
51  
-			self.bus.cyc.eq(self.endpoints["address_data"].stb),
52  
-			self.bus.stb.eq(self.endpoints["address_data"].stb),
53  
-			self.bus.adr.eq(self.token("address_data").a),
  49
+			self.bus.cyc.eq(self.address_data.stb),
  50
+			self.bus.stb.eq(self.address_data.stb),
  51
+			self.bus.adr.eq(self.address_data.payload.a),
54 52
 			self.bus.sel.eq(0xf),
55  
-			self.bus.dat_w.eq(self.token("address_data").d),
56  
-			self.endpoints["address_data"].ack.eq(self.bus.ack)
  53
+			self.bus.dat_w.eq(self.address_data.payload.d),
  54
+			self.address_data.ack.eq(self.bus.ack)
57 55
 		]
58  
-		return Fragment(comb)
61  migen/actorlib/misc.py
... ...
@@ -1,68 +1,65 @@
1 1
 from migen.fhdl.structure import *
  2
+from migen.fhdl.module import Module
2 3
 from migen.genlib.record import *
3 4
 from migen.genlib.fsm import *
4 5
 from migen.flow.actor import *
5 6
 
6 7
 # Generates integers from start to maximum-1
7  
-class IntSequence(Actor):
  8
+class IntSequence(Module):
8 9
 	def __init__(self, nbits, offsetbits=0, step=1):
9  
-		self.nbits = nbits
10  
-		self.offsetbits = offsetbits
11  
-		self.step = step
  10
+		parameters_layout = [("maximum", nbits)]
  11
+		if offsetbits:
  12
+			parameters_layout.append(("offset", offsetbits))
12 13
 		
13  
-		parameters_layout = [("maximum", self.nbits)]
14  
-		if self.offsetbits:
15  
-			parameters_layout.append(("offset", self.offsetbits))
16  
-		
17  
-		Actor.__init__(self,
18  
-			("parameters", Sink, parameters_layout),
19  
-			("source", Source, [("value", max(self.nbits, self.offsetbits))]))
  14
+		self.parameters = Sink(parameters_layout)
  15
+		self.source = Source([("value", max(nbits, offsetbits))])
  16
+		self.busy = Signal()
  17
+	
  18
+		###
20 19
 	
21  
-	def get_fragment(self):
22 20
 		load = Signal()
23 21
 		ce = Signal()
24 22
 		last = Signal()
25 23
 		
26  
-		maximum = Signal(self.nbits)
27  
-		if self.offsetbits:
28  
-			offset = Signal(self.offsetbits)
29  
-		counter = Signal(self.nbits)
  24
+		maximum = Signal(nbits)
  25
+		if offsetbits:
  26
+			offset = Signal(offsetbits)
  27
+		counter = Signal(nbits)
30 28
 		
31  
-		if self.step > 1:
32  
-			comb = [last.eq(counter + self.step >= maximum)]
  29
+		if step > 1:
  30
+			self.comb += last.eq(counter + step >= maximum)
33 31
 		else:
34  
-			comb = [last.eq(counter + 1 == maximum)]
35  
-		sync = [
  32
+			self.comb += last.eq(counter + 1 == maximum)
  33
+		self.sync += [
36 34
 			If(load,
37 35
 				counter.eq(0),
38  
-				maximum.eq(self.token("parameters").maximum),
39  
-				offset.eq(self.token("parameters").offset) if self.offsetbits else None
  36
+				maximum.eq(self.parameters.payload.maximum),
  37
+				offset.eq(self.parameters.payload.offset) if offsetbits else None
40 38
 			).Elif(ce,
41 39
 				If(last,
42 40
 					counter.eq(0)
43 41
 				).Else(
44  
-					counter.eq(counter + self.step)
  42
+					counter.eq(counter + step)
45 43
 				)
46 44
 			)
47 45
 		]
48  
-		if self.offsetbits:
49  
-			comb.append(self.token("source").value.eq(counter + offset))
  46
+		if offsetbits:
  47
+			self.comb += self.source.payload.value.eq(counter + offset)
50 48
 		else:
51  
-			comb.append(self.token("source").value.eq(counter))
52  
-		counter_fragment = Fragment(comb, sync)
  49
+			self.comb += self.source.payload.value.eq(counter)
53 50
 		
54 51
 		fsm = FSM("IDLE", "ACTIVE")
  52
+		self.submodules += fsm
55 53
 		fsm.act(fsm.IDLE,
56 54
 			load.eq(1),
57  
-			self.endpoints["parameters"].ack.eq(1),
58  
-			If(self.endpoints["parameters"].stb, fsm.next_state(fsm.ACTIVE))
  55
+			self.parameters.ack.eq(1),
  56
+			If(self.parameters.stb, fsm.next_state(fsm.ACTIVE))
59 57
 		)
60 58
 		fsm.act(fsm.ACTIVE,
61 59
 			self.busy.eq(1),
62  
-			self.endpoints["source"].stb.eq(1),
63  
-			If(self.endpoints["source"].ack,
  60
+			self.source.stb.eq(1),
  61
+			If(self.source.ack,
64 62
 				ce.eq(1),
65 63
 				If(last, fsm.next_state(fsm.IDLE))
66 64
 			)
67 65
 		)
68  
-		return counter_fragment + fsm.get_fragment()
48  migen/actorlib/sim.py
@@ -20,10 +20,10 @@ def __init__(self, generator, actor):
20 20
 	def _process_transactions(self, s):
21 21
 		completed = set()
22 22
 		for token in self.active:
23  
-			ep = self.actor.endpoints[token.endpoint]
  23
+			ep = getattr(self.actor, token.endpoint)
24 24
 			if isinstance(ep, Sink):
25 25
 				if s.rd(ep.ack) and s.rd(ep.stb):
26  
-					token.value = s.multiread(ep.token)
  26
+					token.value = s.multiread(ep.payload)
27 27
 					completed.add(token)
28 28
 					s.wr(ep.ack, 0)
29 29
 			elif isinstance(ep, Source):
@@ -38,11 +38,11 @@ def _process_transactions(self, s):
38 38
 
39 39
 	def _update_control_signals(self, s):
40 40
 		for token in self.active:
41  
-			ep = self.actor.endpoints[token.endpoint]
  41
+			ep = getattr(self.actor, token.endpoint)
42 42
 			if isinstance(ep, Sink):
43 43
 				s.wr(ep.ack, 1)
44 44
 			elif isinstance(ep, Source):
45  
-				s.multiwrite(ep.token, token.value)
  45
+				s.multiwrite(ep.payload, token.value)
46 46
 				s.wr(ep.stb, 1)
47 47
 			else:
48 48
 				raise TypeError
@@ -56,9 +56,7 @@ def _next_transactions(self):
56 56
 			transactions = None
57 57
 		if isinstance(transactions, Token):
58 58
 			self.active = {transactions}
59  
-		elif isinstance(transactions, tuple) \
60  
-			or isinstance(transactions, list) \
61  
-			or isinstance(transactions, set):
  59
+		elif isinstance(transactions, (tuple, list, set)):
62 60
 			self.active = set(transactions)
63 61
 		elif transactions is None:
64 62
 			self.active = set()
@@ -77,27 +75,25 @@ def do_simulation(self, s):
77 75
 
78 76
 	do_simulation.initialize = True
79 77
 
80  
-class SimActor(Actor):
81  
-	def __init__(self, generator, *endpoint_descriptions, **misc):
82  
-		Actor.__init__(self, *endpoint_descriptions, **misc)
83  
-		self.token_exchanger = TokenExchanger(generator, self)
  78
+class SimActor(Module):
  79
+	def __init__(self, generator):
  80
+		self.busy = Signal()
  81
+		self.submodules.token_exchanger = TokenExchanger(generator, self)
84 82
 	
85  
-	def update_busy(self, s):
  83
+	def do_simulation(self, s):
86 84
 		s.wr(self.busy, self.token_exchanger.busy)
87  
-	
88  
-	def get_fragment(self):
89  
-		return self.token_exchanger.get_fragment() + Fragment(sim=[self.update_busy])
  85
+
  86
+def _dumper_gen(prefix):
  87
+	while True:
  88
+		t = Token("result")
  89
+		yield t
  90
+		if len(t.value) > 1:
  91
+			s = str(t.value)
  92
+		else:
  93
+			s = str(list(t.value.values())[0])
  94
+		print(prefix + s)
90 95
 
91 96
 class Dumper(SimActor):
92 97
 	def __init__(self, layout, prefix=""):
93  
-		def dumper_gen():
94  
-			while True:
95  
-				t = Token("result")
96  
-				yield t
97  
-				if len(t.value) > 1:
98  
-					s = str(t.value)
99  
-				else:
100  
-					s = str(list(t.value.values())[0])
101  
-				print(prefix + s)
102  
-		SimActor.__init__(self, dumper_gen(),
103  
-			("result", Sink, layout))
  98
+		self.result = Sink(layout)
  99
+		SimActor.__init__(self, _dumper_gen(prefix))
44  migen/actorlib/spi.py
@@ -47,41 +47,35 @@ def _create_csrs_assign(layout, target, atomic, prefix=""):
47 47
 
48 48
 (MODE_EXTERNAL, MODE_SINGLE_SHOT, MODE_CONTINUOUS) = range(3)
49 49
 
50  
-class SingleGenerator(Actor):
  50
+class SingleGenerator(Module):
51 51
 	def __init__(self, layout, mode):
52  
-		self._mode = mode
53  
-		Actor.__init__(self, ("source", Source, _convert_layout(layout)))
54  
-		self._csrs, self._assigns = _create_csrs_assign(layout,
55  
-			self.token("source"), self._mode != MODE_SINGLE_SHOT)
  52
+		self.source = Source(_convert_layout(layout))
  53
+		self.busy = Signal()
  54
+		self._csrs, assigns = _create_csrs_assign(layout, self.source.payload,
  55
+		  mode != MODE_SINGLE_SHOT)
56 56
 		if mode == MODE_EXTERNAL:
57  
-			self.trigger = Signal()
  57
+			trigger = self.trigger = Signal()
58 58
 		elif mode == MODE_SINGLE_SHOT:
59 59
 			shoot = CSR()
60 60
 			self._csrs.insert(0, shoot)
61  
-			self.trigger = shoot.re
  61
+			trigger = shoot.re
62 62
 		elif mode == MODE_CONTINUOUS:
63 63
 			enable = CSRStorage()
64 64
 			self._csrs.insert(0, enable)
65  
-			self.trigger = enable.storage
  65
+			trigger = enable.storage
66 66
 		else:
67 67
 			raise ValueError
  68
+		self.comb += self.busy.eq(self.source.stb)
  69
+		stmts = [self.source.stb.eq(trigger)] + assigns
  70
+		self.sync += [If(self.source.ack | ~self.source.stb, *stmts)]
68 71
 	
69 72
 	def get_csrs(self):
70 73
 		return self._csrs
71  
-	
72  
-	def get_fragment(self):
73  
-		stb = self.endpoints["source"].stb
74  
-		ack = self.endpoints["source"].ack
75  
-		comb = [
76  
-			self.busy.eq(stb)
77  
-		]
78  
-		stmts = [stb.eq(self.trigger)] + self._assigns
79  
-		sync = [If(ack | ~stb, *stmts)]
80  
-		return Fragment(comb, sync)
81 74
 
82  
-class Collector(Actor, AutoCSR):
  75
+class Collector(Module, AutoCSR):
83 76
 	def __init__(self, layout, depth=1024):
84  
-		Actor.__init__(self, ("sink", Sink, layout))
  77
+		self.sink = Sink(layout)
  78
+		self.busy = Signal()
85 79
 		self._depth = depth
86 80
 		self._dw = sum(len(s) for s in self.token("sink").flatten())
87 81
 		
@@ -89,13 +83,17 @@ def __init__(self, layout, depth=1024):
89 83
 		self._r_wc = CSRStorage(bits_for(self._depth), write_from_dev=True, atomic_write=True)
90 84
 		self._r_ra = CSRStorage(bits_for(self._depth-1))
91 85
 		self._r_rd = CSRStatus(self._dw)
  86
+		
  87
+		###
92 88
 	
93  
-	def get_fragment(self):
94 89
 		mem = Memory(self._dw, self._depth)
  90
+		self.specials += mem
95 91
 		wp = mem.get_port(write_capable=True)
96 92
 		rp = mem.get_port()
97 93
 		
98  
-		comb = [
  94
+		self.comb += [
  95
+			self.busy.eq(0),
  96
+
99 97
 			If(self._r_wc.r != 0,
100 98
 				self.endpoints["sink"].ack.eq(1),
101 99
 				If(self.endpoints["sink"].stb,
@@ -113,5 +111,3 @@ def get_fragment(self):
113 111
 			rp.adr.eq(self._r_ra.storage),
114 112
 			self._r_rd.status.eq(rp.dat_r)
115 113
 		]
116  
-		
117  
-		return Fragment(comb, specials={mem})
92  migen/actorlib/structuring.py
... ...
@@ -1,4 +1,5 @@
1 1
 from migen.fhdl.structure import *
  2
+from migen.fhdl.module import Module
2 3
 from migen.flow.actor import *
3 4
 
4 5
 def _rawbits_layout(l):
@@ -9,45 +10,42 @@ def _rawbits_layout(l):
9 10
 
10 11
 class Cast(CombinatorialActor):
11 12
 	def __init__(self, layout_from, layout_to, reverse_from=False, reverse_to=False):
12  
-		self.reverse_from = reverse_from
13  
-		self.reverse_to = reverse_to
14  
-		CombinatorialActor.__init__(self,
15  
-			("sink", Sink, _rawbits_layout(layout_from)),
16  
-			("source", Source, _rawbits_layout(layout_to)))
  13
+		self.sink = Sink(_rawbits_layout(layout_from))
  14
+		self.source = Source(_rawbits_layout(layout_to))
  15
+		CombinatorialActor.__init__(self)
17 16
 	
18  
-	def get_process_fragment(self):
19  
-		sigs_from = self.token("sink").flatten()
20  
-		if self.reverse_from:
  17
+		###
  18
+
  19
+		sigs_from = self.sink.payload.flatten()
  20
+		if reverse_from:
21 21
 			sigs_from = list(reversed(sigs_from))
22  
-		sigs_to = self.token("source").flatten()
23  
-		if self.reverse_to:
  22
+		sigs_to = self.source.payload.flatten()
  23
+		if reverse_to:
24 24
 			sigs_to = list(reversed(sigs_to))
25 25
 		if sum(len(s) for s in sigs_from) != sum(len(s) for s in sigs_to):
26 26
 			raise TypeError
27  
-		return Fragment([
28  
-			Cat(*sigs_to).eq(Cat(*sigs_from))
29  
-		])
  27
+		self.comb += Cat(*sigs_to).eq(Cat(*sigs_from))
30 28
 
31 29
 def pack_layout(l, n):
32 30
 	return [("chunk"+str(i), l) for i in range(n)]
33 31
 
34  
-class Unpack(Actor):
  32
+class Unpack(Module):
35 33
 	def __init__(self, n, layout_to):
36  
-		self.n = n
37  
-		Actor.__init__(self,
38  
-			("sink", Sink, pack_layout(layout_to, n)),
39  
-			("source", Source, layout_to))
  34
+		self.sink = Sink(pack_layout(layout_to, n))
  35
+		self.source = Source(layout_to)
  36
+		self.busy = Signal()
40 37
 	
41  
-	def get_fragment(self):
42  
-		mux = Signal(max=self.n)
  38
+		###
  39
+
  40
+		mux = Signal(max=n)
43 41
 		last = Signal()
44  
-		comb = [
45  
-			last.eq(mux == (self.n-1)),
46  
-			self.endpoints["source"].stb.eq(self.endpoints["sink"].stb),
47  
-			self.endpoints["sink"].ack.eq(last & self.endpoints["source"].ack)
  42
+		self.comb += [
  43
+			last.eq(mux == (n-1)),
  44
+			self.source.stb.eq(self.sink.stb),
  45
+			self.sink.ack.eq(last & self.source.ack)
48 46
 		]
49  
-		sync = [
50  
-			If(self.endpoints["source"].stb & self.endpoints["source"].ack,
  47
+		self.sync += [
  48
+			If(self.source.stb & self.source.ack,
51 49
 				If(last,
52 50
 					mux.eq(0)
53 51
 				).Else(
@@ -56,39 +54,36 @@ def get_fragment(self):
56 54
 			)
57 55
 		]
58 56
 		cases = {}
59  
-		for i in range(self.n):
60  
-			cases[i] = [self.token("source").raw_bits().eq(getattr(self.token("sink"), "chunk"+str(i)).raw_bits())]
61  
-		comb.append(Case(mux, cases).makedefault())
62  
-		return Fragment(comb, sync)
  57
+		for i in range(n):
  58
+			cases[i] = [self.source.payload.raw_bits().eq(getattr(self.sink.payload, "chunk"+str(i)).raw_bits())]
  59
+		self.comb += Case(mux, cases).makedefault()
63 60
 
64  
-class Pack(Actor):
  61
+class Pack(Module):
65 62
 	def __init__(self, layout_from, n):
66  
-		self.n = n
67  
-		Actor.__init__(self,
68  
-			("sink", Sink, layout_from),
69  
-			("source", Source, pack_layout(layout_from, n)))
  63
+		self.sink = Sink(layout_from)
  64
+		self.source = Source(pack_layout(layout_from, n))
  65
+		self.busy = Signal()
70 66
 	
71  
-	def get_fragment(self):
72  
-		demux = Signal(max=self.n)
  67
+		###
  68
+
  69
+		demux = Signal(max=n)
73 70
 		
74 71
 		load_part = Signal()
75 72
 		strobe_all = Signal()
76 73
 		cases = {}
77  
-		for i in range(self.n):
78  
-			cases[i] = [getattr(self.token("source"), "chunk"+str(i)).raw_bits().eq(self.token("sink").raw_bits())]
79  
-		comb = [
  74
+		for i in range(n):
  75
+			cases[i] = [getattr(self.source.payload, "chunk"+str(i)).raw_bits().eq(self.sink.payload.raw_bits())]
  76
+		self.comb += [
80 77
 			self.busy.eq(strobe_all),
81  
-			self.endpoints["sink"].ack.eq(~strobe_all | self.endpoints["source"].ack),
82  
-			self.endpoints["source"].stb.eq(strobe_all),
83  
-			load_part.eq(self.endpoints["sink"].stb & self.endpoints["sink"].ack)
  78
+			self.sink.ack.eq(~strobe_all | self.source.ack),
  79
+			self.source.stb.eq(strobe_all),
  80
+			load_part.eq(self.sink.stb & self.sink.ack)
84 81
 		]
85  
-		sync = [
86  
-			If(self.endpoints["source"].ack,
87  
-				strobe_all.eq(0)
88  
-			),
  82
+		self.sync += [
  83
+			If(self.source.ack, strobe_all.eq(0)),
89 84
 			If(load_part,
90 85
 				Case(demux, cases),
91  
-				If(demux == (self.n - 1),
  86
+				If(demux == (n - 1),
92 87
 					demux.eq(0),
93 88
 					strobe_all.eq(1)
94 89
 				).Else(
@@ -96,4 +91,3 @@ def get_fragment(self):
96 91
 				)
97 92
 			)
98 93
 		]
99  
-		return Fragment(comb, sync)
208  migen/flow/actor.py
... ...
@@ -1,173 +1,105 @@
1 1
 from migen.fhdl.structure import *
  2
+from migen.fhdl.module import Module
2 3
 from migen.genlib.misc import optree
3 4
 from migen.genlib.record import *
4 5
 
5  
-class Endpoint:
6  
-	def __init__(self, token):
7  
-		self.token = token
8  
-		if isinstance(self, Sink):
9  
-			self.stb = Signal(name="stb_i")
10  
-			self.ack = Signal(name="ack_o")
  6
+def _make_m2s(layout):
  7
+	r = []
  8
+	for f in layout:
  9
+		if isinstance(f[1], (int, tuple)):
  10
+			r.append((f[0], f[1], DIR_M_TO_S))
11 11
 		else:
12  
-			self.stb = Signal(name="stb_o")
13  
-			self.ack = Signal(name="ack_i")
14  
-	
15  
-	def token_signal(self):
16  
-		sigs = self.token.flatten()
17  
-		assert(len(sigs) == 1)
18  
-		return sigs[0]
19  
-	
20  
-	def __hash__(self):
21  
-		return id(self)
22  
-		
23  
-	def __repr__(self):
24  
-		return "<Endpoint " + str(self.token) + ">"
25  
-
26  
-
27  
-class Sink(Endpoint):
28  
-	def __repr__(self):
29  
-		return "<Sink " + str(self.token) + ">"
30  
-
31  
-class Source(Endpoint):
32  
-	def __repr__(self):
33  
-		return "<Source " + str(self.token) + ">"
34  
-
35  
-class Actor(HUID):
36  
-	def __init__(self, *endpoint_descriptions, endpoints=None):
37  
-		HUID.__init__(self)
38  
-		if endpoints is None:
39  
-			self.endpoints = {}
40  
-			for desc in endpoint_descriptions:
41  
-				# desc: (name, Sink/Source, token layout or existing record)
42  
-				if isinstance(desc[2], Record):
43  
-					token = desc[2]
44  
-				else:
45  
-					token = Record(desc[2])
46  
-				ep = desc[1](token)
47  
-				self.endpoints[desc[0]] = ep
48  
-		else:
49  
-			self.endpoints = endpoints
50  
-		self.name = None
  12
+			r.append((f[0], _make_m2s(f[1])))
  13
+	return r
  14
+
  15
+class _Endpoint(Record):
  16
+	def __init__(self, layout):
  17
+		full_layout = [
  18
+			("payload", _make_m2s(layout)),
  19
+			("stb", 1, DIR_M_TO_S),
  20
+			("ack", 1, DIR_S_TO_M)
  21
+		]
  22
+		Record.__init__(self, full_layout)
  23
+
  24
+class Source(_Endpoint):
  25
+	def connect(self, sink, **kwargs):
  26
+		return Record.connect(self, sink, **kwargs)
  27
+
  28
+class Sink(_Endpoint):
  29
+	def connect(self, source, **kwargs):
  30
+		return source.connect(self, **kwargs)
  31
+
  32
+def get_endpoints(obj, filt=_Endpoint):
  33
+	if hasattr(obj, "get_endpoints") and callable(obj.get_endpoints):
  34
+		return obj.get_endpoints(filt)
  35
+	r = dict()
  36
+	for k, v in obj.__dict__.items():
  37
+		if isinstance(v, filt):
  38
+			r[k] = v
  39
+	return r
  40
+
  41
+def get_single_ep(obj, filt):
  42
+	eps = get_endpoints(obj, filt)
  43
+	if len(eps) != 1:
  44
+		raise ValueError("More than one endpoint")
  45
+	return list(eps.items())[0]
  46
+
  47
+class BinaryActor(Module):
  48
+	def __init__(self, *args, **kwargs):
51 49
 		self.busy = Signal()
  50
+		sink = get_single_ep(self, Sink)[1]
  51
+		source = get_single_ep(self, Source)[1]
  52
+		self.build_binary_control(sink.stb, sink.ack, source.stb, source.ack, *args, **kwargs)
52 53
 
53  
-	def token(self, ep):
54  
-		return self.endpoints[ep].token
55  
-	
56  
-	def filter_endpoints(self, cl):
57  
-		return sorted(k for k, v in self.endpoints.items() if isinstance(v, cl))
58  
-
59  
-	def sinks(self):
60  
-		return self.filter_endpoints(Sink)
61  
-
62  
-	def sources(self):
63  
-		return self.filter_endpoints(Source)
64  
-		
65  
-	def single_sink(self):
66  
-		eps = self.sinks()
67  
-		assert(len(eps) == 1)
68  
-		return eps[0]
69  
-	
70  
-	def single_source(self):
71  
-		eps = self.sources()
72  
-		assert(len(eps) == 1)
73  
-		return eps[0]
74  
-
75  
-	def get_control_fragment(self):
76  
-		raise NotImplementedError("Actor classes must overload get_control_fragment or get_fragment")
77  
-
78  
-	def get_process_fragment(self):
79  
-		raise NotImplementedError("Actor classes must overload get_process_fragment or get_fragment")
80  
-	
81  
-	def get_fragment(self):
82  
-		return self.get_control_fragment() + self.get_process_fragment()
83  
-	
84  
-	def __repr__(self):
85  
-		r = "<" + self.__class__.__name__
86  
-		if self.name is not None:
87  
-			r += ": " + self.name
88  
-		r += ">"
89  
-		return r
90  
-
91  
-class BinaryActor(Actor):
92  
-	def get_binary_control_fragment(self, stb_i, ack_o, stb_o, ack_i):
93  
-		raise NotImplementedError("Binary actor classes must overload get_binary_control_fragment")
94  
-
95  
-	def get_control_fragment(self):
96  
-		def get_single_ep(l):
97  
-			if len(l) != 1:
98  
-				raise ValueError("Binary actors have exactly one sink and one source. Consider using plumbing actors.")
99  
-			return self.endpoints[l[0]]
100  
-		sink = get_single_ep(self.sinks())
101  
-		source = get_single_ep(self.sources())
102  
-		return self.get_binary_control_fragment(sink.stb, sink.ack, source.stb, source.ack)
  54
+	def build_binary_control(self, stb_i, ack_o, stb_o, ack_i):
  55
+		raise NotImplementedError("Binary actor classes must overload build_binary_control_fragment")
103 56
 
104 57
 class CombinatorialActor(BinaryActor):
105  
-	def get_binary_control_fragment(self, stb_i, ack_o, stb_o, ack_i):
106  
-		return Fragment([stb_o.eq(stb_i), ack_o.eq(ack_i), self.busy.eq(0)])
  58
+	def build_binary_control(self, stb_i, ack_o, stb_o, ack_i):
  59
+		self.comb += [stb_o.eq(stb_i), ack_o.eq(ack_i), self.busy.eq(0)]
107 60
 
108 61
 class SequentialActor(BinaryActor):
109  
-	def __init__(self, delay, *endpoint_descriptions, **misc):
110  
-		self.delay = delay
  62
+	def __init__(self, delay):
111 63
 		self.trigger = Signal()
112  
-		BinaryActor.__init__(self, *endpoint_descriptions, **misc)
  64
+		BinaryActor.__init__(self, delay)
113 65
 
114  
-	def get_binary_control_fragment(self, stb_i, ack_o, stb_o, ack_i):
  66
+	def build_binary_control(self, stb_i, ack_o, stb_o, ack_i, delay):
115 67
 		ready = Signal()
116  
-		timer = Signal(max=self.delay+1)
117  
-		comb = [ready.eq(timer == 0)]
118  
-		sync = [
119  
-			If(self.trigger,
120  
-				timer.eq(self.delay)
  68
+		timer = Signal(max=delay+1)
  69
+		self.comb += ready.eq(timer == 0)
  70
+		self.sync += If(self.trigger,
  71
+				timer.eq(delay)
121 72
 			).Elif(~ready,
122 73
 				timer.eq(timer - 1)
123 74
 			)
124  
-		]
125 75
 		
126 76
 		mask = Signal()
127  
-		comb += [
  77
+		self.comb += [
128 78
 			stb_o.eq(ready & mask),
129 79
 			self.trigger.eq(stb_i & (ack_i | ~mask) & ready),
130 80
 			ack_o.eq(self.trigger),
131  
-			busy.eq(~ready)
  81
+			self.busy.eq(~ready)
132 82
 		]
133  
-		sync += [
  83
+		self.sync += [
134 84
 			If(self.trigger, mask.eq(1)),
135 85
 			If(stb_o & ack_i, mask.eq(0))
136 86
 		]
137 87
 
138  
-		return Fragment(comb, sync)
139  
-
140 88
 class PipelinedActor(BinaryActor):
141  
-	def __init__(self, latency, *endpoint_descriptions, **misc):
142  
-		self.latency = latency
  89
+	def __init__(self, latency):
143 90
 		self.pipe_ce = Signal()
144  
-		BinaryActor.__init__(self, *endpoint_descriptions, **misc)
  91
+		BinaryActor.__init__(self, latency)
145 92
 
146  
-	def get_binary_control_fragment(self, stb_i, ack_o, stb_o, ack_i):
147  
-		valid = Signal(self.latency)
148  
-		if self.latency > 1:
149  
-			sync = [If(self.pipe_ce, valid.eq(Cat(stb_i, valid[:self.latency-1])))]
  93
+	def build_binary_control(self, stb_i, ack_o, stb_o, ack_i, latency):
  94
+		valid = Signal(latency)
  95
+		if latency > 1:
  96
+			self.sync += If(self.pipe_ce, valid.eq(Cat(stb_i, valid[:latency-1])))
150 97
 		else:
151  
-			sync = [If(self.pipe_ce, valid.eq(stb_i))]
152  
-		last_valid = valid[self.latency-1]
153  
-		
154  
-		comb = [
  98
+			self.sync += If(self.pipe_ce, valid.eq(stb_i))
  99
+		last_valid = valid[latency-1]
  100
+		self.comb += [
155 101
 			self.pipe_ce.eq(ack_i | ~last_valid),
156 102
 			ack_o.eq(self.pipe_ce),
157 103
 			stb_o.eq(last_valid),
158  
-			self.busy.eq(optree("|", [valid[i] for i in range(self.latency)]))
  104
+			self.busy.eq(optree("|", [valid[i] for i in range(latency)]))
159 105
 		]
160  
-		
161  
-		return Fragment(comb, sync)
162  
-		
163  
-def get_conn_fragment(source, sink):
164  
-	assert isinstance(source, Source)
165  
-	assert isinstance(sink, Sink)
166  
-	sigs_source = source.token.flatten()
167  
-	sigs_sink = sink.token.flatten()
168  
-	comb = [
169  
-		source.ack.eq(sink.ack),
170  
-		sink.stb.eq(source.stb),
171  
-		Cat(*sigs_sink).eq(Cat(*sigs_source))
172  
-	]
173  
-	return Fragment(comb)
2  migen/flow/hooks.py
@@ -30,7 +30,7 @@ class DFGHook(Module):
30 30
 	def __init__(self, dfg, create):
31 31
 		assert(not dfg.is_abstract())
32 32
 		self.nodepair_to_ep = defaultdict(dict)
33  
-		for hookn, (u, v, data) in dfg.edges_iter(data=True):
  33
+		for hookn, (u, v, data) in enumerate(dfg.edges_iter(data=True)):
34 34
 			ep_to_hook = self.nodepair_to_ep[(u, v)]
35 35
 			ep = data["source"]
36 36
 			h = create(u, ep, v)
52  migen/flow/network.py
@@ -4,15 +4,13 @@
4 4
 from migen.genlib.misc import optree
5 5
 from migen.flow.actor import *
6 6
 from migen.flow import plumbing
7  
-from migen.flow.isd import DFGReporter
8 7
 
9 8
 # Abstract actors mean that the actor class should be instantiated with the parameters 
10 9
 # from the dictionary. They are needed to enable actor duplication or sharing during
11 10
 # elaboration, and automatic parametrization of plumbing actors.
12 11
 
13  
-class AbstractActor(HUID):
  12
+class AbstractActor:
14 13
 	def __init__(self, actor_class, parameters=dict(), name=None):
15  
-		HUID.__init__(self)
16 14
 		self.actor_class = actor_class
17 15
 		self.parameters = parameters
18 16
 		self.name = name
@@ -27,6 +25,7 @@ def __repr__(self):
27 25
 		r += ">"
28 26
 		return r
29 27
 
  28
+# TODO: rewrite this without networkx and without non-determinism
30 29
 class DataFlowGraph(MultiDiGraph):
31 30
 	def __init__(self):
32 31
 		MultiDiGraph.__init__(self)
@@ -35,8 +34,6 @@ def __init__(self):
35 34
 	def add_connection(self, source_node, sink_node,
36 35
 	  source_ep=None, sink_ep=None,		# default: assume nodes have 1 source/sink and use that one
37 36
 	  source_subr=None, sink_subr=None):	# default: use whole record
38  
-		assert(isinstance(source_node, (Actor, AbstractActor)))
39  
-		assert(isinstance(sink_node, (Actor, AbstractActor)))
40 37
 		self.add_edge(source_node, sink_node,
41 38
 			source=source_ep, sink=sink_ep,
42 39
 			source_subr=source_subr, sink_subr=sink_subr)
@@ -158,7 +155,7 @@ def _infer_plumbing_layout(self):
158 155
 						continue
159 156
 					other_ep = data["source"]
160 157
 					if other_ep is None:
161  
-						other_ep = other.single_source()
  158
+						other_ep = get_single_ep(other, Source)[1]
162 159
 				elif a.actor_class in plumbing.layout_source:
163 160
 					edges = self.out_edges(a, data=True)
164 161
 					assert(len(edges) == 1)
@@ -167,10 +164,10 @@ def _infer_plumbing_layout(self):
167 164
 						continue
168 165
 					other_ep = data["sink"]
169 166
 					if other_ep is None:
170  
-						other_ep = other.single_sink()
  167
+						other_ep = get_single_ep(other, Sink)[1]
171 168
 				else:
172 169
 					raise AssertionError
173  
-				layout = other.token(other_ep).layout
  170
+				layout = other_ep.payload.layout
174 171
 				a.parameters["layout"] = layout
175 172
 				self.instantiate(a)
176 173
 	
@@ -184,9 +181,9 @@ def _instantiate_actors(self):
184 181
 		# 3. resolve default eps
185 182
 		for u, v, d in self.edges_iter(data=True):
186 183
 			if d["source"] is None:
187  
-				d["source"] = u.single_source()
  184
+				d["source"] = get_single_ep(u, Source)[0]
188 185
 			if d["sink"] is None:
189  
-				d["sink"] = v.single_sink()
  186
+				d["sink"] = get_single_ep(v, Sink)[0]
190 187
 	
191 188
 	# Elaboration turns an abstract DFG into a physical one.
192 189
 	#   Pass 1: eliminate subrecords and divergences
@@ -203,29 +200,14 @@ def elaborate(self, optimizer=None):
203 200
 			optimizer(self)
204 201
 		self._instantiate_actors()
205 202
 
206  
-class CompositeActor(Actor):
207  
-	def __init__(self, dfg, debugger=False, debugger_nbits=48):
  203
+class CompositeActor(Module):
  204
+	def __init__(self, dfg):
208 205
 		dfg.elaborate()
209  
-		self.dfg = dfg
210  
-		if debugger:
211  
-			self.debugger = DFGReporter(self.dfg, debugger_nbits)
212  
-		Actor.__init__(self)
213  
-	
214  
-	def get_csrs(self):
215  
-		if hasattr(self, "debugger"):
216  
-			return self.debugger.get_csrs()
217  
-		else:
218  
-			return []
219  
-	
220  
-	def get_fragment(self):
221  
-		comb = [self.busy.eq(optree("|", [node.busy for node in self.dfg]))]
222  
-		fragment = Fragment(comb)
223  
-		for node in self.dfg:
224  
-			fragment += node.get_fragment()
225  
-		for u, v, d in self.dfg.edges_iter(data=True):
226  
-			ep_src = u.endpoints[d["source"]]
227  
-			ep_dst = v.endpoints[d["sink"]]
228  
-			fragment += get_conn_fragment(ep_src, ep_dst)
229  
-		if hasattr(self, "debugger"):
230  
-			fragment += self.debugger.get_fragment()
231  
-		return fragment
  206
+		self.busy = Signal()
  207
+		self.comb += [self.busy.eq(optree("|", [node.busy for node in dfg]))]
  208
+		for node in dfg:
  209
+			self.submodules += node
  210
+		for u, v, d in dfg.edges_iter(data=True):
  211
+			ep_src = getattr(u, d["source"])
  212
+			ep_dst = getattr(v, d["sink"])
  213
+			self.comb += ep_src.connect(ep_dst, match_by_position=True)
2  migen/flow/perftools.py
@@ -39,7 +39,7 @@ def on_inactive(self):
39 39
 
40 40
 class DFGReporter(DFGHook):
41 41
 	def __init__(self, dfg):
42  
-		DFGHook.__init__(self, dfg, lambda u, ep, v: EndpointReporter(u.endpoints[ep]))
  42
+		DFGHook.__init__(self, dfg, lambda u, ep, v: EndpointReporter(getattr(u, ep)))
43 43
 
44 44
 	def get_edge_labels(self):
45 45
 		d = dict()
64  migen/flow/plumbing.py
@@ -6,54 +6,52 @@
6 6
 
7 7
 class Buffer(PipelinedActor):
8 8
 	def __init__(self, layout):
9  
-		PipelinedActor.__init__(self, 1,
10  
-			("d", Sink, layout), ("q", Source, layout))
11  
-	
12  
-	def get_process_fragment(self):
13  
-		sigs_d = self.token("d").flatten()
14  
-		sigs_q = self.token("q").flatten()
15  
-		sync = [If(self.pipe_ce, Cat(*sigs_q).eq(Cat(*sigs_d)))]
16  
-		return Fragment(sync=sync)
  9
+		self.d = Sink(layout)
  10
+		self.q = Source(layout)
  11
+		PipelinedActor.__init__(self, 1)
  12
+		self.sync += If(self.pipe_ce, self.q.payload.eq(self.d.payload))
17 13
 
18  
-class Combinator(Module, Actor):
  14
+class Combinator(Module):
19 15
 	def __init__(self, layout, subrecords):
20  
-		eps = [("source", Source, layout)]
21  
-		eps += [("sink"+str(n), Sink, layout_partial(layout, r))
22  
-			for n, r in enumerate(subrecords)]
23  
-		Actor.__init__(self, *eps)
  16
+		self.source = Source(layout)
  17
+		sinks = []
  18
+		for n, r in enumerate(subrecords):
  19
+			s = Sink(layout_partial(layout, *r))
  20
+			setattr(self, "sink"+str(n), s)
  21
+			sinks.append(s)
  22
+		self.busy = Signal()
24 23
 
25 24
 		###
26 25
 	
27  
-		source = self.endpoints["source"]
28  
-		sinks = [self.endpoints["sink"+str(n)]
29  
-			for n in range(len(self.endpoints)-1)]
30  
-		self.comb += [source.stb.eq(optree("&", [sink.stb for sink in sinks]))]
31  
-		self.comb += [sink.ack.eq(source.ack & source.stb) for sink in sinks]
32  
-		self.comb += [source.token.eq(sink.token) for sink in sinks]
  26
+		self.comb += [
  27
+			self.busy.eq(0),
  28
+			self.source.stb.eq(optree("&", [sink.stb for sink in sinks]))
  29
+		]
  30
+		self.comb += [sink.ack.eq(self.source.ack & self.source.stb) for sink in sinks]
  31
+		self.comb += [self.source.payload.eq(sink.payload) for sink in sinks]
33 32
 
34  
-class Splitter(Module, Actor):
  33
+class Splitter(Module):
35 34
 	def __init__(self, layout, subrecords):
36  
-		eps = [("sink", Sink, layout)]
37  
-		eps += [("source"+str(n), Source, layout_partial(layout, *r))
38  
-			for n, r in enumerate(subrecords)]
39  
-		Actor.__init__(self, *eps)
  35
+		self.sink = Sink(layout)
  36
+		sources = []
  37
+		for n, r in enumerate(subrecords):
  38
+			s = Source(layout_partial(layout, *r))
  39
+			setattr(self, "source"+str(n), s)
  40
+			sources.append(s)
  41
+		self.busy = Signal()
40 42
 		
41 43
 		###
42 44
 
43  
-		sources = [self.endpoints[e] for e in self.sources()]
44  
-		sink = self.endpoints[self.sinks()[0]]
45  
-
46  
-		self.comb += [source.token.eq(sink.token) for source in sources]
47  
-		
  45
+		self.comb += [source.payload.eq(self.sink.payload) for source in sources]
48 46
 		already_acked = Signal(len(sources))
49  
-		self.sync += If(sink.stb,
  47
+		self.sync += If(self.sink.stb,
50 48
 				already_acked.eq(already_acked | Cat(*[s.ack for s in sources])),
51  
-				If(sink.ack, already_acked.eq(0))
  49
+				If(self.sink.ack, already_acked.eq(0))
52 50
 			)
53  
-		self.comb += sink.ack.eq(optree("&",
  51
+		self.comb += self.sink.ack.eq(optree("&",
54 52
 				[s.ack | already_acked[n] for n, s in enumerate(sources)]))
55 53
 		for n, s in enumerate(sources):
56  
-			self.comb += s.stb.eq(sink.stb & ~already_acked[n])
  54
+			self.comb += s.stb.eq(self.sink.stb & ~already_acked[n])
57 55
 
58 56
 # Actors whose layout should be inferred from what their single sink is connected to.
59 57
 layout_sink = {Buffer, Splitter}
18  migen/genlib/record.py
@@ -34,7 +34,7 @@ def layout_get(layout, name):
34 34
 	for f in layout:
35 35
 		if f[0] == name:
36 36
 			return f
37  
-	raise KeyError
  37
+	raise KeyError(name)
38 38
 
39 39
 def layout_partial(layout, *elements):
40 40
 	r = []
@@ -96,7 +96,11 @@ def flatten(self):
96 96
 	def raw_bits(self):
97 97
 		return Cat(*self.flatten())
98 98
 	
99  
-	def connect(self, *slaves):
  99
+	def connect(self, *slaves, match_by_position=False):
  100
+		if match_by_position:
  101
+			iters = [iter(slave.layout) for slave in slaves]
  102
+		else:
  103
+			iters = [iter(self.layout) for slave in slaves]
100 104
 		r = []
101 105
 		for f in self.layout:
102 106
 			field = f[0]
@@ -104,14 +108,16 @@ def connect(self, *slaves):
104 108
 			if isinstance(self_e, Signal):
105 109
 				direction = f[2]
106 110
 				if direction == DIR_M_TO_S:
107  
-					r += [getattr(slave, field).eq(self_e) for slave in slaves]
  111
+					r += [getattr(slave, next(it)[0]).eq(self_e) for slave, it in zip(slaves, iters)]
108 112
 				elif direction == DIR_S_TO_M:
109  
-					r.append(self_e.eq(optree("|", [getattr(slave, field) for slave in slaves])))
  113
+					r.append(self_e.eq(optree("|", [getattr(slave, next(it)[0])
  114
+					  for slave, it in zip(slaves, iters)])))
110 115
 				else:
111 116
 					raise TypeError
112 117
 			else:
113  
-				for slave in slaves:
114  
-					r += self_e.connect(getattr(slave, field))
  118
+				for slave, it in zip(slaves, iters):
  119
+					r += self_e.connect(getattr(slave, next(it)[0]),
  120
+					  match_by_position=match_by_position)
115 121
 		return r
116 122
 
117 123
 	def __len__(self):
8  migen/pytholite/io.py
@@ -17,7 +17,7 @@ def __init__(self, dataflow=None, buses={}):
17 17
 		if dataflow is not None:
18 18
 			self.busy.reset = 1
19 19
 		self.memory_ports = dict((mem, mem.get_port(write_capable=True, we_granularity=8))
20  
-			for mem in self._memories)
  20
+			for mem in self.buses.values() if isinstance(mem, Memory))
21 21
 	
22 22
 	def get_fragment(self):
23 23
 		return UnifiedIOObject.get_fragment(self) + self.fragment
@@ -39,7 +39,7 @@ def visit_expr_subscript(self, node):
39 39
 		if not isinstance(node.slice, ast.Index):
40 40
 			raise NotImplementedError
41 41
 		field = ast.literal_eval(node.slice.value)
42  
-		signal = getattr(self.ep.token, field)
  42
+		signal = getattr(self.ep.payload, field)
43 43
 		
44 44
 		return signal
45 45
 
@@ -47,7 +47,7 @@ def _gen_df_io(compiler, modelname, to_model, from_model):
47 47
 	epname = ast.literal_eval(to_model["endpoint"])
48 48
 	values = to_model["value"]
49 49
 	idle_wait = ast.literal_eval(to_model["idle_wait"])
50  
-	ep = compiler.ioo.endpoints[epname]
  50
+	ep = getattr(compiler.ioo, epname)
51 51
 	if idle_wait:
52 52
 		state = [compiler.ioo.busy.eq(0)]
53 53