actorlib: WB reader simulation OK
This commit is contained in:
parent
11674242c4
commit
356051e8a8
|
@ -1,27 +1,97 @@
|
||||||
import networkx as nx
|
import networkx as nx
|
||||||
|
from random import Random
|
||||||
|
|
||||||
from migen.fhdl import verilog
|
from migen.fhdl import verilog
|
||||||
from migen.flow.ala import *
|
from migen.flow.ala import *
|
||||||
from migen.flow.network import *
|
from migen.flow.network import *
|
||||||
from migen.actorlib import dma_wishbone, control
|
from migen.actorlib import dma_wishbone
|
||||||
|
from migen.actorlib.sim import *
|
||||||
|
from migen.bus import wishbone
|
||||||
|
from migen.sim.generic import Simulator
|
||||||
|
from migen.sim.icarus import Runner
|
||||||
|
|
||||||
L = [
|
class MyPeripheral:
|
||||||
("x", BV(10), 8),
|
def __init__(self):
|
||||||
("y", BV(10), 8),
|
self.bus = wishbone.Interface()
|
||||||
("level2", [
|
self.ack_en = Signal()
|
||||||
("a", BV(5), 32),
|
self.prng = Random(763627)
|
||||||
("b", BV(5), 16)
|
|
||||||
])
|
|
||||||
]
|
|
||||||
|
|
||||||
adrgen = control.For(10)
|
def do_simulation(self, s):
|
||||||
reader = dma_wishbone.Reader(L)
|
# Only authorize acks on certain cycles to simulate variable latency.
|
||||||
|
s.wr(self.ack_en, self.prng.randrange(0, 2))
|
||||||
|
|
||||||
g = nx.MultiDiGraph()
|
def get_fragment(self):
|
||||||
add_connection(g, adrgen, reader)
|
comb = [
|
||||||
comp = CompositeActor(g)
|
self.bus.ack.eq(self.bus.cyc & self.bus.stb & self.ack_en),
|
||||||
|
self.bus.dat_r.eq(self.bus.adr + 4)
|
||||||
|
]
|
||||||
|
return Fragment(comb, sim=[self.do_simulation])
|
||||||
|
|
||||||
frag = comp.get_fragment()
|
def adrgen_gen():
|
||||||
ios = set(reader.bus.signals())
|
for i in range(10):
|
||||||
ios.add(comp.busy)
|
print("Address: " + str(i))
|
||||||
print(verilog.convert(frag, ios=ios))
|
yield Token("address", {"a": i})
|
||||||
|
|
||||||
|
def dumper_gen():
|
||||||
|
while True:
|
||||||
|
t = Token("data")
|
||||||
|
yield t
|
||||||
|
print("Received: " + str(t.value["d"]))
|
||||||
|
|
||||||
|
def test_reader():
|
||||||
|
print("*** Testing reader")
|
||||||
|
adrgen = SimActor(adrgen_gen(), ("address", Source, [("a", BV(30))]))
|
||||||
|
reader = dma_wishbone.Reader()
|
||||||
|
dumper = SimActor(dumper_gen(), ("data", Sink, [("d", BV(32))]))
|
||||||
|
g = nx.MultiDiGraph()
|
||||||
|
add_connection(g, adrgen, reader)
|
||||||
|
add_connection(g, reader, dumper)
|
||||||
|
comp = CompositeActor(g)
|
||||||
|
|
||||||
|
peripheral = MyPeripheral()
|
||||||
|
interconnect = wishbone.InterconnectPointToPoint(reader.bus, peripheral.bus)
|
||||||
|
|
||||||
|
def end_simulation(s):
|
||||||
|
s.interrupt = adrgen.done and not s.rd(comp.busy)
|
||||||
|
|
||||||
|
fragment = comp.get_fragment() \
|
||||||
|
+ peripheral.get_fragment() \
|
||||||
|
+ interconnect.get_fragment() \
|
||||||
|
+ Fragment(sim=[end_simulation])
|
||||||
|
|
||||||
|
sim = Simulator(fragment, Runner())
|
||||||
|
sim.run()
|
||||||
|
|
||||||
|
def trgen_gen():
|
||||||
|
for i in range(10):
|
||||||
|
a = i
|
||||||
|
d = i+10
|
||||||
|
print("Address: " + str(a) + " Data: " + str(d))
|
||||||
|
yield Token("address_data", {"a": a, "d": d})
|
||||||
|
|
||||||
|
def test_writer():
|
||||||
|
print("*** Testing writer")
|
||||||
|
trgen = SimActor(trgen_gen(), ("address_data", Source, [("a", BV(30)), ("d", BV(32))]))
|
||||||
|
writer = dma_wishbone.Reader()
|
||||||
|
g = nx.MultiDiGraph()
|
||||||
|
add_connection(g, trgen, writer)
|
||||||
|
comp = CompositeActor(g)
|
||||||
|
|
||||||
|
peripheral = MyPeripheral()
|
||||||
|
tap = wishbone.Tap(peripheral.bus)
|
||||||
|
interconnect = wishbone.InterconnectPointToPoint(writer.bus, peripheral.bus)
|
||||||
|
|
||||||
|
def end_simulation(s):
|
||||||
|
s.interrupt = trgen.done and not s.rd(comp.busy)
|
||||||
|
|
||||||
|
fragment = comp.get_fragment() \
|
||||||
|
+ peripheral.get_fragment() \
|
||||||
|
+ tap.get_fragment() \
|
||||||
|
+ interconnect.get_fragment() \
|
||||||
|
+ Fragment(sim=[end_simulation])
|
||||||
|
|
||||||
|
sim = Simulator(fragment, Runner())
|
||||||
|
sim.run()
|
||||||
|
|
||||||
|
test_reader()
|
||||||
|
test_writer()
|
||||||
|
|
|
@ -1,86 +1,58 @@
|
||||||
from migen.fhdl.structure import *
|
from migen.fhdl.structure import *
|
||||||
from migen.corelogic.record import *
|
|
||||||
from migen.corelogic.fsm import *
|
|
||||||
from migen.bus import wishbone
|
from migen.bus import wishbone
|
||||||
from migen.flow.actor import *
|
from migen.flow.actor import *
|
||||||
|
|
||||||
class Reader(Actor):
|
class Reader(Actor):
|
||||||
def __init__(self, layout):
|
def __init__(self):
|
||||||
self.bus = wishbone.Master()
|
self.bus = wishbone.Interface()
|
||||||
Actor.__init__(self,
|
super().__init__(
|
||||||
SchedulingModel(SchedulingModel.DYNAMIC),
|
|
||||||
("address", Sink, [("a", BV(30))]),
|
("address", Sink, [("a", BV(30))]),
|
||||||
("data", Source, layout))
|
("data", Source, [("d", BV(32))]))
|
||||||
|
|
||||||
def get_fragment(self):
|
def get_fragment(self):
|
||||||
components, length = self.token("data").flatten(align=True, return_offset=True)
|
bus_stb = Signal()
|
||||||
nwords = (length + 31)//32
|
|
||||||
|
|
||||||
# Address generator
|
data_reg_loaded = Signal()
|
||||||
ag_stb = Signal()
|
data_reg = Signal(BV(32))
|
||||||
ag_sync = [If(ag_stb, self.bus.adr_o.eq(self.token("address").a))]
|
|
||||||
if nwords > 1:
|
|
||||||
ag_inc = Signal()
|
|
||||||
ag_sync.append(If(ag_inc, self.bus.adr_o.eq(self.bus.adr_o + 1)))
|
|
||||||
address_generator = Fragment(sync=ag_sync)
|
|
||||||
|
|
||||||
# Output buffer
|
comb = [
|
||||||
ob_reg = Signal(BV(length))
|
self.busy.eq(data_reg_loaded),
|
||||||
ob_stbs = Signal(BV(nwords))
|
self.bus.we.eq(0),
|
||||||
ob_sync = []
|
bus_stb.eq(self.endpoints["address"].stb & (~data_reg_loaded | self.endpoints["data"].ack)),
|
||||||
top = length
|
self.bus.cyc.eq(bus_stb),
|
||||||
for w in range(nwords):
|
self.bus.stb.eq(bus_stb),
|
||||||
if top >= 32:
|
self.bus.adr.eq(self.token("address").a),
|
||||||
width = 32
|
self.endpoints["address"].ack.eq(self.bus.ack),
|
||||||
sl = self.bus.dat_i
|
self.endpoints["data"].stb.eq(data_reg_loaded),
|
||||||
else:
|
self.token("data").d.eq(data_reg)
|
||||||
width = top
|
]
|
||||||
sl = self.bus.dat_i[32-top:]
|
sync = [
|
||||||
ob_sync.append(If(ob_stbs[w],
|
If(self.endpoints["data"].ack,
|
||||||
ob_reg[top-width:top].eq(sl)))
|
data_reg_loaded.eq(0)
|
||||||
top -= width
|
),
|
||||||
ob_comb = []
|
If(self.bus.ack,
|
||||||
offset = 0
|
data_reg_loaded.eq(1),
|
||||||
for s in components:
|
data_reg.eq(self.bus.dat_r)
|
||||||
w = s.bv.width
|
|
||||||
if isinstance(s, Signal):
|
|
||||||
ob_comb.append(s.eq(ob_reg[length-offset-w:length-offset]))
|
|
||||||
offset += w
|
|
||||||
output_buffer = Fragment(ob_comb, ob_sync)
|
|
||||||
|
|
||||||
# Controller
|
|
||||||
fetch_states = ["FETCH{0}".format(w) for w in range(nwords)]
|
|
||||||
states = ["IDLE"] + fetch_states + ["STROBE"]
|
|
||||||
fsm = FSM(*states)
|
|
||||||
self.busy.reset = Constant(1)
|
|
||||||
fsm.act(fsm.IDLE,
|
|
||||||
self.busy.eq(0),
|
|
||||||
ag_stb.eq(1),
|
|
||||||
self.endpoints["address"].ack.eq(1),
|
|
||||||
If(self.endpoints["address"].stb, fsm.next_state(fsm.FETCH0))
|
|
||||||
)
|
|
||||||
for w in range(nwords):
|
|
||||||
state = getattr(fsm, fetch_states[w])
|
|
||||||
if w == nwords - 1:
|
|
||||||
next_state = fsm.STROBE
|
|
||||||
else:
|
|
||||||
next_state = getattr(fsm, fetch_states[w+1])
|
|
||||||
fsm.act(state,
|
|
||||||
self.bus.cyc_o.eq(1),
|
|
||||||
self.bus.stb_o.eq(1),
|
|
||||||
ob_stbs[w].eq(1),
|
|
||||||
If(self.bus.ack_i,
|
|
||||||
fsm.next_state(next_state),
|
|
||||||
ag_inc.eq(1) if nwords > 1 else None
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
fsm.act(fsm.STROBE,
|
]
|
||||||
self.endpoints["data"].stb.eq(1),
|
|
||||||
If(self.endpoints["data"].ack, fsm.next_state(fsm.IDLE))
|
|
||||||
)
|
|
||||||
controller = fsm.get_fragment()
|
|
||||||
|
|
||||||
return address_generator + output_buffer + controller
|
return Fragment(comb, sync)
|
||||||
|
|
||||||
class Writer(Actor):
|
class Writer(Actor):
|
||||||
pass # TODO
|
def __init__(self):
|
||||||
|
self.bus = wishbone.Interface()
|
||||||
|
super().__init__(
|
||||||
|
("address_data", Sink, [("a", BV(30)), ("d", BV(32))]))
|
||||||
|
|
||||||
|
def get_fragment(self):
|
||||||
|
comb = [
|
||||||
|
self.busy.eq(0),
|
||||||
|
self.bus.we.eq(1),
|
||||||
|
self.bus.cyc.eq(self.endpoints["address_data"].stb),
|
||||||
|
self.bus.stb.eq(self.endpoints["address_data"].stb),
|
||||||
|
self.bus.adr.eq(self.token("address_data").a),
|
||||||
|
self.bus.sel.eq(0xf),
|
||||||
|
self.bus.dat_w.eq(self.token("address_data").d),
|
||||||
|
self.endpoints["address_data"].ack.eq(self.bus.ack)
|
||||||
|
]
|
||||||
|
return Fragment(comb)
|
||||||
|
|
Loading…
Reference in New Issue