8feab0069c33ae1e099eab1e827bdb7b89ce2267
[litex.git] / litex / soc / misoc / cores / dvi_sampler / dma.py
1 from migen import *
2 from migen.genlib.fsm import FSM, NextState
3
4 from misoc.interconnect.csr import *
5 from misoc.interconnect.csr_eventmanager import *
6
7 # TODO: rewrite dma_lasmi module
8 # TODO: use stream packets to resync DMA
9 #from misoc.mem.sdram.frontend import dma_lasmi
10
11
12 # Slot status: EMPTY=0 LOADED=1 PENDING=2
13 class _Slot(Module, AutoCSR):
14 def __init__(self, addr_bits, alignment_bits):
15 self.ev_source = EventSourceLevel()
16 self.address = Signal(addr_bits)
17 self.address_reached = Signal(addr_bits)
18 self.address_valid = Signal()
19 self.address_done = Signal()
20
21 self._status = CSRStorage(2, write_from_dev=True)
22 self._address = CSRStorage(addr_bits + alignment_bits, alignment_bits=alignment_bits, write_from_dev=True)
23
24 ###
25
26 self.comb += [
27 self.address.eq(self._address.storage),
28 self.address_valid.eq(self._status.storage[0]),
29 self._status.dat_w.eq(2),
30 self._status.we.eq(self.address_done),
31 self._address.dat_w.eq(self.address_reached),
32 self._address.we.eq(self.address_done),
33 self.ev_source.trigger.eq(self._status.storage[1])
34 ]
35
36
37 class _SlotArray(Module, AutoCSR):
38 def __init__(self, nslots, addr_bits, alignment_bits):
39 self.submodules.ev = EventManager()
40 self.address = Signal(addr_bits)
41 self.address_reached = Signal(addr_bits)
42 self.address_valid = Signal()
43 self.address_done = Signal()
44
45 ###
46
47 slots = [_Slot(addr_bits, alignment_bits) for i in range(nslots)]
48 for n, slot in enumerate(slots):
49 setattr(self.submodules, "slot"+str(n), slot)
50 setattr(self.ev, "slot"+str(n), slot.ev_source)
51 self.ev.finalize()
52
53 change_slot = Signal()
54 current_slot = Signal(max=nslots)
55 self.sync += If(change_slot, [If(slot.address_valid, current_slot.eq(n)) for n, slot in reversed(list(enumerate(slots)))])
56 self.comb += change_slot.eq(~self.address_valid | self.address_done)
57
58 self.comb += [
59 self.address.eq(Array(slot.address for slot in slots)[current_slot]),
60 self.address_valid.eq(Array(slot.address_valid for slot in slots)[current_slot])
61 ]
62 self.comb += [slot.address_reached.eq(self.address_reached) for slot in slots]
63 self.comb += [slot.address_done.eq(self.address_done & (current_slot == n)) for n, slot in enumerate(slots)]
64
65
66 class DMA(Module):
67 def __init__(self, lasmim, nslots):
68 bus_aw = lasmim.aw
69 bus_dw = lasmim.dw
70 alignment_bits = bits_for(bus_dw//8) - 1
71
72 fifo_word_width = 24*bus_dw//32
73 self.frame = Sink([("sof", 1), ("pixels", fifo_word_width)])
74 self._frame_size = CSRStorage(bus_aw + alignment_bits, alignment_bits=alignment_bits)
75 self.submodules._slot_array = _SlotArray(nslots, bus_aw, alignment_bits)
76 self.ev = self._slot_array.ev
77
78 ###
79
80 # address generator + maximum memory word count to prevent DMA buffer overrun
81 reset_words = Signal()
82 count_word = Signal()
83 last_word = Signal()
84 current_address = Signal(bus_aw)
85 mwords_remaining = Signal(bus_aw)
86 self.comb += [
87 self._slot_array.address_reached.eq(current_address),
88 last_word.eq(mwords_remaining == 1)
89 ]
90 self.sync += [
91 If(reset_words,
92 current_address.eq(self._slot_array.address),
93 mwords_remaining.eq(self._frame_size.storage)
94 ).Elif(count_word,
95 current_address.eq(current_address + 1),
96 mwords_remaining.eq(mwords_remaining - 1)
97 )
98 ]
99
100 # 24bpp -> 32bpp
101 memory_word = Signal(bus_dw)
102 pixbits = []
103 for i in range(bus_dw//32):
104 for j in range(3):
105 b = (i*3+j)*8
106 pixbits.append(self.frame.pixels[b+6:b+8])
107 pixbits.append(self.frame.pixels[b:b+8])
108 pixbits.append(0)
109 pixbits.append(0)
110 self.comb += memory_word.eq(Cat(*pixbits))
111
112 # bus accessor
113 self.submodules._bus_accessor = dma_lasmi.Writer(lasmim)
114 self.comb += [
115 self._bus_accessor.address_data.a.eq(current_address),
116 self._bus_accessor.address_data.d.eq(memory_word)
117 ]
118
119 # control FSM
120 fsm = FSM()
121 self.submodules += fsm
122
123 fsm.act("WAIT_SOF",
124 reset_words.eq(1),
125 self.frame.ack.eq(~self._slot_array.address_valid | ~self.frame.sof),
126 If(self._slot_array.address_valid & self.frame.sof & self.frame.stb, NextState("TRANSFER_PIXELS"))
127 )
128 fsm.act("TRANSFER_PIXELS",
129 self.frame.ack.eq(self._bus_accessor.address_data.ack),
130 If(self.frame.stb,
131 self._bus_accessor.address_data.stb.eq(1),
132 If(self._bus_accessor.address_data.ack,
133 count_word.eq(1),
134 If(last_word, NextState("EOF"))
135 )
136 )
137 )
138 fsm.act("EOF",
139 If(~self._bus_accessor.busy,
140 self._slot_array.address_done.eq(1),
141 NextState("WAIT_SOF")
142 )
143 )
144
145 def get_csrs(self):
146 return [self._frame_size] + self._slot_array.get_csrs()