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