bus: generic transaction model
This commit is contained in:
parent
ddc0e49981
commit
ab800fa2ed
|
@ -0,0 +1,53 @@
|
||||||
|
from random import Random
|
||||||
|
|
||||||
|
from migen.fhdl.structure import *
|
||||||
|
from migen.fhdl import autofragment
|
||||||
|
from migen.bus.transactions import *
|
||||||
|
from migen.bus import wishbone
|
||||||
|
from migen.sim.generic import Simulator
|
||||||
|
from migen.sim.icarus import Runner
|
||||||
|
|
||||||
|
def my_generator():
|
||||||
|
prng = Random(92837)
|
||||||
|
for x in range(10):
|
||||||
|
t = TWrite(x, 2*x)
|
||||||
|
yield t
|
||||||
|
print("Wrote in " + str(t.latency) + " cycle(s)")
|
||||||
|
for delay in range(prng.randrange(0, 3)):
|
||||||
|
yield None
|
||||||
|
for x in range(10):
|
||||||
|
t = TRead(x)
|
||||||
|
yield t
|
||||||
|
print("Read " + str(t.data) + " in " + str(t.latency) + " cycle(s)")
|
||||||
|
for delay in range(prng.randrange(0, 3)):
|
||||||
|
yield None
|
||||||
|
|
||||||
|
class MyPeripheral:
|
||||||
|
def __init__(self):
|
||||||
|
self.bus = wishbone.Interface()
|
||||||
|
self.ack_en = Signal()
|
||||||
|
self.prng = Random(763627)
|
||||||
|
|
||||||
|
def do_simulation(self, s):
|
||||||
|
# Only authorize acks on certain cycles to simulate variable latency
|
||||||
|
s.wr(self.ack_en, self.prng.randrange(0, 2))
|
||||||
|
|
||||||
|
def get_fragment(self):
|
||||||
|
comb = [
|
||||||
|
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])
|
||||||
|
|
||||||
|
def main():
|
||||||
|
master = wishbone.Initiator(my_generator())
|
||||||
|
slave = MyPeripheral()
|
||||||
|
tap = wishbone.Tap(slave.bus)
|
||||||
|
intercon = wishbone.InterconnectPointToPoint(master.bus, slave.bus)
|
||||||
|
def end_simulation(s):
|
||||||
|
s.interrupt = master.done
|
||||||
|
fragment = autofragment.from_local() + Fragment(sim=[end_simulation])
|
||||||
|
sim = Simulator(fragment, Runner())
|
||||||
|
sim.run()
|
||||||
|
|
||||||
|
main()
|
|
@ -0,0 +1,20 @@
|
||||||
|
from migen.fhdl.structure import bits_for
|
||||||
|
|
||||||
|
class Transaction:
|
||||||
|
def __init__(self, address, data=0, sel=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.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
|
|
@ -2,6 +2,7 @@ from migen.fhdl.structure import *
|
||||||
from migen.corelogic import roundrobin
|
from migen.corelogic import roundrobin
|
||||||
from migen.corelogic.misc import multimux, optree
|
from migen.corelogic.misc import multimux, optree
|
||||||
from migen.bus.simple import *
|
from migen.bus.simple import *
|
||||||
|
from migen.bus.transactions import *
|
||||||
|
|
||||||
_desc = Description(
|
_desc = Description(
|
||||||
(M_TO_S, "adr", 30),
|
(M_TO_S, "adr", 30),
|
||||||
|
@ -127,3 +128,78 @@ class InterconnectShared:
|
||||||
|
|
||||||
def get_fragment(self):
|
def get_fragment(self):
|
||||||
return self._arbiter.get_fragment() + self._decoder.get_fragment()
|
return self._arbiter.get_fragment() + self._decoder.get_fragment()
|
||||||
|
|
||||||
|
class Tap:
|
||||||
|
def __init__(self, bus=None, handler=print):
|
||||||
|
# If bus is None, create one and act as a normal slave.
|
||||||
|
# If we pass an existing one, dump the transactions
|
||||||
|
# without interfering with the bus.
|
||||||
|
if bus is None:
|
||||||
|
self.bus = Interface()
|
||||||
|
self.ack = True
|
||||||
|
else:
|
||||||
|
self.bus = bus
|
||||||
|
self.ack = False
|
||||||
|
self.handler = handler
|
||||||
|
|
||||||
|
def do_simulation(self, s):
|
||||||
|
if s.rd(self.bus.ack):
|
||||||
|
assert(s.rd(self.bus.cyc) and s.rd(self.bus.stb))
|
||||||
|
if s.rd(self.bus.we):
|
||||||
|
transaction = TWrite(s.rd(self.bus.adr),
|
||||||
|
s.rd(self.bus.dat_w),
|
||||||
|
s.rd(self.bus.sel))
|
||||||
|
else:
|
||||||
|
transaction = TRead(s.rd(self.bus.adr),
|
||||||
|
s.rd(self.bus.dat_r))
|
||||||
|
self.handler(transaction)
|
||||||
|
|
||||||
|
def get_fragment(self):
|
||||||
|
if self.ack:
|
||||||
|
sync = [
|
||||||
|
self.bus.ack.eq(0),
|
||||||
|
If(self.bus.cyc & self.bus.stb & ~self.bus.ack,
|
||||||
|
self.bus.ack.eq(1)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
sync = []
|
||||||
|
return Fragment(sync=sync, sim=[self.do_simulation])
|
||||||
|
|
||||||
|
class Initiator:
|
||||||
|
def __init__(self, generator):
|
||||||
|
self.generator = generator
|
||||||
|
self.bus = Interface()
|
||||||
|
self.transaction_start = 0
|
||||||
|
self.transaction = None
|
||||||
|
self.done = False
|
||||||
|
|
||||||
|
def do_simulation(self, s):
|
||||||
|
if not self.done:
|
||||||
|
if self.transaction is None or s.rd(self.bus.ack):
|
||||||
|
if self.transaction is not None:
|
||||||
|
self.transaction.latency = s.cycle_counter - self.transaction_start - 1
|
||||||
|
if isinstance(self.transaction, TRead):
|
||||||
|
self.transaction.data = s.rd(self.bus.dat_r)
|
||||||
|
try:
|
||||||
|
self.transaction = next(self.generator)
|
||||||
|
except StopIteration:
|
||||||
|
self.done = True
|
||||||
|
self.transaction = None
|
||||||
|
if self.transaction is not None:
|
||||||
|
self.transaction_start = s.cycle_counter
|
||||||
|
s.wr(self.bus.cyc, 1)
|
||||||
|
s.wr(self.bus.stb, 1)
|
||||||
|
s.wr(self.bus.adr, self.transaction.address)
|
||||||
|
if isinstance(self.transaction, TWrite):
|
||||||
|
s.wr(self.bus.we, 1)
|
||||||
|
s.wr(self.bus.sel, self.transaction.sel)
|
||||||
|
s.wr(self.bus.dat_w, self.transaction.data)
|
||||||
|
else:
|
||||||
|
s.wr(self.bus.we, 0)
|
||||||
|
else:
|
||||||
|
s.wr(self.bus.cyc, 0)
|
||||||
|
s.wr(self.bus.stb, 0)
|
||||||
|
|
||||||
|
def get_fragment(self):
|
||||||
|
return Fragment(sim=[self.do_simulation])
|
||||||
|
|
Loading…
Reference in New Issue