diff --git a/amaranth_boards/colorlight_5a75b_r8_0.py b/amaranth_boards/colorlight_5a75b_r8_0.py new file mode 100644 index 00000000..f0a0343c --- /dev/null +++ b/amaranth_boards/colorlight_5a75b_r8_0.py @@ -0,0 +1,115 @@ +import os +import subprocess + +from amaranth.build import * +from amaranth.vendor.lattice_ecp5 import * +from amaranth_boards.resources import * + + +__all__ = ["Colorlight_5A75B_R80Platform"] + + +class Colorlight_5A75B_R80Platform(LatticeECP5Platform): + device = "LFE5U-25F" + package = "BG256" + speed = "6" + default_clk = "clk25" + + # Pins according to https://github.com/q3k/chubby75/blob/master/5a-75b/hardware_V8.0.md + # Some of these still need verifying. + + resources = [ + Resource("clk25", 0, Pins("P6", dir="i"), Clock(25e6), Attrs(IO_TYPE="LVCMOS33")), + + *LEDResources(pins="T6", invert = True, + attrs=Attrs(IO_TYPE="LVCMOS33", DRIVE="4")), + + *ButtonResources(pins="R7", invert = True, + attrs=Attrs(IO_TYPE="LVCMOS33", PULLMODE="UP")), + + UARTResource(0, + tx="T6", # led (J19 DATA_LED-) + rx="R7", # btn (J19 KEY+) + attrs=Attrs(IO_TYPE="LVCMOS33") + ), + + # SPIFlash (25Q32JVSIQ) 32-Mbits + Resource("spi_flash", 0, + Subsignal("cs", PinsN("N8", dir="o")), + # Subsignal("clk", Pins("", dir="i")), # driven through USRMCLK + Subsignal("cipo", Pins("T8", dir="i")), # Chip: DI/IO0 + Subsignal("copi", Pins("T7", dir="o")), # DO/IO1 + # Subsignal("wp", PinsN("unknown", dir="o")), # IO2 Todo + # Subsignal("hold", PinsN("unknown", dir="o")), # IO3 Todo + Attrs(IO_TYPE="LVCMOS33") + ), + + # 1x ESMT M12L64322A 2M 200MHz SDRAM (organized as 4 x 512k x 32bit) + SDRAMResource(0, + clk="C8", we_n="B5", cas_n="A6", ras_n="B6", + ba="B7 A8", a="A9 B9 B10 C10 D9 C9 E9 D8 E8 C7 B8", + dq="B2 A2 C3 A3 B3 A4 B4 A5 E7 C6 D7 D6 E6 D5 C5 E5 " + "A11 B11 B12 A13 B13 A14 D14 D13 E11 C13 D11 C12 E10 C11 D10", + attrs=Attrs(PULLMODE="NONE", DRIVE="4", SLEWRATE="FAST", IO_TYPE="LVCMOS33") + ), + + # 2x Realtek RTL8211FD Gigabit Ethernet PHYs + Resource("eth_rgmii", 0, + Subsignal("rst", PinsN("R6", dir="o")), + Subsignal("mdc", Pins("R5", dir="o")), + Subsignal("mdio", Pins("T4", dir="io")), + Subsignal("tx_clk", Pins("L1", dir="o")), + Subsignal("tx_ctl", Pins("L2", dir="o")), + Subsignal("tx_data", Pins("M2 M1 P1 R1", dir="o")), + Subsignal("rx_clk", Pins("J1", dir="i")), + Subsignal("rx_ctl", Pins("J2", dir="i")), + Subsignal("rx_data", Pins("K2 J3 K1 K3", dir="i")), + Attrs(IO_TYPE="LVCMOS33") + ), + + Resource("eth_rgmii", 1, + Subsignal("rst", PinsN("R6", dir="o")), + Subsignal("mdc", Pins("R5", dir="o")), + Subsignal("mdio", Pins("T4", dir="io")), + Subsignal("tx_clk", Pins("J16", dir="o")), + Subsignal("tx_ctl", Pins("K14", dir="o")), + Subsignal("tx_data", Pins("K16 J15 J14 K15", dir="o")), + Subsignal("rx_clk", Pins("M16", dir="i")), + Subsignal("rx_ctl", Pins("P16", dir="i")), + Subsignal("rx_data", Pins("M15 R16 L15 L16", dir="i")), + Attrs(IO_TYPE="LVCMOS33") + ), + + ] + connectors = [ + Connector("j", 1, "C4 D4 E4 - D3 F5 E3 N4 N5 N3 P3 P4 M3 N1 M4 -"), + Connector("j", 2, "F1 F2 G2 - G1 H2 H3 N4 N5 N3 P3 P4 M3 N1 M4 -"), + Connector("j", 3, "B1 C2 C1 - D1 E2 E1 N4 N5 N3 P3 P4 M3 N1 M4 -"), + Connector("j", 4, "P5 R3 P2 - R2 T2 N6 N4 N5 N3 P3 P4 M3 N1 M4 -"), + Connector("j", 5, "T13 R12 R13 - R14 T14 P12 N4 N5 N3 P3 P4 M3 N1 M4 -"), + Connector("j", 6, "R15 T15 P13 - P14 N14 H15 N4 N5 N3 P3 P4 M3 N1 M4 -"), + Connector("j", 7, "G16 H14 G15 - F15 F16 E16 N4 N5 N3 P3 P4 M3 N1 M4 -"), + Connector("j", 8, "D16 E15 C16 - B16 C15 B15 N4 N5 N3 P3 P4 M3 N1 M4 -"), + #Connector("j", 19, " - M13 - - P11"), + ] + + @property + def required_tools(self): + return super().required_tools + [ + "openFPGALoader" + ] + + def toolchain_prepare(self, fragment, name, **kwargs): + overrides = dict(ecppack_opts="--compress") + overrides.update(kwargs) + return super().toolchain_prepare(fragment, name, **overrides) + + def toolchain_program(self, products, name): + tool = os.environ.get("OPENFPGALOADER", "openFPGALoader") + with products.extract("{}.bit".format(name)) as bitstream_filename: + subprocess.check_call([tool, "-c", "ft232", "-m", bitstream_filename]) + + +if __name__ == "__main__": + from .test.blinky import * + Colorlight_5A75B_R80Platform().build(Blinky(), do_program=True) diff --git a/amaranth_boards/pislx16.py b/amaranth_boards/pislx16.py new file mode 100755 index 00000000..4fed7ace --- /dev/null +++ b/amaranth_boards/pislx16.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python3 + +import os +import subprocess + +from amaranth.build import * +from amaranth.vendor.xilinx_spartan_3_6 import * +from amaranth_boards.resources import * + +__all__ = ["PiSLX16Platform"] + +""" +http://piswords.com/xc6slx16.html + +Xilinx spartan6 XC6SLX16 Core Board Xilinx spartan 6 FPGA development board with 256mbit SDRAM + +Useful notes on getting the openocd interface working : + +https://tomverbeure.github.io/2019/09/15/Loading-a-Spartan-6-bitstream-with-openocd.html +""" + +class PiSLX16Platform(XilinxSpartan6Platform): + device = "xc6slx16" + package = "ftg256" + speed = "3" + default_clk = "clk50" + resources = [ + Resource("clk50", 0, Pins("T8", dir="i"), + Clock(50e6), Attrs(IOSTANDARD="LVCMOS33")), + + # 4 Blue LEDs, LED0 .. LED3 + *LEDResources(pins="P4 N5 P5 M6", attrs=Attrs(IOSTANDARD="LVCMOS33")), + + # RESET key is L3 (all keys have pull-ups onboard) + *ButtonResources(pins="C3 D3 E4 E3 L3", attrs=Attrs(IOSTANDARD="LVCMOS33")), + + # SPI Flash M25P16 + *SPIFlashResources(0, + cs_n="T3", clk="R11", copi="T10", cipo="P10", attrs=Attrs(IOSTANDARD="LVCMOS33") + ), + + # UART CH340C + UARTResource(0, rx="C11", tx="D12", attrs=Attrs(IOSTANDARD="LVCMOS33")), + + # DRAM H57V2562GTR SDRAMResource TODO + # I2C AT24C02 EEPROM I2CResource TODO + # SDCardResources + Resource("sd_clk", 0, Pins("M3", dir="o")), + Resource("sd_di", 0, Pins("L5", dir="o")), + Resource("sd_do", 0, Pins("L4", dir="i")), + Resource("sd_cs", 0, Pins("N3", dir="o")), + ] + connectors = [ + Connector("p", 1, + "- - K16 J16 L16 K15 M15 M16 P16 N16 " + "R16 P15 T15 R15 T14 R14 R12 T13 R9 T12 " + "L8 T9 R7 T7 T5 T6 T4 R5 R1 R2 " + "P2 M4 P6 N6 M5 N4 - - - - " + ), + Connector("p", 2, + "- - A4 B5 A5 B6 A6 A7 B8 A8 " + "C8 A9 A10 B10 A11 A12 B12 A13 A14 B14 " + "B15 B16 C15 C16 D16 E15 C9 E11 C10 D11 " + "E16 F15 F16 G16 H15 H16 - - - - " + ), + ] + + # Programming using openocd (programs FPGA's volatile config) + + @property + def file_templates(self): + return { + **super().file_templates, + "{{name}}-openocd.cfg": "adapter_khz 8000", + } + + def toolchain_program_open_ocd(self, products, name, config=None, **kwargs): + openocd = os.environ.get("OPENOCD", "openocd") + with products.extract(f"{name}-openocd.cfg", f"{name}.bit") \ + as (config_filename, vector_filename): + cmd = ";".join([ + "transport select jtag", + "init", + "xc6s_program xc6s.tap", + f"pld load 0 {vector_filename}", + "exit", + ]) + subprocess.check_call([openocd, + "-f", config, + "-f", "cpld/xilinx-xc6s.cfg", + "-f", config_filename, + "-c", cmd, + ]) + + # Programming using openFPGALoader (SPI flash) + + def toolchain_program_open_fpga_loader(self, products, name, config=None, addr=None, dev=None, **kwargs): + with products.extract(f"{name}.bit") as filename: + conf = config or "digilent_hs3" + cmd = [ + "openFPGALoader", + "--fpga-part", self.device + self.package, # "xc6slx16ftg256", + "-c", conf, + filename, + ] + if addr is not None: + cmd += [ "-f", "-o", str(addr) ] + if dev is not None: + cmd += [ "-d", dev ] + + subprocess.check_call(cmd) + + # Programming (default to using Digilent JTAG-HS3) + def toolchain_program(self, products, name, **kwargs): + if kwargs.get("openocd"): + config = kwargs.get("config", "interface/ftdi/digilent_jtag_hs3.cfg") + self.toolchain_program_open_ocd(products, name, config=config) + else: + self.toolchain_program_open_fpga_loader(products, name, **kwargs) + + +if __name__ == "__main__": + from amaranth_boards.test.blinky import Blinky + dut = Blinky() + opts = { + #"openocd" : True, + "config" : "digilent_hs3", # default + "addr" : 0, # write to flash at this offset + } + PiSLX16Platform().build(dut, do_program=True, program_opts=opts, verbose=True) +