from migen import * from migen.genlib.cdc import MultiReg from migen.genlib.io import DifferentialInput, DifferentialOutput from artiq.gateware.rtio import rtlink class Output(Module): def __init__(self, pad, pad_n=None): self.rtlink = rtlink.Interface(rtlink.OInterface(1)) pad_o = Signal(reset_less=True) self.probes = [pad_o] override_en = Signal() override_o = Signal() self.overrides = [override_en, override_o] # # # pad_k = Signal() self.sync.rio_phy += [ If(self.rtlink.o.stb, pad_k.eq(self.rtlink.o.data) ), If(override_en, pad_o.eq(override_o) ).Else( pad_o.eq(pad_k) ) ] if pad_n is None: self.comb += pad.eq(pad_o) else: self.specials += DifferentialOutput(pad_o, pad, pad_n) class Input(Module): def __init__(self, pad, pad_n=None): self.rtlink = rtlink.Interface( rtlink.OInterface(2, 2), rtlink.IInterface(1)) self.overrides = [] self.probes = [] #: Registered copy of the input state, in the rio_phy clock domain. self.input_state = Signal() # # # sensitivity = Signal(2) sample = Signal() self.sync.rio += [ sample.eq(0), If(self.rtlink.o.stb & self.rtlink.o.address[1], sensitivity.eq(self.rtlink.o.data), If(self.rtlink.o.address[0], sample.eq(1)) ) ] i = Signal() i_d = Signal(reset_less=True) pad_i = Signal() if pad_n is None: self.comb += pad_i.eq(pad) else: self.specials += DifferentialInput(pad, pad_n, pad_i) self.specials += MultiReg(pad_i, i, "rio_phy") self.sync.rio_phy += i_d.eq(i) self.comb += [ self.rtlink.i.stb.eq( sample | (sensitivity[0] & ( i & ~i_d)) | (sensitivity[1] & (~i & i_d)) ), self.rtlink.i.data.eq(i), self.input_state.eq(i) ] self.probes += [i] class InOut(Module): def __init__(self, pad): self.rtlink = rtlink.Interface( rtlink.OInterface(2, 2), rtlink.IInterface(1)) override_en = Signal() override_o = Signal() override_oe = Signal() self.overrides = [override_en, override_o, override_oe] self.probes = [] # Output enable, for interfacing to external buffers. self.oe = Signal() # Registered copy of the input state, in the rio_phy clock domain. self.input_state = Signal() # # # ts = TSTriple() self.specials += ts.get_tristate(pad) sensitivity = Signal(2) o_k = Signal() oe_k = Signal() self.oe.attr.add("no_retiming") self.sync.rio_phy += [ If(self.rtlink.o.stb, If(self.rtlink.o.address == 0, o_k.eq(self.rtlink.o.data[0])), If(self.rtlink.o.address == 1, oe_k.eq(self.rtlink.o.data[0])), ), If(override_en, ts.o.eq(override_o), self.oe.eq(override_oe) ).Else( ts.o.eq(o_k), self.oe.eq(oe_k) ) ] self.comb += ts.oe.eq(self.oe) sample = Signal() self.sync.rio += [ sample.eq(0), If(self.rtlink.o.stb & self.rtlink.o.address[1], sensitivity.eq(self.rtlink.o.data), If(self.rtlink.o.address[0], sample.eq(1)) ) ] i = Signal() i_d = Signal() self.specials += MultiReg(ts.i, i, "rio_phy") self.sync.rio_phy += i_d.eq(i) self.comb += [ self.rtlink.i.stb.eq( sample | (sensitivity[0] & ( i & ~i_d)) | (sensitivity[1] & (~i & i_d)) ), self.rtlink.i.data.eq(i), self.input_state.eq(i) ] self.probes += [i, ts.oe] class ClockGen(Module): def __init__(self, pad, pad_n=None, ftw_width=24, dci=False): self.rtlink = rtlink.Interface(rtlink.OInterface(ftw_width)) # # # pad_o = Signal() if pad_n is None: self.comb += pad.eq(pad_o) else: self.specials += DifferentialOutput(pad_o, pad, pad_n) ftw = Signal(ftw_width) acc = Signal(ftw_width) self.sync.rio += If(self.rtlink.o.stb, ftw.eq(self.rtlink.o.data)) self.sync.rio_phy += [ acc.eq(acc + ftw), # rtlink takes precedence over regular acc increments If(self.rtlink.o.stb, If(self.rtlink.o.data != 0, # known phase on frequency write: at rising edge acc.eq(2**(ftw_width - 1)) ).Else( # set output to 0 on stop acc.eq(0) ) ), pad_o.eq(acc[-1]) ]