{ stdenv, fetchgit, python3Packages, nmigen }: python3Packages.buildPythonPackage { name = "litex"; src = fetchgit { url = "git://github.com/enjoy-digital/litex.git"; rev = "33d7cc5fc81cc7785be217f64d756db6092aeff6"; sha256 = "1qpbkn9440175qm5myaalv3nr2sq4fhpz6dicgjv62j907w05wnv"; fetchSubmodules = true; }; patchPhase = '' # those won't be supported rm -rf litex/gen rm -rf litex/build rm -rf litex/boards rm test/test_targets.py # may be supported later rm -rf litex/soc/integration # FIXME: this spews out a lot of irrelevant "pattern doesn't match anything" warnings for file in `find test litex -name "*.py"`; do substituteInPlace "$file" \ --replace "from migen.util.misc import xdir" "from litex.compat import xdir" \ --replace "from migen.genlib.roundrobin import *" "from litex.roundrobin import *" \ --replace "from migen.genlib import roundrobin" "from litex import roundrobin" \ --replace "migen.genlib.misc" "litex.misc" \ --replace "migen.fhdl.tracer" "litex.compat" \ --replace migen nmigen.compat done # BufferizeEndpoints is actually not used anywhere in LiteX, but breaks due to no ModuleTransformer substituteInPlace litex/soc/interconnect/stream.py --replace ModuleTransformer object # this import is not required substituteInPlace litex/soc/interconnect/stream_packet.py --replace "from litex.gen import *" "" # we do not need the alternative simulator substituteInPlace test/test_axi.py --replace "from litex.gen.sim import *" "" cat > litex/compat.py << EOF from nmigen.compat import * from nmigen.tracer import get_var_name def xdir(obj, return_values=False): for attr in dir(obj): if attr[:2] != "__" and attr[-2:] != "__": if return_values: yield attr, getattr(obj, attr) else: yield attr def get_obj_var_name(name): if name is None: return get_var_name() else: return name EOF cat > litex/roundrobin.py << EOF from nmigen.compat import * (SP_WITHDRAW, SP_CE) = range(2) class RoundRobin(Module): def __init__(self, n, switch_policy=SP_WITHDRAW): self.request = Signal(n) self.grant = Signal(max=max(2, n)) self.switch_policy = switch_policy if self.switch_policy == SP_CE: self.ce = Signal() ### if n > 1: cases = {} for i in range(n): switch = [] for j in reversed(range(i+1, i+n)): t = j % n switch = [ If(self.request[t], self.grant.eq(t) ).Else( *switch ) ] if self.switch_policy == SP_WITHDRAW: case = [If(~self.request[i], *switch)] else: case = switch cases[i] = case statement = Case(self.grant, cases) if self.switch_policy == SP_CE: statement = If(self.ce, statement) self.sync += statement else: self.comb += self.grant.eq(0) EOF cat > litex/misc.py << EOF from nmigen.compat import * def split(v, *counts): r = [] offset = 0 for n in counts: if n != 0: r.append(v[offset:offset+n]) else: r.append(None) offset += n return tuple(r) def displacer(signal, shift, output, n=None, reverse=False): if shift is None: return output.eq(signal) if n is None: n = 2**len(shift) w = len(signal) if reverse: r = reversed(range(n)) else: r = range(n) l = [Replicate(shift == i, w) & signal for i in r] return output.eq(Cat(*l)) def chooser(signal, shift, output, n=None, reverse=False): if shift is None: return output.eq(signal) if n is None: n = 2**len(shift) w = len(output) cases = {} for i in range(n): if reverse: s = n - i - 1 else: s = i cases[i] = [output.eq(signal[s*w:(s+1)*w])] return Case(shift, cases).makedefault() def timeline(trigger, events): lastevent = max([e[0] for e in events]) counter = Signal(max=lastevent+1) counterlogic = If(counter != 0, counter.eq(counter + 1) ).Elif(trigger, counter.eq(1) ) # insert counter reset if it doesn't naturally overflow # (test if lastevent+1 is a power of 2) if (lastevent & (lastevent + 1)) != 0: counterlogic = If(counter == lastevent, counter.eq(0) ).Else( counterlogic ) def get_cond(e): if e[0] == 0: return trigger & (counter == 0) else: return counter == e[0] sync = [If(get_cond(e), *e[1]) for e in events] sync.append(counterlogic) return sync class WaitTimer(Module): def __init__(self, t): self.wait = Signal() self.done = Signal() # # # count = Signal(bits_for(t), reset=t) self.comb += self.done.eq(count == 0) self.sync += \ If(self.wait, If(~self.done, count.eq(count - 1)) ).Else(count.eq(count.reset)) class BitSlip(Module): def __init__(self, dw): self.i = Signal(dw) self.o = Signal(dw) self.value = Signal(max=dw) # # # r = Signal(2*dw) self.sync += r.eq(Cat(r[dw:], self.i)) cases = {} for i in range(dw): cases[i] = self.o.eq(r[i:dw+i]) self.sync += Case(self.value, cases) EOF ''; propagatedBuildInputs = [ python3Packages.pyserial nmigen ]; meta = with stdenv.lib; { description = "Partial LiteX cores and tools (via nMigen compatibility mode)"; homepage = "http://enjoy-digital.fr"; license = licenses.bsd2; maintainers = [ maintainers.sb0 ]; }; }