Update copyright notices
[litex.git] / examples / wb_initiator.py
1 # Copyright (C) 2012 Vermeer Manufacturing Co.
2 # License: GPLv3 with additional permissions (see README).
3
4 from random import Random
5
6 from migen.fhdl.structure import *
7 from migen.fhdl import autofragment
8 from migen.bus.transactions import *
9 from migen.bus import wishbone
10 from migen.sim.generic import Simulator
11 from migen.sim.icarus import Runner
12
13 # Our bus master.
14 # Python generators let us program bus transactions in an elegant sequential style.
15 def my_generator():
16 prng = Random(92837)
17
18 # Write to the first addresses.
19 for x in range(10):
20 t = TWrite(x, 2*x)
21 yield t
22 print("Wrote in " + str(t.latency) + " cycle(s)")
23 # Insert some dead cycles to simulate bus inactivity.
24 for delay in range(prng.randrange(0, 3)):
25 yield None
26
27 # Read from the first addresses.
28 for x in range(10):
29 t = TRead(x)
30 yield t
31 print("Read " + str(t.data) + " in " + str(t.latency) + " cycle(s)")
32 for delay in range(prng.randrange(0, 3)):
33 yield None
34
35 # Our bus slave.
36 # All transactions complete with a random delay.
37 # Reads return address + 4. Writes are simply acknowledged.
38 class MyPeripheral:
39 def __init__(self):
40 self.bus = wishbone.Interface()
41 self.ack_en = Signal()
42 self.prng = Random(763627)
43
44 def do_simulation(self, s):
45 # Only authorize acks on certain cycles to simulate variable latency.
46 s.wr(self.ack_en, self.prng.randrange(0, 2))
47
48 def get_fragment(self):
49 comb = [
50 self.bus.ack.eq(self.bus.cyc & self.bus.stb & self.ack_en),
51 self.bus.dat_r.eq(self.bus.adr + 4)
52 ]
53 return Fragment(comb, sim=[self.do_simulation])
54
55 def main():
56 # The "wishbone.Initiator" library component runs our generator
57 # and manipulates the bus signals accordingly.
58 master = wishbone.Initiator(my_generator())
59 # Our slave.
60 slave = MyPeripheral()
61 # The "wishbone.Tap" library component examines the bus at the slave port
62 # and displays the transactions on the console (<TRead...>/<TWrite...>).
63 tap = wishbone.Tap(slave.bus)
64 # Connect the master to the slave.
65 intercon = wishbone.InterconnectPointToPoint(master.bus, slave.bus)
66 # A small extra simulation function to terminate the process when
67 # the initiator is done (i.e. our generator is exhausted).
68 def end_simulation(s):
69 s.interrupt = master.done
70 fragment = autofragment.from_local() + Fragment(sim=[end_simulation])
71 sim = Simulator(fragment, Runner())
72 sim.run()
73
74 main()
75
76 # Output:
77 # <TWrite adr:0x0 dat:0x0>
78 # Wrote in 0 cycle(s)
79 # <TWrite adr:0x1 dat:0x2>
80 # Wrote in 0 cycle(s)
81 # <TWrite adr:0x2 dat:0x4>
82 # Wrote in 0 cycle(s)
83 # <TWrite adr:0x3 dat:0x6>
84 # Wrote in 1 cycle(s)
85 # <TWrite adr:0x4 dat:0x8>
86 # Wrote in 1 cycle(s)
87 # <TWrite adr:0x5 dat:0xa>
88 # Wrote in 2 cycle(s)
89 # ...
90 # <TRead adr:0x0 dat:0x4>
91 # Read 4 in 2 cycle(s)
92 # <TRead adr:0x1 dat:0x5>
93 # Read 5 in 2 cycle(s)
94 # <TRead adr:0x2 dat:0x6>
95 # Read 6 in 1 cycle(s)
96 # <TRead adr:0x3 dat:0x7>
97 # Read 7 in 1 cycle(s)
98 # ...