Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 3 commits
  • 4 files changed
  • 0 comments
  • 1 contributor
7  milkymist/dvisampler/__init__.py
@@ -12,7 +12,7 @@
12 12
 from milkymist.dvisampler.dma import DMA
13 13
 
14 14
 class DVISampler(Module, AutoCSR):
15  
-	def __init__(self, pads, asmiport):
  15
+	def __init__(self, pads, asmiport, n_dma_slots=2):
16 16
 		self.submodules.edid = EDID(pads)
17 17
 		self.submodules.clocking = Clocking(pads)
18 18
 
@@ -79,5 +79,8 @@ def __init__(self, pads, asmiport):
79 79
 			self.frame.b.eq(self.syncpol.b)
80 80
 		]
81 81
 
82  
-		self.submodules.dma = DMA(asmiport)
  82
+		self.submodules.dma = DMA(asmiport, n_dma_slots)
83 83
 		self.comb += self.frame.frame.connect(self.dma.frame)
  84
+		self.ev = self.dma.ev
  85
+
  86
+	autocsr_exclude = {"ev"}
162  milkymist/dvisampler/dma.py
... ...
@@ -1,48 +1,160 @@
1 1
 from migen.fhdl.structure import *
2 2
 from migen.fhdl.module import Module
  3
+from migen.genlib.fsm import FSM
3 4
 from migen.bank.description import *
  5
+from migen.bank.eventmanager import *
4 6
 from migen.flow.actor import *
5  
-from migen.actorlib import structuring, dma_asmi, spi
  7
+from migen.actorlib import dma_asmi
6 8
 
7 9
 from milkymist.dvisampler.common import frame_layout
8 10
 
  11
+# Slot status: EMPTY=0 LOADED=1 PENDING=2
  12
+class _Slot(Module, AutoCSR):
  13
+	def __init__(self, addr_bits, alignment_bits):
  14
+		self.ev_source = EventSourceLevel()
  15
+		self.address = Signal(addr_bits)
  16
+		self.address_valid = Signal()
  17
+		self.address_done = Signal()
  18
+
  19
+		self._r_status = CSRStorage(2, write_from_dev=True)
  20
+		self._r_address = CSRStorage(addr_bits + alignment_bits, alignment_bits=alignment_bits)
  21
+
  22
+		###
  23
+
  24
