litex/migen/actorlib/control.py

95 lines
2.7 KiB
Python

from operator import mul
from functools import reduce
from migen.fhdl.structure import *
from migen.corelogic.record import *
from migen.corelogic.fsm import *
from migen.flow.actor import *
# Generates integers from start to maximum-1
class For(Actor):
def __init__(self, *nbits, start=False, step=False):
self.dimensions = len(nbits)
self.start = start
self.step = step
params = ["end"]
if start: params.append("start")
if step: params.append("step")
self.d_bv = [BV(dimension) for dimension in nbits]
l_sink = [("d{0}".format(n), [(p, bv) for p in params])
for n, bv in enumerate(self.d_bv)]
l_source = [("d{0}".format(n), bv)
for n, bv in enumerate(self.d_bv)]
super().__init__(
("sink", Sink, l_sink),
("source", Source, l_source))
def get_fragment(self):
load = Signal()
ce = Signal()
last = Signal()
counters_v = [Signal(bv, variable=True) for bv in self.d_bv]
counters = [getattr(self.token("source"), "d{0}".format(n))
for n in range(self.dimensions)]
params = [getattr(self.token("sink"), "d{0}".format(n))
for n in range(self.dimensions)]
if self.start:
starts = [p.start for p in params]
start_rs = [Signal(s.bv, variable=True) for s in starts]
else:
start_rs = [Constant(0, bv) for bv in self.d_bv]
if self.step:
steps = [p.step for p in params]
step_rs = [Signal(s.bv, variable=True) for s in steps]
else:
step_rs = [Constant(1, bv) for bv in self.d_bv]
ends = [p.end for p in params]
end_rs = [Signal(s.bv, variable=True) for s in ends]
lasts = Signal(BV(self.dimensions))
on_ce = [
If(lasts[n],
counter.eq(start)
).Else(
counter.eq(counter + step)
)
for n, counter, start, step
in zip(range(self.dimensions), counters_v, start_rs, step_rs)
]
lasts_gen = [
lasts[n].eq(counter + step >= end if self.step else counter + step == end)
for n, counter, step, end
in zip(range(self.dimensions), counters_v, step_rs, end_rs)
]
sync = [
If(load,
Cat(*start_rs).eq(Cat(*starts)) if self.start else None,
Cat(*step_rs).eq(Cat(*steps)) if self.step else None,
Cat(*end_rs).eq(Cat(*ends)),
Cat(*counters_v).eq(Cat(*start_rs))
),
If(ce, *on_ce)
] + lasts_gen + [
Cat(*counters).eq(Cat(*counters_v))
]
counters_fragment = Fragment(sync=sync)
fsm = FSM("IDLE", "ACTIVE")
fsm.act(fsm.IDLE,
load.eq(1),
self.endpoints["sink"].ack.eq(1),
If(self.endpoints["sink"].stb, fsm.next_state(fsm.ACTIVE))
)
fsm.act(fsm.ACTIVE,
self.busy.eq(1),
self.endpoints["source"].stb.eq(1),
If(self.endpoints["source"].ack,
ce.eq(1),
If(last, fsm.next_state(fsm.IDLE))
)
)
return counters_fragment + fsm.get_fragment()