aboutsummaryrefslogtreecommitdiff
path: root/amaranth_boards/nitefury.py
blob: 22dcaf040341c080099226bfd03174f922bfced0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
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)