actorlib: LASMI DMA (untested)
authorSebastien Bourdeauducq <sebastien@milkymist.org>
Mon, 10 Jun 2013 20:29:39 +0000 (22:29 +0200)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Mon, 10 Jun 2013 20:29:39 +0000 (22:29 +0200)
migen/actorlib/dma_lasmi.py [new file with mode: 0644]

diff --git a/migen/actorlib/dma_lasmi.py b/migen/actorlib/dma_lasmi.py
new file mode 100644 (file)
index 0000000..3a0956e
--- /dev/null
@@ -0,0 +1,107 @@
+from migen.fhdl.std import *
+from migen.flow.actor import *
+from migen.genlib.fifo import SyncFIFO
+
+class Reader(Module):
+       def __init__(self, lasmim, fifo_depth=None):
+               self.address = Sink([("a", lasmim.aw)])
+               self.data = Source([("d", lasmim.dw)])
+               self.busy = Signal()
+       
+               ###
+
+               if fifo_depth is None:
+                       fifo_depth = lasmim.read_latency + 2
+               assert(fifo_depth >= lasmim.read_latency)
+       
+               # request issuance
+               request_enable = Signal()
+               request_issued = Signal()
+
+               self.comb += [
+                       self.bus.we.eq(0),
+                       lasmim.stb.eq(self.address.stb & request_enable),
+                       lasmim.adr.eq(self.address.payload.a),
+                       self.address.ack.eq(lasmim.ack),
+                       request_issued.eq(lasmim.stb & lasmim.ack)
+               ]
+
+               # FIFO reservation level counter
+               # incremented when data is planned to be queued
+               # decremented when data is dequeued
+               data_dequeued = Signal()
+               rsv_level = Signal(max=fifo_depth+1)
+               self.sync += [
+                       If(request_issued,
+                               If(~data_dequeued, rsv_level.eq(rsv_level + 1))
+                       ).Elif(data_dequeued,
+                               rsv_level.eq(rsv_level - 1)
+                       )
+               ]
+               self.comb += [
+                       self.busy.eq(rsv_level != 0),
+                       request_enable.eq(rsv_level != fifo_depth)
+               ]
+
+               # data available
+               data_available = request_issued
+               for i in range(lasmim.read_latency):
+                       new_data_available = Signal()
+                       self.sync += new_data_available.eq(data_available)
+                       data_available = new_data_available
+
+               # FIFO
+               fifo = SyncFIFO(lasmim.dw, fifo_depth)
+               self.submodules += fifo
+
+               self.comb += [
+                       fifo.din.eq(lasmim.dat_r),
+                       fifo.we.eq(data_available),
+
+                       self.data.stb.eq(fifo.readable),
+                       fifo.re.eq(self.data.ack),
+                       self.data.payload.d.eq(fifo.dout),
+                       data_dequeued.eq(self.data.stb & self.data.ack)
+               ]
+
+
+class Writer(Module):
+       def __init__(self, lasmim):
+               self.address_data = Sink([("a", lasmim.aw), ("d", lasmim.dw)])
+               self.busy = Signal()
+
+               ###
+
+               self.comb += [
+                       lasmim.we.eq(1),
+                       lasmim.stb.eq(self.address_data.stb),
+                       lasmim.adr.eq(self.address_data.payload.a),
+                       self.address_data.ack.eq(lasmim.ack)
+               ]
+
+               busy_expr = 0
+               data_valid = Signal()
+               data = Signal(lasmim.dw)
+               self.comb += [
+                       data_valid.eq(lasmim.stb & lasmim.ack),
+                       data.eq(self.address_data.payload.d)
+               ]
+
+               for i in range(lasmim.write_latency):
+                       new_data_valid = Signal()
+                       new_data = Signal(lasmim.dw)
+                       self.sync += [
+                               new_data_valid.eq(data_valid),
+                               new_data.eq(data)
+                       ]
+                       busy_expr = busy_expr | new_data_valid
+                       data_valid = new_data_valid
+                       data = new_data
+
+               self.comb += [
+                       If(data_valid,
+                               lasmim.dat_we.eq(2**(lasmim.dw//8)-1),
+                               lasmim.dat_w.eq(data)
+                       ),
+                       self.busy.eq(busy_expr)
+               ]