diff --git a/artiq/gateware/drtio/cdc.py b/artiq/gateware/drtio/cdc.py new file mode 100644 index 000000000..9edd8a1b4 --- /dev/null +++ b/artiq/gateware/drtio/cdc.py @@ -0,0 +1,55 @@ +from migen import * + +from migen.genlib.cdc import PulseSynchronizer + + +class CrossDomainRequest(Module): + def __init__(self, domain, + req_stb, req_ack, req_data, + srv_stb, srv_ack, srv_data): + dsync = getattr(self.sync, domain) + + request = PulseSynchronizer("sys", domain) + reply = PulseSynchronizer(domain, "sys") + self.submodules += request, reply + + ongoing = Signal() + self.comb += request.i.eq(~ongoing & req_stb) + self.sync += [ + req_ack.eq(reply.o), + If(req_stb, ongoing.eq(1)), + If(req_ack, ongoing.eq(0)) + ] + if req_data is not None: + req_data_r = Signal.like(req_data) + req_data_r.attr.add("no_retiming") + self.sync += If(req_stb, req_data_r.eq(req_data)) + dsync += [ + If(request.o, srv_stb.eq(1)), + If(srv_ack, srv_stb.eq(0)) + ] + if req_data is not None: + dsync += If(request.o, srv_data.eq(req_data_r)) + self.comb += reply.i.eq(srv_stb & srv_ack) + + +class CrossDomainNotification(Module): + def __init__(self, domain, rdomain, + emi_stb, emi_data, + rec_stb, rec_ack, rec_data): + emi_data_r = Signal(len(emi_data)) + emi_data_r.attr.add("no_retiming") + dsync = getattr(self.sync, domain) + dsync += If(emi_stb, emi_data_r.eq(emi_data)) + + ps = PulseSynchronizer(domain, rdomain) + self.submodules += ps + self.comb += ps.i.eq(emi_stb) + rsync = getattr(self.sync, rdomain) + rsync += [ + If(rec_ack, rec_stb.eq(0)), + If(ps.o, + rec_data.eq(emi_data_r), + rec_stb.eq(1) + ) + ] diff --git a/artiq/gateware/rtio/tsc.py b/artiq/gateware/rtio/tsc.py new file mode 100644 index 000000000..e93744553 --- /dev/null +++ b/artiq/gateware/rtio/tsc.py @@ -0,0 +1,48 @@ +from migen import * + +from artiq.gateware.rtio.cdc import GrayCodeTransfer + + +class TSC(Module): + def __init__(self, mode, glbl_fine_ts_width=0): + self.glbl_fine_ts_width = glbl_fine_ts_width + + # in rtio domain + self.coarse_ts = Signal(64 - glbl_fine_ts_width) + self.full_ts = Signal(64) + + # in sys domain + # monotonic, may lag behind the counter in the IO clock domain, but + # not be ahead of it. + self.coarse_ts_sys = Signal.like(self.coarse_ts) + self.full_ts_sys = Signal(64) + + # in rtio domain + self.load = Signal() + self.load_value = Signal.like(self.coarse_ts) + + if mode == "async": + self.full_ts_cri = self.full_ts_sys + elif mode == "sync": + self.full_ts_cri = self.full_ts + else: + raise ValueError + + # # # + + self.sync.rtio += If(self.load, + self.coarse_ts.eq(self.load_value) + ).Else( + self.coarse_ts.eq(self.coarse_ts + 1) + ) + coarse_ts_cdc = GrayCodeTransfer(len(self.coarse_ts)) # from rtio to sys + self.submodules += coarse_ts_cdc + self.comb += [ + coarse_ts_cdc.i.eq(self.coarse_ts), + self.coarse_ts_sys.eq(coarse_ts_cdc.o) + ] + + self.comb += [ + self.full_ts.eq(self.coarse_ts << glbl_fine_ts_width), + self.full_ts_sys.eq(self.coarse_ts_sys << glbl_fine_ts_width) + ]