1 # This file is Copyright (c) 2020 Florent Kermarrec <florent@enjoy-digital.fr>
4 """Direct Memory Access (DMA) reader and writer modules."""
8 from litex
.gen
.common
import reverse_bytes
10 from litex
.soc
.interconnect
.csr
import *
11 from litex
.soc
.interconnect
import stream
12 from litex
.soc
.interconnect
import wishbone
14 # Helpers ------------------------------------------------------------------------------------------
16 def format_bytes(s
, endianness
):
17 return {"big": s
, "little": reverse_bytes(s
)}[endianness
]
19 # WishboneDMAReader --------------------------------------------------------------------------------
21 class WishboneDMAReader(Module
, AutoCSR
):
22 """Read data from Wishbone MMAP memory.
24 For every address written to the sink, one word will be produced on the source.
29 Wishbone bus of the SoC to read from.
33 sink : Record("address")
34 Sink for MMAP addresses to be read.
36 source : Record("data")
37 Source for MMAP word results from reading.
39 def __init__(self
, bus
, endianness
="little", with_csr
=False):
40 assert isinstance(bus
, wishbone
.Interface
)
42 self
.sink
= sink
= stream
.Endpoint([("address", bus
.adr_width
, ("last", 1))])
43 self
.source
= source
= stream
.Endpoint([("data", bus
.data_width
)])
47 data
= Signal(bus
.data_width
)
49 self
.submodules
.fsm
= fsm
= FSM(reset_state
="BUS-READ")
51 bus
.stb
.eq(sink
.valid
),
52 bus
.cyc
.eq(sink
.valid
),
54 bus
.sel
.eq(2**(bus
.data_width
//8)-1),
55 bus
.adr
.eq(sink
.address
),
57 NextValue(data
, format_bytes(bus
.dat_r
, endianness
)),
58 NextState("SOURCE-WRITE")
61 fsm
.act("SOURCE-WRITE",
63 source
.last
.eq(sink
.last
),
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)
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
:])
91 self
.comb
+= self
._offset
.status
.eq(offset
)
93 fsm
= FSM(reset_state
="IDLE")
94 fsm
= ResetInserter()(fsm
)
95 self
.submodules
+= fsm
96 self
.comb
+= fsm
.reset
.eq(~self
._enable
.storage
)
102 self
.sink
.valid
.eq(1),
103 self
.sink
.last
.eq(offset
== (length
- 1)),
104 self
.sink
.address
.eq(base
+ offset
),
106 NextValue(offset
, offset
+ 1),
108 If(self
._loop
.storage
,
117 self
._done
.status
.eq(1)
120 # WishboneDMAWriter --------------------------------------------------------------------------------
122 class WishboneDMAWriter(Module
, AutoCSR
):
123 """Write data to Wishbone MMAP memory.
128 Wishbone bus of the SoC to read from.
132 sink : Record("address", "data")
133 Sink for MMAP addresses/datas to be written.
135 def __init__(self
, bus
, endianness
="little", with_csr
=False):
136 assert isinstance(bus
, wishbone
.Interface
)
138 self
.sink
= sink
= stream
.Endpoint([("address", bus
.adr_width
), ("data", bus
.data_width
)])
142 data
= Signal(bus
.data_width
)
145 bus
.stb
.eq(sink
.valid
),
146 bus
.cyc
.eq(sink
.valid
),
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
),
158 self
._sink
= self
.sink
159 self
.sink
= stream
.Endpoint([("data", self
.bus
.data_width
)])
161 self
._base
= CSRStorage(64)
162 self
._length
= CSRStorage(32)
163 self
._enable
= CSRStorage()
164 self
._done
= CSRStatus()
165 self
._loop
= CSRStorage()
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
:])
176 fsm
= FSM(reset_state
="IDLE")
177 fsm
= ResetInserter()(fsm
)
178 self
.submodules
+= fsm
179 self
.comb
+= fsm
.reset
.eq(~self
._enable
.storage
)
181 self
.sink
.ready
.eq(1),
182 NextValue(offset
, 0),
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
,
202 self
._done
.status
.eq(1)