1 from nmigen
import Elaboratable
, Module
, Signal
, Repl
, Cat
, Mux
2 from nmigen
.utils
import log2_int
4 class WishboneDownConvert(Elaboratable
):
7 This module splits Wishbone accesses from a master interface to a smaller
11 Writes from master are split N writes to the slave. Access
12 is acked when the last access is acked by the slave.
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.
20 Manage err signal? (Not implemented since we generally don't
21 use it on Migen/MiSoC modules)
23 def __init__(self
, master
, slave
):
27 def elaborate(self
, platform
):
35 dw_from
= len(master
.dat_r
)
36 dw_to
= len(slave
.dat_w
)
37 ratio
= dw_from
//dw_to
39 print ("wb downconvert from to ratio", dw_from
, dw_to
, ratio
)
46 cached_data
= Signal(dw_from
)
47 shift_reg
= Signal(dw_from
)
49 counter
= Signal(log2_int(ratio
, False))
50 cur_counter
= Signal(log2_int(ratio
, False))
52 counter_done
= Signal()
53 comb
+= counter_done
.eq(counter
== ratio
-1)
54 comb
+= cur_counter
.eq(counter
)
61 sync
+= cached_data
.eq(0)
62 with m
.If(master
.stb
& master
.cyc
):
68 with m
.State("WRITE"):
70 with m
.If(master
.stb
& master
.cyc
):
71 comb
+= skip
.eq(slave
.sel
== 0)
72 comb
+= slave
.we
.eq(1)
73 comb
+= slave
.cyc
.eq(1)
74 comb
+= slave
.stb
.eq(1)
75 with m
.If(slave
.ack | skip
):
76 comb
+= cur_counter
.eq(counter
+ 1) # TODO use Picker
77 sync
+= counter
.eq(cur_counter
)
78 with m
.If(counter_done
):
79 comb
+= master
.ack
.eq(1)
81 with m
.Elif(~master
.cyc
):
86 with m
.If(master
.stb
& master
.cyc
):
87 comb
+= skip
.eq(slave
.sel
== 0)
88 comb
+= slave
.cyc
.eq(1)
89 comb
+= slave
.stb
.eq(1)
90 with m
.If(slave
.ack | skip
):
91 comb
+= cur_counter
.eq(counter
+ 1) # TODO use Picker
92 sync
+= counter
.eq(cur_counter
)
93 with m
.If(counter_done
):
94 comb
+= master
.ack
.eq(1)
95 comb
+= master
.dat_r
.eq(shift_reg
)
97 with m
.Elif(~master
.cyc
):
101 if hasattr(slave
, 'cti'):
102 with m
.If(counter_done
):
103 comb
+= slave
.cti
.eq(7) # indicate end of burst
105 comb
+= slave
.cti
.eq(2)
106 comb
+= slave
.adr
.eq(Cat(cur_counter
, master
.adr
))
108 # write Datapath - select fragments of data, depending on "counter"
109 with m
.Switch(counter
):
110 slen
= slave
.sel
.width
111 for i
in range(ratio
):
113 # select fractions of dat_w and associated "sel" bits
114 print ("sel", i
, "from", i
*slen
, "to", (i
+1)*slen
)
115 comb
+= slave
.sel
.eq(master
.sel
[i
*slen
:(i
+1)*slen
])
116 comb
+= slave
.dat_w
.eq(master
.dat_w
[i
*dw_to
:(i
+1)*dw_to
])
118 # read Datapath - uses cached_data and master.dat_r as a shift-register.
119 # by the time "counter" is done (counter_done) this is complete
120 comb
+= shift_reg
.eq(Cat(cached_data
[dw_to
:], slave
.dat_r
))
121 with m
.If(read
& (slave
.ack | skip
)):
122 sync
+= cached_data
.eq(shift_reg
)