From 20b16b6d40cb81343dce4130d7c08f63a22f686f Mon Sep 17 00:00:00 2001 From: saji Date: Sat, 21 Sep 2024 22:33:47 -0500 Subject: [PATCH] add board,platform, wip cli --- pdm.lock | 67 +++++++------ pyproject.toml | 11 +-- src/groovylight/main.py | 50 ++++++++++ .../platforms/colorlight_5a75b_v8_2.py | 96 +++++++++++++++++++ 4 files changed, 189 insertions(+), 35 deletions(-) create mode 100644 src/groovylight/main.py create mode 100644 src/groovylight/platforms/colorlight_5a75b_v8_2.py diff --git a/pdm.lock b/pdm.lock index 06d89f1..10d8103 100644 --- a/pdm.lock +++ b/pdm.lock @@ -5,14 +5,14 @@ groups = ["default", "dev"] strategy = ["inherit_metadata"] lock_version = "4.5.0" -content_hash = "sha256:7b1a11a64e435bfbced61bd2b5314e78a56b93e0bac7dcb6b043529bc66fc060" +content_hash = "sha256:00a75da930aaa4d4233631525c1b6bb3c9642e99065be33cf83e74d4ad611d08" [[metadata.targets]] requires_python = "==3.12.*" [[package]] name = "amaranth" -version = "0.5.1" +version = "0.5.2" requires_python = "~=3.8" summary = "Amaranth hardware definition language" groups = ["default"] @@ -23,13 +23,22 @@ dependencies = [ "pyvcd<0.5,>=0.2.2", ] files = [ - {file = "amaranth-0.5.1-py3-none-any.whl", hash = "sha256:2d370cc5b97e2472aab0a4eca515ab7f5116274550bd454132520eaec6068fb6"}, - {file = "amaranth-0.5.1.tar.gz", hash = "sha256:58b01efcec24c3696a7465e97a6e62f46466afab1f956a6eb00bda4b791c8345"}, + {file = "amaranth-0.5.2-py3-none-any.whl", hash = "sha256:552ac232a12093d5375e23276c070f21da74d07778bf75c456b8db781a4bc919"}, + {file = "amaranth-0.5.2.tar.gz", hash = "sha256:af52811bca464233a3bbd72193ede584e75de592391cae92d1cbf24b98a3c954"}, +] + +[[package]] +name = "amaranth-boards" +version = "0" +summary = "Placeholder package name reserved for Amaranth HDL" +groups = ["default"] +files = [ + {file = "amaranth_boards-0-py3-none-any.whl", hash = "sha256:0cc6af682122197b532eef7c2d378a59905ac5e63ec5c69b9147b1e05bf2c600"}, ] [[package]] name = "basedpyright" -version = "1.17.0" +version = "1.17.5" requires_python = ">=3.8" summary = "static type checking for Python (but based)" groups = ["dev"] @@ -37,8 +46,8 @@ dependencies = [ "nodejs-wheel-binaries>=20.13.1", ] files = [ - {file = "basedpyright-1.17.0-py3-none-any.whl", hash = "sha256:a7e070be5d3930223df0a435590932fbc114242b7f8d1723c5d717754e7a3b4e"}, - {file = "basedpyright-1.17.0.tar.gz", hash = "sha256:79e2740156a040fdc68e4372940f40694375ef7e4a0ca70bacf8910af08717e0"}, + {file = "basedpyright-1.17.5-py3-none-any.whl", hash = "sha256:7ea23951be3620fe4638f6f51625a3d5a65a57ce004e836c608058610153362b"}, + {file = "basedpyright-1.17.5.tar.gz", hash = "sha256:8315f5f2fddfdad162513ef9d9a0b24bb00cc862e8883819ae98a3e28472874d"}, ] [[package]] @@ -152,7 +161,7 @@ files = [ [[package]] name = "pytest" -version = "8.3.2" +version = "8.3.3" requires_python = ">=3.8" summary = "pytest: simple powerful testing with Python" groups = ["dev"] @@ -165,8 +174,8 @@ dependencies = [ "tomli>=1; python_version < \"3.11\"", ] files = [ - {file = "pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5"}, - {file = "pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce"}, + {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, + {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, ] [[package]] @@ -193,27 +202,27 @@ files = [ [[package]] name = "ruff" -version = "0.6.2" +version = "0.6.7" requires_python = ">=3.7" summary = "An extremely fast Python linter and code formatter, written in Rust." groups = ["dev"] files = [ - {file = "ruff-0.6.2-py3-none-linux_armv6l.whl", hash = "sha256:5c8cbc6252deb3ea840ad6a20b0f8583caab0c5ef4f9cca21adc5a92b8f79f3c"}, - {file = "ruff-0.6.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:17002fe241e76544448a8e1e6118abecbe8cd10cf68fde635dad480dba594570"}, - {file = "ruff-0.6.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3dbeac76ed13456f8158b8f4fe087bf87882e645c8e8b606dd17b0b66c2c1158"}, - {file = "ruff-0.6.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:094600ee88cda325988d3f54e3588c46de5c18dae09d683ace278b11f9d4d534"}, - {file = "ruff-0.6.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:316d418fe258c036ba05fbf7dfc1f7d3d4096db63431546163b472285668132b"}, - {file = "ruff-0.6.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d72b8b3abf8a2d51b7b9944a41307d2f442558ccb3859bbd87e6ae9be1694a5d"}, - {file = "ruff-0.6.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2aed7e243be68487aa8982e91c6e260982d00da3f38955873aecd5a9204b1d66"}, - {file = "ruff-0.6.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d371f7fc9cec83497fe7cf5eaf5b76e22a8efce463de5f775a1826197feb9df8"}, - {file = "ruff-0.6.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8f310d63af08f583363dfb844ba8f9417b558199c58a5999215082036d795a1"}, - {file = "ruff-0.6.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7db6880c53c56addb8638fe444818183385ec85eeada1d48fc5abe045301b2f1"}, - {file = "ruff-0.6.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:1175d39faadd9a50718f478d23bfc1d4da5743f1ab56af81a2b6caf0a2394f23"}, - {file = "ruff-0.6.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:5b939f9c86d51635fe486585389f54582f0d65b8238e08c327c1534844b3bb9a"}, - {file = "ruff-0.6.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d0d62ca91219f906caf9b187dea50d17353f15ec9bb15aae4a606cd697b49b4c"}, - {file = "ruff-0.6.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7438a7288f9d67ed3c8ce4d059e67f7ed65e9fe3aa2ab6f5b4b3610e57e3cb56"}, - {file = "ruff-0.6.2-py3-none-win32.whl", hash = "sha256:279d5f7d86696df5f9549b56b9b6a7f6c72961b619022b5b7999b15db392a4da"}, - {file = "ruff-0.6.2-py3-none-win_amd64.whl", hash = "sha256:d9f3469c7dd43cd22eb1c3fc16926fb8258d50cb1b216658a07be95dd117b0f2"}, - {file = "ruff-0.6.2-py3-none-win_arm64.whl", hash = "sha256:f28fcd2cd0e02bdf739297516d5643a945cc7caf09bd9bcb4d932540a5ea4fa9"}, - {file = "ruff-0.6.2.tar.gz", hash = "sha256:239ee6beb9e91feb8e0ec384204a763f36cb53fb895a1a364618c6abb076b3be"}, + {file = "ruff-0.6.7-py3-none-linux_armv6l.whl", hash = "sha256:08277b217534bfdcc2e1377f7f933e1c7957453e8a79764d004e44c40db923f2"}, + {file = "ruff-0.6.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:c6707a32e03b791f4448dc0dce24b636cbcdee4dd5607adc24e5ee73fd86c00a"}, + {file = "ruff-0.6.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:533d66b7774ef224e7cf91506a7dafcc9e8ec7c059263ec46629e54e7b1f90ab"}, + {file = "ruff-0.6.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17a86aac6f915932d259f7bec79173e356165518859f94649d8c50b81ff087e9"}, + {file = "ruff-0.6.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b3f8822defd260ae2460ea3832b24d37d203c3577f48b055590a426a722d50ef"}, + {file = "ruff-0.6.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9ba4efe5c6dbbb58be58dd83feedb83b5e95c00091bf09987b4baf510fee5c99"}, + {file = "ruff-0.6.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:525201b77f94d2b54868f0cbe5edc018e64c22563da6c5c2e5c107a4e85c1c0d"}, + {file = "ruff-0.6.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8854450839f339e1049fdbe15d875384242b8e85d5c6947bb2faad33c651020b"}, + {file = "ruff-0.6.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2f0b62056246234d59cbf2ea66e84812dc9ec4540518e37553513392c171cb18"}, + {file = "ruff-0.6.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b1462fa56c832dc0cea5b4041cfc9c97813505d11cce74ebc6d1aae068de36b"}, + {file = "ruff-0.6.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:02b083770e4cdb1495ed313f5694c62808e71764ec6ee5db84eedd82fd32d8f5"}, + {file = "ruff-0.6.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0c05fd37013de36dfa883a3854fae57b3113aaa8abf5dea79202675991d48624"}, + {file = "ruff-0.6.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f49c9caa28d9bbfac4a637ae10327b3db00f47d038f3fbb2195c4d682e925b14"}, + {file = "ruff-0.6.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a0e1655868164e114ba43a908fd2d64a271a23660195017c17691fb6355d59bb"}, + {file = "ruff-0.6.7-py3-none-win32.whl", hash = "sha256:a939ca435b49f6966a7dd64b765c9df16f1faed0ca3b6f16acdf7731969deb35"}, + {file = "ruff-0.6.7-py3-none-win_amd64.whl", hash = "sha256:590445eec5653f36248584579c06252ad2e110a5d1f32db5420de35fb0e1c977"}, + {file = "ruff-0.6.7-py3-none-win_arm64.whl", hash = "sha256:b28f0d5e2f771c1fe3c7a45d3f53916fc74a480698c4b5731f0bea61e52137c8"}, + {file = "ruff-0.6.7.tar.gz", hash = "sha256:44e52129d82266fa59b587e2cd74def5637b730a69c4542525dfdecfaae38bd5"}, ] diff --git a/pyproject.toml b/pyproject.toml index b1e5a64..2e41bbd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,22 +7,21 @@ authors = [ ] dependencies = [ "amaranth>=0.5.1", + "amaranth-boards>=0", ] requires-python = "==3.12.*" readme = "README.md" license = {text = "MIT"} - -[tool.pdm] -distribution = false - -[tool.pdm.dev-dependencies] # or the poetry equivalent +[tool.pdm.dev-dependencies] dev = [ - "basedpyright", # you can pin the version here if you want, or just rely on the lockfile + "basedpyright", "ruff", "pytest>=8.3.2", ] +[project.scripts] +groovylight = "groovylight.main:main" [tool.ruff.lint] diff --git a/src/groovylight/main.py b/src/groovylight/main.py new file mode 100644 index 0000000..fd11adc --- /dev/null +++ b/src/groovylight/main.py @@ -0,0 +1,50 @@ +# main entry point for CLI applications. + + +import logging +import argparse + + +logger = logging.getLogger(__loader__.name) + + +def setup_logger(args): + root_logger = logging.getLogger() + handler = logging.StreamHandler() + + formatter = logging.Formatter( + style="{", fmt="{levelname:s}: {name:s}: {message:s}" + ) + handler.setFormatter(formatter) + + root_logger.addHandler(handler) + root_logger.setLevel(args.loglevel) + + +def main(): + parser = argparse.ArgumentParser() + + parser.add_argument( + "-d", + "--debug", + help="Print debug-level statements", + action="store_const", + dest="loglevel", + const=logging.DEBUG, + default=logging.INFO, + ) + parser.add_argument( + "-L", + "--log-file", + help="Log to file", + type=argparse.FileType("w"), + metavar="FILE", + ) + + args = parser.parse_args() + + setup_logger(args) + + +if __name__ == "__main__": + main() diff --git a/src/groovylight/platforms/colorlight_5a75b_v8_2.py b/src/groovylight/platforms/colorlight_5a75b_v8_2.py new file mode 100644 index 0000000..f992258 --- /dev/null +++ b/src/groovylight/platforms/colorlight_5a75b_v8_2.py @@ -0,0 +1,96 @@ +import os +import subprocess +from amaranth.vendor import LatticeECP5Platform +from amaranth.build import Resource, Pins, Attrs, Clock, Subsignal, PinsN, Connector +from amaranth_boards.resources import SDRAMResource + + +class Colorlight_5A75B_R82Platform(LatticeECP5Platform): + device = "LFE5U-25F" + package = "BG256" + speed = "6" + default_clk = "clk25" + + resources = [ + Resource( + "clk25", 0, Pins("P6", dir="i"), Clock(25e6), Attrs(IO_TYPE="LVCMOS33") + ), + Resource( + "spi_flash", + 0, + Subsignal("cs", PinsN("N8", dir="o")), + Subsignal("cipo", Pins("T7", dir="i")), + Subsignal("copi", Pins("T8", dir="o")), + Attrs(IO_TYPE="LVCMOS33"), + ), + Resource("usr_btn", 0, Pins("R7", dir="i"), Attrs(IO_TYPE="LVCMOS33")), + Resource("usr_led", 0, Pins("T6", dir="o"), Attrs(IO_TYPE="LVCMOS33")), + 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 B14 D14 D13 " + "E11 C13 D11 C12 D10 C11 D10", + attrs=Attrs( + PULLMODE="NONE", DRIVE="4", SLEWRATE="FAST", IO_TYPE="LVCMOS33" + ), + ), + 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"), + ), + # Broadcom B50612D Gigabit Ethernet Transceiver + 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 F3 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 -"), + ] + + @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])