|
| 1 | +import os |
| 2 | +import subprocess |
| 3 | +import shutil |
| 4 | + |
| 5 | +from amaranth.build import * |
| 6 | +from amaranth.vendor.lattice_ecp5 import * |
| 7 | +from .resources import * |
| 8 | + |
| 9 | + |
| 10 | +__all__ = ["ButterStickPlatform"] |
| 11 | + |
| 12 | + |
| 13 | +class ButterStickPlatform(LatticeECP5Platform): |
| 14 | + device = "LFE5UM5G-85F" |
| 15 | + package = "BG381" |
| 16 | + speed = "8" |
| 17 | + default_clk = "clk30" |
| 18 | + |
| 19 | + def ulpi_io_type(self): |
| 20 | + return _vccio_iotype(2) |
| 21 | + |
| 22 | + resources = [ |
| 23 | + Resource("clk30", 0, Pins("B12", dir="i"), |
| 24 | + Clock(30e6), Attrs(IO_TYPE="LVCMOS33")), |
| 25 | + |
| 26 | + # LED Anodes |
| 27 | + *LEDResources(pins="C13 D12 U2 T3 D13 E13 C16", attrs=Attrs(IO_TYPE="LVCMOS33")), |
| 28 | + |
| 29 | + # LED Cathodes. Use invert to default as on to allow LEDs to be used in white with single bit IO |
| 30 | + # note that G and B are swapped to match the LEDs and not the schematic labels |
| 31 | + RGBLEDResource(0, r="T1", g="U1", b="R1", invert=True, attrs=Attrs(IO_TYPE="LVCMOS33")), |
| 32 | + |
| 33 | + *ButtonResources( |
| 34 | + pins={0: "U16", 1: "T17" }, invert=True, |
| 35 | + attrs=Attrs(IO_TYPE="SSTL135_I")), |
| 36 | + |
| 37 | + *SPIFlashResources(0, |
| 38 | + cs_n="R2", clk="U3", cipo="V2", copi="W2", wp_n="Y2", hold_n="W1", |
| 39 | + attrs=Attrs(IO_TYPE="LVCMOS33", SLEWRATE="FAST"), |
| 40 | + ), |
| 41 | + |
| 42 | + *SDCardResources("sdcard", 0, |
| 43 | + clk="B13", cmd="A13", dat0="C12", dat1="A12", dat2="D14", dat3="A14", |
| 44 | + attrs=Attrs(IO_TYPE="LVCMOS33", SLEWRATE="FAST"), |
| 45 | + ), |
| 46 | + |
| 47 | + Resource("ddr3", 0, |
| 48 | + Subsignal("rst", PinsN("E17", dir="o")), |
| 49 | + Subsignal("clk", DiffPairs("C20", "J19", dir="o"), Attrs(IO_TYPE="SSTL135D_I")), |
| 50 | + Subsignal("clk_en", Pins("F18 J18", dir="o")), |
| 51 | + Subsignal("cs", PinsN("J20 J16", dir="o")), |
| 52 | + Subsignal("we", PinsN("G19", dir="o")), |
| 53 | + Subsignal("ras", PinsN("K18", dir="o")), |
| 54 | + Subsignal("cas", PinsN("J17", dir="o")), |
| 55 | + Subsignal("a", Pins("G16 E19 E20 F16 F19 E16 F17 L20 M20 E18 G18 D18 H18 C18 D17 G20", dir="o")), |
| 56 | + Subsignal("ba", Pins("H16 F20 H20", dir="o")), |
| 57 | + Subsignal("dqs", DiffPairs("T19 N16", "R18 M17", dir="io"), |
| 58 | + Attrs(IO_TYPE="SSTL135D_I", TERMINATION="OFF", |
| 59 | + DIFFRESISTOR="100")), |
| 60 | + Subsignal("dq", Pins("U19 T18 U18 R20 P18 P19 P20 N20 L19 L17 L16 R16 N18 R17 N17 P17", |
| 61 | + dir="io"), Attrs(TERMINATION="75")), |
| 62 | + Subsignal("dm", Pins("U20 L18", dir="o")), |
| 63 | + Subsignal("odt", Pins("K20 H17", dir="o")), |
| 64 | + Attrs(IO_TYPE="SSTL135_I", SLEWRATE="FAST") |
| 65 | + ), |
| 66 | + |
| 67 | + Resource("eth_rgmii", 0, |
| 68 | + Subsignal("rst", PinsN("B20", dir="o")), |
| 69 | + Subsignal("mdc", Pins("A19", dir="o")), |
| 70 | + Subsignal("mdio", Pins("D16", dir="io")), |
| 71 | + Subsignal("tx_clk", Pins("E15", dir="o")), |
| 72 | + Subsignal("tx_ctl", Pins("D15", dir="o")), |
| 73 | + Subsignal("tx_data", Pins("C15 B16 A18 B19", dir="o")), |
| 74 | + Subsignal("rx_clk", Pins("D11", dir="i")), |
| 75 | + Subsignal("rx_ctl", Pins("B18", dir="i")), |
| 76 | + Subsignal("rx_data", Pins("A16 C17 B17 A17", dir="i")), |
| 77 | + Attrs(IO_TYPE="LVCMOS33", SLEWRATE="FAST") |
| 78 | + ), |
| 79 | + |
| 80 | + ULPIResource(0, data="B9 C6 A7 E9 A8 D9 C10 C7", |
| 81 | + rst="C9", clk="B6", dir="A6", stp="C8", nxt="B8", |
| 82 | + clk_dir="o", rst_invert=True, attrs=Attrs(IO_TYPE="LVCMOS18")), |
| 83 | + |
| 84 | + I2CResource(0, scl="E14", sda="C14", |
| 85 | + attrs=Attrs(IO_TYPE="LVCMOS33")), |
| 86 | + |
| 87 | + # SYGYZY VIO level control pwm pins (use with care) |
| 88 | + Resource("vccio_ctrl", 0, |
| 89 | + Subsignal("pdm", Pins("V1 E11 T2", dir="o")), |
| 90 | + Subsignal("en", Pins("E12", dir="o")), |
| 91 | + Attrs(IO_TYPE="LVCMOS33") |
| 92 | + ), |
| 93 | + # Used to reload FPGA configuration (drives program_n) |
| 94 | + Resource("program", 0, PinsN("R3", dir="o"), Attrs(IO_TYPE="LVCMOS33")), |
| 95 | + ] |
| 96 | + connectors = [ |
| 97 | + Connector("syzygy", 0, { |
| 98 | + # single ended |
| 99 | + "S0":"G2", "S1":"J3", |
| 100 | + "S2":"F1", "S3":"K3", |
| 101 | + "S4":"J4", "S5":"K2", |
| 102 | + "S6":"J5", "S7":"J1", |
| 103 | + "S8":"N2", "S9":"L3", |
| 104 | + "S10":"M1", "S11":"L2", |
| 105 | + "S12":"N3", "S13":"N4", |
| 106 | + "S14":"M3", "S15":"P5", |
| 107 | + "S16":"H1", "S17":"K5", |
| 108 | + "S18":"K4", "S19":"K1", |
| 109 | + "S20":"L4", "S21":"L1", |
| 110 | + "S22":"L5", "S23":"M4", |
| 111 | + "S24":"N1", "S25":"N5", |
| 112 | + "S26":"P3", "S27":"P4", |
| 113 | + "S28":"H2", "S29":"P1", |
| 114 | + "S30":"G1", "S31":"P2", |
| 115 | + # diff pairs |
| 116 | + |
| 117 | + }), |
| 118 | + Connector("syzygy", 1, { |
| 119 | + # single ended |
| 120 | + |
| 121 | + # diff pairs |
| 122 | + "D0P":"E4", "D0N":"D5", |
| 123 | + "D1P":"A4", "D1N":"A5", |
| 124 | + "D2P":"C4", "D2N":"B4", |
| 125 | + "D3P":"B2", "D3N":"C2", |
| 126 | + "D4P":"A2", "D4N":"B1", |
| 127 | + "D5P":"C1", "D5N":"D1", |
| 128 | + "D6P":"F4", "D6N":"E3", |
| 129 | + "D7P":"D2", "D7N":"E1", |
| 130 | + }), |
| 131 | + ] |
| 132 | + |
| 133 | + def __init__(self, *, vccio_enable=True, vccio_voltages = [ 3.3, 3.3, 1.8 ], **kwargs): |
| 134 | + super().__init__(**kwargs) |
| 135 | + self._vccio_enable = vccio_enable |
| 136 | + self._vccio_voltages = vccio_voltages |
| 137 | + |
| 138 | + def vccio_voltage(self, vccio_index): |
| 139 | + if not self._vccio_enable: |
| 140 | + return None |
| 141 | + else: |
| 142 | + return self._vccio_voltages[vccio_index] |
| 143 | + |
| 144 | + def _vccio_iotype(self, vccio_index): |
| 145 | + if not self._vccio_enable or self._vccio_voltages[vccio_index] == 3.3: |
| 146 | + return "LVCMOS33" |
| 147 | + if self._vccio_voltages[vccio_index] == 2.5: |
| 148 | + return "LVCMOS25" |
| 149 | + if self._vccio_voltages[vccio_index] == 1.8: |
| 150 | + return "LVCMOS18" |
| 151 | + assert False |
| 152 | + |
| 153 | + @property |
| 154 | + def required_tools(self): |
| 155 | + return super().required_tools + [ |
| 156 | + "dfu-suffix" |
| 157 | + ] |
| 158 | + |
| 159 | + @property |
| 160 | + def command_templates(self): |
| 161 | + return super().command_templates + [ |
| 162 | + r""" |
| 163 | + {{invoke_tool("dfu-suffix")}} |
| 164 | + -v 1209 -p 5af1 -a {{name}}.bit |
| 165 | + """ |
| 166 | + ] |
| 167 | + |
| 168 | + def toolchain_prepare(self, fragment, name, **kwargs): |
| 169 | + overrides = dict(ecppack_opts="--compress --freq 38.8") |
| 170 | + overrides.update(kwargs) |
| 171 | + return super().toolchain_prepare(fragment, name, **overrides) |
| 172 | + |
| 173 | + def toolchain_program(self, products, name): |
| 174 | + dfu_util = os.environ.get("DFU_UTIL", "dfu-util") |
| 175 | + with products.extract("{}.bit".format(name)) as bitstream_filename: |
| 176 | + subprocess.check_call([dfu_util, "-a", "0", "-D", bitstream_filename, "-R"]) |
| 177 | + |
| 178 | + |
| 179 | +if __name__ == "__main__": |
| 180 | + from .test.blinky import * |
| 181 | + ButterStickPlatform().build(Blinky(), do_program=True) |
0 commit comments