diff options
Diffstat (limited to 'amaranth_boards')
| -rw-r--r-- | amaranth_boards/nitefury.py | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/amaranth_boards/nitefury.py b/amaranth_boards/nitefury.py new file mode 100644 index 0000000..22dcaf0 --- /dev/null +++ b/amaranth_boards/nitefury.py @@ -0,0 +1,145 @@ +import os +import subprocess +import textwrap +import unittest + +from amaranth.build import * +from amaranth.vendor import XilinxPlatform +from .resources import * + + +__all__ = ["NitefuryIIPlatform", "LitefuryPlatform"] + + +class _BasePlatform(XilinxPlatform): + speed = "2" + default_clk = "clk200" + + resources = [ + Resource("clk200", 0, DiffPairs(p="J19", n="H19", dir="i"), + Clock(200e6), Attrs(IOSTANDARD="DIFF_SSTL15")), + # 4 Programmable LEDs + *LEDResources(pins="G3 H3 G4 H4", attrs=Attrs(IOSTANDARD="LVCMOS33")), + # SPIFlash + *SPIFlashResources(0, + cs_n="T19", clk="L16", copi="P22", cipo="R22", wp_n="P21", hold_n="R21", + attrs=Attrs(IOSTANDARD="LVCMOS33") + ), + # 1 M.2 indicator LED + Resource("m2led", 0, Pins("M1"), Attrs(IOSTANDARD="LVCMOS33")), + # PCIE + Resource("pcie", 0, + Subsignal("clkreq", PinsN("G1", dir="o"), Attrs(IOSTANDARD="LVCMOS33")), + Subsignal("rst", PinsN("J1", dir="o"), Attrs(IOSTANDARD="LVCMOS33", PULLUP=1)), + Subsignal("clk", DiffPairs(p="F6", n="E6", dir="i"), Attrs(IOSTANDARD="DIFF_SSTL15")), + Subsignal("rx", DiffPairs(p="B10 B8 D11 D9", n="A10 A8 C11 C9", dir="i")), + Subsignal("tx", DiffPairs(p="B6 B4 D5 D7", n="A6 A4 C5 C7", dir="o")), + ), + # DDR + Resource("ddr3", 0, + Subsignal("rst", PinsN("K16", dir="o"), Attrs(IOStandard="LVCMOS15")), + Subsignal("clk", DiffPairs(p="K17", n="J17", dir="o")), + Subsignal("clk_en", Pins("H22", dir="o")), + # Subsignal("cs", PinsN("U8", dir="o")), + Subsignal("we", PinsN("L16", dir="o")), + Subsignal("ras", PinsN("H20", dir="o")), + Subsignal("cas", PinsN("K18", dir="o")), + Subsignal("a", Pins("M15 L21 M16 L18 K21 M18 M21 N20 M20 N19 J21 M22 K22 N18 N22 J22", dir="o")), + Subsignal("ba", Pins("L19 J20 L20", dir="o")), + Subsignal("dqs", DiffPairs(p="F18 B21", n="E18 A21", dir="io"), + Attrs(IOSTANDARD="DIFF_SSTL135")), + Subsignal("dq", Pins("D19 B20 E19 A20 F19 C19 F20 C18 E22 G21 D20 E21 C22 D21 B22 D22", dir="io"), + Attrs(IN_TERM="UNTUNED_SPLIT_50")), + Subsignal("dm", Pins("A19 G22", dir="o")), + Subsignal("odt", Pins("K19", dir="o")), + Attrs(IOSTANDARD="SSTL15", SLEW="FAST"), + ), + ] + connectors = [] + + def toolchain_prepare(self, fragment, name, **kwargs): + overrides = { + "script_before_bitstream": + """ + set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design] + set_property BITSTREAM.CONFIG.CONFIGRATE 16 [current_design] + set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design] + """, + "script_after_bitstream": + "write_cfgmem -force -format bin -interface spix4 -size 16 " + "-loadbit \"up 0x0 {name}.bit\" -file {name}.bin".format(name=name), + "add_constraints": + """ + set_property INTERNAL_VREF 0.675 [get_iobanks 34] + set_property CFGBVS VCCO [current_design] + set_property CONFIG_VOLTAGE 3.3 [current_design] + """ + } + return super().toolchain_prepare(fragment, name, **overrides, **kwargs) + + def toolchain_program(self, product, name, *, programmer="openfpgaloader", flash=True): + assert programmer in ("vivado", "openfpgaloader") + + if programmer == "vivado": + if flash: + # It does not appear possible to reset the FPGA via TCL after + # flash programming. + with product.extract("{}.bin".format(name)) as bitstream_filename: + cmd = textwrap.dedent(""" + open_hw_manager + connect_hw_server + open_hw_target + current_hw_device [lindex [get_hw_devices xc7a*] 0]] + create_hw_cfgmem -hw_device [current_hw_device] s25fl256sxxxxxx0-spi-x1_x2_x4 + set_property PROGRAM.FILES {{{}}} [current_hw_cfgmem] + set_property PROGRAM.ADDRESS_RANGE {{use_file}} [current_hw_cfgmem] + set_property PROGRAM.BLANK_CHECK 1 [current_hw_cfgmem] + set_property PROGRAM.ERASE 1 [current_hw_cfgmem] + set_property PROGRAM.CFG_PROGRAM 1 [current_hw_cfgmem] + set_property PROGRAM.VERIFY 1 [current_hw_cfgmem] + create_hw_bitstream -hw_device [current_hw_device] [get_property PROGRAM.HW_CFGMEM_BITFILE [current_hw_device]] + program_hw_devices + program_hw_cfgmem + close_hw_manager + puts "Vivado TCL cannot reset boards. Reset or power-cycle your board now." + """).format(bitstream_filename).encode("utf-8") + subprocess.run(["vivado", "-nolog", "-nojournal", "-mode", "tcl"], input=cmd, check=True) + else: + with product.extract("{}.bit".format(name)) as bitstream_filename: + cmd = textwrap.dedent(""" + open_hw_manager + connect_hw_server + open_hw_target + current_hw_device [lindex [get_hw_devices] 0] + set_property PROGRAM.FILE {{{}}} [current_hw_device] + program_hw_devices + close_hw_manager + """).format(bitstream_filename).encode("utf-8") + subprocess.run(["vivado", "-nolog", "-nojournal", "-mode", "tcl"], input=cmd, check=True) + else: + # openfpgaloader + openfpgaloader = os.environ.get("OPENFPGALOADER", "openFPGALoader") + with product.extract("{}.bin".format(name)) as fn: + # TODO: @timkpaine has digilent_hs3 cable + subprocess.check_call([openfpgaloader, "-c", "digilent_hs3", fn]) + + +class LitefuryPlatform(_BasePlatform): + device = "xc7a100t" + package = "fgg484" + + +class NitefuryIIPlatform(_BasePlatform): + device = "xc7a200t" + package = "fbg484" + + +class TestCase(unittest.TestCase): + def test_smoke(self): + from .test.blinky import Blinky + NitefuryIIPlatform().build(Blinky(), do_build=False) + + +if __name__ == "__main__": + from .test.blinky import * + NitefuryIIPlatform().build(Blinky(), do_program=True) |
