You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

maxi_dma.py 8.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. from migen import *
  2. from migen_axi.interconnect import axi
  3. from misoc.interconnect.csr import *
  4. from artiq.gateware import rtio
  5. from operator import attrgetter
  6. class MAXI_DMA(Module, AutoCSR):
  7. def __init__(self, bus=None, user=None, trigger_stb=None):
  8. self.bus = bus or axi.Interface(data_width=64)
  9. self.addr_base = CSRStorage(32)
  10. self.trig_count = CSRStatus(32)
  11. self.write_count = CSRStatus(32)
  12. # Dout : Data received from CPU, output by DMA module
  13. # Din : Data driven into DMA module, written into CPU
  14. # When stb assert, index shows word being read/written, dout/din holds
  15. # data
  16. #
  17. # Cycle:
  18. # trigger_stb pulsed at start
  19. # Then out_burst_len words are strobed out of dout
  20. # Then, when din_ready is high, in_burst_len words are strobed in to din
  21. self.dout_stb = Signal()
  22. self.din_stb = Signal()
  23. self.dout_index = Signal(max=16)
  24. self.din_index = Signal(max=16)
  25. self.din_ready = Signal()
  26. self.dout = Signal(64)
  27. self.din = Signal(64)
  28. self.out_burst_len = Signal(max=16)
  29. self.in_burst_len = Signal(max=16)
  30. ###
  31. self.trigger_stb = trigger_stb
  32. self.sync += If(trigger_stb, self.trig_count.status.eq(self.trig_count.status+1))
  33. if user:
  34. self.comb += user.aruser.eq(0x1f)
  35. self.comb += user.awuser.eq(0x1f)
  36. ar, aw, w, r, b = attrgetter("ar", "aw", "w", "r", "b")(self.bus)
  37. ### Read
  38. self.comb += [
  39. ar.addr.eq(self.addr_base.storage),
  40. self.dout.eq(r.data),
  41. r.ready.eq(1),
  42. ar.burst.eq(axi.Burst.incr.value),
  43. ar.len.eq(self.out_burst_len-1), # Number of transfers in burst (0->1 transfer, 1->2 transfers...)
  44. ar.size.eq(3), # Width of burst: 3 = 8 bytes = 64 bits
  45. ar.cache.eq(0xf),
  46. ]
  47. # read control
  48. self.submodules.read_fsm = read_fsm = FSM(reset_state="IDLE")
  49. read_fsm.act("IDLE",
  50. If(trigger_stb,
  51. ar.valid.eq(1),
  52. If(ar.ready,
  53. NextState("READ")
  54. ).Else(
  55. NextState("READ_START")
  56. )
  57. )
  58. )
  59. read_fsm.act("READ_START",
  60. ar.valid.eq(1),
  61. If(ar.ready,
  62. NextState("READ"),
  63. )
  64. )
  65. read_fsm.act("READ",
  66. ar.valid.eq(0),
  67. If(r.last & r.valid,
  68. NextState("IDLE")
  69. )
  70. )
  71. self.sync += [
  72. If(read_fsm.ongoing("IDLE"),
  73. self.dout_index.eq(0)
  74. ).Else(If(r.valid & read_fsm.ongoing("READ"),
  75. self.dout_index.eq(self.dout_index+1)
  76. )
  77. )
  78. ]
  79. self.comb += self.dout_stb.eq(r.valid & r.ready)
  80. ### Write
  81. self.comb += [
  82. w.data.eq(self.din),
  83. aw.addr.eq(self.addr_base.storage+32), # Write to next cache line
  84. w.strb.eq(0xff),
  85. aw.burst.eq(axi.Burst.incr.value),
  86. aw.len.eq(self.in_burst_len-1), # Number of transfers in burst minus 1
  87. aw.size.eq(3), # Width of burst: 3 = 8 bytes = 64 bits
  88. aw.cache.eq(0xf),
  89. b.ready.eq(1),
  90. ]
  91. # write control
  92. self.submodules.write_fsm = write_fsm = FSM(reset_state="IDLE")
  93. write_fsm.act("IDLE",
  94. w.valid.eq(0),
  95. aw.valid.eq(0),
  96. If(trigger_stb,
  97. aw.valid.eq(1),
  98. If(aw.ready, # assumes aw.ready is not randomly deasserted
  99. NextState("DATA_WAIT")
  100. ).Else(
  101. NextState("AW_READY_WAIT")
  102. )
  103. )
  104. )
  105. write_fsm.act("AW_READY_WAIT",
  106. aw.valid.eq(1),
  107. If(aw.ready,
  108. NextState("DATA_WAIT"),
  109. )
  110. )
  111. write_fsm.act("DATA_WAIT",
  112. aw.valid.eq(0),
  113. If(self.din_ready,
  114. w.valid.eq(1),
  115. NextState("WRITE")
  116. )
  117. )
  118. write_fsm.act("WRITE",
  119. w.valid.eq(1),
  120. If(w.ready & w.last,
  121. NextState("IDLE")
  122. )
  123. )
  124. self.sync += If(w.ready & w.valid, self.write_count.status.eq(self.write_count.status+1))
  125. self.sync += [
  126. If(write_fsm.ongoing("IDLE"),
  127. self.din_index.eq(0)
  128. ),
  129. If(w.ready & w.valid, self.din_index.eq(self.din_index+1))
  130. ]
  131. self.comb += [
  132. w.last.eq(0),
  133. If(self.din_index==aw.len, w.last.eq(1))
  134. ]
  135. self.comb += self.din_stb.eq(w.valid & w.ready)
  136. class DMA_Test(Module):
  137. def __init__(self, engine=None):
  138. if engine is None:
  139. engine = MAXI_DMA()
  140. N = 4
  141. regs = [Signal(64) for _ in range(N)]
  142. self.comb += [
  143. engine.out_burst_len.eq(N),
  144. engine.in_burst_len.eq(N),
  145. ]
  146. self.sync += [
  147. If(engine.trigger_stb, engine.din_ready.eq(0)),
  148. If(engine.dout_stb & (engine.dout_index==3), engine.din_ready.eq(1))
  149. ]
  150. dout_cases = {}
  151. for i in range(N):
  152. dout_cases[i] = regs[i].eq(engine.dout)
  153. din_cases = {}
  154. for i in range(N):
  155. din_cases[i] = engine.din.eq(regs[i])
  156. self.sync += [
  157. If(engine.dout_stb,
  158. Case(engine.dout_index, dout_cases)
  159. ),
  160. ]
  161. self.comb += [
  162. If(engine.din_stb,
  163. Case(engine.din_index, din_cases)
  164. )
  165. ]
  166. class DMA_KernelInitiator(Module):
  167. def __init__(self, engine=None, cri=None):
  168. self.engine = engine or MAXI_DMA()
  169. self.cri = cri or rtio.cri.Interface()
  170. ###
  171. cri = self.cri
  172. self.comb += [
  173. engine.out_burst_len.eq(4),
  174. engine.in_burst_len.eq(4),
  175. ]
  176. cmd = Signal(8)
  177. cmd_write = Signal()
  178. cmd_read = Signal()
  179. self.comb += [
  180. cmd_write.eq(cmd==0),
  181. cmd_read.eq(cmd==1)
  182. ]
  183. dout_cases = {}
  184. dout_lw = Signal(32)
  185. dout_hw = Signal(32)
  186. self.comb += [
  187. dout_lw.eq(engine.dout[:32]),
  188. dout_hw.eq(engine.dout[32:])
  189. ]
  190. dout_cases[0] = [
  191. cmd.eq(dout_lw[24:]),
  192. cri.chan_sel.eq(dout_lw[:24]),
  193. cri.o_address.eq(dout_hw[:16])
  194. ]
  195. dout_cases[1] = [
  196. cri.o_timestamp.eq(engine.dout)
  197. ]
  198. dout_cases[2] = [cri.o_data.eq(engine.dout)] # only lowest 64 bits
  199. self.sync += [
  200. cri.cmd.eq(rtio.cri.commands["nop"]),
  201. If(engine.dout_stb,
  202. Case(engine.dout_index, dout_cases),
  203. If(engine.dout_index==2,
  204. If(cmd_write, cri.cmd.eq(rtio.cri.commands["write"])),
  205. If(cmd_read, cri.cmd.eq(rtio.cri.commands["read"]))
  206. )
  207. )
  208. ]
  209. # If input event, wait for response before allow input data to be
  210. # sampled
  211. # TODO: If output, wait for wait flag clear
  212. RTIO_I_STATUS_WAIT_STATUS = 4
  213. RTIO_O_STATUS_WAIT = 1
  214. self.submodules.fsm = fsm = FSM(reset_state="IDLE")
  215. fsm.act("IDLE",
  216. If(engine.trigger_stb, NextState("WAIT_OUT_CYCLE"))
  217. )
  218. fsm.act("WAIT_OUT_CYCLE",
  219. engine.din_ready.eq(0),
  220. If(engine.dout_stb & (engine.dout_index==3),
  221. NextState("WAIT_READY")
  222. )
  223. )
  224. fsm.act("WAIT_READY",
  225. If(cmd_read & (cri.i_status & RTIO_I_STATUS_WAIT_STATUS == 0) \
  226. | cmd_write & ~(cri.o_status & RTIO_O_STATUS_WAIT),
  227. engine.din_ready.eq(1),
  228. NextState("IDLE")
  229. )
  230. )
  231. din_cases_cmdwrite = {
  232. 0: [engine.din.eq((1<<16) | cri.o_status)],
  233. 1: [engine.din.eq(0)],
  234. }
  235. din_cases_cmdread = {
  236. 0: [engine.din[:32].eq((1<<16) | cri.i_status), engine.din[32:].eq(cri.i_data)],
  237. 1: [engine.din.eq(cri.i_timestamp)]
  238. }
  239. self.comb += [
  240. If(cmd_read, Case(engine.din_index, din_cases_cmdread)),
  241. If(cmd_write, Case(engine.din_index, din_cases_cmdwrite)),
  242. ]