artiq/artiq/gateware/ad9xxx.py

192 lines
5.4 KiB
Python
Raw Normal View History

2014-07-23 01:37:53 +08:00
from migen.fhdl.std import *
from migen.genlib.fsm import *
from migen.genlib.misc import WaitTimer
2014-07-23 01:37:53 +08:00
from migen.bus import wishbone
from migen.bus.transactions import *
from migen.sim.generic import run_simulation
2014-09-05 12:03:22 +08:00
2015-06-29 03:37:27 +08:00
class AD9xxx(Module):
"""Wishbone interface to the AD9858 and AD9914 DDS chips.
2014-09-05 12:03:22 +08:00
2015-06-29 03:37:27 +08:00
Addresses 0-2**flen(pads.a)-1 map the AD9xxx registers.
2014-09-05 12:03:22 +08:00
2015-06-29 03:37:27 +08:00
Write to address 2**flen(pads.a) to pulse the FUD signal.
Address 2**flen(pads.a)+1 is a GPIO register that controls the
sel and reset signals. sel is mapped to the lower bits, followed by reset.
2014-09-05 12:03:22 +08:00
Write timing:
Address is set one cycle before assertion of we_n.
we_n is asserted for one cycle, at the same time as valid data is driven.
Read timing:
Address is set one cycle before assertion of rd_n.
rd_n is asserted for read_wait_cycles, data is sampled at the end.
rd_n is deasserted and data bus is not driven again before hiz_wait_cycles.
2014-09-05 12:03:22 +08:00
Design:
All IO pads are registered.
2015-06-29 03:37:27 +08:00
With QC1 adapter:
2014-09-05 12:03:22 +08:00
LVDS driver/receiver propagation delays are 3.6+4.5 ns max
LVDS state transition delays are 20, 15 ns max
Schmitt trigger delays are 6.4ns max
Round-trip addr A setup (> RX, RD, D to Z), RD prop, D valid (< D
valid), D prop is ~15 + 10 + 20 + 10 = 55ns
"""
def __init__(self, pads,
read_wait_cycles=10, hiz_wait_cycles=3,
bus=None):
2014-09-05 12:03:22 +08:00
if bus is None:
2015-06-29 03:37:27 +08:00
bus = wishbone.Interface(data_width=flen(pads.d))
2014-09-05 12:03:22 +08:00
self.bus = bus
# # #
2015-06-29 03:37:27 +08:00
dts = TSTriple(flen(pads.d))
2014-09-05 12:03:22 +08:00
self.specials += dts.get_tristate(pads.d)
hold_address = Signal()
2015-06-29 03:37:27 +08:00
dr = Signal(flen(pads.d))
2014-09-05 12:03:22 +08:00
rx = Signal()
self.sync += [
If(~hold_address, pads.a.eq(bus.adr)),
2014-09-05 12:03:22 +08:00
dts.o.eq(bus.dat_w),
dr.eq(dts.i),
dts.oe.eq(~rx)
]
2015-06-29 03:37:27 +08:00
gpio = Signal(flen(pads.sel) + 1)
2014-09-05 12:03:22 +08:00
gpio_load = Signal()
self.sync += If(gpio_load, gpio.eq(bus.dat_w))
2015-06-29 03:37:27 +08:00
self.comb += pads.sel.eq(gpio),
if hasattr(pads, "rst"):
self.comb += pads.rst.eq(gpio[-1])
else:
self.comb += pads.rst_n.eq(~gpio[-1])
2014-09-05 12:03:22 +08:00
bus_r_gpio = Signal()
self.comb += If(bus_r_gpio,
bus.dat_r.eq(gpio)
).Else(
bus.dat_r.eq(dr)
)
fud = Signal()
2015-06-29 03:37:27 +08:00
if hasattr(pads, "fud"):
self.sync += pads.fud.eq(fud)
else:
self.sync += pads.fud_n.eq(~fud)
2014-09-05 12:03:22 +08:00
pads.wr_n.reset = 1
pads.rd_n.reset = 1
wr = Signal()
rd = Signal()
self.sync += pads.wr_n.eq(~wr), pads.rd_n.eq(~rd)
self.submodules.read_timer = WaitTimer(read_wait_cycles)
self.submodules.hiz_timer = WaitTimer(hiz_wait_cycles)
2014-09-05 12:03:22 +08:00
fsm = FSM("IDLE")
self.submodules += fsm
fsm.act("IDLE",
If(bus.cyc & bus.stb,
2015-06-29 03:37:27 +08:00
If(bus.adr[flen(pads.a)],
2014-09-05 12:03:22 +08:00
If(bus.adr[0],
NextState("GPIO")
).Else(
NextState("FUD")
2014-09-05 12:03:22 +08:00
)
).Else(
If(bus.we,
NextState("WRITE")
).Else(
NextState("READ")
)
)
)
)
fsm.act("WRITE",
# 3ns A setup to WR active
wr.eq(1),
NextState("WRITE0")
)
fsm.act("WRITE0",
# 3.5ns D setup to WR inactive
# 0ns D and A hold to WR inactive
bus.ack.eq(1),
NextState("IDLE")
)
fsm.act("READ",
# 15ns D valid to A setup
# 15ns D valid to RD active
rx.eq(1),
rd.eq(1),
self.read_timer.wait.eq(1),
If(self.read_timer.done,
bus.ack.eq(1),
NextState("WAIT_HIZ")
)
2014-09-05 12:03:22 +08:00
)
fsm.act("WAIT_HIZ",
2014-09-05 12:03:22 +08:00
rx.eq(1),
# For some reason, AD9858 has an address hold time to RD inactive.
hold_address.eq(1),
self.hiz_timer.wait.eq(1),
If(self.hiz_timer.done, NextState("IDLE"))
2014-09-05 12:03:22 +08:00
)
fsm.act("FUD",
# 4ns FUD setup to SYNCLK
# 0ns FUD hold to SYNCLK
fud.eq(1),
bus.ack.eq(1),
NextState("IDLE")
)
2014-09-05 12:03:22 +08:00
fsm.act("GPIO",
bus.ack.eq(1),
bus_r_gpio.eq(1),
If(bus.we, gpio_load.eq(1)),
NextState("IDLE")
)
2014-07-23 01:37:53 +08:00
def _test_gen():
2014-09-05 12:03:22 +08:00
# Test external bus writes
yield TWrite(4, 2)
yield TWrite(5, 3)
yield
# Test external bus reads
yield TRead(14)
yield TRead(15)
yield
# Test FUD
yield TWrite(64, 0)
yield
# Test GPIO
yield TWrite(65, 0xff)
yield
2014-07-23 01:37:53 +08:00
class _TestPads:
2014-09-05 12:03:22 +08:00
def __init__(self):
self.a = Signal(6)
self.d = Signal(8)
self.sel = Signal(5)
self.fud_n = Signal()
self.wr_n = Signal()
self.rd_n = Signal()
self.rst_n = Signal()
2014-07-23 01:37:53 +08:00
class _TB(Module):
2014-09-05 12:03:22 +08:00
def __init__(self):
pads = _TestPads()
2015-06-29 03:37:27 +08:00
self.submodules.dut = AD9xxx(pads, drive_fud=True)
2014-09-05 12:03:22 +08:00
self.submodules.initiator = wishbone.Initiator(_test_gen())
2014-09-05 17:06:41 +08:00
self.submodules.interconnect = wishbone.InterconnectPointToPoint(
self.initiator.bus, self.dut.bus)
2014-09-05 12:03:22 +08:00
2014-07-23 01:37:53 +08:00
if __name__ == "__main__":
2015-06-29 03:37:27 +08:00
run_simulation(_TB(), vcd_name="ad9xxx.vcd")