diff --git a/Makefile b/Makefile index 667b8e7..ed97303 100644 --- a/Makefile +++ b/Makefile @@ -8,9 +8,15 @@ test: .PHONY: build build: build/mirny.vm6 +.PHONY: legacy_almazny +legacy_almazny: build/mirny_legacy_almazny.vm6 + build/mirny.vm6: mirny.py mirny_cpld.py python mirny_impl.py +build/mirny_legacy_almazny.vm6: mirny.py mirny_cpld.py + python mirny_impl.py --legacy-almazny + REV:=$(shell git describe --always --abbrev=8 --dirty) .PHONY: release diff --git a/README.md b/README.md index 1bea35a..5e93809 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,39 @@ -# Mirny CPLD code +# Mirny CPLD gateware -[Mirny overview](https://github.com/sinara-hw/mirny/wiki) +## Hardware + +[![Hardware](https://github.com/sinara-hw/mirny/wiki/Mirny_v1.0_top_small.jpg)](https://github.com/sinara-hw/mirny/wiki) [Mirny Schematics](https://github.com/sinara-hw/mirny/releases) ## Building -Needs migen and ISE. +Needs [migen](https://github.com/m-labs/migen) and [Xilinx ISE](https://www.xilinx.com/products/design-tools/ise-design-suite.html). Assumes ISE is installed in ``/opt/Xilinx``. ``` make -# and then look at/use flash.sh or make flash - -# or use fxload and xc3sprog: -/sbin/fxload -t fx2 -I /opt/Xilinx/14.7/ISE_DS/ISE/bin/lin64/xusb_xp2.hex -D /dev/bus/usb/001/*`cat /sys/bus/usb/devices/1-3/devnum` && sleep 10 && \ -xc3sprog -c xpc -m /opt/Xilinx/14.7/ISE_DS/ISE/xbr/data -v build/mirny.jed:w -# look for "Verify: Success" ``` +## Flashing + +With Digilent [JTAG HS2](https://store.digilentinc.com/jtag-hs2-programming-cable/) cable: + + - download firmware to dongle. Manually (adjust USB bus as needed): + ``` + /sbin/fxload -t fx2 -I /opt/Xilinx/14.7/ISE_DS/ISE/bin/lin64/xusb_xp2.hex -D /dev/bus/usb/001/*`cat /sys/bus/usb/devices/1-3/devnum` + ``` + or automatically via the ``udev`` rule: + ``` + SUBSYSTEM=="usb", ACTION="add", ATTR{idVendor}=="0403", ATTR{idProduct}=="6014", ATTR{manufacturer}=="Digilent", RUN+="/usr/bin/fxload -v -t fx2 -I /opt/Xilinx/14.7/ISE_DS/ISE/bin/lin64/xusb_xp2.hex -D $tempnode" + ``` + + - install [xc3sprog](http://xc3sprog.sourceforge.net/) + + - ``flash_xc3.sh jtaghs2`` + + - look for ``Verify: Success`` + + # License GPLv3+ diff --git a/flash_xc3.sh b/flash_xc3.sh index 4c8a94c..c84b4d6 100755 --- a/flash_xc3.sh +++ b/flash_xc3.sh @@ -1,8 +1,9 @@ #!/bin/bash set -e -set -x -/sbin/fxload -t fx2 -I /opt/Xilinx/14.7/ISE_DS/ISE/bin/lin64/xusb_xp2.hex -D /dev/bus/usb/001/*`cat /sys/bus/usb/devices/1-7/devnum` -sleep 7 -../xc3sprog/build/xc3sprog -c xpc -m /opt/Xilinx/14.7/ISE_DS/ISE/xbr/data -v build/mirny.jed:w +XC3SPROG=xc3sprog +CABLE=${1-xpc} + +set -x +$XC3SPROG -c $CABLE -m /opt/Xilinx/14.7/ISE_DS/ISE/xbr/data -v build/mirny.jed:w diff --git a/mirny.py b/mirny.py index 82edca2..6dc2612 100644 --- a/mirny.py +++ b/mirny.py @@ -153,7 +153,6 @@ class SR(Module): ), ] - def intersection(a, b): (aa, am), (ba, bm) = a, b # TODO @@ -182,26 +181,26 @@ class Mirny(Module): SPI --- - SPI xfer is ADR(7), WE(1), DAT(REG: 16, ATT: 8, PLL: 32) - - | ADR | TARGET | - |--------+--------| - | 0 | REG0 | - | 1 | REG1 | - | 2 | REG2 | - | 3 | REG3 | - | 4 | PLL0 | - | 5 | PLL1 | - | 6 | PLL2 | - | 7 | PLL3 | - | 8 | ATT0 | - | 9 | ATT1 | - | a | ATT2 | - | b | ATT3 | - | c | reserved | - | d | reserved | - | e | reserved | - | f | reserved | + SPI xfer is ADR(7), WE(1), DAT(REG: 16, ATT: 8, PLL: 32, SR: 8) + + | ADR | TARGET | + |-----+----------------------| + | 0 | REG0 | + | 1 | REG1 | + | 2 | REG2 | + | 3 | REG3 | + | 4 | PLL0 | + | 5 | PLL1 | + | 6 | PLL2 | + | 7 | PLL3 | + | 8 | ATT0 | + | 9 | ATT1 | + | a | ATT2 | + | b | ATT3 | + | c | (Legacy Almazny) SR1 | + | d | (Legacy Almazny) SR2 | + | e | (Legacy Almazny) SR3 | + | f | (Legacy Almazny) SR4 | The SPI interface is CPOL=0, CPHA=0, SPI mode 0, 4-wire, full fuplex. @@ -223,8 +222,8 @@ class Mirny(Module): | Name | Width | Function | |-----------+-------+------------------------------------| | CE_N | 4 | PLL chip enable (bar) | - | CLK_SEL | 2 | Selects CLK source: 0 OSC, 1 MMCX, | - | | | 2 reserved, 3 SMA | + | CLK_SEL | 2 | Selects CLK source: | + | | | 0 OSC, 1 reserved, 2 MMCX, 3 SMA | | DIV | 2 | Clock divider configuration: | | | | 0: divide-by-one, | | | | 1: reserved, | @@ -234,6 +233,7 @@ class Mirny(Module): | FSEN_N | 1 | LVDS fail safe, Type 2 (bar) | | MUXOUT_EEM| 1 | route MUXOUT to EEM[4:8] | | EEM_MEZZIO| 1 | route EEM[4:8] to MEZZ_IO[0:4] | + | ALMAZNY_OE| 1 | Almazny OE in legacy Almazny mode | | Name | Width | Function | |-----------+-------+------------------------------------| @@ -250,7 +250,7 @@ class Mirny(Module): The test points expose miscellaneous signals for debugging and are not part of the protocol revision. """ - def __init__(self, platform): + def __init__(self, platform, legacy_almazny=False): self.eem = eem = [] for i in range(8): tsi = TSTriple() @@ -292,7 +292,7 @@ class Mirny(Module): self.sr.ext.cs.eq(eem[3].i), ] - regs = [REG(), REG(width=12), REG(width=4), REG()] + regs = [REG(), REG(width=13), REG(width=4), REG()] self.submodules += regs for i, reg in enumerate(regs): self.sr.connect(reg.bus, adr=i, mask=mask) @@ -310,23 +310,47 @@ class Mirny(Module): clk = platform.request("clk") clk_div = TSTriple() self.specials += clk_div.get_tristate(clk.div) - # in_sel: 00: XO, 01: MMCX, 10: n/a (SMA+XO), 11: SMA + # in_sel: 00: XO, 01: n/a (SMA+XO), 10: MMCX, 11: SMA # dividers: 00(z): 1, 01(z): 1, 10(low): 2, 11(high) 4 self.comb += [ Cat(clk.in_sel, clk_div.o, clk_div.oe).eq(regs[1].write[4:8]), platform.request("fsen").eq(~regs[1].write[9]), ] - for i, m in enumerate(platform.request("mezz_io")): - tsi = TSTriple() - self.specials += tsi.get_tristate(m) + if legacy_almazny: + almazny_io = platform.request("legacy_almazny_common") + almazny_adr = 0b1100 # 1100 - and then 1101, 1110, 1111 for sr 1-4 + ext = Record(ext_layout) + self.sr.connect_ext(ext, almazny_adr, almazny_adr) + latches = AsyncRst(width=4, reset=0xF) + self.submodules += latches + self.comb += [ - tsi.o.eq(regs[3].write[i] | (0 if i >= 4 else - (regs[1].write[11] & eem[i + 4].i))), - regs[3].read[i].eq(tsi.i), - tsi.oe.eq(regs[3].write[i + 8]), - regs[3].read[i + 8].eq(tsi.oe), + latches.ce.eq(ext.cs), + almazny_io.clk.eq(ext.sck), + almazny_io.mosi.eq(ext.sdi), + almazny_io.srclr.eq(1) ] + + for i in range(4): + almazny = platform.request("legacy_almazny", i) + self.sync += latches.i[i].eq(self.sr.bus.adr[:2] != i) + self.comb += [ + almazny.latch.eq(latches.o[i]), + almazny.noe.eq(~regs[1].write[12]) + ] + + else: + for i, m in enumerate(platform.request("mezz_io")): + tsi = TSTriple() + self.specials += tsi.get_tristate(m) + self.comb += [ + tsi.o.eq(regs[3].write[i] | (0 if i >= 4 else + (regs[1].write[11] & eem[i + 4].i))), + regs[3].read[i].eq(tsi.i), + tsi.oe.eq(regs[3].write[i + 8]), + regs[3].read[i + 8].eq(tsi.oe), + ] for i in range(4): rf_sw = platform.request("rf_sw", i) diff --git a/mirny_cpld.py b/mirny_cpld.py index 70fc164..a688d89 100644 --- a/mirny_cpld.py +++ b/mirny_cpld.py @@ -16,9 +16,33 @@ _io = [ # fail save LVDS enable, LVDS mode selection # high: type 2 receiver, failsafe low ("fsen", 0, Pins("P80")), - + + # IO from 0 to 7 ("mezz_io", 0, Pins("P57 P58 P59 P60 P61 P64 P68 P69")), + # legacy (v1.0-1.1) Almazny pins + ("legacy_almazny_common", 0, + Subsignal("mosi", Pins("P94")), + Subsignal("clk", Pins("P97")), + Subsignal("srclr", Pins("P60")), + ), + ("legacy_almazny", 0, + Subsignal("latch", Pins("P96")), + Subsignal("noe", Pins("P95")), + ), + ("legacy_almazny", 1, + Subsignal("latch", Pins("P100")), + Subsignal("noe", Pins("P98")), + ), + ("legacy_almazny", 2, + Subsignal("latch", Pins("P92")), + Subsignal("noe", Pins("P101")), + ), + ("legacy_almazny", 3, + Subsignal("latch", Pins("P57")), + Subsignal("noe", Pins("P58")), + ), + ("clk", 0, Subsignal("div", Pins("P53")), Subsignal("in_sel", Pins("P54 P56")), diff --git a/mirny_impl.py b/mirny_impl.py index 0c42b0b..d7022dc 100644 --- a/mirny_impl.py +++ b/mirny_impl.py @@ -1,10 +1,23 @@ +import argparse + +def get_argparser(): + parser = argparse.ArgumentParser( + description="Mirny CPLD firmware" + ) + parser.add_argument("--legacy-almazny", action="store_true", default=False) + + return parser + def main(): from mirny_cpld import Platform from mirny import Mirny + args = get_argparser().parse_args() + p = Platform() - mirny = Mirny(p) - p.build(mirny, build_name="mirny", mode="cpld") + mirny = Mirny(p, args.legacy_almazny) + build_name = "mirny" if not args.legacy_almazny else "mirny_legacy_almazny" + p.build(mirny, build_name=build_name, mode="cpld") if __name__ == "__main__":