cores/dma, liblitesdcard/sdcard: use 64 bits for dma base address
[litex.git] / litex / soc / cores / dma.py
1 # This file is Copyright (c) 2020 Florent Kermarrec <florent@enjoy-digital.fr>
2 # License: BSD
3
4 """Direct Memory Access (DMA) reader and writer modules."""
5
6 from migen import *
7
8 from litex.gen.common import reverse_bytes
9
10 from litex.soc.interconnect.csr import *
11 from litex.soc.interconnect import stream
12 from litex.soc.interconnect import wishbone
13
14 # Helpers ------------------------------------------------------------------------------------------
15
16 def format_bytes(s, endianness):
17 return {"big": s, "little": reverse_bytes(s)}[endianness]
18
19 # WishboneDMAReader --------------------------------------------------------------------------------
20
21 class WishboneDMAReader(Module, AutoCSR):
22 """Read data from Wishbone MMAP memory.
23
24 For every address written to the sink, one word will be produced on the source.
25
26 Parameters
27 ----------
28 bus : bus
29 Wishbone bus of the SoC to read from.
30
31 Attributes
32 ----------
33 sink : Record("address")
34 Sink for MMAP addresses to be read.
35
36 source : Record("data")
37 Source for MMAP word results from reading.
38 """
39 def __init__(self, bus, endianness="little", with_csr=False):
40 assert isinstance(bus, wishbone.Interface)
41 self.bus = bus
42 self.sink = sink = stream.Endpoint([("address", bus.adr_width, ("last", 1))])
43 self.source = source = stream.Endpoint([("data", bus.data_width)])
44
45 # # #
46
47 data = Signal(bus.data_width)
48
49 self.submodules.fsm = fsm = FSM(reset_state="BUS-READ")
50 fsm.act("BUS-READ",
51 bus.stb.eq(sink.valid),
52 bus.cyc.eq(sink.valid),
53 bus.we.eq(0),
54 bus.sel.eq(2**(bus.data_width//8)-1),
55 bus.adr.eq(sink.address),
56 If(bus.stb & bus.ack,
57 NextValue(data, format_bytes(bus.dat_r, endianness)),
58 NextState("SOURCE-WRITE")
59 )
60 )
61 fsm.act("SOURCE-WRITE",
62 source.valid.eq(1),
63 source.last.eq(sink.last),
64 source.data.eq(data),
65 If(source.ready,
66 sink.ready.eq(1),
67 NextState("BUS-READ")
68 )
69 )
70
71 if with_csr:
72 self.add_csr()
73
74 def add_csr(self):
75 self._base = CSRStorage(64)
76 self._length = CSRStorage(32)
77 self._enable = CSRStorage()
78 self._done = CSRStatus()
79 self._loop = CSRStorage()
80 self._offset = CSRStatus(32)
81
82 # # #
83
84 shift = log2_int(self.bus.data_width//8)
85 base = Signal(self.bus.adr_width)
86 offset = Signal(self.bus.adr_width)
87 length = Signal(self.bus.adr_width)
88 self.comb += base.eq(self._base.storage[shift:])
89 self.comb += length.eq(self._length.storage[shift:])
90
91 self.comb += self._offset.status.eq(offset)
92
93 fsm = FSM(reset_state="IDLE")
94 fsm = ResetInserter()(fsm)
95 self.submodules += fsm
96 self.comb += fsm.reset.eq(~self._enable.storage)
97 fsm.act("IDLE",
98 NextValue(offset, 0),
99 NextState("RUN"),
100 )
101 fsm.act("RUN",
102 self.sink.valid.eq(1),
103 self.sink.last.eq(offset == (length - 1)),
104 self.sink.address.eq(base + offset),
105 If(self.sink.ready,
106 NextValue(offset, offset + 1),
107 If(self.sink.last,
108 If(self._loop.storage,
109 NextValue(offset, 0)
110 ).Else(
111 NextState("DONE")
112 )
113 )
114 )
115 )
116 fsm.act("DONE",
117 self._done.status.eq(1)
118 )
119
120 # WishboneDMAWriter --------------------------------------------------------------------------------
121
122 class WishboneDMAWriter(Module, AutoCSR):
123 """Write data to Wishbone MMAP memory.
124
125 Parameters
126 ----------
127 bus : bus
128 Wishbone bus of the SoC to read from.
129
130 Attributes
131 ----------
132 sink : Record("address", "data")
133 Sink for MMAP addresses/datas to be written.
134 """
135 def __init__(self, bus, endianness="little", with_csr=False):
136 assert isinstance(bus, wishbone.Interface)
137 self.bus = bus
138 self.sink = sink = stream.Endpoint([("address", bus.adr_width), ("data", bus.data_width)])
139
140 # # #
141
142 data = Signal(bus.data_width)
143
144 self.comb += [
145 bus.stb.eq(sink.valid),
146 bus.cyc.eq(sink.valid),
147 bus.we.eq(1),
148 bus.sel.eq(2**(bus.data_width//8)-1),
149 bus.adr.eq(sink.address),
150 bus.dat_w.eq(format_bytes(sink.data, endianness)),
151 sink.ready.eq(bus.ack),
152 ]
153
154 if with_csr:
155 self.add_csr()
156
157 def add_csr(self):
158 self._sink = self.sink
159 self.sink = stream.Endpoint([("data", self.bus.data_width)])
160
161 self._base = CSRStorage(64)
162 self._length = CSRStorage(32)
163 self._enable = CSRStorage()
164 self._done = CSRStatus()
165 self._loop = CSRStorage()
166
167 # # #
168
169 shift = log2_int(self.bus.data_width//8)
170 base = Signal(self.bus.adr_width)
171 offset = Signal(self.bus.adr_width)
172 length = Signal(self.bus.adr_width)
173 self.comb += base.eq(self._base.storage[shift:])
174 self.comb += length.eq(self._length.storage[shift:])
175
176 fsm = FSM(reset_state="IDLE")
177 fsm = ResetInserter()(fsm)
178 self.submodules += fsm
179 self.comb += fsm.reset.eq(~self._enable.storage)
180 fsm.act("IDLE",
181 self.sink.ready.eq(1),
182 NextValue(offset, 0),
183 NextState("RUN"),
184 )
185 fsm.act("RUN",
186 self._sink.valid.eq(self.sink.valid),
187 self._sink.data.eq(self.sink.data),
188 self._sink.address.eq(base + offset),
189 self.sink.ready.eq(self._sink.ready),
190 If(self.sink.valid & self.sink.ready,
191 NextValue(offset, offset + 1),
192 If(offset == (length - 1),
193 If(self._loop.storage,
194 NextValue(offset, 0)
195 ).Else(
196 NextState("DONE")
197 )
198 )
199 )
200 )
201 fsm.act("DONE",
202 self._done.status.eq(1)
203 )