+		self.comb += [
  25
+			self.address.eq(self._r_address.storage),
  26
+			self.address_valid.eq(self._r_status.storage[0]),
  27
+			self._r_status.dat_w.eq(2),
  28
+			self._r_status.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.ev = EventManager()
  35
+		self.address = Signal(addr_bits)
  36
+		self.address_valid = Signal()
  37
+		self.address_done = Signal()
  38
+
  39
+		###
  40
+
  41
+		slots = [_Slot(addr_bits, alignment_bits) for i in range(nslots)]
  42
+		for n, slot in enumerate(slots):
  43
+			setattr(self.submodules, "slot"+str(n), slot)
  44
+			setattr(self.ev, "slot"+str(n), slot.ev_source)
  45
+		self.ev.finalize()
  46
+
  47
+		change_slot = Signal()
  48
+		current_slot = Signal(max=nslots)
  49
+		self.sync += If(change_slot, [If(slot.address_valid, current_slot.eq(n)) for n, slot in enumerate(slots)])
  50
+		self.comb += change_slot.eq(~self.address_valid | self.address_done)
  51
+
  52
+		self.comb += [
  53
+			self.address.eq(Array(slot.address for slot in slots)[current_slot]),
  54
+			self.address_valid.eq(Array(slot.address_valid for slot in slots)[current_slot])
  55
+		]
  56
+		self.comb += [slot.address_done.eq(self.address_done & (current_slot == n)) for n, slot in enumerate(slots)]
  57
+
9 58
 class DMA(Module):
10  
-	def __init__(self, asmiport):
  59
+	def __init__(self, asmiport, nslots):
  60
+		bus_aw = asmiport.hub.aw
  61
+		bus_dw = asmiport.hub.dw
  62
+		alignment_bits = bits_for(bus_dw//8) - 1
  63
+
11 64
 		self.frame = Sink(frame_layout)
12  
-		self.shoot = CSR()
  65
+		self._r_frame_size = CSRStorage(bus_aw + alignment_bits, alignment_bits=alignment_bits)
  66
+		self.submodules._slot_array = _SlotArray(nslots, bus_aw, alignment_bits)
  67
+		self.ev = self._slot_array.ev
13 68
 
14 69
 		###
15 70
 
  71
+		# start of frame detection
16 72
 		sof = Signal()
17 73
 		parity_r = Signal()
18  
-		self.comb += sof.eq(self.frame.stb & (parity_r ^ self.frame.payload.parity))
19 74
 		self.sync += If(self.frame.stb & self.frame.ack, parity_r.eq(self.frame.payload.parity))
  75
+		self.comb += sof.eq(parity_r ^ self.frame.payload.parity)
20 76
 
21  
-		pending = Signal()
22  
-		frame_en = Signal()
  77
+		# address generator + maximum memory word count to prevent DMA buffer overrun
  78
+		reset_words = Signal()
  79
+		count_word = Signal()
  80
+		last_word = Signal()
  81
+		current_address = Signal(bus_aw)
  82
+		mwords_remaining = Signal(bus_aw)
  83
+		self.comb += last_word.eq(mwords_remaining == 1)
23 84
 		self.sync += [
24  
-			If(sof,
25  
-				frame_en.eq(0),
26  
-				If(pending, frame_en.eq(1)),
27  
-				pending.eq(0)
28  
-			),
29  
-			If(self.shoot.re, pending.eq(1))
  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
+			)
30 92
 		]
31 93
 
32  
-		pack_factor = asmiport.hub.dw//32
33  
-		self.submodules.packer = structuring.Pack(list(reversed([("pad", 2), ("r", 10), ("g", 10), ("b", 10)])), pack_factor)
34  
-		self.submodules.cast = structuring.Cast(self.packer.source.payload.layout, asmiport.hub.dw, reverse_from=False)
35  
-		self.submodules.dma = spi.DMAWriteController(dma_asmi.Writer(asmiport), spi.MODE_EXTERNAL)
  94
+		# pack pixels into memory words
  95
+		write_pixel = Signal()
  96
+		last_pixel = Signal()
  97
+		cur_memory_word = Signal(bus_dw)
  98
+		encoded_pixel = Signal(32)
36 99
 		self.comb += [
37  
-			self.dma.generator.trigger.eq(self.shoot.re),
38  
-			self.packer.sink.stb.eq(self.frame.stb & frame_en),
39  
-			self.frame.ack.eq(self.packer.sink.ack | (~frame_en & ~(pending & sof))),
40  
-			self.packer.sink.payload.r.eq(self.frame.payload.r << 2),
41  
-			self.packer.sink.payload.g.eq(self.frame.payload.g << 2),
42  
-			self.packer.sink.payload.b.eq(self.frame.payload.b << 2),
43  
-			self.packer.source.connect(self.cast.sink, match_by_position=True),
44  
-			self.cast.source.connect(self.dma.data, match_by_position=True)
  100
+			encoded_pixel.eq(Cat(
  101
+				Replicate(0, 2), self.frame.payload.b,
  102
+				Replicate(0, 2), self.frame.payload.g,
  103
+				Replicate(0, 2), self.frame.payload.r))
45 104
 		]
  105
+		pack_factor = bus_dw//32
  106
+		assert(pack_factor & (pack_factor - 1) == 0) # only support powers of 2
  107
+		pack_counter = Signal(max=pack_factor)
  108
+		self.comb += last_pixel.eq(pack_counter == (pack_factor - 1))
  109
+		self.sync += If(write_pixel,
  110
+				[If(pack_counter == i, cur_memory_word[32*i:32*(i+1)].eq(encoded_pixel)) for i in range(pack_factor)],
  111
+				pack_counter.eq(pack_counter + 1)
  112
+			)
  113
+
  114
+		# bus accessor
  115
+		self.submodules._bus_accessor = dma_asmi.Writer(asmiport)
  116
+		self.comb += [
  117
+			self._bus_accessor.address_data.payload.a.eq(current_address),
  118
+			self._bus_accessor.address_data.payload.d.eq(cur_memory_word)
  119
+		]
  120
+
  121
+		# control FSM
  122
+		fsm = FSM("WAIT_SOF", "TRANSFER_PIXEL", "TO_MEMORY", "EOF")
  123
+		self.submodules += fsm
  124
+
  125
+		fsm.act(fsm.WAIT_SOF,
  126
+			self.frame.ack.eq(~sof),
  127
+			reset_words.eq(1),
  128
+			If(self._slot_array.address_valid,
  129
+				If(self.frame.stb & sof, fsm.next_state(fsm.TRANSFER_PIXEL))
  130
+			)
  131
+		)
  132
+		fsm.act(fsm.TRANSFER_PIXEL,
  133
+			self.frame.ack.eq(1),
  134
+			If(self.frame.stb,
  135
+				write_pixel.eq(1),
  136
+				If(last_pixel,
  137
+					fsm.next_state(fsm.TO_MEMORY)
  138
+				)
  139
+			)
  140
+		)
  141
+		fsm.act(fsm.TO_MEMORY,
  142
+			self._bus_accessor.address_data.stb.eq(1),
  143
+			If(self._bus_accessor.address_data.ack,
  144
+				count_word.eq(1),
  145
+				If(last_word,
  146
+					fsm.next_state(fsm.EOF)
  147
+				).Else(
  148
+					fsm.next_state(fsm.TRANSFER_PIXEL)
  149
+				)
  150
+			)
  151
+		)
  152
+		fsm.act(fsm.EOF,
  153
+			If(~self._bus_accessor.busy,
  154
+				self._slot_array.address_done.eq(1),
  155
+				fsm.next_state(fsm.WAIT_SOF)
  156
+			)
  157
+		)
46 158
 
47 159
 	def get_csrs(self):
48  
-		return [self.shoot] + self.dma.get_csrs()
  160
+		return [self._r_frame_size] + self._slot_array.get_csrs()
8  software/videomixer/main.c
@@ -26,12 +26,12 @@ static void print_status(void)
26 26
 
27 27
 static void capture_fb(void)
28 28
 {
29  
-	dvisampler0_dma_base_write((unsigned int)framebuffer);
30  
-	dvisampler0_dma_length_write(sizeof(framebuffer));
31  
-	dvisampler0_dma_shoot_write(1);
  29
+	dvisampler0_dma_frame_size_write(sizeof(framebuffer));
  30
+	dvisampler0_dma_slot0_address_write((unsigned int)framebuffer);
  31
+	dvisampler0_dma_slot0_status_write(1);
32 32
 
33 33
 	printf("waiting for DMA...");
34  
-	while(dvisampler0_dma_busy_read());
  34
+	while(dvisampler0_dma_slot0_status_read() != 2);
35 35
 	printf("done\n");
36 36
 }
37 37
 
5  top.py
@@ -83,6 +83,8 @@ class SoC(Module):
83 83
 		"uart":			0,
84 84
 		"timer0":		1,
85 85
 		"minimac":		2,
  86
+		"dvisampler0":  3,
  87
+		"dvisampler1":  4,
86 88
 	}
87 89
 
88 90
 	def __init__(self, platform):
@@ -153,7 +155,8 @@ def __init__(self, platform):
153 155
 		# Interrupts
154 156
 		#
155 157
 		for k, v in sorted(self.interrupt_map.items(), key=itemgetter(1)):
156  
-			self.comb += self.cpu.interrupt[v].eq(getattr(self, k).ev.irq)
  158
+			if hasattr(self, k):
  159
+				self.comb += self.cpu.interrupt[v].eq(getattr(self, k).ev.irq)
157 160
 
158 161
 		#
159 162
 		# Clocking

No commit comments for this range

Something went wrong with that request. Please try again.