replace PartitionedSignal with SimdSignal
[soc.git] / src / soc / bus / wb_downconvert.py
1 from nmigen import Elaboratable, Module, Signal, Repl, Cat, Mux
2 from nmigen.utils import log2_int
3
4 class WishboneDownConvert(Elaboratable):
5 """DownConverter
6
7 This module splits Wishbone accesses from a master interface to a smaller
8 slave interface.
9
10 Writes:
11 Writes from master are split N writes to the slave. Access
12 is acked when the last access is acked by the slave.
13
14 Reads:
15 Read from master are split in N reads to the the slave.
16 Read data from the slave are cached before being presented,
17 concatenated on the last access.
18
19 TODO:
20 Manage err signal? (Not implemented since we generally don't
21 use it on Migen/MiSoC modules)
22 """
23 def __init__(self, master, slave):
24 self.master = master
25 self.slave = slave
26
27 def elaborate(self, platform):
28
29 master = self.master
30 slave = self.slave
31 m = Module()
32 comb = m.d.comb
33 sync = m.d.sync
34
35 dw_from = len(master.dat_r)
36 dw_to = len(slave.dat_w)
37 ratio = dw_from//dw_to
38
39 print ("wb downconvert from to ratio", dw_from, dw_to, ratio)
40
41 # # #
42
43 read = Signal()
44 write = Signal()
45
46 cached_data = Signal(dw_from)
47 shift_reg = Signal(dw_from)
48
49 counter = Signal(log2_int(ratio, False))
50 counter_reset = Signal()
51 counter_ce = Signal()
52 with m.If(counter_reset):
53 sync += counter.eq(0)
54 with m.Elif(counter_ce):
55 sync += counter.eq(counter + 1)
56
57 counter_done = Signal()
58 comb += counter_done.eq(counter == ratio-1)
59
60 # Main FSM
61 with m.FSM() as fsm:
62 with m.State("IDLE"):
63 comb += counter_reset.eq(1)
64 sync += cached_data.eq(0)
65 with m.If(master.stb & master.cyc):
66 with m.If(master.we):
67 m.next = "WRITE"
68 with m.Else():
69 m.next = "READ"
70
71 with m.State("WRITE"):
72 comb += write.eq(1)
73 comb += slave.we.eq(1)
74 comb += slave.cyc.eq(1)
75 with m.If(master.stb & master.cyc):
76 comb += slave.stb.eq(1)
77 with m.If(slave.ack):
78 comb += counter_ce.eq(1)
79 with m.If(counter_done):
80 comb += master.ack.eq(1)
81 m.next = "IDLE"
82 with m.Elif(~master.cyc):
83 m.next = "IDLE"
84
85 with m.State("READ"):
86 comb += read.eq(1)
87 comb += slave.cyc.eq(1)
88 with m.If(master.stb & master.cyc):
89 comb += slave.stb.eq(1)
90 with m.If(slave.ack):
91 comb += counter_ce.eq(1)
92 with m.If(counter_done):
93 comb += master.ack.eq(1)
94 comb += master.dat_r.eq(shift_reg)
95 m.next = "IDLE"
96 with m.Elif(~master.cyc):
97 m.next = "IDLE"
98
99 # Address
100 if hasattr(slave, 'cti'):
101 with m.If(counter_done):
102 comb += slave.cti.eq(7) # indicate end of burst
103 with m.Else():
104 comb += slave.cti.eq(2)
105 comb += slave.adr.eq(Cat(counter, master.adr))
106
107 # write Datapath - select fragments of data, depending on "counter"
108 with m.Switch(counter):
109 slen = slave.sel.width
110 for i in range(ratio):
111 with m.Case(i):
112 # select fractions of dat_w and associated "sel" bits
113 print ("sel", i, "from", i*slen, "to", (i+1)*slen)
114 comb += slave.sel.eq(master.sel[i*slen:(i+1)*slen])
115 comb += slave.dat_w.eq(master.dat_w[i*dw_to:(i+1)*dw_to])
116
117 # read Datapath - uses cached_data and master.dat_r as a shift-register.
118 # by the time "counter" is done (counter_done) this is complete
119 comb += shift_reg.eq(Cat(cached_data[dw_to:], slave.dat_r))
120 with m.If(read & counter_ce):
121 sync += cached_data.eq(shift_reg)
122
123
124 return m