litex/migen/actorlib/spi.py

190 lines
5.6 KiB
Python
Raw Normal View History

# Simple Processor Interface
from migen.fhdl.std import *
from migen.bank.description import *
from migen.flow.actor import *
2013-04-30 12:55:01 -04:00
from migen.flow.network import *
from migen.flow import plumbing
from migen.actorlib import misc
from migen.bank.eventmanager import *
2012-10-09 15:11:15 -04:00
# layout is a list of tuples, either:
# - (name, nbits, [reset value], [alignment bits])
2012-10-09 15:11:15 -04:00
# - (name, sublayout)
def _convert_layout(layout):
r = []
for element in layout:
if isinstance(element[1], list):
r.append((element[0], _convert_layout(element[1])))
else:
r.append((element[0], element[1]))
return r
(MODE_EXTERNAL, MODE_SINGLE_SHOT, MODE_CONTINUOUS) = range(3)
class SingleGenerator(Module, AutoCSR):
2012-10-09 15:11:15 -04:00
def __init__(self, layout, mode):
2013-04-10 13:12:42 -04:00
self.source = Source(_convert_layout(layout))
self.busy = Signal()
self.comb += self.busy.eq(self.source.stb)
2012-10-09 15:11:15 -04:00
if mode == MODE_EXTERNAL:
self.trigger = Signal()
trigger = self.trigger
2012-10-09 15:11:15 -04:00
elif mode == MODE_SINGLE_SHOT:
self._r_shoot = CSR()
trigger = self._r_shoot.re
2012-10-09 15:11:15 -04:00
elif mode == MODE_CONTINUOUS:
self._r_enable = CSRStorage()
trigger = self._r_enable.storage
2012-10-09 15:11:15 -04:00
else:
raise ValueError
self.sync += If(self.source.ack | ~self.source.stb, self.source.stb.eq(trigger))
self._create_csrs(layout, self.source.payload, mode != MODE_SINGLE_SHOT)
def _create_csrs(self, layout, target, atomic, prefix=""):
for element in layout:
if isinstance(element[1], list):
self._create_csrs(element[1], atomic,
getattr(target, element[0]),
element[0] + "_")
else:
name = element[0]
nbits = element[1]
if len(element) > 2:
reset = element[2]
else:
reset = 0
if len(element) > 3:
alignment = element[3]
else:
alignment = 0
regname = prefix + name
reg = CSRStorage(nbits + alignment, reset=reset, atomic_write=atomic,
alignment_bits=alignment, name=regname)
setattr(self, "r_"+regname, reg)
self.sync += If(self.source.ack | ~self.source.stb,
getattr(target, name).eq(reg.storage))
2012-10-09 15:11:15 -04:00
2013-04-10 13:12:42 -04:00
class Collector(Module, AutoCSR):
def __init__(self, layout, depth=1024):
2013-04-10 13:12:42 -04:00
self.sink = Sink(layout)
self.busy = Signal()
dw = sum(len(s) for s in self.sink.payload.flatten())
self._r_wa = CSRStorage(bits_for(depth-1), write_from_dev=True)
self._r_wc = CSRStorage(bits_for(depth), write_from_dev=True, atomic_write=True)
self._r_ra = CSRStorage(bits_for(depth-1))
self._r_rd = CSRStatus(dw)
2013-04-10 13:12:42 -04:00
###
mem = Memory(dw, depth)
2013-04-10 13:12:42 -04:00
self.specials += mem
2012-11-26 12:27:59 -05:00
wp = mem.get_port(write_capable=True)
rp = mem.get_port()
self.specials += wp, rp
2013-04-10 13:12:42 -04:00
self.comb += [
self.busy.eq(0),
2013-03-30 12:28:41 -04:00
If(self._r_wc.r != 0,
self.sink.ack.eq(1),
If(self.sink.stb,
2013-03-30 12:28:41 -04:00
self._r_wa.we.eq(1),
self._r_wc.we.eq(1),
2012-11-26 12:27:59 -05:00
wp.we.eq(1)
)
),
2013-03-30 12:28:41 -04:00
self._r_wa.dat_w.eq(self._r_wa.storage + 1),
self._r_wc.dat_w.eq(self._r_wc.storage - 1),
2013-03-30 12:28:41 -04:00
wp.adr.eq(self._r_wa.storage),
wp.dat_w.eq(self.sink.payload.raw_bits()),
2013-03-30 12:28:41 -04:00
rp.adr.eq(self._r_ra.storage),
self._r_rd.status.eq(rp.dat_r)
]
2013-04-30 12:55:01 -04:00
2013-05-04 11:38:54 -04:00
class _DMAController(Module):
def __init__(self, bus_accessor, bus_aw, bus_dw, mode, base_reset=0, length_reset=0, generate_irq=False):
2013-05-04 11:38:54 -04:00
self.alignment_bits = bits_for(bus_dw//8) - 1
2013-04-30 12:55:01 -04:00
layout = [
2013-05-04 11:38:54 -04:00
("length", bus_aw + self.alignment_bits, length_reset, self.alignment_bits),
("base", bus_aw + self.alignment_bits, base_reset, self.alignment_bits)
2013-04-30 12:55:01 -04:00
]
self.generator = SingleGenerator(layout, mode)
2013-05-04 11:38:54 -04:00
self.r_busy = CSRStatus()
self.length = self.generator.r_length.storage
self.base = self.generator.r_base.storage
if hasattr(self.generator, "trigger"):
self.trigger = self.generator.trigger
self.generate_irq = generate_irq
if generate_irq:
self.submodules.ev = EventManager()
self.ev.done = EventSourceProcess()
self.ev.finalize()
self.comb += self.ev.done.trigger.eq(self.r_busy.status)
2013-05-04 11:38:54 -04:00
def get_csrs(self):
csrs = self.generator.get_csrs() + [self.r_busy]
if self.generate_irq:
csrs += self.ev.get_csrs()
return csrs
2013-05-04 11:38:54 -04:00
class DMAReadController(_DMAController):
def __init__(self, bus_accessor, *args, **kwargs):
bus_aw = flen(bus_accessor.address.payload.a)
bus_dw = flen(bus_accessor.data.payload.d)
2013-05-04 11:38:54 -04:00
_DMAController.__init__(self, bus_accessor, bus_aw, bus_dw, *args, **kwargs)
2013-04-30 12:55:01 -04:00
g = DataFlowGraph()
g.add_pipeline(self.generator,
misc.IntSequence(bus_aw, bus_aw),
AbstractActor(plumbing.Buffer),
bus_accessor,
AbstractActor(plumbing.Buffer))
comp_actor = CompositeActor(g)
self.submodules += comp_actor
self.data = comp_actor.q
self.busy = comp_actor.busy
2013-05-04 11:38:54 -04:00
self.comb += self.r_busy.status.eq(self.busy)
class DMAWriteController(_DMAController):
def __init__(self, bus_accessor, *args, ack_when_inactive=False, **kwargs):
bus_aw = flen(bus_accessor.address_data.payload.a)
bus_dw = flen(bus_accessor.address_data.payload.d)
2013-05-04 11:38:54 -04:00
_DMAController.__init__(self, bus_accessor, bus_aw, bus_dw, *args, **kwargs)
2013-04-30 12:55:01 -04:00
2013-05-04 11:38:54 -04:00
g = DataFlowGraph()
adr_buffer = AbstractActor(plumbing.Buffer)
int_sequence = misc.IntSequence(bus_aw, bus_aw)
2013-05-04 11:38:54 -04:00
g.add_pipeline(self.generator,
int_sequence,
2013-05-04 11:38:54 -04:00
adr_buffer)
g.add_connection(adr_buffer, bus_accessor, sink_subr=["a"])
g.add_connection(AbstractActor(plumbing.Buffer), bus_accessor, sink_subr=["d"])
comp_actor = CompositeActor(g)
self.submodules += comp_actor
if ack_when_inactive:
demultiplexer = plumbing.Demultiplexer(comp_actor.d.payload.layout, 2)
self.comb +=[
demultiplexer.sel.eq(~adr_buffer.busy),
demultiplexer.source0.connect(comp_actor.d),
demultiplexer.source1.ack.eq(1),
]
self.submodules += demultiplexer
self.data = demultiplexer.sink
else:
self.data = comp_actor.d
2013-05-04 11:38:54 -04:00
self.busy = comp_actor.busy
self.comb += self.r_busy.status.eq(self.busy)