litex/migen/actorlib/spi.py

118 lines
3.1 KiB
Python
Raw Normal View History

# Simple Processor Interface
from migen.fhdl.structure import *
2013-02-22 11:56:35 -05:00
from migen.fhdl.specials import Memory
from migen.bank.description import *
from migen.flow.actor 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
2013-03-30 12:28:41 -04:00
def _create_csrs_assign(layout, target, atomic, prefix=""):
csrs = []
2012-10-09 15:11:15 -04:00
assigns = []
for element in layout:
if isinstance(element[1], list):
2013-03-30 12:28:41 -04:00
r_csrs, r_assigns = _create_csrs_assign(element[1],
2012-10-09 15:11:15 -04:00
atomic,
getattr(target, element[0]),
element[0] + "_")
2013-03-30 12:28:41 -04:00
csrs += r_csrs
2012-10-09 15:11:15 -04:00
assigns += r_assigns
else:
name = element[0]
nbits = element[1]
2012-10-09 15:11:15 -04:00
if len(element) > 2:
reset = element[2]
else:
reset = 0
if len(element) > 3:
alignment = element[3]
else:
alignment = 0
2013-03-30 12:28:41 -04:00
reg = CSRStorage(nbits + alignment, reset=reset, atomic_write=atomic, name=prefix + name)
csrs.append(reg)
assigns.append(getattr(target, name).eq(reg.storage[alignment:]))
return csrs, assigns
2012-10-09 15:11:15 -04:00
(MODE_EXTERNAL, MODE_SINGLE_SHOT, MODE_CONTINUOUS) = range(3)
class SingleGenerator(Actor):
def __init__(self, layout, mode):
self._mode = mode
2012-12-18 08:54:33 -05:00
Actor.__init__(self, ("source", Source, _convert_layout(layout)))
2013-03-30 12:28:41 -04:00
self._csrs, self._assigns = _create_csrs_assign(layout,
2012-10-09 15:11:15 -04:00
self.token("source"), self._mode != MODE_SINGLE_SHOT)
if mode == MODE_EXTERNAL:
self.trigger = Signal()
elif mode == MODE_SINGLE_SHOT:
2013-03-30 12:28:41 -04:00
shoot = CSR()
self._csrs.insert(0, shoot)
2012-10-09 15:11:15 -04:00
self.trigger = shoot.re
elif mode == MODE_CONTINUOUS:
2013-03-30 12:28:41 -04:00
enable = CSRStorage()
self._csrs.insert(0, enable)
self.trigger = enable.storage
2012-10-09 15:11:15 -04:00
else:
raise ValueError
2013-03-30 12:28:41 -04:00
def get_csrs(self):
return self._csrs
2012-10-09 15:11:15 -04:00
def get_fragment(self):
stb = self.endpoints["source"].stb
ack = self.endpoints["source"].ack
comb = [
self.busy.eq(stb)
]
stmts = [stb.eq(self.trigger)] + self._assigns
sync = [If(ack | ~stb, *stmts)]
return Fragment(comb, sync)
2013-03-30 12:28:41 -04:00
class Collector(Actor, AutoCSR):
def __init__(self, layout, depth=1024):
2012-12-18 08:54:33 -05:00
Actor.__init__(self, ("sink", Sink, layout))
self._depth = depth
self._dw = sum(len(s) for s in self.token("sink").flatten())
2013-03-30 12:28:41 -04:00
self._r_wa = CSRStorage(bits_for(self._depth-1), write_from_dev=True)
self._r_wc = CSRStorage(bits_for(self._depth), write_from_dev=True, atomic_write=True)
self._r_ra = CSRStorage(bits_for(self._depth-1))
self._r_rd = CSRStatus(self._dw)
def get_fragment(self):
2012-11-26 12:27:59 -05:00
mem = Memory(self._dw, self._depth)
wp = mem.get_port(write_capable=True)
rp = mem.get_port()
comb = [
2013-03-30 12:28:41 -04:00
If(self._r_wc.r != 0,
self.endpoints["sink"].ack.eq(1),
If(self.endpoints["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),
2012-11-26 12:27:59 -05:00
wp.dat_w.eq(Cat(*self.token("sink").flatten())),
2013-03-30 12:28:41 -04:00
rp.adr.eq(self._r_ra.storage),
self._r_rd.status.eq(rp.dat_r)
]
2013-02-22 11:56:35 -05:00
return Fragment(comb, specials={mem})