Introducing the smc peripheral Co-authored-by: hailin wu <hailin.wu@aspeedtech.com>
diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 8a91f25..8c16755 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock
@@ -2747,8 +2747,8 @@ "bzlTransitiveDigest": "pJGPYIkbVrEoiR6YLuU72xx4PvVY4idccFMOWJLmQ+4=", "usagesDigest": "/Nz9QH+EBlDXoVXWiAEH8owsAo1cu+GkXjlRdolG7Sk=", "recordedFileInputs": { - "@@//third_party/crates_io/Cargo.lock": "fceaaabe11711662d270b2d8d38d98d379704ecc394b1f1cbcfef930d9ae932a", - "@@//third_party/crates_io/Cargo.toml": "d79aadc37ac91c8bd72ad8ca8fa294bc16c18c90d7782e4c4354c4c6b04a13dc", + "@@//third_party/crates_io/Cargo.lock": "c8d7a00cd9081a5935c93eafea054e8d69d1c6322e5c6d4fbe0464693208b4f2", + "@@//third_party/crates_io/Cargo.toml": "d88440ec6c2a131a354f20107470c17c1b81166cda3ee71a75bee2b477bd0528", "@@caliptra_deps+//crates_io/embedded/Cargo.lock": "d6c0101f48da22f2bc2d339f358de79bad3dd03218c6db29a14099b9f7757691", "@@caliptra_deps+//crates_io/embedded/Cargo.toml": "8f9f4ed2721db13476b12fdac045dac2142b38f189a8abb5f4c446dc0c6ac3dd", "@@caliptra_deps+//crates_io/host/Cargo.lock": "ae555b01424917ec61d892c15d7a66af88c2f10be4e0e7b0bc2357b702883b89", @@ -2774,9 +2774,9 @@ "repoRuleId": "@@rules_rust+//crate_universe:extensions.bzl%_generate_repo", "attributes": { "contents": { - "BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'openprot'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files(\n [\n \"cargo-bazel.json\",\n \"crates.bzl\",\n \"defs.bzl\",\n ] + glob(\n allow_empty = True,\n include = [\"*.bazel\"],\n ),\n)\n\nfilegroup(\n name = \"srcs\",\n srcs = glob(\n allow_empty = True,\n include = [\n \"*.bazel\",\n \"*.bzl\",\n ],\n ),\n)\n\n# Workspace Member Dependencies\nalias(\n name = \"aes-0.8.4\",\n actual = \"@rust_crates__aes-0.8.4//:aes\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"aes\",\n actual = \"@rust_crates__aes-0.8.4//:aes\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"aes-gcm-0.10.3\",\n actual = \"@rust_crates__aes-gcm-0.10.3//:aes_gcm\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"aes-gcm\",\n actual = \"@rust_crates__aes-gcm-0.10.3//:aes_gcm\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"aligned-0.4.3\",\n actual = \"@rust_crates__aligned-0.4.3//:aligned\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"aligned\",\n actual = \"@rust_crates__aligned-0.4.3//:aligned\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"anyhow-1.0.102\",\n actual = \"@rust_crates__anyhow-1.0.102//:anyhow\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"anyhow\",\n actual = \"@rust_crates__anyhow-1.0.102//:anyhow\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"bitfield-0.14.0\",\n actual = \"@rust_crates__bitfield-0.14.0//:bitfield\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"bitfield\",\n actual = \"@rust_crates__bitfield-0.14.0//:bitfield\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"bitfield-struct-0.11.0\",\n actual = \"@rust_crates__bitfield-struct-0.11.0//:bitfield_struct\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"bitfield-struct\",\n actual = \"@rust_crates__bitfield-struct-0.11.0//:bitfield_struct\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"bitflags-2.11.1\",\n actual = \"@rust_crates__bitflags-2.11.1//:bitflags\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"bitflags\",\n actual = \"@rust_crates__bitflags-2.11.1//:bitflags\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"byteorder-1.5.0\",\n actual = \"@rust_crates__byteorder-1.5.0//:byteorder\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"byteorder\",\n actual = \"@rust_crates__byteorder-1.5.0//:byteorder\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"cfg-if-1.0.4\",\n actual = \"@rust_crates__cfg-if-1.0.4//:cfg_if\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"cfg-if\",\n actual = \"@rust_crates__cfg-if-1.0.4//:cfg_if\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"cipher-0.4.4\",\n actual = \"@rust_crates__cipher-0.4.4//:cipher\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"cipher\",\n actual = \"@rust_crates__cipher-0.4.4//:cipher\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"clap-4.6.1\",\n actual = \"@rust_crates__clap-4.6.1//:clap\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"clap\",\n actual = \"@rust_crates__clap-4.6.1//:clap\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"compiler_builtins-0.1.160\",\n actual = \"@rust_crates__compiler_builtins-0.1.160//:compiler_builtins\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"compiler_builtins\",\n actual = \"@rust_crates__compiler_builtins-0.1.160//:compiler_builtins\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"cortex-m-0.7.7\",\n actual = \"@rust_crates__cortex-m-0.7.7//:cortex_m\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"cortex-m\",\n actual = \"@rust_crates__cortex-m-0.7.7//:cortex_m\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"cortex-m-rt-0.7.5\",\n actual = \"@rust_crates__cortex-m-rt-0.7.5//:cortex_m_rt\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"cortex-m-rt\",\n actual = \"@rust_crates__cortex-m-rt-0.7.5//:cortex_m_rt\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"cortex-m-semihosting-0.5.0\",\n actual = \"@rust_crates__cortex-m-semihosting-0.5.0//:cortex_m_semihosting\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"cortex-m-semihosting\",\n actual = \"@rust_crates__cortex-m-semihosting-0.5.0//:cortex_m_semihosting\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"ctr-0.9.2\",\n actual = \"@rust_crates__ctr-0.9.2//:ctr\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"ctr\",\n actual = \"@rust_crates__ctr-0.9.2//:ctr\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"ecdsa-0.16.9\",\n actual = \"@rust_crates__ecdsa-0.16.9//:ecdsa\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"ecdsa\",\n actual = \"@rust_crates__ecdsa-0.16.9//:ecdsa\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"embedded-hal-1.0.0\",\n actual = \"@rust_crates__embedded-hal-1.0.0//:embedded_hal\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"embedded-hal\",\n actual = \"@rust_crates__embedded-hal-1.0.0//:embedded_hal\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"embedded-hal-async-1.0.0\",\n actual = \"@rust_crates__embedded-hal-async-1.0.0//:embedded_hal_async\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"embedded-hal-async\",\n actual = \"@rust_crates__embedded-hal-async-1.0.0//:embedded_hal_async\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"embedded-hal-nb-1.0.0\",\n actual = \"@rust_crates__embedded-hal-nb-1.0.0//:embedded_hal_nb\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"embedded-hal-nb\",\n actual = \"@rust_crates__embedded-hal-nb-1.0.0//:embedded_hal_nb\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"embedded-io-0.6.1\",\n actual = \"@rust_crates__embedded-io-0.6.1//:embedded_io\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"embedded-io\",\n actual = \"@rust_crates__embedded-io-0.6.1//:embedded_io\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"fugit-0.3.9\",\n actual = \"@rust_crates__fugit-0.3.9//:fugit\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"fugit\",\n actual = \"@rust_crates__fugit-0.3.9//:fugit\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"futures-0.3.32\",\n actual = \"@rust_crates__futures-0.3.32//:futures\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"futures\",\n actual = \"@rust_crates__futures-0.3.32//:futures\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"heapless-0.9.2\",\n actual = \"@rust_crates__heapless-0.9.2//:heapless\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"heapless\",\n actual = \"@rust_crates__heapless-0.9.2//:heapless\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"hex-0.4.3\",\n actual = \"@rust_crates__hex-0.4.3//:hex\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"hex\",\n actual = \"@rust_crates__hex-0.4.3//:hex\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"hex-literal-0.4.1\",\n actual = \"@rust_crates__hex-literal-0.4.1//:hex_literal\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"hex-literal\",\n actual = \"@rust_crates__hex-literal-0.4.1//:hex_literal\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"hmac-0.12.1\",\n actual = \"@rust_crates__hmac-0.12.1//:hmac\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"hmac\",\n actual = \"@rust_crates__hmac-0.12.1//:hmac\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"k256-0.13.4\",\n actual = \"@rust_crates__k256-0.13.4//:k256\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"k256\",\n actual = \"@rust_crates__k256-0.13.4//:k256\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"log-0.4.29\",\n actual = \"@rust_crates__log-0.4.29//:log\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"log\",\n actual = \"@rust_crates__log-0.4.29//:log\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"mctp-0.2.0\",\n actual = \"@rust_crates__mctp-0.2.0//:mctp\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"mctp\",\n actual = \"@rust_crates__mctp-0.2.0//:mctp\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"mctp-lib-0.1.0\",\n actual = \"@rust_crates__mctp-lib-0.1.0//:mctp_lib\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"mctp-lib\",\n actual = \"@rust_crates__mctp-lib-0.1.0//:mctp_lib\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"memoffset-0.9.1\",\n actual = \"@rust_crates__memoffset-0.9.1//:memoffset\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"memoffset\",\n actual = \"@rust_crates__memoffset-0.9.1//:memoffset\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"minijinja-2.19.0\",\n actual = \"@rust_crates__minijinja-2.19.0//:minijinja\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"minijinja\",\n actual = \"@rust_crates__minijinja-2.19.0//:minijinja\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"nb-1.1.0\",\n actual = \"@rust_crates__nb-1.1.0//:nb\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"nb\",\n actual = \"@rust_crates__nb-1.1.0//:nb\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"nom-7.1.3\",\n actual = \"@rust_crates__nom-7.1.3//:nom\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"nom\",\n actual = \"@rust_crates__nom-7.1.3//:nom\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"object-0.37.3\",\n actual = \"@rust_crates__object-0.37.3//:object\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"object\",\n actual = \"@rust_crates__object-0.37.3//:object\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"openprot-hal-blocking-0.1.0\",\n actual = \"@rust_crates__openprot-hal-blocking-0.1.0//:openprot_hal_blocking\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"openprot-hal-blocking\",\n actual = \"@rust_crates__openprot-hal-blocking-0.1.0//:openprot_hal_blocking\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"p256-0.13.2\",\n actual = \"@rust_crates__p256-0.13.2//:p256\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"p256\",\n actual = \"@rust_crates__p256-0.13.2//:p256\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"p384-0.13.1\",\n actual = \"@rust_crates__p384-0.13.1//:p384\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"p384\",\n actual = \"@rust_crates__p384-0.13.1//:p384\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"panic-halt-1.0.0\",\n actual = \"@rust_crates__panic-halt-1.0.0//:panic_halt\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"panic-halt\",\n actual = \"@rust_crates__panic-halt-1.0.0//:panic_halt\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"paste-1.0.15\",\n actual = \"@rust_crates__paste-1.0.15//:paste\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"paste\",\n actual = \"@rust_crates__paste-1.0.15//:paste\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"proc-macro2-1.0.106\",\n actual = \"@rust_crates__proc-macro2-1.0.106//:proc_macro2\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"proc-macro2\",\n actual = \"@rust_crates__proc-macro2-1.0.106//:proc_macro2\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"prost-0.13.5\",\n actual = \"@rust_crates__prost-0.13.5//:prost\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"prost\",\n actual = \"@rust_crates__prost-0.13.5//:prost\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"quote-1.0.45\",\n actual = \"@rust_crates__quote-1.0.45//:quote\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"quote\",\n actual = \"@rust_crates__quote-1.0.45//:quote\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"rand_core-0.9.5\",\n actual = \"@rust_crates__rand_core-0.9.5//:rand_core\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"rand_core\",\n actual = \"@rust_crates__rand_core-0.9.5//:rand_core\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"riscv-0.12.1\",\n actual = \"@rust_crates__riscv-0.12.1//:riscv\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"riscv\",\n actual = \"@rust_crates__riscv-0.12.1//:riscv\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"riscv-rt-0.12.2\",\n actual = \"@rust_crates__riscv-rt-0.12.2//:riscv_rt\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"riscv-rt\",\n actual = \"@rust_crates__riscv-rt-0.12.2//:riscv_rt\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"riscv-semihosting-0.1.3\",\n actual = \"@rust_crates__riscv-semihosting-0.1.3//:riscv_semihosting\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"riscv-semihosting\",\n actual = \"@rust_crates__riscv-semihosting-0.1.3//:riscv_semihosting\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"rustc-demangle-0.1.27\",\n actual = \"@rust_crates__rustc-demangle-0.1.27//:rustc_demangle\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"rustc-demangle\",\n actual = \"@rust_crates__rustc-demangle-0.1.27//:rustc_demangle\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"sec1-0.7.3\",\n actual = \"@rust_crates__sec1-0.7.3//:sec1\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"sec1\",\n actual = \"@rust_crates__sec1-0.7.3//:sec1\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde-1.0.228\",\n actual = \"@rust_crates__serde-1.0.228//:serde\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde\",\n actual = \"@rust_crates__serde-1.0.228//:serde\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde_derive-1.0.228\",\n actual = \"@rust_crates__serde_derive-1.0.228//:serde_derive\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde_derive\",\n actual = \"@rust_crates__serde_derive-1.0.228//:serde_derive\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde_json5-0.2.1\",\n actual = \"@rust_crates__serde_json5-0.2.1//:serde_json5\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde_json5\",\n actual = \"@rust_crates__serde_json5-0.2.1//:serde_json5\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"sha2-0.10.9\",\n actual = \"@rust_crates__sha2-0.10.9//:sha2\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"sha2\",\n actual = \"@rust_crates__sha2-0.10.9//:sha2\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"sha3-0.10.9\",\n actual = \"@rust_crates__sha3-0.10.9//:sha3\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"sha3\",\n actual = \"@rust_crates__sha3-0.10.9//:sha3\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"smlang-0.8.0\",\n actual = \"@rust_crates__smlang-0.8.0//:smlang\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"smlang\",\n actual = \"@rust_crates__smlang-0.8.0//:smlang\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"subtle-2.6.1\",\n actual = \"@rust_crates__subtle-2.6.1//:subtle\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"subtle\",\n actual = \"@rust_crates__subtle-2.6.1//:subtle\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"syn-1.0.109\",\n actual = \"@rust_crates__syn-1.0.109//:syn\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"syn1-1.0.109\",\n actual = \"@rust_crates__syn-1.0.109//:syn\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"syn1\",\n actual = \"@rust_crates__syn-1.0.109//:syn\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"syn-2.0.117\",\n actual = \"@rust_crates__syn-2.0.117//:syn\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"syn\",\n actual = \"@rust_crates__syn-2.0.117//:syn\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"thiserror-2.0.18\",\n actual = \"@rust_crates__thiserror-2.0.18//:thiserror\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"thiserror\",\n actual = \"@rust_crates__thiserror-2.0.18//:thiserror\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tock-registers-0.9.0\",\n actual = \"@rust_crates__tock-registers-0.9.0//:tock_registers\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tock-registers\",\n actual = \"@rust_crates__tock-registers-0.9.0//:tock_registers\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tokio-1.52.1\",\n actual = \"@rust_crates__tokio-1.52.1//:tokio\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tokio\",\n actual = \"@rust_crates__tokio-1.52.1//:tokio\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tokio-util-0.7.18\",\n actual = \"@rust_crates__tokio-util-0.7.18//:tokio_util\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tokio-util\",\n actual = \"@rust_crates__tokio-util-0.7.18//:tokio_util\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"vcell-0.1.3\",\n actual = \"@rust_crates__vcell-0.1.3//:vcell\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"vcell\",\n actual = \"@rust_crates__vcell-0.1.3//:vcell\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"zerocopy-0.8.48\",\n actual = \"@rust_crates__zerocopy-0.8.48//:zerocopy\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"zerocopy\",\n actual = \"@rust_crates__zerocopy-0.8.48//:zerocopy\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"zeroize-1.8.2\",\n actual = \"@rust_crates__zeroize-1.8.2//:zeroize\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"zeroize\",\n actual = \"@rust_crates__zeroize-1.8.2//:zeroize\",\n tags = [\"manual\"],\n)\n", + "BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'openprot'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files(\n [\n \"cargo-bazel.json\",\n \"crates.bzl\",\n \"defs.bzl\",\n ] + glob(\n allow_empty = True,\n include = [\"*.bazel\"],\n ),\n)\n\nfilegroup(\n name = \"srcs\",\n srcs = glob(\n allow_empty = True,\n include = [\n \"*.bazel\",\n \"*.bzl\",\n ],\n ),\n)\n\n# Workspace Member Dependencies\nalias(\n name = \"aes-0.8.4\",\n actual = \"@rust_crates__aes-0.8.4//:aes\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"aes\",\n actual = \"@rust_crates__aes-0.8.4//:aes\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"aes-gcm-0.10.3\",\n actual = \"@rust_crates__aes-gcm-0.10.3//:aes_gcm\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"aes-gcm\",\n actual = \"@rust_crates__aes-gcm-0.10.3//:aes_gcm\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"aligned-0.4.3\",\n actual = \"@rust_crates__aligned-0.4.3//:aligned\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"aligned\",\n actual = \"@rust_crates__aligned-0.4.3//:aligned\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"anyhow-1.0.102\",\n actual = \"@rust_crates__anyhow-1.0.102//:anyhow\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"anyhow\",\n actual = \"@rust_crates__anyhow-1.0.102//:anyhow\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"bitfield-0.14.0\",\n actual = \"@rust_crates__bitfield-0.14.0//:bitfield\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"bitfield\",\n actual = \"@rust_crates__bitfield-0.14.0//:bitfield\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"bitfield-struct-0.11.0\",\n actual = \"@rust_crates__bitfield-struct-0.11.0//:bitfield_struct\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"bitfield-struct\",\n actual = \"@rust_crates__bitfield-struct-0.11.0//:bitfield_struct\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"bitflags-2.11.1\",\n actual = \"@rust_crates__bitflags-2.11.1//:bitflags\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"bitflags\",\n actual = \"@rust_crates__bitflags-2.11.1//:bitflags\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"byteorder-1.5.0\",\n actual = \"@rust_crates__byteorder-1.5.0//:byteorder\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"byteorder\",\n actual = \"@rust_crates__byteorder-1.5.0//:byteorder\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"cfg-if-1.0.4\",\n actual = \"@rust_crates__cfg-if-1.0.4//:cfg_if\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"cfg-if\",\n actual = \"@rust_crates__cfg-if-1.0.4//:cfg_if\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"cipher-0.4.4\",\n actual = \"@rust_crates__cipher-0.4.4//:cipher\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"cipher\",\n actual = \"@rust_crates__cipher-0.4.4//:cipher\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"clap-4.6.1\",\n actual = \"@rust_crates__clap-4.6.1//:clap\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"clap\",\n actual = \"@rust_crates__clap-4.6.1//:clap\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"compiler_builtins-0.1.160\",\n actual = \"@rust_crates__compiler_builtins-0.1.160//:compiler_builtins\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"compiler_builtins\",\n actual = \"@rust_crates__compiler_builtins-0.1.160//:compiler_builtins\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"cortex-m-0.7.7\",\n actual = \"@rust_crates__cortex-m-0.7.7//:cortex_m\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"cortex-m\",\n actual = \"@rust_crates__cortex-m-0.7.7//:cortex_m\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"cortex-m-rt-0.7.5\",\n actual = \"@rust_crates__cortex-m-rt-0.7.5//:cortex_m_rt\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"cortex-m-rt\",\n actual = \"@rust_crates__cortex-m-rt-0.7.5//:cortex_m_rt\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"cortex-m-semihosting-0.5.0\",\n actual = \"@rust_crates__cortex-m-semihosting-0.5.0//:cortex_m_semihosting\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"cortex-m-semihosting\",\n actual = \"@rust_crates__cortex-m-semihosting-0.5.0//:cortex_m_semihosting\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"ctr-0.9.2\",\n actual = \"@rust_crates__ctr-0.9.2//:ctr\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"ctr\",\n actual = \"@rust_crates__ctr-0.9.2//:ctr\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"ecdsa-0.16.9\",\n actual = \"@rust_crates__ecdsa-0.16.9//:ecdsa\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"ecdsa\",\n actual = \"@rust_crates__ecdsa-0.16.9//:ecdsa\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"embedded-hal-1.0.0\",\n actual = \"@rust_crates__embedded-hal-1.0.0//:embedded_hal\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"embedded-hal\",\n actual = \"@rust_crates__embedded-hal-1.0.0//:embedded_hal\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"embedded-hal-async-1.0.0\",\n actual = \"@rust_crates__embedded-hal-async-1.0.0//:embedded_hal_async\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"embedded-hal-async\",\n actual = \"@rust_crates__embedded-hal-async-1.0.0//:embedded_hal_async\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"embedded-hal-nb-1.0.0\",\n actual = \"@rust_crates__embedded-hal-nb-1.0.0//:embedded_hal_nb\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"embedded-hal-nb\",\n actual = \"@rust_crates__embedded-hal-nb-1.0.0//:embedded_hal_nb\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"embedded-io-0.6.1\",\n actual = \"@rust_crates__embedded-io-0.6.1//:embedded_io\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"embedded-io\",\n actual = \"@rust_crates__embedded-io-0.6.1//:embedded_io\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"embedded-storage-0.3.1\",\n actual = \"@rust_crates__embedded-storage-0.3.1//:embedded_storage\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"embedded-storage\",\n actual = \"@rust_crates__embedded-storage-0.3.1//:embedded_storage\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"fugit-0.3.9\",\n actual = \"@rust_crates__fugit-0.3.9//:fugit\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"fugit\",\n actual = \"@rust_crates__fugit-0.3.9//:fugit\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"futures-0.3.32\",\n actual = \"@rust_crates__futures-0.3.32//:futures\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"futures\",\n actual = \"@rust_crates__futures-0.3.32//:futures\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"heapless-0.9.2\",\n actual = \"@rust_crates__heapless-0.9.2//:heapless\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"heapless\",\n actual = \"@rust_crates__heapless-0.9.2//:heapless\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"hex-0.4.3\",\n actual = \"@rust_crates__hex-0.4.3//:hex\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"hex\",\n actual = \"@rust_crates__hex-0.4.3//:hex\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"hex-literal-0.4.1\",\n actual = \"@rust_crates__hex-literal-0.4.1//:hex_literal\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"hex-literal\",\n actual = \"@rust_crates__hex-literal-0.4.1//:hex_literal\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"hmac-0.12.1\",\n actual = \"@rust_crates__hmac-0.12.1//:hmac\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"hmac\",\n actual = \"@rust_crates__hmac-0.12.1//:hmac\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"k256-0.13.4\",\n actual = \"@rust_crates__k256-0.13.4//:k256\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"k256\",\n actual = \"@rust_crates__k256-0.13.4//:k256\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"log-0.4.29\",\n actual = \"@rust_crates__log-0.4.29//:log\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"log\",\n actual = \"@rust_crates__log-0.4.29//:log\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"mctp-0.2.0\",\n actual = \"@rust_crates__mctp-0.2.0//:mctp\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"mctp\",\n actual = \"@rust_crates__mctp-0.2.0//:mctp\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"mctp-lib-0.1.0\",\n actual = \"@rust_crates__mctp-lib-0.1.0//:mctp_lib\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"mctp-lib\",\n actual = \"@rust_crates__mctp-lib-0.1.0//:mctp_lib\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"memoffset-0.9.1\",\n actual = \"@rust_crates__memoffset-0.9.1//:memoffset\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"memoffset\",\n actual = \"@rust_crates__memoffset-0.9.1//:memoffset\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"minijinja-2.19.0\",\n actual = \"@rust_crates__minijinja-2.19.0//:minijinja\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"minijinja\",\n actual = \"@rust_crates__minijinja-2.19.0//:minijinja\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"nb-1.1.0\",\n actual = \"@rust_crates__nb-1.1.0//:nb\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"nb\",\n actual = \"@rust_crates__nb-1.1.0//:nb\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"nom-7.1.3\",\n actual = \"@rust_crates__nom-7.1.3//:nom\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"nom\",\n actual = \"@rust_crates__nom-7.1.3//:nom\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"object-0.37.3\",\n actual = \"@rust_crates__object-0.37.3//:object\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"object\",\n actual = \"@rust_crates__object-0.37.3//:object\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"openprot-hal-blocking-0.1.0\",\n actual = \"@rust_crates__openprot-hal-blocking-0.1.0//:openprot_hal_blocking\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"openprot-hal-blocking\",\n actual = \"@rust_crates__openprot-hal-blocking-0.1.0//:openprot_hal_blocking\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"p256-0.13.2\",\n actual = \"@rust_crates__p256-0.13.2//:p256\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"p256\",\n actual = \"@rust_crates__p256-0.13.2//:p256\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"p384-0.13.1\",\n actual = \"@rust_crates__p384-0.13.1//:p384\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"p384\",\n actual = \"@rust_crates__p384-0.13.1//:p384\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"panic-halt-1.0.0\",\n actual = \"@rust_crates__panic-halt-1.0.0//:panic_halt\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"panic-halt\",\n actual = \"@rust_crates__panic-halt-1.0.0//:panic_halt\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"paste-1.0.15\",\n actual = \"@rust_crates__paste-1.0.15//:paste\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"paste\",\n actual = \"@rust_crates__paste-1.0.15//:paste\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"proc-macro2-1.0.106\",\n actual = \"@rust_crates__proc-macro2-1.0.106//:proc_macro2\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"proc-macro2\",\n actual = \"@rust_crates__proc-macro2-1.0.106//:proc_macro2\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"prost-0.13.5\",\n actual = \"@rust_crates__prost-0.13.5//:prost\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"prost\",\n actual = \"@rust_crates__prost-0.13.5//:prost\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"quote-1.0.45\",\n actual = \"@rust_crates__quote-1.0.45//:quote\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"quote\",\n actual = \"@rust_crates__quote-1.0.45//:quote\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"rand_core-0.9.5\",\n actual = \"@rust_crates__rand_core-0.9.5//:rand_core\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"rand_core\",\n actual = \"@rust_crates__rand_core-0.9.5//:rand_core\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"riscv-0.12.1\",\n actual = \"@rust_crates__riscv-0.12.1//:riscv\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"riscv\",\n actual = \"@rust_crates__riscv-0.12.1//:riscv\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"riscv-rt-0.12.2\",\n actual = \"@rust_crates__riscv-rt-0.12.2//:riscv_rt\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"riscv-rt\",\n actual = \"@rust_crates__riscv-rt-0.12.2//:riscv_rt\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"riscv-semihosting-0.1.3\",\n actual = \"@rust_crates__riscv-semihosting-0.1.3//:riscv_semihosting\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"riscv-semihosting\",\n actual = \"@rust_crates__riscv-semihosting-0.1.3//:riscv_semihosting\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"rustc-demangle-0.1.27\",\n actual = \"@rust_crates__rustc-demangle-0.1.27//:rustc_demangle\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"rustc-demangle\",\n actual = \"@rust_crates__rustc-demangle-0.1.27//:rustc_demangle\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"sec1-0.7.3\",\n actual = \"@rust_crates__sec1-0.7.3//:sec1\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"sec1\",\n actual = \"@rust_crates__sec1-0.7.3//:sec1\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde-1.0.228\",\n actual = \"@rust_crates__serde-1.0.228//:serde\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde\",\n actual = \"@rust_crates__serde-1.0.228//:serde\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde_derive-1.0.228\",\n actual = \"@rust_crates__serde_derive-1.0.228//:serde_derive\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde_derive\",\n actual = \"@rust_crates__serde_derive-1.0.228//:serde_derive\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde_json5-0.2.1\",\n actual = \"@rust_crates__serde_json5-0.2.1//:serde_json5\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde_json5\",\n actual = \"@rust_crates__serde_json5-0.2.1//:serde_json5\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"sha2-0.10.9\",\n actual = \"@rust_crates__sha2-0.10.9//:sha2\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"sha2\",\n actual = \"@rust_crates__sha2-0.10.9//:sha2\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"sha3-0.10.9\",\n actual = \"@rust_crates__sha3-0.10.9//:sha3\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"sha3\",\n actual = \"@rust_crates__sha3-0.10.9//:sha3\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"smlang-0.8.0\",\n actual = \"@rust_crates__smlang-0.8.0//:smlang\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"smlang\",\n actual = \"@rust_crates__smlang-0.8.0//:smlang\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"subtle-2.6.1\",\n actual = \"@rust_crates__subtle-2.6.1//:subtle\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"subtle\",\n actual = \"@rust_crates__subtle-2.6.1//:subtle\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"syn-1.0.109\",\n actual = \"@rust_crates__syn-1.0.109//:syn\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"syn1-1.0.109\",\n actual = \"@rust_crates__syn-1.0.109//:syn\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"syn1\",\n actual = \"@rust_crates__syn-1.0.109//:syn\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"syn-2.0.117\",\n actual = \"@rust_crates__syn-2.0.117//:syn\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"syn\",\n actual = \"@rust_crates__syn-2.0.117//:syn\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"thiserror-2.0.18\",\n actual = \"@rust_crates__thiserror-2.0.18//:thiserror\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"thiserror\",\n actual = \"@rust_crates__thiserror-2.0.18//:thiserror\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tock-registers-0.9.0\",\n actual = \"@rust_crates__tock-registers-0.9.0//:tock_registers\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tock-registers\",\n actual = \"@rust_crates__tock-registers-0.9.0//:tock_registers\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tokio-1.52.1\",\n actual = \"@rust_crates__tokio-1.52.1//:tokio\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tokio\",\n actual = \"@rust_crates__tokio-1.52.1//:tokio\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tokio-util-0.7.18\",\n actual = \"@rust_crates__tokio-util-0.7.18//:tokio_util\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tokio-util\",\n actual = \"@rust_crates__tokio-util-0.7.18//:tokio_util\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"vcell-0.1.3\",\n actual = \"@rust_crates__vcell-0.1.3//:vcell\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"vcell\",\n actual = \"@rust_crates__vcell-0.1.3//:vcell\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"zerocopy-0.8.48\",\n actual = \"@rust_crates__zerocopy-0.8.48//:zerocopy\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"zerocopy\",\n actual = \"@rust_crates__zerocopy-0.8.48//:zerocopy\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"zeroize-1.8.2\",\n actual = \"@rust_crates__zeroize-1.8.2//:zeroize\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"zeroize\",\n actual = \"@rust_crates__zeroize-1.8.2//:zeroize\",\n tags = [\"manual\"],\n)\n", "alias_rules.bzl": "\"\"\"Alias that transitions its target to `compilation_mode=opt`. Use `transition_alias=\"opt\"` to enable.\"\"\"\n\nload(\"@rules_cc//cc:defs.bzl\", \"CcInfo\")\nload(\"@rules_rust//rust:rust_common.bzl\", \"COMMON_PROVIDERS\")\n\ndef _transition_alias_impl(ctx):\n # `ctx.attr.actual` is a list of 1 item due to the transition\n providers = [ctx.attr.actual[0][provider] for provider in COMMON_PROVIDERS]\n if CcInfo in ctx.attr.actual[0]:\n providers.append(ctx.attr.actual[0][CcInfo])\n return providers\n\ndef _change_compilation_mode(compilation_mode):\n def _change_compilation_mode_impl(_settings, _attr):\n return {\n \"//command_line_option:compilation_mode\": compilation_mode,\n }\n\n return transition(\n implementation = _change_compilation_mode_impl,\n inputs = [],\n outputs = [\n \"//command_line_option:compilation_mode\",\n ],\n )\n\ndef _transition_alias_rule(compilation_mode):\n return rule(\n implementation = _transition_alias_impl,\n provides = COMMON_PROVIDERS,\n attrs = {\n \"actual\": attr.label(\n mandatory = True,\n doc = \"`rust_library()` target to transition to `compilation_mode=opt`.\",\n providers = COMMON_PROVIDERS,\n cfg = _change_compilation_mode(compilation_mode),\n ),\n \"_allowlist_function_transition\": attr.label(\n default = \"@bazel_tools//tools/allowlists/function_transition_allowlist\",\n ),\n },\n doc = \"Transitions a Rust library crate to the `compilation_mode=opt`.\",\n )\n\ntransition_alias_dbg = _transition_alias_rule(\"dbg\")\ntransition_alias_fastbuild = _transition_alias_rule(\"fastbuild\")\ntransition_alias_opt = _transition_alias_rule(\"opt\")\n", - "defs.bzl": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'openprot'\n###############################################################################\n\"\"\"\n# `crates_repository` API\n\n- [aliases](#aliases)\n- [crate_deps](#crate_deps)\n- [all_crate_deps](#all_crate_deps)\n- [crate_repositories](#crate_repositories)\n\n\"\"\"\n\nload(\"@bazel_tools//tools/build_defs/repo:git.bzl\", \"git_repository\")\nload(\"@bazel_tools//tools/build_defs/repo:http.bzl\", \"http_archive\")\nload(\"@bazel_tools//tools/build_defs/repo:utils.bzl\", \"maybe\")\nload(\"@bazel_skylib//lib:selects.bzl\", \"selects\")\nload(\"@rules_rust//crate_universe/private:local_crate_mirror.bzl\", \"local_crate_mirror\")\n\n###############################################################################\n# MACROS API\n###############################################################################\n\n# An identifier that represent common dependencies (unconditional).\n_COMMON_CONDITION = \"\"\n\ndef _flatten_dependency_maps(all_dependency_maps):\n \"\"\"Flatten a list of dependency maps into one dictionary.\n\n Dependency maps have the following structure:\n\n ```python\n DEPENDENCIES_MAP = {\n # The first key in the map is a Bazel package\n # name of the workspace this file is defined in.\n \"workspace_member_package\": {\n\n # Not all dependencies are supported for all platforms.\n # the condition key is the condition required to be true\n # on the host platform.\n \"condition\": {\n\n # An alias to a crate target. # The label of the crate target the\n # Aliases are only crate names. # package name refers to.\n \"package_name\": \"@full//:label\",\n }\n }\n }\n ```\n\n Args:\n all_dependency_maps (list): A list of dicts as described above\n\n Returns:\n dict: A dictionary as described above\n \"\"\"\n dependencies = {}\n\n for workspace_deps_map in all_dependency_maps:\n for pkg_name, conditional_deps_map in workspace_deps_map.items():\n if pkg_name not in dependencies:\n non_frozen_map = dict()\n for key, values in conditional_deps_map.items():\n non_frozen_map.update({key: dict(values.items())})\n dependencies.setdefault(pkg_name, non_frozen_map)\n continue\n\n for condition, deps_map in conditional_deps_map.items():\n # If the condition has not been recorded, do so and continue\n if condition not in dependencies[pkg_name]:\n dependencies[pkg_name].setdefault(condition, dict(deps_map.items()))\n continue\n\n # Alert on any miss-matched dependencies\n inconsistent_entries = []\n for crate_name, crate_label in deps_map.items():\n existing = dependencies[pkg_name][condition].get(crate_name)\n if existing and existing != crate_label:\n inconsistent_entries.append((crate_name, existing, crate_label))\n dependencies[pkg_name][condition].update({crate_name: crate_label})\n\n return dependencies\n\ndef crate_deps(deps, package_name = None):\n \"\"\"Finds the fully qualified label of the requested crates for the package where this macro is called.\n\n Args:\n deps (list): The desired list of crate targets.\n package_name (str, optional): The package name of the set of dependencies to look up.\n Defaults to `native.package_name()`.\n\n Returns:\n list: A list of labels to generated rust targets (str)\n \"\"\"\n\n if not deps:\n return []\n\n if package_name == None:\n package_name = native.package_name()\n\n # Join both sets of dependencies\n dependencies = _flatten_dependency_maps([\n _NORMAL_DEPENDENCIES,\n _NORMAL_DEV_DEPENDENCIES,\n _PROC_MACRO_DEPENDENCIES,\n _PROC_MACRO_DEV_DEPENDENCIES,\n _BUILD_DEPENDENCIES,\n _BUILD_PROC_MACRO_DEPENDENCIES,\n ]).pop(package_name, {})\n\n # Combine all conditional packages so we can easily index over a flat list\n # TODO: Perhaps this should actually return select statements and maintain\n # the conditionals of the dependencies\n flat_deps = {}\n for deps_set in dependencies.values():\n for crate_name, crate_label in deps_set.items():\n flat_deps.update({crate_name: crate_label})\n\n missing_crates = []\n crate_targets = []\n for crate_target in deps:\n if crate_target not in flat_deps:\n missing_crates.append(crate_target)\n else:\n crate_targets.append(flat_deps[crate_target])\n\n if missing_crates:\n fail(\"Could not find crates `{}` among dependencies of `{}`. Available dependencies were `{}`\".format(\n missing_crates,\n package_name,\n dependencies,\n ))\n\n return crate_targets\n\ndef all_crate_deps(\n normal = False, \n normal_dev = False, \n proc_macro = False, \n proc_macro_dev = False,\n build = False,\n build_proc_macro = False,\n package_name = None):\n \"\"\"Finds the fully qualified label of all requested direct crate dependencies \\\n for the package where this macro is called.\n\n If no parameters are set, all normal dependencies are returned. Setting any one flag will\n otherwise impact the contents of the returned list.\n\n Args:\n normal (bool, optional): If True, normal dependencies are included in the\n output list.\n normal_dev (bool, optional): If True, normal dev dependencies will be\n included in the output list.\n proc_macro (bool, optional): If True, proc_macro dependencies are included\n in the output list.\n proc_macro_dev (bool, optional): If True, dev proc_macro dependencies are\n included in the output list.\n build (bool, optional): If True, build dependencies are included\n in the output list.\n build_proc_macro (bool, optional): If True, build proc_macro dependencies are\n included in the output list.\n package_name (str, optional): The package name of the set of dependencies to look up.\n Defaults to `native.package_name()` when unset.\n\n Returns:\n list: A list of labels to generated rust targets (str)\n \"\"\"\n\n if package_name == None:\n package_name = native.package_name()\n\n # Determine the relevant maps to use\n all_dependency_maps = []\n if normal:\n all_dependency_maps.append(_NORMAL_DEPENDENCIES)\n if normal_dev:\n all_dependency_maps.append(_NORMAL_DEV_DEPENDENCIES)\n if proc_macro:\n all_dependency_maps.append(_PROC_MACRO_DEPENDENCIES)\n if proc_macro_dev:\n all_dependency_maps.append(_PROC_MACRO_DEV_DEPENDENCIES)\n if build:\n all_dependency_maps.append(_BUILD_DEPENDENCIES)\n if build_proc_macro:\n all_dependency_maps.append(_BUILD_PROC_MACRO_DEPENDENCIES)\n\n # Default to always using normal dependencies\n if not all_dependency_maps:\n all_dependency_maps.append(_NORMAL_DEPENDENCIES)\n\n dependencies = _flatten_dependency_maps(all_dependency_maps).pop(package_name, None)\n\n if not dependencies:\n if dependencies == None:\n fail(\"Tried to get all_crate_deps for package \" + package_name + \" but that package had no Cargo.toml file\")\n else:\n return []\n\n crate_deps = list(dependencies.pop(_COMMON_CONDITION, {}).values())\n for condition, deps in dependencies.items():\n crate_deps += selects.with_or({\n tuple(_CONDITIONS[condition]): deps.values(),\n \"//conditions:default\": [],\n })\n\n return crate_deps\n\ndef aliases(\n normal = False,\n normal_dev = False,\n proc_macro = False,\n proc_macro_dev = False,\n build = False,\n build_proc_macro = False,\n package_name = None):\n \"\"\"Produces a map of Crate alias names to their original label\n\n If no dependency kinds are specified, `normal` and `proc_macro` are used by default.\n Setting any one flag will otherwise determine the contents of the returned dict.\n\n Args:\n normal (bool, optional): If True, normal dependencies are included in the\n output list.\n normal_dev (bool, optional): If True, normal dev dependencies will be\n included in the output list..\n proc_macro (bool, optional): If True, proc_macro dependencies are included\n in the output list.\n proc_macro_dev (bool, optional): If True, dev proc_macro dependencies are\n included in the output list.\n build (bool, optional): If True, build dependencies are included\n in the output list.\n build_proc_macro (bool, optional): If True, build proc_macro dependencies are\n included in the output list.\n package_name (str, optional): The package name of the set of dependencies to look up.\n Defaults to `native.package_name()` when unset.\n\n Returns:\n dict: The aliases of all associated packages\n \"\"\"\n if package_name == None:\n package_name = native.package_name()\n\n # Determine the relevant maps to use\n all_aliases_maps = []\n if normal:\n all_aliases_maps.append(_NORMAL_ALIASES)\n if normal_dev:\n all_aliases_maps.append(_NORMAL_DEV_ALIASES)\n if proc_macro:\n all_aliases_maps.append(_PROC_MACRO_ALIASES)\n if proc_macro_dev:\n all_aliases_maps.append(_PROC_MACRO_DEV_ALIASES)\n if build:\n all_aliases_maps.append(_BUILD_ALIASES)\n if build_proc_macro:\n all_aliases_maps.append(_BUILD_PROC_MACRO_ALIASES)\n\n # Default to always using normal aliases\n if not all_aliases_maps:\n all_aliases_maps.append(_NORMAL_ALIASES)\n all_aliases_maps.append(_PROC_MACRO_ALIASES)\n\n aliases = _flatten_dependency_maps(all_aliases_maps).pop(package_name, None)\n\n if not aliases:\n return dict()\n\n common_items = aliases.pop(_COMMON_CONDITION, {}).items()\n\n # If there are only common items in the dictionary, immediately return them\n if not len(aliases.keys()) == 1:\n return dict(common_items)\n\n # Build a single select statement where each conditional has accounted for the\n # common set of aliases.\n crate_aliases = {\"//conditions:default\": dict(common_items)}\n for condition, deps in aliases.items():\n condition_triples = _CONDITIONS[condition]\n for triple in condition_triples:\n if triple in crate_aliases:\n crate_aliases[triple].update(deps)\n else:\n crate_aliases.update({triple: dict(deps.items() + common_items)})\n\n return select(crate_aliases)\n\n###############################################################################\n# WORKSPACE MEMBER DEPS AND ALIASES\n###############################################################################\n\n_NORMAL_DEPENDENCIES = {\n \"third_party/crates_io\": {\n _COMMON_CONDITION: {\n \"aes\": Label(\"@rust_crates//:aes-0.8.4\"),\n \"aes-gcm\": Label(\"@rust_crates//:aes-gcm-0.10.3\"),\n \"aligned\": Label(\"@rust_crates//:aligned-0.4.3\"),\n \"anyhow\": Label(\"@rust_crates//:anyhow-1.0.102\"),\n \"bitfield\": Label(\"@rust_crates//:bitfield-0.14.0\"),\n \"bitflags\": Label(\"@rust_crates//:bitflags-2.11.1\"),\n \"byteorder\": Label(\"@rust_crates//:byteorder-1.5.0\"),\n \"cfg-if\": Label(\"@rust_crates//:cfg-if-1.0.4\"),\n \"cipher\": Label(\"@rust_crates//:cipher-0.4.4\"),\n \"clap\": Label(\"@rust_crates//:clap-4.6.1\"),\n \"compiler_builtins\": Label(\"@rust_crates//:compiler_builtins-0.1.160\"),\n \"cortex-m\": Label(\"@rust_crates//:cortex-m-0.7.7\"),\n \"cortex-m-rt\": Label(\"@rust_crates//:cortex-m-rt-0.7.5\"),\n \"cortex-m-semihosting\": Label(\"@rust_crates//:cortex-m-semihosting-0.5.0\"),\n \"ctr\": Label(\"@rust_crates//:ctr-0.9.2\"),\n \"ecdsa\": Label(\"@rust_crates//:ecdsa-0.16.9\"),\n \"embedded-hal\": Label(\"@rust_crates//:embedded-hal-1.0.0\"),\n \"embedded-hal-async\": Label(\"@rust_crates//:embedded-hal-async-1.0.0\"),\n \"embedded-hal-nb\": Label(\"@rust_crates//:embedded-hal-nb-1.0.0\"),\n \"embedded-io\": Label(\"@rust_crates//:embedded-io-0.6.1\"),\n \"fugit\": Label(\"@rust_crates//:fugit-0.3.9\"),\n \"futures\": Label(\"@rust_crates//:futures-0.3.32\"),\n \"heapless\": Label(\"@rust_crates//:heapless-0.9.2\"),\n \"hex\": Label(\"@rust_crates//:hex-0.4.3\"),\n \"hex-literal\": Label(\"@rust_crates//:hex-literal-0.4.1\"),\n \"hmac\": Label(\"@rust_crates//:hmac-0.12.1\"),\n \"k256\": Label(\"@rust_crates//:k256-0.13.4\"),\n \"log\": Label(\"@rust_crates//:log-0.4.29\"),\n \"mctp\": Label(\"@rust_crates//:mctp-0.2.0\"),\n \"mctp-lib\": Label(\"@rust_crates//:mctp-lib-0.1.0\"),\n \"memoffset\": Label(\"@rust_crates//:memoffset-0.9.1\"),\n \"minijinja\": Label(\"@rust_crates//:minijinja-2.19.0\"),\n \"nb\": Label(\"@rust_crates//:nb-1.1.0\"),\n \"nom\": Label(\"@rust_crates//:nom-7.1.3\"),\n \"object\": Label(\"@rust_crates//:object-0.37.3\"),\n \"openprot-hal-blocking\": Label(\"@rust_crates//:openprot-hal-blocking-0.1.0\"),\n \"p256\": Label(\"@rust_crates//:p256-0.13.2\"),\n \"p384\": Label(\"@rust_crates//:p384-0.13.1\"),\n \"panic-halt\": Label(\"@rust_crates//:panic-halt-1.0.0\"),\n \"proc-macro2\": Label(\"@rust_crates//:proc-macro2-1.0.106\"),\n \"prost\": Label(\"@rust_crates//:prost-0.13.5\"),\n \"quote\": Label(\"@rust_crates//:quote-1.0.45\"),\n \"rand_core\": Label(\"@rust_crates//:rand_core-0.9.5\"),\n \"riscv\": Label(\"@rust_crates//:riscv-0.12.1\"),\n \"riscv-rt\": Label(\"@rust_crates//:riscv-rt-0.12.2\"),\n \"riscv-semihosting\": Label(\"@rust_crates//:riscv-semihosting-0.1.3\"),\n \"rustc-demangle\": Label(\"@rust_crates//:rustc-demangle-0.1.27\"),\n \"sec1\": Label(\"@rust_crates//:sec1-0.7.3\"),\n \"serde\": Label(\"@rust_crates//:serde-1.0.228\"),\n \"serde_json5\": Label(\"@rust_crates//:serde_json5-0.2.1\"),\n \"sha2\": Label(\"@rust_crates//:sha2-0.10.9\"),\n \"sha3\": Label(\"@rust_crates//:sha3-0.10.9\"),\n \"smlang\": Label(\"@rust_crates//:smlang-0.8.0\"),\n \"subtle\": Label(\"@rust_crates//:subtle-2.6.1\"),\n \"syn1\": Label(\"@rust_crates//:syn-1.0.109\"),\n \"syn\": Label(\"@rust_crates//:syn-2.0.117\"),\n \"thiserror\": Label(\"@rust_crates//:thiserror-2.0.18\"),\n \"tock-registers\": Label(\"@rust_crates//:tock-registers-0.9.0\"),\n \"tokio\": Label(\"@rust_crates//:tokio-1.52.1\"),\n \"tokio-util\": Label(\"@rust_crates//:tokio-util-0.7.18\"),\n \"vcell\": Label(\"@rust_crates//:vcell-0.1.3\"),\n \"zerocopy\": Label(\"@rust_crates//:zerocopy-0.8.48\"),\n \"zeroize\": Label(\"@rust_crates//:zeroize-1.8.2\"),\n },\n },\n}\n\n\n_NORMAL_ALIASES = {\n \"third_party/crates_io\": {\n _COMMON_CONDITION: {\n Label(\"@rust_crates//:syn-1.0.109\"): \"syn1\",\n },\n },\n}\n\n\n_NORMAL_DEV_DEPENDENCIES = {\n \"third_party/crates_io\": {\n },\n}\n\n\n_NORMAL_DEV_ALIASES = {\n \"third_party/crates_io\": {\n },\n}\n\n\n_PROC_MACRO_DEPENDENCIES = {\n \"third_party/crates_io\": {\n _COMMON_CONDITION: {\n \"bitfield-struct\": Label(\"@rust_crates//:bitfield-struct-0.11.0\"),\n \"paste\": Label(\"@rust_crates//:paste-1.0.15\"),\n \"serde_derive\": Label(\"@rust_crates//:serde_derive-1.0.228\"),\n },\n },\n}\n\n\n_PROC_MACRO_ALIASES = {\n \"third_party/crates_io\": {\n },\n}\n\n\n_PROC_MACRO_DEV_DEPENDENCIES = {\n \"third_party/crates_io\": {\n },\n}\n\n\n_PROC_MACRO_DEV_ALIASES = {\n \"third_party/crates_io\": {\n },\n}\n\n\n_BUILD_DEPENDENCIES = {\n \"third_party/crates_io\": {\n },\n}\n\n\n_BUILD_ALIASES = {\n \"third_party/crates_io\": {\n },\n}\n\n\n_BUILD_PROC_MACRO_DEPENDENCIES = {\n \"third_party/crates_io\": {\n },\n}\n\n\n_BUILD_PROC_MACRO_ALIASES = {\n \"third_party/crates_io\": {\n },\n}\n\n\n_CONDITIONS = {\n \"aarch64-apple-darwin\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\"],\n \"aarch64-linux-android\": [],\n \"aarch64-unknown-linux-gnu\": [\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\"],\n \"cfg(all(any(target_os = \\\"linux\\\", target_os = \\\"android\\\"), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\": [],\n \"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\": [\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:riscv32imc-unknown-none-elf\",\"@rules_rust//rust/platform:thumbv7em-none-eabi\",\"@rules_rust//rust/platform:x86_64-apple-darwin\"],\n \"cfg(all(target_arch = \\\"aarch64\\\", target_os = \\\"linux\\\"))\": [\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\"],\n \"cfg(all(target_arch = \\\"aarch64\\\", target_vendor = \\\"apple\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\"],\n \"cfg(all(target_arch = \\\"loongarch64\\\", target_os = \\\"linux\\\"))\": [],\n \"cfg(any())\": [],\n \"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-apple-darwin\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any(target_arch = \\\"arm\\\", target_pointer_width = \\\"32\\\", target_pointer_width = \\\"64\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:riscv32imc-unknown-none-elf\",\"@rules_rust//rust/platform:thumbv7em-none-eabi\",\"@rules_rust//rust/platform:x86_64-apple-darwin\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any(unix, target_os = \\\"hermit\\\", target_os = \\\"wasi\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-apple-darwin\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any(unix, target_os = \\\"wasi\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-apple-darwin\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(target_arch = \\\"aarch64\\\")\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\"],\n \"cfg(target_os = \\\"hermit\\\")\": [],\n \"cfg(target_os = \\\"redox\\\")\": [],\n \"cfg(target_os = \\\"wasi\\\")\": [],\n \"cfg(unix)\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-apple-darwin\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(windows)\": [],\n \"riscv32imc-unknown-none-elf\": [\"@rules_rust//rust/platform:riscv32imc-unknown-none-elf\"],\n \"thumbv7em-none-eabi\": [\"@rules_rust//rust/platform:thumbv7em-none-eabi\"],\n \"x86_64-apple-darwin\": [\"@rules_rust//rust/platform:x86_64-apple-darwin\"],\n \"x86_64-unknown-linux-gnu\": [\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n}\n\n###############################################################################\n\ndef crate_repositories():\n \"\"\"A macro for defining repositories for all generated crates.\n\n Returns:\n A list of repos visible to the module through the module extension.\n \"\"\"\n maybe(\n http_archive,\n name = \"rust_crates__adler2-2.0.1\",\n sha256 = \"320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/adler2/2.0.1/download\"],\n strip_prefix = \"adler2-2.0.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.adler2-2.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__aead-0.5.2\",\n sha256 = \"d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/aead/0.5.2/download\"],\n strip_prefix = \"aead-0.5.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.aead-0.5.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__aes-0.8.4\",\n sha256 = \"b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/aes/0.8.4/download\"],\n strip_prefix = \"aes-0.8.4\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.aes-0.8.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__aes-gcm-0.10.3\",\n sha256 = \"831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/aes-gcm/0.10.3/download\"],\n strip_prefix = \"aes-gcm-0.10.3\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.aes-gcm-0.10.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__aligned-0.4.3\",\n sha256 = \"ee4508988c62edf04abd8d92897fca0c2995d907ce1dfeaf369dac3716a40685\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/aligned/0.4.3/download\"],\n strip_prefix = \"aligned-0.4.3\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.aligned-0.4.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__anstream-1.0.0\",\n sha256 = \"824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/anstream/1.0.0/download\"],\n strip_prefix = \"anstream-1.0.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.anstream-1.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__anstyle-1.0.14\",\n sha256 = \"940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/anstyle/1.0.14/download\"],\n strip_prefix = \"anstyle-1.0.14\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.anstyle-1.0.14.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__anstyle-parse-1.0.0\",\n sha256 = \"52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/anstyle-parse/1.0.0/download\"],\n strip_prefix = \"anstyle-parse-1.0.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.anstyle-parse-1.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__anstyle-query-1.1.5\",\n sha256 = \"40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/anstyle-query/1.1.5/download\"],\n strip_prefix = \"anstyle-query-1.1.5\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.anstyle-query-1.1.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__anstyle-wincon-3.0.11\",\n sha256 = \"291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/anstyle-wincon/3.0.11/download\"],\n strip_prefix = \"anstyle-wincon-3.0.11\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.anstyle-wincon-3.0.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__anyhow-1.0.102\",\n sha256 = \"7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/anyhow/1.0.102/download\"],\n strip_prefix = \"anyhow-1.0.102\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.anyhow-1.0.102.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__as-slice-0.2.1\",\n sha256 = \"516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/as-slice/0.2.1/download\"],\n strip_prefix = \"as-slice-0.2.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.as-slice-0.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__autocfg-1.5.0\",\n sha256 = \"c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/autocfg/1.5.0/download\"],\n strip_prefix = \"autocfg-1.5.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.autocfg-1.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__bare-metal-0.2.5\",\n sha256 = \"5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bare-metal/0.2.5/download\"],\n strip_prefix = \"bare-metal-0.2.5\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.bare-metal-0.2.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__base16ct-0.2.0\",\n sha256 = \"4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/base16ct/0.2.0/download\"],\n strip_prefix = \"base16ct-0.2.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.base16ct-0.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__bitfield-0.13.2\",\n sha256 = \"46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bitfield/0.13.2/download\"],\n strip_prefix = \"bitfield-0.13.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.bitfield-0.13.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__bitfield-0.14.0\",\n sha256 = \"2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bitfield/0.14.0/download\"],\n strip_prefix = \"bitfield-0.14.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.bitfield-0.14.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__bitfield-struct-0.11.0\",\n sha256 = \"d3ca019570363e800b05ad4fd890734f28ac7b72f563ad8a35079efb793616f8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bitfield-struct/0.11.0/download\"],\n strip_prefix = \"bitfield-struct-0.11.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.bitfield-struct-0.11.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__bitflags-2.11.1\",\n sha256 = \"c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bitflags/2.11.1/download\"],\n strip_prefix = \"bitflags-2.11.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.bitflags-2.11.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__block-buffer-0.10.4\",\n sha256 = \"3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/block-buffer/0.10.4/download\"],\n strip_prefix = \"block-buffer-0.10.4\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.block-buffer-0.10.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__byteorder-1.5.0\",\n sha256 = \"1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/byteorder/1.5.0/download\"],\n strip_prefix = \"byteorder-1.5.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.byteorder-1.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__bytes-1.11.1\",\n sha256 = \"1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bytes/1.11.1/download\"],\n strip_prefix = \"bytes-1.11.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.bytes-1.11.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__cfg-if-1.0.4\",\n sha256 = \"9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cfg-if/1.0.4/download\"],\n strip_prefix = \"cfg-if-1.0.4\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.cfg-if-1.0.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__cipher-0.4.4\",\n sha256 = \"773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cipher/0.4.4/download\"],\n strip_prefix = \"cipher-0.4.4\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.cipher-0.4.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__clap-4.6.1\",\n sha256 = \"1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/clap/4.6.1/download\"],\n strip_prefix = \"clap-4.6.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.clap-4.6.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__clap_builder-4.6.0\",\n sha256 = \"714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/clap_builder/4.6.0/download\"],\n strip_prefix = \"clap_builder-4.6.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.clap_builder-4.6.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__clap_derive-4.6.1\",\n sha256 = \"f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/clap_derive/4.6.1/download\"],\n strip_prefix = \"clap_derive-4.6.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.clap_derive-4.6.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__clap_lex-1.1.0\",\n sha256 = \"c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/clap_lex/1.1.0/download\"],\n strip_prefix = \"clap_lex-1.1.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.clap_lex-1.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__colorchoice-1.0.5\",\n sha256 = \"1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/colorchoice/1.0.5/download\"],\n strip_prefix = \"colorchoice-1.0.5\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.colorchoice-1.0.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__compiler_builtins-0.1.160\",\n sha256 = \"6376049cfa92c0aa8b9ac95fae22184b981c658208d4ed8a1dc553cd83612895\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/compiler_builtins/0.1.160/download\"],\n strip_prefix = \"compiler_builtins-0.1.160\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.compiler_builtins-0.1.160.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__const-oid-0.9.6\",\n sha256 = \"c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/const-oid/0.9.6/download\"],\n strip_prefix = \"const-oid-0.9.6\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.const-oid-0.9.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__cortex-m-0.7.7\",\n sha256 = \"8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cortex-m/0.7.7/download\"],\n strip_prefix = \"cortex-m-0.7.7\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.cortex-m-0.7.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__cortex-m-rt-0.7.5\",\n sha256 = \"801d4dec46b34c299ccf6b036717ae0fce602faa4f4fe816d9013b9a7c9f5ba6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cortex-m-rt/0.7.5/download\"],\n strip_prefix = \"cortex-m-rt-0.7.5\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.cortex-m-rt-0.7.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__cortex-m-rt-macros-0.7.5\",\n sha256 = \"e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cortex-m-rt-macros/0.7.5/download\"],\n strip_prefix = \"cortex-m-rt-macros-0.7.5\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.cortex-m-rt-macros-0.7.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__cortex-m-semihosting-0.5.0\",\n sha256 = \"c23234600452033cc77e4b761e740e02d2c4168e11dbf36ab14a0f58973592b0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cortex-m-semihosting/0.5.0/download\"],\n strip_prefix = \"cortex-m-semihosting-0.5.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.cortex-m-semihosting-0.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__cpufeatures-0.2.17\",\n sha256 = \"59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cpufeatures/0.2.17/download\"],\n strip_prefix = \"cpufeatures-0.2.17\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.cpufeatures-0.2.17.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__crc-3.4.0\",\n sha256 = \"5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crc/3.4.0/download\"],\n strip_prefix = \"crc-3.4.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.crc-3.4.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__crc-catalog-2.5.0\",\n sha256 = \"217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crc-catalog/2.5.0/download\"],\n strip_prefix = \"crc-catalog-2.5.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.crc-catalog-2.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__crc32fast-1.5.0\",\n sha256 = \"9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crc32fast/1.5.0/download\"],\n strip_prefix = \"crc32fast-1.5.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.crc32fast-1.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__critical-section-1.2.0\",\n sha256 = \"790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/critical-section/1.2.0/download\"],\n strip_prefix = \"critical-section-1.2.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.critical-section-1.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__crypto-bigint-0.5.5\",\n sha256 = \"0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crypto-bigint/0.5.5/download\"],\n strip_prefix = \"crypto-bigint-0.5.5\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.crypto-bigint-0.5.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__crypto-common-0.1.7\",\n sha256 = \"78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crypto-common/0.1.7/download\"],\n strip_prefix = \"crypto-common-0.1.7\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.crypto-common-0.1.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__ctr-0.9.2\",\n sha256 = \"0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ctr/0.9.2/download\"],\n strip_prefix = \"ctr-0.9.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.ctr-0.9.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__der-0.7.10\",\n sha256 = \"e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/der/0.7.10/download\"],\n strip_prefix = \"der-0.7.10\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.der-0.7.10.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__digest-0.10.7\",\n sha256 = \"9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/digest/0.10.7/download\"],\n strip_prefix = \"digest-0.10.7\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.digest-0.10.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__ecdsa-0.16.9\",\n sha256 = \"ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ecdsa/0.16.9/download\"],\n strip_prefix = \"ecdsa-0.16.9\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.ecdsa-0.16.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__either-1.15.0\",\n sha256 = \"48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/either/1.15.0/download\"],\n strip_prefix = \"either-1.15.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.either-1.15.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__elliptic-curve-0.13.8\",\n sha256 = \"b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/elliptic-curve/0.13.8/download\"],\n strip_prefix = \"elliptic-curve-0.13.8\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.elliptic-curve-0.13.8.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__embedded-crc-macros-1.0.0\",\n sha256 = \"4f1c75747a43b086df1a87fb2a889590bc0725e0abf54bba6d0c4bf7bd9e762c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/embedded-crc-macros/1.0.0/download\"],\n strip_prefix = \"embedded-crc-macros-1.0.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.embedded-crc-macros-1.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__embedded-hal-0.2.7\",\n sha256 = \"35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/embedded-hal/0.2.7/download\"],\n strip_prefix = \"embedded-hal-0.2.7\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.embedded-hal-0.2.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__embedded-hal-1.0.0\",\n sha256 = \"361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/embedded-hal/1.0.0/download\"],\n strip_prefix = \"embedded-hal-1.0.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.embedded-hal-1.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__embedded-hal-async-1.0.0\",\n sha256 = \"0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/embedded-hal-async/1.0.0/download\"],\n strip_prefix = \"embedded-hal-async-1.0.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.embedded-hal-async-1.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__embedded-hal-nb-1.0.0\",\n sha256 = \"fba4268c14288c828995299e59b12babdbe170f6c6d73731af1b4648142e8605\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/embedded-hal-nb/1.0.0/download\"],\n strip_prefix = \"embedded-hal-nb-1.0.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.embedded-hal-nb-1.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__embedded-io-0.6.1\",\n sha256 = \"edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/embedded-io/0.6.1/download\"],\n strip_prefix = \"embedded-io-0.6.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.embedded-io-0.6.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__embedded-io-async-0.6.1\",\n sha256 = \"3ff09972d4073aa8c299395be75161d582e7629cd663171d62af73c8d50dba3f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/embedded-io-async/0.6.1/download\"],\n strip_prefix = \"embedded-io-async-0.6.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.embedded-io-async-0.6.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__equivalent-1.0.2\",\n sha256 = \"877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/equivalent/1.0.2/download\"],\n strip_prefix = \"equivalent-1.0.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.equivalent-1.0.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__errno-0.3.14\",\n sha256 = \"39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/errno/0.3.14/download\"],\n strip_prefix = \"errno-0.3.14\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.errno-0.3.14.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__ff-0.13.1\",\n sha256 = \"c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ff/0.13.1/download\"],\n strip_prefix = \"ff-0.13.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.ff-0.13.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__flate2-1.1.9\",\n sha256 = \"843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/flate2/1.1.9/download\"],\n strip_prefix = \"flate2-1.1.9\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.flate2-1.1.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__foldhash-0.1.5\",\n sha256 = \"d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/foldhash/0.1.5/download\"],\n strip_prefix = \"foldhash-0.1.5\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.foldhash-0.1.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__fugit-0.3.9\",\n sha256 = \"4e639847d312d9a82d2e75b0edcc1e934efcc64e6cb7aa94f0b1fbec0bc231d6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/fugit/0.3.9/download\"],\n strip_prefix = \"fugit-0.3.9\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.fugit-0.3.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__futures-0.3.32\",\n sha256 = \"8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures/0.3.32/download\"],\n strip_prefix = \"futures-0.3.32\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.futures-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__futures-channel-0.3.32\",\n sha256 = \"07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-channel/0.3.32/download\"],\n strip_prefix = \"futures-channel-0.3.32\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.futures-channel-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__futures-core-0.3.32\",\n sha256 = \"7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-core/0.3.32/download\"],\n strip_prefix = \"futures-core-0.3.32\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.futures-core-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__futures-executor-0.3.32\",\n sha256 = \"baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-executor/0.3.32/download\"],\n strip_prefix = \"futures-executor-0.3.32\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.futures-executor-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__futures-io-0.3.32\",\n sha256 = \"cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-io/0.3.32/download\"],\n strip_prefix = \"futures-io-0.3.32\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.futures-io-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__futures-macro-0.3.32\",\n sha256 = \"e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-macro/0.3.32/download\"],\n strip_prefix = \"futures-macro-0.3.32\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.futures-macro-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__futures-sink-0.3.32\",\n sha256 = \"c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-sink/0.3.32/download\"],\n strip_prefix = \"futures-sink-0.3.32\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.futures-sink-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__futures-task-0.3.32\",\n sha256 = \"037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-task/0.3.32/download\"],\n strip_prefix = \"futures-task-0.3.32\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.futures-task-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__futures-util-0.3.32\",\n sha256 = \"389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-util/0.3.32/download\"],\n strip_prefix = \"futures-util-0.3.32\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.futures-util-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__gcd-2.3.0\",\n sha256 = \"1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/gcd/2.3.0/download\"],\n strip_prefix = \"gcd-2.3.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.gcd-2.3.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__generic-array-0.14.7\",\n sha256 = \"85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/generic-array/0.14.7/download\"],\n strip_prefix = \"generic-array-0.14.7\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.generic-array-0.14.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__ghash-0.5.1\",\n sha256 = \"f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ghash/0.5.1/download\"],\n strip_prefix = \"ghash-0.5.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.ghash-0.5.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__group-0.13.0\",\n sha256 = \"f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/group/0.13.0/download\"],\n strip_prefix = \"group-0.13.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.group-0.13.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__hash32-0.3.1\",\n sha256 = \"47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hash32/0.3.1/download\"],\n strip_prefix = \"hash32-0.3.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.hash32-0.3.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__hashbrown-0.15.5\",\n sha256 = \"9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hashbrown/0.15.5/download\"],\n strip_prefix = \"hashbrown-0.15.5\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.hashbrown-0.15.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__hashbrown-0.17.0\",\n sha256 = \"4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hashbrown/0.17.0/download\"],\n strip_prefix = \"hashbrown-0.17.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.hashbrown-0.17.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__heapless-0.8.0\",\n sha256 = \"0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/heapless/0.8.0/download\"],\n strip_prefix = \"heapless-0.8.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.heapless-0.8.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__heapless-0.9.2\",\n sha256 = \"2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/heapless/0.9.2/download\"],\n strip_prefix = \"heapless-0.9.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.heapless-0.9.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__heck-0.5.0\",\n sha256 = \"2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/heck/0.5.0/download\"],\n strip_prefix = \"heck-0.5.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.heck-0.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__hex-0.4.3\",\n sha256 = \"7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hex/0.4.3/download\"],\n strip_prefix = \"hex-0.4.3\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.hex-0.4.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__hex-literal-0.4.1\",\n sha256 = \"6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hex-literal/0.4.1/download\"],\n strip_prefix = \"hex-literal-0.4.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.hex-literal-0.4.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__hmac-0.12.1\",\n sha256 = \"6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hmac/0.12.1/download\"],\n strip_prefix = \"hmac-0.12.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.hmac-0.12.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__indexmap-2.14.0\",\n sha256 = \"d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/indexmap/2.14.0/download\"],\n strip_prefix = \"indexmap-2.14.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.indexmap-2.14.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__inout-0.1.4\",\n sha256 = \"879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/inout/0.1.4/download\"],\n strip_prefix = \"inout-0.1.4\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.inout-0.1.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__is_terminal_polyfill-1.70.2\",\n sha256 = \"a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/is_terminal_polyfill/1.70.2/download\"],\n strip_prefix = \"is_terminal_polyfill-1.70.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.is_terminal_polyfill-1.70.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__itertools-0.14.0\",\n sha256 = \"2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/itertools/0.14.0/download\"],\n strip_prefix = \"itertools-0.14.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.itertools-0.14.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__k256-0.13.4\",\n sha256 = \"f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/k256/0.13.4/download\"],\n strip_prefix = \"k256-0.13.4\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.k256-0.13.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__keccak-0.1.6\",\n sha256 = \"cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/keccak/0.1.6/download\"],\n strip_prefix = \"keccak-0.1.6\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.keccak-0.1.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__libc-0.2.186\",\n sha256 = \"68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/libc/0.2.186/download\"],\n strip_prefix = \"libc-0.2.186\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.libc-0.2.186.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__linux-raw-sys-0.12.1\",\n sha256 = \"32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/linux-raw-sys/0.12.1/download\"],\n strip_prefix = \"linux-raw-sys-0.12.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.linux-raw-sys-0.12.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__lock_api-0.4.14\",\n sha256 = \"224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/lock_api/0.4.14/download\"],\n strip_prefix = \"lock_api-0.4.14\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.lock_api-0.4.14.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__log-0.4.29\",\n sha256 = \"5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/log/0.4.29/download\"],\n strip_prefix = \"log-0.4.29\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.log-0.4.29.bazel\"),\n )\n\n maybe(\n git_repository,\n name = \"rust_crates__mctp-0.2.0\",\n commit = \"114dee1a7cfbae601ce11901b20516ebe217a4b2\",\n init_submodules = True,\n remote = \"https://github.com/CodeConstruct/mctp-rs.git\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.mctp-0.2.0.bazel\"),\n strip_prefix = \"mctp\",\n )\n\n maybe(\n git_repository,\n name = \"rust_crates__mctp-estack-0.1.0\",\n commit = \"114dee1a7cfbae601ce11901b20516ebe217a4b2\",\n init_submodules = True,\n remote = \"https://github.com/CodeConstruct/mctp-rs.git\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.mctp-estack-0.1.0.bazel\"),\n strip_prefix = \"mctp-estack\",\n )\n\n maybe(\n git_repository,\n name = \"rust_crates__mctp-lib-0.1.0\",\n commit = \"742fa0e991aa2b87509ff12739e011a674643d91\",\n init_submodules = True,\n remote = \"https://github.com/OpenPRoT/mctp-lib.git\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.mctp-lib-0.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__memchr-2.8.0\",\n sha256 = \"f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/memchr/2.8.0/download\"],\n strip_prefix = \"memchr-2.8.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.memchr-2.8.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__memo-map-0.3.3\",\n sha256 = \"38d1115007560874e373613744c6fba374c17688327a71c1476d1a5954cc857b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/memo-map/0.3.3/download\"],\n strip_prefix = \"memo-map-0.3.3\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.memo-map-0.3.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__memoffset-0.9.1\",\n sha256 = \"488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/memoffset/0.9.1/download\"],\n strip_prefix = \"memoffset-0.9.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.memoffset-0.9.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__minijinja-2.19.0\",\n sha256 = \"805bfd7352166bae857ee569628b52bcd85a1cecf7810861ebceb1686b72b75d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/minijinja/2.19.0/download\"],\n strip_prefix = \"minijinja-2.19.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.minijinja-2.19.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__minimal-lexical-0.2.1\",\n sha256 = \"68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/minimal-lexical/0.2.1/download\"],\n strip_prefix = \"minimal-lexical-0.2.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.minimal-lexical-0.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__miniz_oxide-0.8.9\",\n sha256 = \"1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/miniz_oxide/0.8.9/download\"],\n strip_prefix = \"miniz_oxide-0.8.9\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.miniz_oxide-0.8.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__mio-1.2.0\",\n sha256 = \"50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/mio/1.2.0/download\"],\n strip_prefix = \"mio-1.2.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.mio-1.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__nb-0.1.3\",\n sha256 = \"801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/nb/0.1.3/download\"],\n strip_prefix = \"nb-0.1.3\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.nb-0.1.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__nb-1.1.0\",\n sha256 = \"8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/nb/1.1.0/download\"],\n strip_prefix = \"nb-1.1.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.nb-1.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__nom-7.1.3\",\n sha256 = \"d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/nom/7.1.3/download\"],\n strip_prefix = \"nom-7.1.3\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.nom-7.1.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__object-0.37.3\",\n sha256 = \"ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/object/0.37.3/download\"],\n strip_prefix = \"object-0.37.3\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.object-0.37.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__once_cell_polyfill-1.70.2\",\n sha256 = \"384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/once_cell_polyfill/1.70.2/download\"],\n strip_prefix = \"once_cell_polyfill-1.70.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.once_cell_polyfill-1.70.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__opaque-debug-0.3.1\",\n sha256 = \"c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/opaque-debug/0.3.1/download\"],\n strip_prefix = \"opaque-debug-0.3.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.opaque-debug-0.3.1.bazel\"),\n )\n\n maybe(\n git_repository,\n name = \"rust_crates__openprot-hal-blocking-0.1.0\",\n commit = \"c6cd23a56f3cc7945b062ea1bcdabf3af0dba82d\",\n init_submodules = True,\n remote = \"https://github.com/rusty1968/openprot.git\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.openprot-hal-blocking-0.1.0.bazel\"),\n strip_prefix = \"hal/blocking\",\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__p256-0.13.2\",\n sha256 = \"c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/p256/0.13.2/download\"],\n strip_prefix = \"p256-0.13.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.p256-0.13.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__p384-0.13.1\",\n sha256 = \"fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/p384/0.13.1/download\"],\n strip_prefix = \"p384-0.13.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.p384-0.13.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__panic-halt-1.0.0\",\n sha256 = \"a513e167849a384b7f9b746e517604398518590a9142f4846a32e3c2a4de7b11\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/panic-halt/1.0.0/download\"],\n strip_prefix = \"panic-halt-1.0.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.panic-halt-1.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__parking_lot-0.12.5\",\n sha256 = \"93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/parking_lot/0.12.5/download\"],\n strip_prefix = \"parking_lot-0.12.5\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.parking_lot-0.12.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__parking_lot_core-0.9.12\",\n sha256 = \"2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/parking_lot_core/0.9.12/download\"],\n strip_prefix = \"parking_lot_core-0.9.12\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.parking_lot_core-0.9.12.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__paste-1.0.15\",\n sha256 = \"57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/paste/1.0.15/download\"],\n strip_prefix = \"paste-1.0.15\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.paste-1.0.15.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__pest-2.8.6\",\n sha256 = \"e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pest/2.8.6/download\"],\n strip_prefix = \"pest-2.8.6\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.pest-2.8.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__pest_derive-2.8.6\",\n sha256 = \"11f486f1ea21e6c10ed15d5a7c77165d0ee443402f0780849d1768e7d9d6fe77\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pest_derive/2.8.6/download\"],\n strip_prefix = \"pest_derive-2.8.6\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.pest_derive-2.8.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__pest_generator-2.8.6\",\n sha256 = \"8040c4647b13b210a963c1ed407c1ff4fdfa01c31d6d2a098218702e6664f94f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pest_generator/2.8.6/download\"],\n strip_prefix = \"pest_generator-2.8.6\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.pest_generator-2.8.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__pest_meta-2.8.6\",\n sha256 = \"89815c69d36021a140146f26659a81d6c2afa33d216d736dd4be5381a7362220\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pest_meta/2.8.6/download\"],\n strip_prefix = \"pest_meta-2.8.6\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.pest_meta-2.8.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__pin-project-lite-0.2.17\",\n sha256 = \"a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pin-project-lite/0.2.17/download\"],\n strip_prefix = \"pin-project-lite-0.2.17\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.pin-project-lite-0.2.17.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__polyval-0.6.2\",\n sha256 = \"9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/polyval/0.6.2/download\"],\n strip_prefix = \"polyval-0.6.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.polyval-0.6.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__primeorder-0.13.6\",\n sha256 = \"353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/primeorder/0.13.6/download\"],\n strip_prefix = \"primeorder-0.13.6\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.primeorder-0.13.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__proc-macro2-1.0.106\",\n sha256 = \"8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/proc-macro2/1.0.106/download\"],\n strip_prefix = \"proc-macro2-1.0.106\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.proc-macro2-1.0.106.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__prost-0.13.5\",\n sha256 = \"2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/prost/0.13.5/download\"],\n strip_prefix = \"prost-0.13.5\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.prost-0.13.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__prost-derive-0.13.5\",\n sha256 = \"8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/prost-derive/0.13.5/download\"],\n strip_prefix = \"prost-derive-0.13.5\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.prost-derive-0.13.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__quote-1.0.45\",\n sha256 = \"41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/quote/1.0.45/download\"],\n strip_prefix = \"quote-1.0.45\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.quote-1.0.45.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__rand_core-0.6.4\",\n sha256 = \"ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rand_core/0.6.4/download\"],\n strip_prefix = \"rand_core-0.6.4\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.rand_core-0.6.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__rand_core-0.9.5\",\n sha256 = \"76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rand_core/0.9.5/download\"],\n strip_prefix = \"rand_core-0.9.5\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.rand_core-0.9.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__redox_syscall-0.5.18\",\n sha256 = \"ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/redox_syscall/0.5.18/download\"],\n strip_prefix = \"redox_syscall-0.5.18\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.redox_syscall-0.5.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__rfc6979-0.4.0\",\n sha256 = \"f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rfc6979/0.4.0/download\"],\n strip_prefix = \"rfc6979-0.4.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.rfc6979-0.4.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__riscv-0.11.1\",\n sha256 = \"2f5c1b8bf41ea746266cdee443d1d1e9125c86ce1447e1a2615abd34330d33a9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/riscv/0.11.1/download\"],\n strip_prefix = \"riscv-0.11.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.riscv-0.11.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__riscv-0.12.1\",\n sha256 = \"5ea8ff73d3720bdd0a97925f0bf79ad2744b6da8ff36be3840c48ac81191d7a7\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/riscv/0.12.1/download\"],\n strip_prefix = \"riscv-0.12.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.riscv-0.12.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__riscv-0.13.0\",\n sha256 = \"afa3cdbeccae4359f6839a00e8b77e5736caa200ba216caf38d24e4c16e2b586\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/riscv/0.13.0/download\"],\n strip_prefix = \"riscv-0.13.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.riscv-0.13.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__riscv-macros-0.1.0\",\n sha256 = \"f265be5d634272320a7de94cea15c22a3bfdd4eb42eb43edc528415f066a1f25\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/riscv-macros/0.1.0/download\"],\n strip_prefix = \"riscv-macros-0.1.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.riscv-macros-0.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__riscv-macros-0.2.0\",\n sha256 = \"e8c4aa1ea1af6dcc83a61be12e8189f9b293c3ba5a487778a4cd89fb060fdbbc\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/riscv-macros/0.2.0/download\"],\n strip_prefix = \"riscv-macros-0.2.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.riscv-macros-0.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__riscv-pac-0.2.0\",\n sha256 = \"8188909339ccc0c68cfb5a04648313f09621e8b87dc03095454f1a11f6c5d436\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/riscv-pac/0.2.0/download\"],\n strip_prefix = \"riscv-pac-0.2.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.riscv-pac-0.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__riscv-rt-0.12.2\",\n sha256 = \"c0d35e32cf1383183e8885d8a9aa4402a087fd094dc34c2cb6df6687d0229dfe\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/riscv-rt/0.12.2/download\"],\n strip_prefix = \"riscv-rt-0.12.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.riscv-rt-0.12.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__riscv-rt-macros-0.2.2\",\n sha256 = \"30f19a85fe107b65031e0ba8ec60c34c2494069fe910d6c297f5e7cb5a6f76d0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/riscv-rt-macros/0.2.2/download\"],\n strip_prefix = \"riscv-rt-macros-0.2.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.riscv-rt-macros-0.2.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__riscv-semihosting-0.1.3\",\n sha256 = \"1086dd4bcc13de1cb14b93849411e3466de7e5907d2d8eb269032536e93facc6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/riscv-semihosting/0.1.3/download\"],\n strip_prefix = \"riscv-semihosting-0.1.3\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.riscv-semihosting-0.1.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__rustc-demangle-0.1.27\",\n sha256 = \"b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rustc-demangle/0.1.27/download\"],\n strip_prefix = \"rustc-demangle-0.1.27\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.rustc-demangle-0.1.27.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__rustc_version-0.2.3\",\n sha256 = \"138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rustc_version/0.2.3/download\"],\n strip_prefix = \"rustc_version-0.2.3\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.rustc_version-0.2.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__rustix-1.1.4\",\n sha256 = \"b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rustix/1.1.4/download\"],\n strip_prefix = \"rustix-1.1.4\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.rustix-1.1.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__ruzstd-0.8.2\",\n sha256 = \"e5ff0cc5e135c8870a775d3320910cd9b564ec036b4dc0b8741629020be63f01\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ruzstd/0.8.2/download\"],\n strip_prefix = \"ruzstd-0.8.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.ruzstd-0.8.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__scopeguard-1.2.0\",\n sha256 = \"94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/scopeguard/1.2.0/download\"],\n strip_prefix = \"scopeguard-1.2.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.scopeguard-1.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__sec1-0.7.3\",\n sha256 = \"d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/sec1/0.7.3/download\"],\n strip_prefix = \"sec1-0.7.3\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.sec1-0.7.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__semver-0.9.0\",\n sha256 = \"1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/semver/0.9.0/download\"],\n strip_prefix = \"semver-0.9.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.semver-0.9.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__semver-parser-0.7.0\",\n sha256 = \"388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/semver-parser/0.7.0/download\"],\n strip_prefix = \"semver-parser-0.7.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.semver-parser-0.7.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__serde-1.0.228\",\n sha256 = \"9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde/1.0.228/download\"],\n strip_prefix = \"serde-1.0.228\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.serde-1.0.228.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__serde_core-1.0.228\",\n sha256 = \"41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_core/1.0.228/download\"],\n strip_prefix = \"serde_core-1.0.228\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.serde_core-1.0.228.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__serde_derive-1.0.228\",\n sha256 = \"d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_derive/1.0.228/download\"],\n strip_prefix = \"serde_derive-1.0.228\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.serde_derive-1.0.228.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__serde_json5-0.2.1\",\n sha256 = \"5d34d03f54462862f2a42918391c9526337f53171eaa4d8894562be7f252edd3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_json5/0.2.1/download\"],\n strip_prefix = \"serde_json5-0.2.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.serde_json5-0.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__sha2-0.10.9\",\n sha256 = \"a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/sha2/0.10.9/download\"],\n strip_prefix = \"sha2-0.10.9\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.sha2-0.10.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__sha3-0.10.9\",\n sha256 = \"77fd7028345d415a4034cf8777cd4f8ab1851274233b45f84e3d955502d93874\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/sha3/0.10.9/download\"],\n strip_prefix = \"sha3-0.10.9\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.sha3-0.10.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__signal-hook-registry-1.4.8\",\n sha256 = \"c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/signal-hook-registry/1.4.8/download\"],\n strip_prefix = \"signal-hook-registry-1.4.8\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.signal-hook-registry-1.4.8.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__signature-2.2.0\",\n sha256 = \"77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/signature/2.2.0/download\"],\n strip_prefix = \"signature-2.2.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.signature-2.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__simd-adler32-0.3.9\",\n sha256 = \"703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/simd-adler32/0.3.9/download\"],\n strip_prefix = \"simd-adler32-0.3.9\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.simd-adler32-0.3.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__slab-0.4.12\",\n sha256 = \"0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/slab/0.4.12/download\"],\n strip_prefix = \"slab-0.4.12\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.slab-0.4.12.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__smallvec-1.15.1\",\n sha256 = \"67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/smallvec/1.15.1/download\"],\n strip_prefix = \"smallvec-1.15.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.smallvec-1.15.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__smbus-pec-1.0.1\",\n sha256 = \"ca0763a680cd5d72b28f7bfc8a054c117d8841380a6ad4f72f05bd2a34217d3e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/smbus-pec/1.0.1/download\"],\n strip_prefix = \"smbus-pec-1.0.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.smbus-pec-1.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__smlang-0.8.0\",\n sha256 = \"1de84f9f80bbe6272174e2bfdb8cf7ce4815b218038a42161c2f21c1d872c215\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/smlang/0.8.0/download\"],\n strip_prefix = \"smlang-0.8.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.smlang-0.8.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__smlang-macros-0.8.0\",\n sha256 = \"231b4425dcc43afc7e18c34e7c6738cd252d42d91d909c948df14107c9ae79f1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/smlang-macros/0.8.0/download\"],\n strip_prefix = \"smlang-macros-0.8.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.smlang-macros-0.8.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__socket2-0.6.3\",\n sha256 = \"3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/socket2/0.6.3/download\"],\n strip_prefix = \"socket2-0.6.3\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.socket2-0.6.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__stable_deref_trait-1.2.1\",\n sha256 = \"6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/stable_deref_trait/1.2.1/download\"],\n strip_prefix = \"stable_deref_trait-1.2.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.stable_deref_trait-1.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__string_morph-0.1.0\",\n sha256 = \"183aaf7fa637cc7b5f54c45b8f7cb6e8d73831f9f75a56b6defa5bf8c51d1699\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/string_morph/0.1.0/download\"],\n strip_prefix = \"string_morph-0.1.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.string_morph-0.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__strsim-0.11.1\",\n sha256 = \"7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/strsim/0.11.1/download\"],\n strip_prefix = \"strsim-0.11.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.strsim-0.11.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__subtle-2.6.1\",\n sha256 = \"13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/subtle/2.6.1/download\"],\n strip_prefix = \"subtle-2.6.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.subtle-2.6.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__syn-1.0.109\",\n sha256 = \"72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/syn/1.0.109/download\"],\n strip_prefix = \"syn-1.0.109\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.syn-1.0.109.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__syn-2.0.117\",\n sha256 = \"e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/syn/2.0.117/download\"],\n strip_prefix = \"syn-2.0.117\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.syn-2.0.117.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__terminal_size-0.4.4\",\n sha256 = \"230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/terminal_size/0.4.4/download\"],\n strip_prefix = \"terminal_size-0.4.4\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.terminal_size-0.4.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__thiserror-2.0.18\",\n sha256 = \"4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/thiserror/2.0.18/download\"],\n strip_prefix = \"thiserror-2.0.18\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.thiserror-2.0.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__thiserror-impl-2.0.18\",\n sha256 = \"ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/thiserror-impl/2.0.18/download\"],\n strip_prefix = \"thiserror-impl-2.0.18\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.thiserror-impl-2.0.18.bazel\"),\n )\n\n maybe(\n git_repository,\n name = \"rust_crates__tock-registers-0.9.0\",\n commit = \"9554639b17501a9f5940cef7a1770a0823e790c3\",\n init_submodules = True,\n remote = \"https://github.com/tock/tock.git\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.tock-registers-0.9.0.bazel\"),\n strip_prefix = \"libraries/tock-register-interface\",\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__tokio-1.52.1\",\n sha256 = \"b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tokio/1.52.1/download\"],\n strip_prefix = \"tokio-1.52.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.tokio-1.52.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__tokio-macros-2.7.0\",\n sha256 = \"385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tokio-macros/2.7.0/download\"],\n strip_prefix = \"tokio-macros-2.7.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.tokio-macros-2.7.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__tokio-util-0.7.18\",\n sha256 = \"9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tokio-util/0.7.18/download\"],\n strip_prefix = \"tokio-util-0.7.18\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.tokio-util-0.7.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__twox-hash-2.1.2\",\n sha256 = \"9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/twox-hash/2.1.2/download\"],\n strip_prefix = \"twox-hash-2.1.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.twox-hash-2.1.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__typenum-1.20.0\",\n sha256 = \"40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/typenum/1.20.0/download\"],\n strip_prefix = \"typenum-1.20.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.typenum-1.20.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__ucd-trie-0.1.7\",\n sha256 = \"2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ucd-trie/0.1.7/download\"],\n strip_prefix = \"ucd-trie-0.1.7\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.ucd-trie-0.1.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__unicode-ident-1.0.24\",\n sha256 = \"e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unicode-ident/1.0.24/download\"],\n strip_prefix = \"unicode-ident-1.0.24\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.unicode-ident-1.0.24.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__universal-hash-0.5.1\",\n sha256 = \"fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/universal-hash/0.5.1/download\"],\n strip_prefix = \"universal-hash-0.5.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.universal-hash-0.5.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__utf8parse-0.2.2\",\n sha256 = \"06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/utf8parse/0.2.2/download\"],\n strip_prefix = \"utf8parse-0.2.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.utf8parse-0.2.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__uuid-1.23.1\",\n sha256 = \"ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/uuid/1.23.1/download\"],\n strip_prefix = \"uuid-1.23.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.uuid-1.23.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__vcell-0.1.3\",\n sha256 = \"77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/vcell/0.1.3/download\"],\n strip_prefix = \"vcell-0.1.3\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.vcell-0.1.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__version_check-0.9.5\",\n sha256 = \"0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/version_check/0.9.5/download\"],\n strip_prefix = \"version_check-0.9.5\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.version_check-0.9.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__void-1.0.2\",\n sha256 = \"6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/void/1.0.2/download\"],\n strip_prefix = \"void-1.0.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.void-1.0.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__volatile-register-0.2.2\",\n sha256 = \"de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/volatile-register/0.2.2/download\"],\n strip_prefix = \"volatile-register-0.2.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.volatile-register-0.2.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__wasi-0.11.1-wasi-snapshot-preview1\",\n sha256 = \"ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasi/0.11.1+wasi-snapshot-preview1/download\"],\n strip_prefix = \"wasi-0.11.1+wasi-snapshot-preview1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.wasi-0.11.1+wasi-snapshot-preview1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__windows-link-0.2.1\",\n sha256 = \"f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows-link/0.2.1/download\"],\n strip_prefix = \"windows-link-0.2.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.windows-link-0.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__windows-sys-0.61.2\",\n sha256 = \"ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows-sys/0.61.2/download\"],\n strip_prefix = \"windows-sys-0.61.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.windows-sys-0.61.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__zerocopy-0.8.48\",\n sha256 = \"eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zerocopy/0.8.48/download\"],\n strip_prefix = \"zerocopy-0.8.48\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.zerocopy-0.8.48.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__zerocopy-derive-0.8.48\",\n sha256 = \"70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zerocopy-derive/0.8.48/download\"],\n strip_prefix = \"zerocopy-derive-0.8.48\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.zerocopy-derive-0.8.48.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__zeroize-1.8.2\",\n sha256 = \"b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zeroize/1.8.2/download\"],\n strip_prefix = \"zeroize-1.8.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.zeroize-1.8.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__zeroize_derive-1.4.3\",\n sha256 = \"85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zeroize_derive/1.4.3/download\"],\n strip_prefix = \"zeroize_derive-1.4.3\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.zeroize_derive-1.4.3.bazel\"),\n )\n\n return [\n struct(repo=\"rust_crates__aes-0.8.4\", is_dev_dep = False),\n struct(repo=\"rust_crates__aes-gcm-0.10.3\", is_dev_dep = False),\n struct(repo=\"rust_crates__aligned-0.4.3\", is_dev_dep = False),\n struct(repo=\"rust_crates__anyhow-1.0.102\", is_dev_dep = False),\n struct(repo=\"rust_crates__bitfield-0.14.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__bitfield-struct-0.11.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__bitflags-2.11.1\", is_dev_dep = False),\n struct(repo=\"rust_crates__byteorder-1.5.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__cfg-if-1.0.4\", is_dev_dep = False),\n struct(repo=\"rust_crates__cipher-0.4.4\", is_dev_dep = False),\n struct(repo=\"rust_crates__clap-4.6.1\", is_dev_dep = False),\n struct(repo=\"rust_crates__compiler_builtins-0.1.160\", is_dev_dep = False),\n struct(repo=\"rust_crates__cortex-m-0.7.7\", is_dev_dep = False),\n struct(repo=\"rust_crates__cortex-m-rt-0.7.5\", is_dev_dep = False),\n struct(repo=\"rust_crates__cortex-m-semihosting-0.5.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__ctr-0.9.2\", is_dev_dep = False),\n struct(repo=\"rust_crates__ecdsa-0.16.9\", is_dev_dep = False),\n struct(repo=\"rust_crates__embedded-hal-1.0.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__embedded-hal-async-1.0.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__embedded-hal-nb-1.0.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__embedded-io-0.6.1\", is_dev_dep = False),\n struct(repo=\"rust_crates__fugit-0.3.9\", is_dev_dep = False),\n struct(repo=\"rust_crates__futures-0.3.32\", is_dev_dep = False),\n struct(repo=\"rust_crates__heapless-0.9.2\", is_dev_dep = False),\n struct(repo=\"rust_crates__hex-0.4.3\", is_dev_dep = False),\n struct(repo=\"rust_crates__hex-literal-0.4.1\", is_dev_dep = False),\n struct(repo=\"rust_crates__hmac-0.12.1\", is_dev_dep = False),\n struct(repo=\"rust_crates__k256-0.13.4\", is_dev_dep = False),\n struct(repo=\"rust_crates__log-0.4.29\", is_dev_dep = False),\n struct(repo=\"rust_crates__mctp-0.2.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__mctp-lib-0.1.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__memoffset-0.9.1\", is_dev_dep = False),\n struct(repo=\"rust_crates__minijinja-2.19.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__nb-1.1.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__nom-7.1.3\", is_dev_dep = False),\n struct(repo=\"rust_crates__object-0.37.3\", is_dev_dep = False),\n struct(repo=\"rust_crates__openprot-hal-blocking-0.1.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__p256-0.13.2\", is_dev_dep = False),\n struct(repo=\"rust_crates__p384-0.13.1\", is_dev_dep = False),\n struct(repo=\"rust_crates__panic-halt-1.0.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__paste-1.0.15\", is_dev_dep = False),\n struct(repo=\"rust_crates__proc-macro2-1.0.106\", is_dev_dep = False),\n struct(repo=\"rust_crates__prost-0.13.5\", is_dev_dep = False),\n struct(repo=\"rust_crates__quote-1.0.45\", is_dev_dep = False),\n struct(repo=\"rust_crates__rand_core-0.9.5\", is_dev_dep = False),\n struct(repo=\"rust_crates__riscv-0.12.1\", is_dev_dep = False),\n struct(repo=\"rust_crates__riscv-rt-0.12.2\", is_dev_dep = False),\n struct(repo=\"rust_crates__riscv-semihosting-0.1.3\", is_dev_dep = False),\n struct(repo=\"rust_crates__rustc-demangle-0.1.27\", is_dev_dep = False),\n struct(repo=\"rust_crates__sec1-0.7.3\", is_dev_dep = False),\n struct(repo=\"rust_crates__serde-1.0.228\", is_dev_dep = False),\n struct(repo=\"rust_crates__serde_derive-1.0.228\", is_dev_dep = False),\n struct(repo=\"rust_crates__serde_json5-0.2.1\", is_dev_dep = False),\n struct(repo=\"rust_crates__sha2-0.10.9\", is_dev_dep = False),\n struct(repo=\"rust_crates__sha3-0.10.9\", is_dev_dep = False),\n struct(repo=\"rust_crates__smlang-0.8.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__subtle-2.6.1\", is_dev_dep = False),\n struct(repo=\"rust_crates__syn-1.0.109\", is_dev_dep = False),\n struct(repo=\"rust_crates__syn-2.0.117\", is_dev_dep = False),\n struct(repo=\"rust_crates__thiserror-2.0.18\", is_dev_dep = False),\n struct(repo=\"rust_crates__tock-registers-0.9.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__tokio-1.52.1\", is_dev_dep = False),\n struct(repo=\"rust_crates__tokio-util-0.7.18\", is_dev_dep = False),\n struct(repo=\"rust_crates__vcell-0.1.3\", is_dev_dep = False),\n struct(repo=\"rust_crates__zerocopy-0.8.48\", is_dev_dep = False),\n struct(repo=\"rust_crates__zeroize-1.8.2\", is_dev_dep = False),\n ]\n" + "defs.bzl": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'openprot'\n###############################################################################\n\"\"\"\n# `crates_repository` API\n\n- [aliases](#aliases)\n- [crate_deps](#crate_deps)\n- [all_crate_deps](#all_crate_deps)\n- [crate_repositories](#crate_repositories)\n\n\"\"\"\n\nload(\"@bazel_tools//tools/build_defs/repo:git.bzl\", \"git_repository\")\nload(\"@bazel_tools//tools/build_defs/repo:http.bzl\", \"http_archive\")\nload(\"@bazel_tools//tools/build_defs/repo:utils.bzl\", \"maybe\")\nload(\"@bazel_skylib//lib:selects.bzl\", \"selects\")\nload(\"@rules_rust//crate_universe/private:local_crate_mirror.bzl\", \"local_crate_mirror\")\n\n###############################################################################\n# MACROS API\n###############################################################################\n\n# An identifier that represent common dependencies (unconditional).\n_COMMON_CONDITION = \"\"\n\ndef _flatten_dependency_maps(all_dependency_maps):\n \"\"\"Flatten a list of dependency maps into one dictionary.\n\n Dependency maps have the following structure:\n\n ```python\n DEPENDENCIES_MAP = {\n # The first key in the map is a Bazel package\n # name of the workspace this file is defined in.\n \"workspace_member_package\": {\n\n # Not all dependencies are supported for all platforms.\n # the condition key is the condition required to be true\n # on the host platform.\n \"condition\": {\n\n # An alias to a crate target. # The label of the crate target the\n # Aliases are only crate names. # package name refers to.\n \"package_name\": \"@full//:label\",\n }\n }\n }\n ```\n\n Args:\n all_dependency_maps (list): A list of dicts as described above\n\n Returns:\n dict: A dictionary as described above\n \"\"\"\n dependencies = {}\n\n for workspace_deps_map in all_dependency_maps:\n for pkg_name, conditional_deps_map in workspace_deps_map.items():\n if pkg_name not in dependencies:\n non_frozen_map = dict()\n for key, values in conditional_deps_map.items():\n non_frozen_map.update({key: dict(values.items())})\n dependencies.setdefault(pkg_name, non_frozen_map)\n continue\n\n for condition, deps_map in conditional_deps_map.items():\n # If the condition has not been recorded, do so and continue\n if condition not in dependencies[pkg_name]:\n dependencies[pkg_name].setdefault(condition, dict(deps_map.items()))\n continue\n\n # Alert on any miss-matched dependencies\n inconsistent_entries = []\n for crate_name, crate_label in deps_map.items():\n existing = dependencies[pkg_name][condition].get(crate_name)\n if existing and existing != crate_label:\n inconsistent_entries.append((crate_name, existing, crate_label))\n dependencies[pkg_name][condition].update({crate_name: crate_label})\n\n return dependencies\n\ndef crate_deps(deps, package_name = None):\n \"\"\"Finds the fully qualified label of the requested crates for the package where this macro is called.\n\n Args:\n deps (list): The desired list of crate targets.\n package_name (str, optional): The package name of the set of dependencies to look up.\n Defaults to `native.package_name()`.\n\n Returns:\n list: A list of labels to generated rust targets (str)\n \"\"\"\n\n if not deps:\n return []\n\n if package_name == None:\n package_name = native.package_name()\n\n # Join both sets of dependencies\n dependencies = _flatten_dependency_maps([\n _NORMAL_DEPENDENCIES,\n _NORMAL_DEV_DEPENDENCIES,\n _PROC_MACRO_DEPENDENCIES,\n _PROC_MACRO_DEV_DEPENDENCIES,\n _BUILD_DEPENDENCIES,\n _BUILD_PROC_MACRO_DEPENDENCIES,\n ]).pop(package_name, {})\n\n # Combine all conditional packages so we can easily index over a flat list\n # TODO: Perhaps this should actually return select statements and maintain\n # the conditionals of the dependencies\n flat_deps = {}\n for deps_set in dependencies.values():\n for crate_name, crate_label in deps_set.items():\n flat_deps.update({crate_name: crate_label})\n\n missing_crates = []\n crate_targets = []\n for crate_target in deps:\n if crate_target not in flat_deps:\n missing_crates.append(crate_target)\n else:\n crate_targets.append(flat_deps[crate_target])\n\n if missing_crates:\n fail(\"Could not find crates `{}` among dependencies of `{}`. Available dependencies were `{}`\".format(\n missing_crates,\n package_name,\n dependencies,\n ))\n\n return crate_targets\n\ndef all_crate_deps(\n normal = False, \n normal_dev = False, \n proc_macro = False, \n proc_macro_dev = False,\n build = False,\n build_proc_macro = False,\n package_name = None):\n \"\"\"Finds the fully qualified label of all requested direct crate dependencies \\\n for the package where this macro is called.\n\n If no parameters are set, all normal dependencies are returned. Setting any one flag will\n otherwise impact the contents of the returned list.\n\n Args:\n normal (bool, optional): If True, normal dependencies are included in the\n output list.\n normal_dev (bool, optional): If True, normal dev dependencies will be\n included in the output list.\n proc_macro (bool, optional): If True, proc_macro dependencies are included\n in the output list.\n proc_macro_dev (bool, optional): If True, dev proc_macro dependencies are\n included in the output list.\n build (bool, optional): If True, build dependencies are included\n in the output list.\n build_proc_macro (bool, optional): If True, build proc_macro dependencies are\n included in the output list.\n package_name (str, optional): The package name of the set of dependencies to look up.\n Defaults to `native.package_name()` when unset.\n\n Returns:\n list: A list of labels to generated rust targets (str)\n \"\"\"\n\n if package_name == None:\n package_name = native.package_name()\n\n # Determine the relevant maps to use\n all_dependency_maps = []\n if normal:\n all_dependency_maps.append(_NORMAL_DEPENDENCIES)\n if normal_dev:\n all_dependency_maps.append(_NORMAL_DEV_DEPENDENCIES)\n if proc_macro:\n all_dependency_maps.append(_PROC_MACRO_DEPENDENCIES)\n if proc_macro_dev:\n all_dependency_maps.append(_PROC_MACRO_DEV_DEPENDENCIES)\n if build:\n all_dependency_maps.append(_BUILD_DEPENDENCIES)\n if build_proc_macro:\n all_dependency_maps.append(_BUILD_PROC_MACRO_DEPENDENCIES)\n\n # Default to always using normal dependencies\n if not all_dependency_maps:\n all_dependency_maps.append(_NORMAL_DEPENDENCIES)\n\n dependencies = _flatten_dependency_maps(all_dependency_maps).pop(package_name, None)\n\n if not dependencies:\n if dependencies == None:\n fail(\"Tried to get all_crate_deps for package \" + package_name + \" but that package had no Cargo.toml file\")\n else:\n return []\n\n crate_deps = list(dependencies.pop(_COMMON_CONDITION, {}).values())\n for condition, deps in dependencies.items():\n crate_deps += selects.with_or({\n tuple(_CONDITIONS[condition]): deps.values(),\n \"//conditions:default\": [],\n })\n\n return crate_deps\n\ndef aliases(\n normal = False,\n normal_dev = False,\n proc_macro = False,\n proc_macro_dev = False,\n build = False,\n build_proc_macro = False,\n package_name = None):\n \"\"\"Produces a map of Crate alias names to their original label\n\n If no dependency kinds are specified, `normal` and `proc_macro` are used by default.\n Setting any one flag will otherwise determine the contents of the returned dict.\n\n Args:\n normal (bool, optional): If True, normal dependencies are included in the\n output list.\n normal_dev (bool, optional): If True, normal dev dependencies will be\n included in the output list..\n proc_macro (bool, optional): If True, proc_macro dependencies are included\n in the output list.\n proc_macro_dev (bool, optional): If True, dev proc_macro dependencies are\n included in the output list.\n build (bool, optional): If True, build dependencies are included\n in the output list.\n build_proc_macro (bool, optional): If True, build proc_macro dependencies are\n included in the output list.\n package_name (str, optional): The package name of the set of dependencies to look up.\n Defaults to `native.package_name()` when unset.\n\n Returns:\n dict: The aliases of all associated packages\n \"\"\"\n if package_name == None:\n package_name = native.package_name()\n\n # Determine the relevant maps to use\n all_aliases_maps = []\n if normal:\n all_aliases_maps.append(_NORMAL_ALIASES)\n if normal_dev:\n all_aliases_maps.append(_NORMAL_DEV_ALIASES)\n if proc_macro:\n all_aliases_maps.append(_PROC_MACRO_ALIASES)\n if proc_macro_dev:\n all_aliases_maps.append(_PROC_MACRO_DEV_ALIASES)\n if build:\n all_aliases_maps.append(_BUILD_ALIASES)\n if build_proc_macro:\n all_aliases_maps.append(_BUILD_PROC_MACRO_ALIASES)\n\n # Default to always using normal aliases\n if not all_aliases_maps:\n all_aliases_maps.append(_NORMAL_ALIASES)\n all_aliases_maps.append(_PROC_MACRO_ALIASES)\n\n aliases = _flatten_dependency_maps(all_aliases_maps).pop(package_name, None)\n\n if not aliases:\n return dict()\n\n common_items = aliases.pop(_COMMON_CONDITION, {}).items()\n\n # If there are only common items in the dictionary, immediately return them\n if not len(aliases.keys()) == 1:\n return dict(common_items)\n\n # Build a single select statement where each conditional has accounted for the\n # common set of aliases.\n crate_aliases = {\"//conditions:default\": dict(common_items)}\n for condition, deps in aliases.items():\n condition_triples = _CONDITIONS[condition]\n for triple in condition_triples:\n if triple in crate_aliases:\n crate_aliases[triple].update(deps)\n else:\n crate_aliases.update({triple: dict(deps.items() + common_items)})\n\n return select(crate_aliases)\n\n###############################################################################\n# WORKSPACE MEMBER DEPS AND ALIASES\n###############################################################################\n\n_NORMAL_DEPENDENCIES = {\n \"third_party/crates_io\": {\n _COMMON_CONDITION: {\n \"aes\": Label(\"@rust_crates//:aes-0.8.4\"),\n \"aes-gcm\": Label(\"@rust_crates//:aes-gcm-0.10.3\"),\n \"aligned\": Label(\"@rust_crates//:aligned-0.4.3\"),\n \"anyhow\": Label(\"@rust_crates//:anyhow-1.0.102\"),\n \"bitfield\": Label(\"@rust_crates//:bitfield-0.14.0\"),\n \"bitflags\": Label(\"@rust_crates//:bitflags-2.11.1\"),\n \"byteorder\": Label(\"@rust_crates//:byteorder-1.5.0\"),\n \"cfg-if\": Label(\"@rust_crates//:cfg-if-1.0.4\"),\n \"cipher\": Label(\"@rust_crates//:cipher-0.4.4\"),\n \"clap\": Label(\"@rust_crates//:clap-4.6.1\"),\n \"compiler_builtins\": Label(\"@rust_crates//:compiler_builtins-0.1.160\"),\n \"cortex-m\": Label(\"@rust_crates//:cortex-m-0.7.7\"),\n \"cortex-m-rt\": Label(\"@rust_crates//:cortex-m-rt-0.7.5\"),\n \"cortex-m-semihosting\": Label(\"@rust_crates//:cortex-m-semihosting-0.5.0\"),\n \"ctr\": Label(\"@rust_crates//:ctr-0.9.2\"),\n \"ecdsa\": Label(\"@rust_crates//:ecdsa-0.16.9\"),\n \"embedded-hal\": Label(\"@rust_crates//:embedded-hal-1.0.0\"),\n \"embedded-hal-async\": Label(\"@rust_crates//:embedded-hal-async-1.0.0\"),\n \"embedded-hal-nb\": Label(\"@rust_crates//:embedded-hal-nb-1.0.0\"),\n \"embedded-io\": Label(\"@rust_crates//:embedded-io-0.6.1\"),\n \"embedded-storage\": Label(\"@rust_crates//:embedded-storage-0.3.1\"),\n \"fugit\": Label(\"@rust_crates//:fugit-0.3.9\"),\n \"futures\": Label(\"@rust_crates//:futures-0.3.32\"),\n \"heapless\": Label(\"@rust_crates//:heapless-0.9.2\"),\n \"hex\": Label(\"@rust_crates//:hex-0.4.3\"),\n \"hex-literal\": Label(\"@rust_crates//:hex-literal-0.4.1\"),\n \"hmac\": Label(\"@rust_crates//:hmac-0.12.1\"),\n \"k256\": Label(\"@rust_crates//:k256-0.13.4\"),\n \"log\": Label(\"@rust_crates//:log-0.4.29\"),\n \"mctp\": Label(\"@rust_crates//:mctp-0.2.0\"),\n \"mctp-lib\": Label(\"@rust_crates//:mctp-lib-0.1.0\"),\n \"memoffset\": Label(\"@rust_crates//:memoffset-0.9.1\"),\n \"minijinja\": Label(\"@rust_crates//:minijinja-2.19.0\"),\n \"nb\": Label(\"@rust_crates//:nb-1.1.0\"),\n \"nom\": Label(\"@rust_crates//:nom-7.1.3\"),\n \"object\": Label(\"@rust_crates//:object-0.37.3\"),\n \"openprot-hal-blocking\": Label(\"@rust_crates//:openprot-hal-blocking-0.1.0\"),\n \"p256\": Label(\"@rust_crates//:p256-0.13.2\"),\n \"p384\": Label(\"@rust_crates//:p384-0.13.1\"),\n \"panic-halt\": Label(\"@rust_crates//:panic-halt-1.0.0\"),\n \"proc-macro2\": Label(\"@rust_crates//:proc-macro2-1.0.106\"),\n \"prost\": Label(\"@rust_crates//:prost-0.13.5\"),\n \"quote\": Label(\"@rust_crates//:quote-1.0.45\"),\n \"rand_core\": Label(\"@rust_crates//:rand_core-0.9.5\"),\n \"riscv\": Label(\"@rust_crates//:riscv-0.12.1\"),\n \"riscv-rt\": Label(\"@rust_crates//:riscv-rt-0.12.2\"),\n \"riscv-semihosting\": Label(\"@rust_crates//:riscv-semihosting-0.1.3\"),\n \"rustc-demangle\": Label(\"@rust_crates//:rustc-demangle-0.1.27\"),\n \"sec1\": Label(\"@rust_crates//:sec1-0.7.3\"),\n \"serde\": Label(\"@rust_crates//:serde-1.0.228\"),\n \"serde_json5\": Label(\"@rust_crates//:serde_json5-0.2.1\"),\n \"sha2\": Label(\"@rust_crates//:sha2-0.10.9\"),\n \"sha3\": Label(\"@rust_crates//:sha3-0.10.9\"),\n \"smlang\": Label(\"@rust_crates//:smlang-0.8.0\"),\n \"subtle\": Label(\"@rust_crates//:subtle-2.6.1\"),\n \"syn1\": Label(\"@rust_crates//:syn-1.0.109\"),\n \"syn\": Label(\"@rust_crates//:syn-2.0.117\"),\n \"thiserror\": Label(\"@rust_crates//:thiserror-2.0.18\"),\n \"tock-registers\": Label(\"@rust_crates//:tock-registers-0.9.0\"),\n \"tokio\": Label(\"@rust_crates//:tokio-1.52.1\"),\n \"tokio-util\": Label(\"@rust_crates//:tokio-util-0.7.18\"),\n \"vcell\": Label(\"@rust_crates//:vcell-0.1.3\"),\n \"zerocopy\": Label(\"@rust_crates//:zerocopy-0.8.48\"),\n \"zeroize\": Label(\"@rust_crates//:zeroize-1.8.2\"),\n },\n },\n}\n\n\n_NORMAL_ALIASES = {\n \"third_party/crates_io\": {\n _COMMON_CONDITION: {\n Label(\"@rust_crates//:syn-1.0.109\"): \"syn1\",\n },\n },\n}\n\n\n_NORMAL_DEV_DEPENDENCIES = {\n \"third_party/crates_io\": {\n },\n}\n\n\n_NORMAL_DEV_ALIASES = {\n \"third_party/crates_io\": {\n },\n}\n\n\n_PROC_MACRO_DEPENDENCIES = {\n \"third_party/crates_io\": {\n _COMMON_CONDITION: {\n \"bitfield-struct\": Label(\"@rust_crates//:bitfield-struct-0.11.0\"),\n \"paste\": Label(\"@rust_crates//:paste-1.0.15\"),\n \"serde_derive\": Label(\"@rust_crates//:serde_derive-1.0.228\"),\n },\n },\n}\n\n\n_PROC_MACRO_ALIASES = {\n \"third_party/crates_io\": {\n },\n}\n\n\n_PROC_MACRO_DEV_DEPENDENCIES = {\n \"third_party/crates_io\": {\n },\n}\n\n\n_PROC_MACRO_DEV_ALIASES = {\n \"third_party/crates_io\": {\n },\n}\n\n\n_BUILD_DEPENDENCIES = {\n \"third_party/crates_io\": {\n },\n}\n\n\n_BUILD_ALIASES = {\n \"third_party/crates_io\": {\n },\n}\n\n\n_BUILD_PROC_MACRO_DEPENDENCIES = {\n \"third_party/crates_io\": {\n },\n}\n\n\n_BUILD_PROC_MACRO_ALIASES = {\n \"third_party/crates_io\": {\n },\n}\n\n\n_CONDITIONS = {\n \"aarch64-apple-darwin\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\"],\n \"aarch64-linux-android\": [],\n \"aarch64-unknown-linux-gnu\": [\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\"],\n \"cfg(all(any(target_os = \\\"linux\\\", target_os = \\\"android\\\"), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\": [],\n \"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\": [\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:riscv32imc-unknown-none-elf\",\"@rules_rust//rust/platform:thumbv7em-none-eabi\",\"@rules_rust//rust/platform:x86_64-apple-darwin\"],\n \"cfg(all(target_arch = \\\"aarch64\\\", target_os = \\\"linux\\\"))\": [\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\"],\n \"cfg(all(target_arch = \\\"aarch64\\\", target_vendor = \\\"apple\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\"],\n \"cfg(all(target_arch = \\\"loongarch64\\\", target_os = \\\"linux\\\"))\": [],\n \"cfg(any())\": [],\n \"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-apple-darwin\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any(target_arch = \\\"arm\\\", target_pointer_width = \\\"32\\\", target_pointer_width = \\\"64\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:riscv32imc-unknown-none-elf\",\"@rules_rust//rust/platform:thumbv7em-none-eabi\",\"@rules_rust//rust/platform:x86_64-apple-darwin\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any(unix, target_os = \\\"hermit\\\", target_os = \\\"wasi\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-apple-darwin\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any(unix, target_os = \\\"wasi\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-apple-darwin\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(target_arch = \\\"aarch64\\\")\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\"],\n \"cfg(target_os = \\\"hermit\\\")\": [],\n \"cfg(target_os = \\\"redox\\\")\": [],\n \"cfg(target_os = \\\"wasi\\\")\": [],\n \"cfg(unix)\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-apple-darwin\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(windows)\": [],\n \"riscv32imc-unknown-none-elf\": [\"@rules_rust//rust/platform:riscv32imc-unknown-none-elf\"],\n \"thumbv7em-none-eabi\": [\"@rules_rust//rust/platform:thumbv7em-none-eabi\"],\n \"x86_64-apple-darwin\": [\"@rules_rust//rust/platform:x86_64-apple-darwin\"],\n \"x86_64-unknown-linux-gnu\": [\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n}\n\n###############################################################################\n\ndef crate_repositories():\n \"\"\"A macro for defining repositories for all generated crates.\n\n Returns:\n A list of repos visible to the module through the module extension.\n \"\"\"\n maybe(\n http_archive,\n name = \"rust_crates__adler2-2.0.1\",\n sha256 = \"320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/adler2/2.0.1/download\"],\n strip_prefix = \"adler2-2.0.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.adler2-2.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__aead-0.5.2\",\n sha256 = \"d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/aead/0.5.2/download\"],\n strip_prefix = \"aead-0.5.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.aead-0.5.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__aes-0.8.4\",\n sha256 = \"b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/aes/0.8.4/download\"],\n strip_prefix = \"aes-0.8.4\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.aes-0.8.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__aes-gcm-0.10.3\",\n sha256 = \"831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/aes-gcm/0.10.3/download\"],\n strip_prefix = \"aes-gcm-0.10.3\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.aes-gcm-0.10.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__aligned-0.4.3\",\n sha256 = \"ee4508988c62edf04abd8d92897fca0c2995d907ce1dfeaf369dac3716a40685\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/aligned/0.4.3/download\"],\n strip_prefix = \"aligned-0.4.3\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.aligned-0.4.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__anstream-1.0.0\",\n sha256 = \"824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/anstream/1.0.0/download\"],\n strip_prefix = \"anstream-1.0.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.anstream-1.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__anstyle-1.0.14\",\n sha256 = \"940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/anstyle/1.0.14/download\"],\n strip_prefix = \"anstyle-1.0.14\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.anstyle-1.0.14.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__anstyle-parse-1.0.0\",\n sha256 = \"52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/anstyle-parse/1.0.0/download\"],\n strip_prefix = \"anstyle-parse-1.0.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.anstyle-parse-1.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__anstyle-query-1.1.5\",\n sha256 = \"40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/anstyle-query/1.1.5/download\"],\n strip_prefix = \"anstyle-query-1.1.5\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.anstyle-query-1.1.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__anstyle-wincon-3.0.11\",\n sha256 = \"291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/anstyle-wincon/3.0.11/download\"],\n strip_prefix = \"anstyle-wincon-3.0.11\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.anstyle-wincon-3.0.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__anyhow-1.0.102\",\n sha256 = \"7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/anyhow/1.0.102/download\"],\n strip_prefix = \"anyhow-1.0.102\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.anyhow-1.0.102.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__as-slice-0.2.1\",\n sha256 = \"516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/as-slice/0.2.1/download\"],\n strip_prefix = \"as-slice-0.2.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.as-slice-0.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__autocfg-1.5.0\",\n sha256 = \"c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/autocfg/1.5.0/download\"],\n strip_prefix = \"autocfg-1.5.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.autocfg-1.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__bare-metal-0.2.5\",\n sha256 = \"5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bare-metal/0.2.5/download\"],\n strip_prefix = \"bare-metal-0.2.5\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.bare-metal-0.2.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__base16ct-0.2.0\",\n sha256 = \"4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/base16ct/0.2.0/download\"],\n strip_prefix = \"base16ct-0.2.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.base16ct-0.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__bitfield-0.13.2\",\n sha256 = \"46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bitfield/0.13.2/download\"],\n strip_prefix = \"bitfield-0.13.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.bitfield-0.13.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__bitfield-0.14.0\",\n sha256 = \"2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bitfield/0.14.0/download\"],\n strip_prefix = \"bitfield-0.14.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.bitfield-0.14.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__bitfield-struct-0.11.0\",\n sha256 = \"d3ca019570363e800b05ad4fd890734f28ac7b72f563ad8a35079efb793616f8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bitfield-struct/0.11.0/download\"],\n strip_prefix = \"bitfield-struct-0.11.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.bitfield-struct-0.11.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__bitflags-2.11.1\",\n sha256 = \"c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bitflags/2.11.1/download\"],\n strip_prefix = \"bitflags-2.11.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.bitflags-2.11.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__block-buffer-0.10.4\",\n sha256 = \"3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/block-buffer/0.10.4/download\"],\n strip_prefix = \"block-buffer-0.10.4\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.block-buffer-0.10.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__byteorder-1.5.0\",\n sha256 = \"1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/byteorder/1.5.0/download\"],\n strip_prefix = \"byteorder-1.5.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.byteorder-1.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__bytes-1.11.1\",\n sha256 = \"1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bytes/1.11.1/download\"],\n strip_prefix = \"bytes-1.11.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.bytes-1.11.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__cfg-if-1.0.4\",\n sha256 = \"9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cfg-if/1.0.4/download\"],\n strip_prefix = \"cfg-if-1.0.4\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.cfg-if-1.0.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__cipher-0.4.4\",\n sha256 = \"773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cipher/0.4.4/download\"],\n strip_prefix = \"cipher-0.4.4\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.cipher-0.4.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__clap-4.6.1\",\n sha256 = \"1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/clap/4.6.1/download\"],\n strip_prefix = \"clap-4.6.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.clap-4.6.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__clap_builder-4.6.0\",\n sha256 = \"714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/clap_builder/4.6.0/download\"],\n strip_prefix = \"clap_builder-4.6.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.clap_builder-4.6.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__clap_derive-4.6.1\",\n sha256 = \"f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/clap_derive/4.6.1/download\"],\n strip_prefix = \"clap_derive-4.6.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.clap_derive-4.6.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__clap_lex-1.1.0\",\n sha256 = \"c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/clap_lex/1.1.0/download\"],\n strip_prefix = \"clap_lex-1.1.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.clap_lex-1.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__colorchoice-1.0.5\",\n sha256 = \"1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/colorchoice/1.0.5/download\"],\n strip_prefix = \"colorchoice-1.0.5\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.colorchoice-1.0.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__compiler_builtins-0.1.160\",\n sha256 = \"6376049cfa92c0aa8b9ac95fae22184b981c658208d4ed8a1dc553cd83612895\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/compiler_builtins/0.1.160/download\"],\n strip_prefix = \"compiler_builtins-0.1.160\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.compiler_builtins-0.1.160.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__const-oid-0.9.6\",\n sha256 = \"c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/const-oid/0.9.6/download\"],\n strip_prefix = \"const-oid-0.9.6\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.const-oid-0.9.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__cortex-m-0.7.7\",\n sha256 = \"8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cortex-m/0.7.7/download\"],\n strip_prefix = \"cortex-m-0.7.7\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.cortex-m-0.7.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__cortex-m-rt-0.7.5\",\n sha256 = \"801d4dec46b34c299ccf6b036717ae0fce602faa4f4fe816d9013b9a7c9f5ba6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cortex-m-rt/0.7.5/download\"],\n strip_prefix = \"cortex-m-rt-0.7.5\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.cortex-m-rt-0.7.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__cortex-m-rt-macros-0.7.5\",\n sha256 = \"e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cortex-m-rt-macros/0.7.5/download\"],\n strip_prefix = \"cortex-m-rt-macros-0.7.5\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.cortex-m-rt-macros-0.7.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__cortex-m-semihosting-0.5.0\",\n sha256 = \"c23234600452033cc77e4b761e740e02d2c4168e11dbf36ab14a0f58973592b0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cortex-m-semihosting/0.5.0/download\"],\n strip_prefix = \"cortex-m-semihosting-0.5.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.cortex-m-semihosting-0.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__cpufeatures-0.2.17\",\n sha256 = \"59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cpufeatures/0.2.17/download\"],\n strip_prefix = \"cpufeatures-0.2.17\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.cpufeatures-0.2.17.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__crc-3.4.0\",\n sha256 = \"5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crc/3.4.0/download\"],\n strip_prefix = \"crc-3.4.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.crc-3.4.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__crc-catalog-2.5.0\",\n sha256 = \"217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crc-catalog/2.5.0/download\"],\n strip_prefix = \"crc-catalog-2.5.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.crc-catalog-2.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__crc32fast-1.5.0\",\n sha256 = \"9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crc32fast/1.5.0/download\"],\n strip_prefix = \"crc32fast-1.5.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.crc32fast-1.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__critical-section-1.2.0\",\n sha256 = \"790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/critical-section/1.2.0/download\"],\n strip_prefix = \"critical-section-1.2.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.critical-section-1.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__crypto-bigint-0.5.5\",\n sha256 = \"0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crypto-bigint/0.5.5/download\"],\n strip_prefix = \"crypto-bigint-0.5.5\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.crypto-bigint-0.5.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__crypto-common-0.1.7\",\n sha256 = \"78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crypto-common/0.1.7/download\"],\n strip_prefix = \"crypto-common-0.1.7\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.crypto-common-0.1.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__ctr-0.9.2\",\n sha256 = \"0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ctr/0.9.2/download\"],\n strip_prefix = \"ctr-0.9.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.ctr-0.9.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__der-0.7.10\",\n sha256 = \"e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/der/0.7.10/download\"],\n strip_prefix = \"der-0.7.10\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.der-0.7.10.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__digest-0.10.7\",\n sha256 = \"9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/digest/0.10.7/download\"],\n strip_prefix = \"digest-0.10.7\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.digest-0.10.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__ecdsa-0.16.9\",\n sha256 = \"ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ecdsa/0.16.9/download\"],\n strip_prefix = \"ecdsa-0.16.9\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.ecdsa-0.16.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__either-1.15.0\",\n sha256 = \"48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/either/1.15.0/download\"],\n strip_prefix = \"either-1.15.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.either-1.15.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__elliptic-curve-0.13.8\",\n sha256 = \"b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/elliptic-curve/0.13.8/download\"],\n strip_prefix = \"elliptic-curve-0.13.8\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.elliptic-curve-0.13.8.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__embedded-crc-macros-1.0.0\",\n sha256 = \"4f1c75747a43b086df1a87fb2a889590bc0725e0abf54bba6d0c4bf7bd9e762c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/embedded-crc-macros/1.0.0/download\"],\n strip_prefix = \"embedded-crc-macros-1.0.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.embedded-crc-macros-1.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__embedded-hal-0.2.7\",\n sha256 = \"35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/embedded-hal/0.2.7/download\"],\n strip_prefix = \"embedded-hal-0.2.7\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.embedded-hal-0.2.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__embedded-hal-1.0.0\",\n sha256 = \"361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/embedded-hal/1.0.0/download\"],\n strip_prefix = \"embedded-hal-1.0.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.embedded-hal-1.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__embedded-hal-async-1.0.0\",\n sha256 = \"0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/embedded-hal-async/1.0.0/download\"],\n strip_prefix = \"embedded-hal-async-1.0.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.embedded-hal-async-1.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__embedded-hal-nb-1.0.0\",\n sha256 = \"fba4268c14288c828995299e59b12babdbe170f6c6d73731af1b4648142e8605\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/embedded-hal-nb/1.0.0/download\"],\n strip_prefix = \"embedded-hal-nb-1.0.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.embedded-hal-nb-1.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__embedded-io-0.6.1\",\n sha256 = \"edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/embedded-io/0.6.1/download\"],\n strip_prefix = \"embedded-io-0.6.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.embedded-io-0.6.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__embedded-io-async-0.6.1\",\n sha256 = \"3ff09972d4073aa8c299395be75161d582e7629cd663171d62af73c8d50dba3f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/embedded-io-async/0.6.1/download\"],\n strip_prefix = \"embedded-io-async-0.6.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.embedded-io-async-0.6.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__embedded-storage-0.3.1\",\n sha256 = \"a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/embedded-storage/0.3.1/download\"],\n strip_prefix = \"embedded-storage-0.3.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.embedded-storage-0.3.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__equivalent-1.0.2\",\n sha256 = \"877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/equivalent/1.0.2/download\"],\n strip_prefix = \"equivalent-1.0.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.equivalent-1.0.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__errno-0.3.14\",\n sha256 = \"39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/errno/0.3.14/download\"],\n strip_prefix = \"errno-0.3.14\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.errno-0.3.14.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__ff-0.13.1\",\n sha256 = \"c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ff/0.13.1/download\"],\n strip_prefix = \"ff-0.13.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.ff-0.13.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__flate2-1.1.9\",\n sha256 = \"843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/flate2/1.1.9/download\"],\n strip_prefix = \"flate2-1.1.9\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.flate2-1.1.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__foldhash-0.1.5\",\n sha256 = \"d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/foldhash/0.1.5/download\"],\n strip_prefix = \"foldhash-0.1.5\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.foldhash-0.1.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__fugit-0.3.9\",\n sha256 = \"4e639847d312d9a82d2e75b0edcc1e934efcc64e6cb7aa94f0b1fbec0bc231d6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/fugit/0.3.9/download\"],\n strip_prefix = \"fugit-0.3.9\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.fugit-0.3.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__futures-0.3.32\",\n sha256 = \"8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures/0.3.32/download\"],\n strip_prefix = \"futures-0.3.32\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.futures-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__futures-channel-0.3.32\",\n sha256 = \"07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-channel/0.3.32/download\"],\n strip_prefix = \"futures-channel-0.3.32\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.futures-channel-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__futures-core-0.3.32\",\n sha256 = \"7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-core/0.3.32/download\"],\n strip_prefix = \"futures-core-0.3.32\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.futures-core-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__futures-executor-0.3.32\",\n sha256 = \"baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-executor/0.3.32/download\"],\n strip_prefix = \"futures-executor-0.3.32\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.futures-executor-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__futures-io-0.3.32\",\n sha256 = \"cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-io/0.3.32/download\"],\n strip_prefix = \"futures-io-0.3.32\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.futures-io-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__futures-macro-0.3.32\",\n sha256 = \"e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-macro/0.3.32/download\"],\n strip_prefix = \"futures-macro-0.3.32\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.futures-macro-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__futures-sink-0.3.32\",\n sha256 = \"c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-sink/0.3.32/download\"],\n strip_prefix = \"futures-sink-0.3.32\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.futures-sink-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__futures-task-0.3.32\",\n sha256 = \"037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-task/0.3.32/download\"],\n strip_prefix = \"futures-task-0.3.32\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.futures-task-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__futures-util-0.3.32\",\n sha256 = \"389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-util/0.3.32/download\"],\n strip_prefix = \"futures-util-0.3.32\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.futures-util-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__gcd-2.3.0\",\n sha256 = \"1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/gcd/2.3.0/download\"],\n strip_prefix = \"gcd-2.3.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.gcd-2.3.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__generic-array-0.14.7\",\n sha256 = \"85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/generic-array/0.14.7/download\"],\n strip_prefix = \"generic-array-0.14.7\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.generic-array-0.14.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__ghash-0.5.1\",\n sha256 = \"f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ghash/0.5.1/download\"],\n strip_prefix = \"ghash-0.5.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.ghash-0.5.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__group-0.13.0\",\n sha256 = \"f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/group/0.13.0/download\"],\n strip_prefix = \"group-0.13.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.group-0.13.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__hash32-0.3.1\",\n sha256 = \"47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hash32/0.3.1/download\"],\n strip_prefix = \"hash32-0.3.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.hash32-0.3.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__hashbrown-0.15.5\",\n sha256 = \"9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hashbrown/0.15.5/download\"],\n strip_prefix = \"hashbrown-0.15.5\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.hashbrown-0.15.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__hashbrown-0.17.0\",\n sha256 = \"4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hashbrown/0.17.0/download\"],\n strip_prefix = \"hashbrown-0.17.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.hashbrown-0.17.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__heapless-0.8.0\",\n sha256 = \"0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/heapless/0.8.0/download\"],\n strip_prefix = \"heapless-0.8.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.heapless-0.8.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__heapless-0.9.2\",\n sha256 = \"2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/heapless/0.9.2/download\"],\n strip_prefix = \"heapless-0.9.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.heapless-0.9.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__heck-0.5.0\",\n sha256 = \"2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/heck/0.5.0/download\"],\n strip_prefix = \"heck-0.5.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.heck-0.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__hex-0.4.3\",\n sha256 = \"7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hex/0.4.3/download\"],\n strip_prefix = \"hex-0.4.3\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.hex-0.4.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__hex-literal-0.4.1\",\n sha256 = \"6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hex-literal/0.4.1/download\"],\n strip_prefix = \"hex-literal-0.4.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.hex-literal-0.4.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__hmac-0.12.1\",\n sha256 = \"6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hmac/0.12.1/download\"],\n strip_prefix = \"hmac-0.12.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.hmac-0.12.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__indexmap-2.14.0\",\n sha256 = \"d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/indexmap/2.14.0/download\"],\n strip_prefix = \"indexmap-2.14.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.indexmap-2.14.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__inout-0.1.4\",\n sha256 = \"879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/inout/0.1.4/download\"],\n strip_prefix = \"inout-0.1.4\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.inout-0.1.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__is_terminal_polyfill-1.70.2\",\n sha256 = \"a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/is_terminal_polyfill/1.70.2/download\"],\n strip_prefix = \"is_terminal_polyfill-1.70.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.is_terminal_polyfill-1.70.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__itertools-0.14.0\",\n sha256 = \"2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/itertools/0.14.0/download\"],\n strip_prefix = \"itertools-0.14.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.itertools-0.14.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__k256-0.13.4\",\n sha256 = \"f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/k256/0.13.4/download\"],\n strip_prefix = \"k256-0.13.4\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.k256-0.13.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__keccak-0.1.6\",\n sha256 = \"cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/keccak/0.1.6/download\"],\n strip_prefix = \"keccak-0.1.6\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.keccak-0.1.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__libc-0.2.186\",\n sha256 = \"68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/libc/0.2.186/download\"],\n strip_prefix = \"libc-0.2.186\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.libc-0.2.186.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__linux-raw-sys-0.12.1\",\n sha256 = \"32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/linux-raw-sys/0.12.1/download\"],\n strip_prefix = \"linux-raw-sys-0.12.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.linux-raw-sys-0.12.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__lock_api-0.4.14\",\n sha256 = \"224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/lock_api/0.4.14/download\"],\n strip_prefix = \"lock_api-0.4.14\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.lock_api-0.4.14.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__log-0.4.29\",\n sha256 = \"5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/log/0.4.29/download\"],\n strip_prefix = \"log-0.4.29\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.log-0.4.29.bazel\"),\n )\n\n maybe(\n git_repository,\n name = \"rust_crates__mctp-0.2.0\",\n commit = \"114dee1a7cfbae601ce11901b20516ebe217a4b2\",\n init_submodules = True,\n remote = \"https://github.com/CodeConstruct/mctp-rs.git\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.mctp-0.2.0.bazel\"),\n strip_prefix = \"mctp\",\n )\n\n maybe(\n git_repository,\n name = \"rust_crates__mctp-estack-0.1.0\",\n commit = \"114dee1a7cfbae601ce11901b20516ebe217a4b2\",\n init_submodules = True,\n remote = \"https://github.com/CodeConstruct/mctp-rs.git\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.mctp-estack-0.1.0.bazel\"),\n strip_prefix = \"mctp-estack\",\n )\n\n maybe(\n git_repository,\n name = \"rust_crates__mctp-lib-0.1.0\",\n commit = \"742fa0e991aa2b87509ff12739e011a674643d91\",\n init_submodules = True,\n remote = \"https://github.com/OpenPRoT/mctp-lib.git\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.mctp-lib-0.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__memchr-2.8.0\",\n sha256 = \"f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/memchr/2.8.0/download\"],\n strip_prefix = \"memchr-2.8.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.memchr-2.8.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__memo-map-0.3.3\",\n sha256 = \"38d1115007560874e373613744c6fba374c17688327a71c1476d1a5954cc857b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/memo-map/0.3.3/download\"],\n strip_prefix = \"memo-map-0.3.3\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.memo-map-0.3.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__memoffset-0.9.1\",\n sha256 = \"488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/memoffset/0.9.1/download\"],\n strip_prefix = \"memoffset-0.9.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.memoffset-0.9.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__minijinja-2.19.0\",\n sha256 = \"805bfd7352166bae857ee569628b52bcd85a1cecf7810861ebceb1686b72b75d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/minijinja/2.19.0/download\"],\n strip_prefix = \"minijinja-2.19.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.minijinja-2.19.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__minimal-lexical-0.2.1\",\n sha256 = \"68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/minimal-lexical/0.2.1/download\"],\n strip_prefix = \"minimal-lexical-0.2.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.minimal-lexical-0.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__miniz_oxide-0.8.9\",\n sha256 = \"1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/miniz_oxide/0.8.9/download\"],\n strip_prefix = \"miniz_oxide-0.8.9\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.miniz_oxide-0.8.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__mio-1.2.0\",\n sha256 = \"50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/mio/1.2.0/download\"],\n strip_prefix = \"mio-1.2.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.mio-1.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__nb-0.1.3\",\n sha256 = \"801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/nb/0.1.3/download\"],\n strip_prefix = \"nb-0.1.3\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.nb-0.1.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__nb-1.1.0\",\n sha256 = \"8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/nb/1.1.0/download\"],\n strip_prefix = \"nb-1.1.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.nb-1.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__nom-7.1.3\",\n sha256 = \"d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/nom/7.1.3/download\"],\n strip_prefix = \"nom-7.1.3\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.nom-7.1.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__object-0.37.3\",\n sha256 = \"ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/object/0.37.3/download\"],\n strip_prefix = \"object-0.37.3\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.object-0.37.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__once_cell_polyfill-1.70.2\",\n sha256 = \"384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/once_cell_polyfill/1.70.2/download\"],\n strip_prefix = \"once_cell_polyfill-1.70.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.once_cell_polyfill-1.70.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__opaque-debug-0.3.1\",\n sha256 = \"c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/opaque-debug/0.3.1/download\"],\n strip_prefix = \"opaque-debug-0.3.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.opaque-debug-0.3.1.bazel\"),\n )\n\n maybe(\n git_repository,\n name = \"rust_crates__openprot-hal-blocking-0.1.0\",\n commit = \"c6cd23a56f3cc7945b062ea1bcdabf3af0dba82d\",\n init_submodules = True,\n remote = \"https://github.com/rusty1968/openprot.git\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.openprot-hal-blocking-0.1.0.bazel\"),\n strip_prefix = \"hal/blocking\",\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__p256-0.13.2\",\n sha256 = \"c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/p256/0.13.2/download\"],\n strip_prefix = \"p256-0.13.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.p256-0.13.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__p384-0.13.1\",\n sha256 = \"fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/p384/0.13.1/download\"],\n strip_prefix = \"p384-0.13.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.p384-0.13.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__panic-halt-1.0.0\",\n sha256 = \"a513e167849a384b7f9b746e517604398518590a9142f4846a32e3c2a4de7b11\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/panic-halt/1.0.0/download\"],\n strip_prefix = \"panic-halt-1.0.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.panic-halt-1.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__parking_lot-0.12.5\",\n sha256 = \"93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/parking_lot/0.12.5/download\"],\n strip_prefix = \"parking_lot-0.12.5\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.parking_lot-0.12.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__parking_lot_core-0.9.12\",\n sha256 = \"2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/parking_lot_core/0.9.12/download\"],\n strip_prefix = \"parking_lot_core-0.9.12\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.parking_lot_core-0.9.12.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__paste-1.0.15\",\n sha256 = \"57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/paste/1.0.15/download\"],\n strip_prefix = \"paste-1.0.15\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.paste-1.0.15.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__pest-2.8.6\",\n sha256 = \"e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pest/2.8.6/download\"],\n strip_prefix = \"pest-2.8.6\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.pest-2.8.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__pest_derive-2.8.6\",\n sha256 = \"11f486f1ea21e6c10ed15d5a7c77165d0ee443402f0780849d1768e7d9d6fe77\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pest_derive/2.8.6/download\"],\n strip_prefix = \"pest_derive-2.8.6\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.pest_derive-2.8.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__pest_generator-2.8.6\",\n sha256 = \"8040c4647b13b210a963c1ed407c1ff4fdfa01c31d6d2a098218702e6664f94f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pest_generator/2.8.6/download\"],\n strip_prefix = \"pest_generator-2.8.6\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.pest_generator-2.8.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__pest_meta-2.8.6\",\n sha256 = \"89815c69d36021a140146f26659a81d6c2afa33d216d736dd4be5381a7362220\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pest_meta/2.8.6/download\"],\n strip_prefix = \"pest_meta-2.8.6\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.pest_meta-2.8.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__pin-project-lite-0.2.17\",\n sha256 = \"a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pin-project-lite/0.2.17/download\"],\n strip_prefix = \"pin-project-lite-0.2.17\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.pin-project-lite-0.2.17.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__polyval-0.6.2\",\n sha256 = \"9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/polyval/0.6.2/download\"],\n strip_prefix = \"polyval-0.6.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.polyval-0.6.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__primeorder-0.13.6\",\n sha256 = \"353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/primeorder/0.13.6/download\"],\n strip_prefix = \"primeorder-0.13.6\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.primeorder-0.13.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__proc-macro2-1.0.106\",\n sha256 = \"8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/proc-macro2/1.0.106/download\"],\n strip_prefix = \"proc-macro2-1.0.106\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.proc-macro2-1.0.106.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__prost-0.13.5\",\n sha256 = \"2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/prost/0.13.5/download\"],\n strip_prefix = \"prost-0.13.5\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.prost-0.13.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__prost-derive-0.13.5\",\n sha256 = \"8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/prost-derive/0.13.5/download\"],\n strip_prefix = \"prost-derive-0.13.5\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.prost-derive-0.13.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__quote-1.0.45\",\n sha256 = \"41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/quote/1.0.45/download\"],\n strip_prefix = \"quote-1.0.45\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.quote-1.0.45.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__rand_core-0.6.4\",\n sha256 = \"ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rand_core/0.6.4/download\"],\n strip_prefix = \"rand_core-0.6.4\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.rand_core-0.6.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__rand_core-0.9.5\",\n sha256 = \"76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rand_core/0.9.5/download\"],\n strip_prefix = \"rand_core-0.9.5\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.rand_core-0.9.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__redox_syscall-0.5.18\",\n sha256 = \"ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/redox_syscall/0.5.18/download\"],\n strip_prefix = \"redox_syscall-0.5.18\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.redox_syscall-0.5.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__rfc6979-0.4.0\",\n sha256 = \"f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rfc6979/0.4.0/download\"],\n strip_prefix = \"rfc6979-0.4.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.rfc6979-0.4.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__riscv-0.11.1\",\n sha256 = \"2f5c1b8bf41ea746266cdee443d1d1e9125c86ce1447e1a2615abd34330d33a9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/riscv/0.11.1/download\"],\n strip_prefix = \"riscv-0.11.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.riscv-0.11.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__riscv-0.12.1\",\n sha256 = \"5ea8ff73d3720bdd0a97925f0bf79ad2744b6da8ff36be3840c48ac81191d7a7\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/riscv/0.12.1/download\"],\n strip_prefix = \"riscv-0.12.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.riscv-0.12.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__riscv-0.13.0\",\n sha256 = \"afa3cdbeccae4359f6839a00e8b77e5736caa200ba216caf38d24e4c16e2b586\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/riscv/0.13.0/download\"],\n strip_prefix = \"riscv-0.13.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.riscv-0.13.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__riscv-macros-0.1.0\",\n sha256 = \"f265be5d634272320a7de94cea15c22a3bfdd4eb42eb43edc528415f066a1f25\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/riscv-macros/0.1.0/download\"],\n strip_prefix = \"riscv-macros-0.1.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.riscv-macros-0.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__riscv-macros-0.2.0\",\n sha256 = \"e8c4aa1ea1af6dcc83a61be12e8189f9b293c3ba5a487778a4cd89fb060fdbbc\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/riscv-macros/0.2.0/download\"],\n strip_prefix = \"riscv-macros-0.2.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.riscv-macros-0.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__riscv-pac-0.2.0\",\n sha256 = \"8188909339ccc0c68cfb5a04648313f09621e8b87dc03095454f1a11f6c5d436\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/riscv-pac/0.2.0/download\"],\n strip_prefix = \"riscv-pac-0.2.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.riscv-pac-0.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__riscv-rt-0.12.2\",\n sha256 = \"c0d35e32cf1383183e8885d8a9aa4402a087fd094dc34c2cb6df6687d0229dfe\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/riscv-rt/0.12.2/download\"],\n strip_prefix = \"riscv-rt-0.12.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.riscv-rt-0.12.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__riscv-rt-macros-0.2.2\",\n sha256 = \"30f19a85fe107b65031e0ba8ec60c34c2494069fe910d6c297f5e7cb5a6f76d0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/riscv-rt-macros/0.2.2/download\"],\n strip_prefix = \"riscv-rt-macros-0.2.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.riscv-rt-macros-0.2.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__riscv-semihosting-0.1.3\",\n sha256 = \"1086dd4bcc13de1cb14b93849411e3466de7e5907d2d8eb269032536e93facc6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/riscv-semihosting/0.1.3/download\"],\n strip_prefix = \"riscv-semihosting-0.1.3\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.riscv-semihosting-0.1.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__rustc-demangle-0.1.27\",\n sha256 = \"b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rustc-demangle/0.1.27/download\"],\n strip_prefix = \"rustc-demangle-0.1.27\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.rustc-demangle-0.1.27.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__rustc_version-0.2.3\",\n sha256 = \"138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rustc_version/0.2.3/download\"],\n strip_prefix = \"rustc_version-0.2.3\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.rustc_version-0.2.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__rustix-1.1.4\",\n sha256 = \"b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rustix/1.1.4/download\"],\n strip_prefix = \"rustix-1.1.4\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.rustix-1.1.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__ruzstd-0.8.2\",\n sha256 = \"e5ff0cc5e135c8870a775d3320910cd9b564ec036b4dc0b8741629020be63f01\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ruzstd/0.8.2/download\"],\n strip_prefix = \"ruzstd-0.8.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.ruzstd-0.8.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__scopeguard-1.2.0\",\n sha256 = \"94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/scopeguard/1.2.0/download\"],\n strip_prefix = \"scopeguard-1.2.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.scopeguard-1.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__sec1-0.7.3\",\n sha256 = \"d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/sec1/0.7.3/download\"],\n strip_prefix = \"sec1-0.7.3\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.sec1-0.7.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__semver-0.9.0\",\n sha256 = \"1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/semver/0.9.0/download\"],\n strip_prefix = \"semver-0.9.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.semver-0.9.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__semver-parser-0.7.0\",\n sha256 = \"388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/semver-parser/0.7.0/download\"],\n strip_prefix = \"semver-parser-0.7.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.semver-parser-0.7.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__serde-1.0.228\",\n sha256 = \"9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde/1.0.228/download\"],\n strip_prefix = \"serde-1.0.228\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.serde-1.0.228.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__serde_core-1.0.228\",\n sha256 = \"41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_core/1.0.228/download\"],\n strip_prefix = \"serde_core-1.0.228\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.serde_core-1.0.228.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__serde_derive-1.0.228\",\n sha256 = \"d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_derive/1.0.228/download\"],\n strip_prefix = \"serde_derive-1.0.228\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.serde_derive-1.0.228.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__serde_json5-0.2.1\",\n sha256 = \"5d34d03f54462862f2a42918391c9526337f53171eaa4d8894562be7f252edd3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_json5/0.2.1/download\"],\n strip_prefix = \"serde_json5-0.2.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.serde_json5-0.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__sha2-0.10.9\",\n sha256 = \"a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/sha2/0.10.9/download\"],\n strip_prefix = \"sha2-0.10.9\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.sha2-0.10.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__sha3-0.10.9\",\n sha256 = \"77fd7028345d415a4034cf8777cd4f8ab1851274233b45f84e3d955502d93874\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/sha3/0.10.9/download\"],\n strip_prefix = \"sha3-0.10.9\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.sha3-0.10.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__signal-hook-registry-1.4.8\",\n sha256 = \"c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/signal-hook-registry/1.4.8/download\"],\n strip_prefix = \"signal-hook-registry-1.4.8\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.signal-hook-registry-1.4.8.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__signature-2.2.0\",\n sha256 = \"77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/signature/2.2.0/download\"],\n strip_prefix = \"signature-2.2.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.signature-2.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__simd-adler32-0.3.9\",\n sha256 = \"703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/simd-adler32/0.3.9/download\"],\n strip_prefix = \"simd-adler32-0.3.9\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.simd-adler32-0.3.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__slab-0.4.12\",\n sha256 = \"0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/slab/0.4.12/download\"],\n strip_prefix = \"slab-0.4.12\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.slab-0.4.12.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__smallvec-1.15.1\",\n sha256 = \"67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/smallvec/1.15.1/download\"],\n strip_prefix = \"smallvec-1.15.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.smallvec-1.15.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__smbus-pec-1.0.1\",\n sha256 = \"ca0763a680cd5d72b28f7bfc8a054c117d8841380a6ad4f72f05bd2a34217d3e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/smbus-pec/1.0.1/download\"],\n strip_prefix = \"smbus-pec-1.0.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.smbus-pec-1.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__smlang-0.8.0\",\n sha256 = \"1de84f9f80bbe6272174e2bfdb8cf7ce4815b218038a42161c2f21c1d872c215\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/smlang/0.8.0/download\"],\n strip_prefix = \"smlang-0.8.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.smlang-0.8.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__smlang-macros-0.8.0\",\n sha256 = \"231b4425dcc43afc7e18c34e7c6738cd252d42d91d909c948df14107c9ae79f1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/smlang-macros/0.8.0/download\"],\n strip_prefix = \"smlang-macros-0.8.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.smlang-macros-0.8.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__socket2-0.6.3\",\n sha256 = \"3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/socket2/0.6.3/download\"],\n strip_prefix = \"socket2-0.6.3\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.socket2-0.6.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__stable_deref_trait-1.2.1\",\n sha256 = \"6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/stable_deref_trait/1.2.1/download\"],\n strip_prefix = \"stable_deref_trait-1.2.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.stable_deref_trait-1.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__string_morph-0.1.0\",\n sha256 = \"183aaf7fa637cc7b5f54c45b8f7cb6e8d73831f9f75a56b6defa5bf8c51d1699\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/string_morph/0.1.0/download\"],\n strip_prefix = \"string_morph-0.1.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.string_morph-0.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__strsim-0.11.1\",\n sha256 = \"7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/strsim/0.11.1/download\"],\n strip_prefix = \"strsim-0.11.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.strsim-0.11.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__subtle-2.6.1\",\n sha256 = \"13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/subtle/2.6.1/download\"],\n strip_prefix = \"subtle-2.6.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.subtle-2.6.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__syn-1.0.109\",\n sha256 = \"72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/syn/1.0.109/download\"],\n strip_prefix = \"syn-1.0.109\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.syn-1.0.109.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__syn-2.0.117\",\n sha256 = \"e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/syn/2.0.117/download\"],\n strip_prefix = \"syn-2.0.117\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.syn-2.0.117.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__terminal_size-0.4.4\",\n sha256 = \"230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/terminal_size/0.4.4/download\"],\n strip_prefix = \"terminal_size-0.4.4\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.terminal_size-0.4.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__thiserror-2.0.18\",\n sha256 = \"4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/thiserror/2.0.18/download\"],\n strip_prefix = \"thiserror-2.0.18\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.thiserror-2.0.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__thiserror-impl-2.0.18\",\n sha256 = \"ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/thiserror-impl/2.0.18/download\"],\n strip_prefix = \"thiserror-impl-2.0.18\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.thiserror-impl-2.0.18.bazel\"),\n )\n\n maybe(\n git_repository,\n name = \"rust_crates__tock-registers-0.9.0\",\n commit = \"9554639b17501a9f5940cef7a1770a0823e790c3\",\n init_submodules = True,\n remote = \"https://github.com/tock/tock.git\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.tock-registers-0.9.0.bazel\"),\n strip_prefix = \"libraries/tock-register-interface\",\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__tokio-1.52.1\",\n sha256 = \"b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tokio/1.52.1/download\"],\n strip_prefix = \"tokio-1.52.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.tokio-1.52.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__tokio-macros-2.7.0\",\n sha256 = \"385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tokio-macros/2.7.0/download\"],\n strip_prefix = \"tokio-macros-2.7.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.tokio-macros-2.7.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__tokio-util-0.7.18\",\n sha256 = \"9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tokio-util/0.7.18/download\"],\n strip_prefix = \"tokio-util-0.7.18\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.tokio-util-0.7.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__twox-hash-2.1.2\",\n sha256 = \"9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/twox-hash/2.1.2/download\"],\n strip_prefix = \"twox-hash-2.1.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.twox-hash-2.1.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__typenum-1.20.0\",\n sha256 = \"40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/typenum/1.20.0/download\"],\n strip_prefix = \"typenum-1.20.0\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.typenum-1.20.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__ucd-trie-0.1.7\",\n sha256 = \"2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ucd-trie/0.1.7/download\"],\n strip_prefix = \"ucd-trie-0.1.7\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.ucd-trie-0.1.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__unicode-ident-1.0.24\",\n sha256 = \"e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unicode-ident/1.0.24/download\"],\n strip_prefix = \"unicode-ident-1.0.24\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.unicode-ident-1.0.24.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__universal-hash-0.5.1\",\n sha256 = \"fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/universal-hash/0.5.1/download\"],\n strip_prefix = \"universal-hash-0.5.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.universal-hash-0.5.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__utf8parse-0.2.2\",\n sha256 = \"06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/utf8parse/0.2.2/download\"],\n strip_prefix = \"utf8parse-0.2.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.utf8parse-0.2.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__uuid-1.23.1\",\n sha256 = \"ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/uuid/1.23.1/download\"],\n strip_prefix = \"uuid-1.23.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.uuid-1.23.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__vcell-0.1.3\",\n sha256 = \"77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/vcell/0.1.3/download\"],\n strip_prefix = \"vcell-0.1.3\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.vcell-0.1.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__version_check-0.9.5\",\n sha256 = \"0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/version_check/0.9.5/download\"],\n strip_prefix = \"version_check-0.9.5\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.version_check-0.9.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__void-1.0.2\",\n sha256 = \"6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/void/1.0.2/download\"],\n strip_prefix = \"void-1.0.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.void-1.0.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__volatile-register-0.2.2\",\n sha256 = \"de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/volatile-register/0.2.2/download\"],\n strip_prefix = \"volatile-register-0.2.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.volatile-register-0.2.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__wasi-0.11.1-wasi-snapshot-preview1\",\n sha256 = \"ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasi/0.11.1+wasi-snapshot-preview1/download\"],\n strip_prefix = \"wasi-0.11.1+wasi-snapshot-preview1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.wasi-0.11.1+wasi-snapshot-preview1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__windows-link-0.2.1\",\n sha256 = \"f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows-link/0.2.1/download\"],\n strip_prefix = \"windows-link-0.2.1\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.windows-link-0.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__windows-sys-0.61.2\",\n sha256 = \"ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows-sys/0.61.2/download\"],\n strip_prefix = \"windows-sys-0.61.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.windows-sys-0.61.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__zerocopy-0.8.48\",\n sha256 = \"eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zerocopy/0.8.48/download\"],\n strip_prefix = \"zerocopy-0.8.48\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.zerocopy-0.8.48.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__zerocopy-derive-0.8.48\",\n sha256 = \"70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zerocopy-derive/0.8.48/download\"],\n strip_prefix = \"zerocopy-derive-0.8.48\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.zerocopy-derive-0.8.48.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__zeroize-1.8.2\",\n sha256 = \"b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zeroize/1.8.2/download\"],\n strip_prefix = \"zeroize-1.8.2\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.zeroize-1.8.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"rust_crates__zeroize_derive-1.4.3\",\n sha256 = \"85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zeroize_derive/1.4.3/download\"],\n strip_prefix = \"zeroize_derive-1.4.3\",\n build_file = Label(\"@rust_crates//rust_crates:BUILD.zeroize_derive-1.4.3.bazel\"),\n )\n\n return [\n struct(repo=\"rust_crates__aes-0.8.4\", is_dev_dep = False),\n struct(repo=\"rust_crates__aes-gcm-0.10.3\", is_dev_dep = False),\n struct(repo=\"rust_crates__aligned-0.4.3\", is_dev_dep = False),\n struct(repo=\"rust_crates__anyhow-1.0.102\", is_dev_dep = False),\n struct(repo=\"rust_crates__bitfield-0.14.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__bitfield-struct-0.11.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__bitflags-2.11.1\", is_dev_dep = False),\n struct(repo=\"rust_crates__byteorder-1.5.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__cfg-if-1.0.4\", is_dev_dep = False),\n struct(repo=\"rust_crates__cipher-0.4.4\", is_dev_dep = False),\n struct(repo=\"rust_crates__clap-4.6.1\", is_dev_dep = False),\n struct(repo=\"rust_crates__compiler_builtins-0.1.160\", is_dev_dep = False),\n struct(repo=\"rust_crates__cortex-m-0.7.7\", is_dev_dep = False),\n struct(repo=\"rust_crates__cortex-m-rt-0.7.5\", is_dev_dep = False),\n struct(repo=\"rust_crates__cortex-m-semihosting-0.5.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__ctr-0.9.2\", is_dev_dep = False),\n struct(repo=\"rust_crates__ecdsa-0.16.9\", is_dev_dep = False),\n struct(repo=\"rust_crates__embedded-hal-1.0.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__embedded-hal-async-1.0.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__embedded-hal-nb-1.0.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__embedded-io-0.6.1\", is_dev_dep = False),\n struct(repo=\"rust_crates__embedded-storage-0.3.1\", is_dev_dep = False),\n struct(repo=\"rust_crates__fugit-0.3.9\", is_dev_dep = False),\n struct(repo=\"rust_crates__futures-0.3.32\", is_dev_dep = False),\n struct(repo=\"rust_crates__heapless-0.9.2\", is_dev_dep = False),\n struct(repo=\"rust_crates__hex-0.4.3\", is_dev_dep = False),\n struct(repo=\"rust_crates__hex-literal-0.4.1\", is_dev_dep = False),\n struct(repo=\"rust_crates__hmac-0.12.1\", is_dev_dep = False),\n struct(repo=\"rust_crates__k256-0.13.4\", is_dev_dep = False),\n struct(repo=\"rust_crates__log-0.4.29\", is_dev_dep = False),\n struct(repo=\"rust_crates__mctp-0.2.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__mctp-lib-0.1.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__memoffset-0.9.1\", is_dev_dep = False),\n struct(repo=\"rust_crates__minijinja-2.19.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__nb-1.1.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__nom-7.1.3\", is_dev_dep = False),\n struct(repo=\"rust_crates__object-0.37.3\", is_dev_dep = False),\n struct(repo=\"rust_crates__openprot-hal-blocking-0.1.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__p256-0.13.2\", is_dev_dep = False),\n struct(repo=\"rust_crates__p384-0.13.1\", is_dev_dep = False),\n struct(repo=\"rust_crates__panic-halt-1.0.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__paste-1.0.15\", is_dev_dep = False),\n struct(repo=\"rust_crates__proc-macro2-1.0.106\", is_dev_dep = False),\n struct(repo=\"rust_crates__prost-0.13.5\", is_dev_dep = False),\n struct(repo=\"rust_crates__quote-1.0.45\", is_dev_dep = False),\n struct(repo=\"rust_crates__rand_core-0.9.5\", is_dev_dep = False),\n struct(repo=\"rust_crates__riscv-0.12.1\", is_dev_dep = False),\n struct(repo=\"rust_crates__riscv-rt-0.12.2\", is_dev_dep = False),\n struct(repo=\"rust_crates__riscv-semihosting-0.1.3\", is_dev_dep = False),\n struct(repo=\"rust_crates__rustc-demangle-0.1.27\", is_dev_dep = False),\n struct(repo=\"rust_crates__sec1-0.7.3\", is_dev_dep = False),\n struct(repo=\"rust_crates__serde-1.0.228\", is_dev_dep = False),\n struct(repo=\"rust_crates__serde_derive-1.0.228\", is_dev_dep = False),\n struct(repo=\"rust_crates__serde_json5-0.2.1\", is_dev_dep = False),\n struct(repo=\"rust_crates__sha2-0.10.9\", is_dev_dep = False),\n struct(repo=\"rust_crates__sha3-0.10.9\", is_dev_dep = False),\n struct(repo=\"rust_crates__smlang-0.8.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__subtle-2.6.1\", is_dev_dep = False),\n struct(repo=\"rust_crates__syn-1.0.109\", is_dev_dep = False),\n struct(repo=\"rust_crates__syn-2.0.117\", is_dev_dep = False),\n struct(repo=\"rust_crates__thiserror-2.0.18\", is_dev_dep = False),\n struct(repo=\"rust_crates__tock-registers-0.9.0\", is_dev_dep = False),\n struct(repo=\"rust_crates__tokio-1.52.1\", is_dev_dep = False),\n struct(repo=\"rust_crates__tokio-util-0.7.18\", is_dev_dep = False),\n struct(repo=\"rust_crates__vcell-0.1.3\", is_dev_dep = False),\n struct(repo=\"rust_crates__zerocopy-0.8.48\", is_dev_dep = False),\n struct(repo=\"rust_crates__zeroize-1.8.2\", is_dev_dep = False),\n ]\n" } } }, @@ -3660,6 +3660,22 @@ "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'openprot'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"embedded_io_async\",\n deps = [\n \"@rust_crates__embedded-io-0.6.1//:embedded_io\",\n \"@rust_crates__embedded-io-async-0.6.1//:build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=embedded-io-async\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:riscv32imc-unknown-none-elf\": [],\n \"@rules_rust//rust/platform:thumbv7em-none-eabi\": [],\n \"@rules_rust//rust/platform:x86_64-apple-darwin\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.1\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n edition = \"2021\",\n pkg_name = \"embedded-io-async\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=embedded-io-async\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.6.1\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" } }, + "rust_crates__embedded-storage-0.3.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/embedded-storage/0.3.1/download" + ], + "strip_prefix": "embedded-storage-0.3.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'openprot'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"embedded_storage\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=embedded-storage\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:riscv32imc-unknown-none-elf\": [],\n \"@rules_rust//rust/platform:thumbv7em-none-eabi\": [],\n \"@rules_rust//rust/platform:x86_64-apple-darwin\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.1\",\n)\n" + } + }, "rust_crates__equivalent-1.0.2": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": {
diff --git a/target/ast10x0/peripherals/BUILD.bazel b/target/ast10x0/peripherals/BUILD.bazel index 2a498bf..5da2edc 100644 --- a/target/ast10x0/peripherals/BUILD.bazel +++ b/target/ast10x0/peripherals/BUILD.bazel
@@ -30,6 +30,17 @@ "scu/reset.rs", "scu/status.rs", "scu/types.rs", + "smc/controller.rs", + "smc/device/block_device.rs", + "smc/device/flash.rs", + "smc/device/mod.rs", + "smc/fmc.rs", + "smc/helpers.rs", + "smc/interrupts.rs", + "smc/mod.rs", + "smc/registers.rs", + "smc/spi.rs", + "smc/types.rs", "uart/mod.rs", ], crate_name = "ast10x0_peripherals", @@ -41,10 +52,12 @@ target_compatible_with = TARGET_COMPATIBLE_WITH, deps = [ "@ast1060_pac", + "@pigweed//pw_log/rust:pw_log", "@rust_crates//:bitflags", "@rust_crates//:embedded-hal", "@rust_crates//:embedded-hal-nb", "@rust_crates//:embedded-io", + "@rust_crates//:embedded-storage", "@rust_crates//:nb", ], )
diff --git a/target/ast10x0/peripherals/lib.rs b/target/ast10x0/peripherals/lib.rs index 141dead..4ae0fac 100644 --- a/target/ast10x0/peripherals/lib.rs +++ b/target/ast10x0/peripherals/lib.rs
@@ -5,4 +5,5 @@ pub mod i2c; pub mod scu; +pub mod smc; pub mod uart;
diff --git a/target/ast10x0/peripherals/scu/pinctrl.rs b/target/ast10x0/peripherals/scu/pinctrl.rs index 3f4cccd..a3a0d0d 100644 --- a/target/ast10x0/peripherals/scu/pinctrl.rs +++ b/target/ast10x0/peripherals/scu/pinctrl.rs
@@ -544,6 +544,9 @@ /// 1-based naming where "2" means "second bus", matching PAC I2c1. pub const PINCTRL_I2C1: &[PinctrlPin] = &[PIN_SCU414_30, PIN_SCU414_31]; +/// FMC quad-SPI pin group: mux selection on SCU430[10:11]. +pub const PINCTRL_FMC_QUAD: &[PinctrlPin] = &[PIN_SCU430_10, PIN_SCU430_11]; + /// I2C2 pin group: SCL3/SDA3 mux selection on SCU418[0:1]. /// /// The SVD names these EnblSCL3FnPin/EnblSDA3FnPin, corresponding to
diff --git a/target/ast10x0/peripherals/smc/README.md b/target/ast10x0/peripherals/smc/README.md new file mode 100644 index 0000000..3c15db2 --- /dev/null +++ b/target/ast10x0/peripherals/smc/README.md
@@ -0,0 +1,65 @@ +# SMC — Static Memory Controller + +Driver for the AST1060 FMC and SPI static memory controllers, supporting +memory-mapped flash reads, DMA transfers, and interrupt handling. + +## Module Structure + +``` +smc/ +├── mod.rs — Re-exports all public types; module declarations +├── types.rs — Core types: SmcError, ChipSelect, FlashConfig, SmcConfig, +│ SmcController, TransferMode, AddressWidth, SmcRetryable +├── register_traits.rs — SmcRegisterBackend trait (shared register contract) +├── fmc_backend.rs — FmcRegisterBackend: wraps ast1060_pac::fmc::RegisterBlock +├── spi_backend.rs — SpiRegisterBackend: wraps ast1060_pac::spi::RegisterBlock +├── controller.rs — Generic Smc<B: SmcRegisterBackend, Mode> state machine; +│ type aliases UninitSmc / ReadySmc / UninitSpiSmc / ReadySpiSmc +├── fmc.rs — FmcUninit / FmcReady: FMC-specific facade over UninitSmc/ReadySmc +├── spi.rs — SpiUninit / SpiReady: SPI-specific facade over UninitSpiSmc/ReadySpiSmc +├── interrupts.rs — SmcInterrupt, SmcInterruptDecoder, SmcIsrContext +├── helpers.rs — Internal helpers: segment encoding, DMA validation, frequency divisor +└── device/ — SPI NOR flash device facade: SpiNorFlash, SpiNorFlashDevice + ├── flash.rs trait, FlashCommandProfile, FlashAddressingPolicy, JedecId + └── block_device.rs SpiNorBlockDevice, BlockDeviceInfo +``` + +## Architecture + +The driver uses a two-level abstraction: + +**Register backend** (`SmcRegisterBackend` trait) +Abstracts the PAC-level differences between FMC and SPI register blocks. +The same register offset can have different field layouts in the two PACs: + +| Backend | PAC type | Notes | +|----------------------|-----------------------------------|-------------------------------------| +| `FmcRegisterBackend` | `ast1060_pac::fmc::RegisterBlock` | Named fields (e.g. `dmaintenbl()`) | +| `SpiRegisterBackend` | `ast1060_pac::spi::RegisterBlock` | Raw bit access; adds `spi06c/074()` | + +**Controller state machine** (`Smc<B, Mode>`) +A type-state generic over backend `B` and mode (`Uninitialized` / `Ready`). +Transitions from `Uninitialized` → `Ready` happen through `init()`, which +configures timing, segments, and transfer mode. + +**Facade types** (`FmcUninit/FmcReady`, `SpiUninit/SpiReady`) +Thin wrappers around the concrete `Smc<…>` aliases, intended as the +primary API surface for callers. + +## Key Types + +| Type | Description | +|------------------------|----------------------------------------------| +| `SmcRegisterBackend` | Trait: register read/write/modify operations | +| `FmcRegisterBackend` | FMC PAC register backend | +| `SpiRegisterBackend` | SPI PAC register backend | +| `Smc<B, Mode>` | Generic controller state machine | +| `UninitSmc`/`ReadySmc` | FMC controller type aliases | +| `UninitSpiSmc`/`ReadySpiSmc` | SPI controller type aliases | +| `FmcUninit`/`FmcReady` | FMC facade | +| `SpiUninit`/`SpiReady` | SPI facade | +| `SmcConfig` | Controller configuration (timing, segments) | +| `FlashConfig` | Per-CS flash geometry | +| `ChipSelect` | `Cs0` / `Cs1` | +| `TransferMode` | Single / Dual / Quad SPI | +| `SmcInterrupt` | DMA completion / error interrupt variants |
diff --git a/target/ast10x0/peripherals/smc/controller.rs b/target/ast10x0/peripherals/smc/controller.rs new file mode 100644 index 0000000..c3e5823 --- /dev/null +++ b/target/ast10x0/peripherals/smc/controller.rs
@@ -0,0 +1,809 @@ +// Licensed under the Apache-2.0 license +// SPDX-License-Identifier: Apache-2.0 + +//! Generic SMC controller implementation + +use core::cell::UnsafeCell; +use core::marker::PhantomData; + +use crate::smc::helpers::{ + encode_segment, flash_capacity_bytes, get_mid_point_of_longest_one, spi_calibration_enable, + spi_freq_div, total_capacity_bytes, validate_dma_read, validate_mapped_range, + SPI_CTRL_FREQ_MASK, SPI_DMA_CALC_CKSUM, SPI_DMA_CALIB_MODE, SPI_DMA_ENABLE, + SPI_DMA_RAM_MAP_BASE, +}; +use crate::smc::interrupts::{SmcInterrupt, SmcInterruptDecoder}; +use crate::smc::registers::SmcRegisters; +use crate::smc::types::*; + +/// Internal controller state +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum SmcState { + /// Controller is initialized and idle — no operation in progress. + Idle, + /// A DMA transfer has been kicked and is in progress. + DmaInFlight, + /// Controller encountered an unrecoverable hardware fault. + Faulted, +} + +const ASPEED_SPI_USER: u32 = 0x3; +const ASPEED_SPI_USER_INACTIVE: u32 = 0x4; +const ASPEED_SPI_NORMAL_READ: u32 = 0x1; +pub const SPI_NOR_CMD_QREAD: u32 = 0x6B; +pub const SPI_NOR_CMD_QREAD_4B: u32 = 0x6C; +const SPI_NOR_4B_READ_THRESHOLD_BYTES: usize = 16 * 1024 * 1024; +const SPI_NOR_ADDR_WIDTH_MASK: u32 = 0x11; +const DMA_STATUS_RELEVANT_BITS: u32 = (1 << 11) | (1 << 10) | (1 << 9); +/// Mask for bits that are not IO mode or mode-type fields — preserves +/// frequency divisor and other config bits across per-phase ctrl writes. +const SPI_CTRL_IO_MODE_MASK: u32 = !0x7000_0000; +const SPI_CALIB_LEN: usize = 0x400; + +struct CalibrationScratch(UnsafeCell<[u8; SPI_CALIB_LEN]>); + +// Calibration runs during controller initialization with exclusive controller +// ownership, so this scratch buffer is not accessed concurrently. +unsafe impl Sync for CalibrationScratch {} + +static CALIBRATION_SCRATCH: CalibrationScratch = CalibrationScratch(UnsafeCell::new([0; SPI_CALIB_LEN])); + +const fn spi_nor_qread_cmd_for_capacity(capacity_bytes: usize) -> u32 { + if capacity_bytes > SPI_NOR_4B_READ_THRESHOLD_BYTES { + SPI_NOR_CMD_QREAD_4B + } else { + SPI_NOR_CMD_QREAD + } +} + +const fn spi_nor_uses_4b_addr(capacity_bytes: usize) -> bool { + capacity_bytes > SPI_NOR_4B_READ_THRESHOLD_BYTES +} + +const fn spi_nor_addr_width_mask(cs: ChipSelect) -> u32 { + SPI_NOR_ADDR_WIDTH_MASK << (cs as u32) +} + +const fn spi_nor_addr_width_reg(current: u32, cs: ChipSelect, use_4b: bool) -> u32 { + let mask = spi_nor_addr_width_mask(cs); + if use_4b { + current | mask + } else { + current & !mask + } +} + +/// Type-state marker: controller is constructed but not initialized. +pub struct Uninitialized; + +/// Type-state marker: controller has completed hardware initialization. +pub struct Ready; + +/// Generic Static Memory Controller (SMC) +/// +/// The `Mode` type parameter enforces init ordering at compile time. +pub struct Smc<Mode> { + regs: SmcRegisters, + controller_id: SmcController, + config: SmcConfig, + state: SmcState, + /// Per-CS normal-read control register values stored at init time. + /// Indexed by `ChipSelect as usize`. Restored unconditionally after every + /// user-mode transaction, matching aspeed-rust `deactivate_user()` behavior. + normal_read_ctrl: [u32; 2], + /// Per-CS AHB flash window base addresses. + /// CS0 starts at `controller_id.flash_window_address()`; + /// CS1 starts immediately after the CS0 segment. + flash_window_base: [usize; 2], + _mode: PhantomData<fn() -> Mode>, +} + +/// Ergonomic alias for the uninitialized controller handle. +pub type UninitSmc = Smc<Uninitialized>; + +/// Ergonomic alias for the initialized controller handle. +pub type ReadySmc = Smc<Ready>; + +impl Smc<Uninitialized> { + /// Create a new SMC controller instance. + /// + /// # Safety + /// Caller must ensure: + /// - No other Smc instance exists for this hardware controller + /// - The controller's base address points to valid hardware + pub unsafe fn new(config: SmcConfig) -> Result<Self, SmcError> { + if config.cs0.is_none() && config.cs1.is_none() { + return Err(SmcError::InvalidCapacity); + } + + let base = config.controller_id.base_address() as *const _; + // SAFETY: Caller ensures base address is valid and no other instance exists. + let regs = unsafe { SmcRegisters::new(base) }; + + Ok(Self { + regs, + controller_id: config.controller_id, + config, + state: SmcState::Idle, + normal_read_ctrl: [0; 2], + flash_window_base: [0; 2], + _mode: PhantomData, + }) + } + + /// Initialize hardware and transition to `Ready` mode. + pub fn init(self) -> Result<Smc<Ready>, SmcError> { + // Phase 3: Topology-aware initialization + // + // The SmcTopology enum encodes the controller's role and master_idx: + // - BootSpi { master_idx }: Boot firmware path (typically FMC, master_idx=0) + // - HostSpi { master_idx }: Host BMC SPI path (typically SPI1, master_idx=0) + // - NormalSpi { master_idx }: Normal user SPI path (typically SPI2, master_idx=2) + // + // Topology gates behavior in setup_segments() and configure_timing(): + // The topology is consulted via self.config.topology. + + // 1. Configure flash types and write-enable per CS + let mut conf = 0u32; + if self.config.cs0.is_some() { + conf |= 1 << 16; // CONF_ENABLE_W0 + conf |= 0x2 << 0; // FLASH_TYPE_SPI + } + if self.config.cs1.is_some() { + conf |= 1 << 17; // CONF_ENABLE_W1 + conf |= 0x2 << 2; // FLASH_TYPE_SPI + } + self.regs.write_config(conf); + + // 2. Set up segment addresses (memory mapping) + Self::setup_segments(&self)?; + + // Snapshot per-CS normal-read control register values after all init writes. + // CS1 value is captured even if cs1 is None (safe: register read is harmless). + let cs0_normal_read = self.regs.read_cs0_ctrl(); + let cs1_normal_read = self.regs.read_cs1_ctrl(); + + // Compute per-CS AHB flash window base addresses. + let base = self.controller_id.flash_window_address(); + let cs0_size = flash_capacity_bytes(self.config.cs0).unwrap_or(0); + let flash_window_base = [base, base + cs0_size]; + + Ok(Smc { + regs: self.regs, + controller_id: self.controller_id, + config: self.config, + state: SmcState::Idle, + normal_read_ctrl: [cs0_normal_read, cs1_normal_read], + flash_window_base, + _mode: PhantomData, + }) + } + fn setup_segments(&self) -> Result<(), SmcError> { + // Decode-range sizing is topology-aware. + // + // For BootSpi (FMC, master_idx=0): Full decode range from configured capacity. + // Used for boot firmware; exclusive access to flash; no shared-bus concerns. + // + // For HostSpi / NormalSpi when master_idx != 0: Potential shared-bus topology. + // When multiple masters multiplex a single SPI flash, decode ranges may need + // to be restricted. Phase 3+ may implement decode_range_reinit logic keyed + // on config.topology.master_idx() to prevent collisions. + // + // For now, all topologies use the full capacity from FlashConfig. + // Phase 3+: add conditional decode-range sizing based on topology + master_idx. + + let cs0_size = flash_capacity_bytes(self.config.cs0)?; + let cs1_size = flash_capacity_bytes(self.config.cs1)?; + total_capacity_bytes(self.config.cs0, self.config.cs1)?; + + if cs0_size > 0 { + let seg = encode_segment(0, cs0_size)?; + self.regs.write_cs0_segment(seg); + } + + if cs1_size > 0 { + let seg = encode_segment(cs0_size, cs0_size + cs1_size)?; + self.regs.write_cs1_segment(seg); + } + + Ok(()) + } +} + +impl Smc<Ready> { + /// Perform a programmed I/O read via memory window. + /// + /// Reads directly from the flash memory window. Hardware automatically + /// converts memory accesses to SPI transactions. + pub fn read(&self, cs: ChipSelect, offset: u32, buf: &mut [u8]) -> Result<usize, SmcError> { + let cs_config = self.cs_config(cs)?; + let cs_capacity = flash_capacity_bytes(Some(cs_config))?; + let cs_idx = cs as usize; + let window = self.flash_window_base[cs_idx] as *const u8; + let offset = validate_mapped_range(offset, buf.len(), cs_capacity)?; + let flash_ptr = window.wrapping_add(offset); + pw_log::debug!( + "read: offset0x{:08x}, size:0x{:08x}, flash ptr:0x{:08x}", + offset as u32, + buf.len() as u32, + flash_ptr as u32 + ); + // SAFETY: `flash_ptr` is derived from the controller's fixed MMIO flash + // window using `wrapping_add`, which avoids imposing Rust allocation + // provenance rules on the raw address arithmetic itself. The actual read + // below requires the requested `[offset, offset + buf.len())` range to be + // backed by the controller's mapped flash aperture, and `buf` provides a + // valid, writable destination that does not overlap this MMIO window. + unsafe { + core::ptr::copy_nonoverlapping(flash_ptr, buf.as_mut_ptr(), buf.len()); + } + + Ok(buf.len()) + } + #[inline(never)] + pub fn loop_delay(spin_cnt: u32) { + for _ in 0..spin_cnt { + core::hint::spin_loop(); + } + } + /// Initiate a DMA read operation (non-blocking). + pub fn dma_read( + &mut self, + cs: ChipSelect, + flash_offset: u32, + dram_addr: usize, + len: u32, + ) -> Result<(), SmcError> { + if self.state != SmcState::Idle { + return Err(SmcError::ControllerNotReady); + } + if !self.config.dma_enabled { + return Err(SmcError::DmaNotEnabled); + } + if cs == ChipSelect::Cs1 && self.config.cs1.is_none() { + return Err(SmcError::InvalidChipSelect); + } + self.regs.disable_dma(); + Self::loop_delay(0x1000); + + let cs_config = self.cs_config(cs)?; + let cs_capacity = flash_capacity_bytes(Some(cs_config))?; + pw_log::debug!( + "flash_offset: 0x{:08x}, cs_cap: 0x{:08x}", + flash_offset as u32, + cs_capacity as u32 + ); + let cs_idx = cs as usize; + + let validated = validate_dma_read( + flash_offset, + self.flash_window_base[cs_idx], + cs_capacity, + dram_addr, + len, + )?; + pw_log::debug!( + "flash start: 0x{:08x}, cs_cap: 0x{:08x}, dram_addr: 0x{:08x} len: 0x{:08x} ", + validated.flash_start as u32, + cs_capacity as u32, + validated.dram_addr as u32, + validated.dma_len_reg as u32 + ); + + // Set CS0 control register to normal-read mode before programming DMA + // registers. The DMA engine reads the CSx control register to know which + // SPI command to issue; it must be in normal-read mode (not user mode) + // before the kick. Matches aspeed-rust fmccontroller.rs::read_dma + // ctrl construction: preserve frequency bits, set ASPEED_SPI_NORMAL_READ. + let cs_idx = cs as usize; + let ctrl_val = self.normal_read_ctrl[cs_idx] | ASPEED_SPI_NORMAL_READ; + self.regs.write_cs_ctrl(cs, ctrl_val); + + // Acquire the DMA bus arbiter before programming any DMA registers. + // On SPI1/SPI2: writes SPI_DMA_GET_REQ_MAGIC and spins until DMAGrant + // (bit 30 of spi080) is set. On FMC: bits 20–31 are Reserved — the write + // is a no-op and the spin condition is immediately false. Safe to call + // unconditionally on all controllers, matching aspeed-rust's approach. + self.regs.acquire_dma_arbiter(); + pw_log::debug!("acquired dma bus arbiter"); + // Program DMA registers in the order used by aspeed-rust fmccontroller.rs::read_dma: + // fmc084 = flash side DMA address (R_DMA_FLASH_ADDR) + // = flash_window_base[cs] - SPI_DMA_FLASH_MAP_BASE + cs_offset + // (computed in validate_dma_read) + // fmc088 = DRAM/SRAM destination address (R_DMA_DRAM_ADDR) + // = physical_sram_addr + SPI_DMA_RAM_MAP_BASE + // fmc08c = transfer length - 1 (R_DMA_LEN) + self.regs.write_dma_flash_addr(validated.flash_start as u32); + self.regs + .write_dma_dram_addr(validated.dram_addr + SPI_DMA_RAM_MAP_BASE); + self.regs.write_dma_len(validated.dma_len_reg); + + // Enable the completion IRQ before kicking DMA. QEMU evaluates + // INTR_CTRL_DMA_EN exactly once at DMA-done time + // (`aspeed_smc_dma_done` in qemu/hw/ssi/aspeed_smc.c) and won't + // re-fire the IRQ if the bit is set after the fact; aspeed-rust + // arms the IRQ before starting DMA for the same reason + // (`spicontroller.rs::read_dma`). + if self.config.enable_interrupts { + pw_log::debug!("enable dma irq"); + self.regs.enable_dma_irq(); + } + + // Kick DMA via read-modify-write to preserve timing calibration + // bits (fmc080 bits 8-19), matching aspeed-rust fmccontroller.rs::read_dma. + pw_log::debug!("start dma read..."); + self.regs.kick_dma_read(); + self.state = SmcState::DmaInFlight; + Ok(()) + } + + /// Read raw DMA/interrupt status register bits (FMC008). + pub fn dma_status(&self) -> u32 { + self.regs.read_dma_status() + } + + /// Clear DMA-related status bits in the status register (FMC008). + /// + /// `clear_mask` is write-1-to-clear and should contain only relevant bits. + pub fn clear_dma_status(&self, clear_mask: u32) { + self.regs + .clear_dma_status(clear_mask & DMA_STATUS_RELEVANT_BITS); + } + + /// Decode status bits and transition controller state. + /// + /// Called by both `handle_dma_irq` (IRQ-driven) and `poll_dma_completion` + /// (polling). Assumes `status & DMA_STATUS_RELEVANT_BITS != 0`. + fn complete_dma(&mut self, status: u32) -> Result<SmcInterrupt, SmcError> { + let relevant = status & DMA_STATUS_RELEVANT_BITS; + let dma_in_flight = self.state == SmcState::DmaInFlight; + let decoded = SmcInterruptDecoder::decode_with_context(status, dma_in_flight); + self.clear_dma_status(relevant); + + match decoded { + SmcInterrupt::DmaComplete => { + self.regs.disable_dma(); + self.state = SmcState::Idle; + Ok(decoded) + } + SmcInterrupt::DmaError => { + self.regs.disable_dma(); + self.state = SmcState::Idle; + Err(SmcError::DmaAborted) + } + SmcInterrupt::CommandAbort => { + self.state = SmcState::Faulted; + Err(SmcError::HardwareError) + } + SmcInterrupt::WriteProtected => { + self.state = SmcState::Faulted; + Err(SmcError::WriteProtected) + } + SmcInterrupt::Unknown => Err(SmcError::HardwareError), + } + } + + /// Decode and complete an in-flight DMA operation from an IRQ event. + /// + /// Returns the decoded interrupt cause when a completion/error event was + /// observed and processed. If no relevant status bits are set, returns + /// `SmcError::ControllerNotReady` to indicate no completion work was found. + pub fn handle_dma_irq(&mut self) -> Result<SmcInterrupt, SmcError> { + self.regs.disable_dma_irq(); + let status = self.dma_status(); + pw_log::info!("SMC handle_dma_irq: status=0x{:08x}", status as u32); + if status & DMA_STATUS_RELEVANT_BITS == 0 { + return Err(SmcError::ControllerNotReady); + } + self.complete_dma(status) + } + + /// Poll for DMA completion without requiring an IRQ. + /// + /// Returns `Poll::Pending` while the transfer is still in progress. + /// Returns `Poll::Ready(Ok(()))` on success or `Poll::Ready(Err(SmcError))` + /// on failure. Returns `Poll::Ready(Err(SmcError::ControllerNotReady))` if + /// no DMA is in flight. + /// + /// Suitable for spin-poll loops in contexts where `enable_interrupts` is + /// false (e.g., QEMU tests without an IRQ handler): + /// ```ignore + /// loop { + /// match controller.poll_dma_completion() { + /// Poll::Ready(result) => break result, + /// Poll::Pending => {} + /// } + /// } + /// ``` + pub fn poll_dma_completion(&mut self) -> core::task::Poll<Result<(), SmcError>> { + if self.state != SmcState::DmaInFlight { + return core::task::Poll::Ready(Err(SmcError::ControllerNotReady)); + } + let status = self.dma_status(); + if status & DMA_STATUS_RELEVANT_BITS == 0 { + return core::task::Poll::Pending; + } + core::task::Poll::Ready(self.complete_dma(status).map(|_| ())) + } + + pub fn poll_blocking_dma_completion(&self, timeout: u32) -> u32 { + let mut to = timeout; + + while (self.regs.read_dma_status() & DMA_STATUS_RELEVANT_BITS) == 0 { + to -= 1; + + if to == 0 { + return 0; + } + } + return to; + } + /// Check if controller is ready for operations. + pub fn is_ready(&self) -> bool { + self.state == SmcState::Idle + } + + #[doc(hidden)] + pub fn test_force_dma_in_flight(&mut self) { + self.state = SmcState::DmaInFlight; + } + + /// Get the controller identifier. + pub fn controller_id(&self) -> SmcController { + self.controller_id + } + + /// Return configured total flash capacity for this controller in bytes. + pub fn capacity_bytes(&self) -> Result<usize, SmcError> { + total_capacity_bytes(self.config.cs0, self.config.cs1) + } + + /// Return configured flash capacity in bytes for the given chip select. + /// + /// Returns `SmcError::InvalidChipSelect` if the slot was not populated + /// at construction time. Used by the device facade to bounds-check + /// per-CS reads and to compute per-CS controller-window offsets. + pub fn cs_capacity_bytes(&self, cs: ChipSelect) -> Result<usize, SmcError> { + crate::smc::helpers::cs_capacity_bytes(&self.config, cs) + } + + /// Return the configured `FlashConfig` for the requested chip select. + /// + /// Returns `SmcError::InvalidChipSelect` if the slot was not populated at + /// construction time. Used by device-facade constructors to validate the + /// caller-supplied `FlashConfig` against the per-CS configuration the + /// controller was actually initialized with. + pub fn cs_config(&self, cs: ChipSelect) -> Result<FlashConfig, SmcError> { + let slot = match cs { + ChipSelect::Cs0 => self.config.cs0, + ChipSelect::Cs1 => self.config.cs1, + }; + slot.ok_or(SmcError::InvalidChipSelect) + } + + /// Execute a raw user-mode SPI transfer on CS0 for this controller. + /// + /// The `mode` parameter controls the IO width written to the CS control + /// register for each phase (cmd / addr+payload / rx), matching the + /// per-phase register update pattern used by aspeed-rust's + /// `spi_nor_transceive_user()`. + pub fn transceive_user( + &self, + cs: ChipSelect, + cmd: &[u8], + tx_payload: &[u8], + rx: &mut [u8], + mode: TransferMode, + ) -> Result<(), SmcError> { + if self.state != SmcState::Idle { + return Err(SmcError::ControllerNotReady); + } + if cs == ChipSelect::Cs1 && self.config.cs1.is_none() { + return Err(SmcError::InvalidChipSelect); + } + + let cs_idx = cs as usize; + // Derive user-mode base from the stored normal-read value: preserve + // frequency bits and replace mode type with ASPEED_SPI_USER. + let user_base = (self.normal_read_ctrl[cs_idx] & SPI_CTRL_FREQ_MASK) | ASPEED_SPI_USER; + let window = self.flash_window_base[cs_idx] as *mut u32; + + // Assert CS: inactive first, then active (matches aspeed-rust activate_user). + self.regs + .write_cs_ctrl(cs, user_base | ASPEED_SPI_USER_INACTIVE); + self.regs.write_cs_ctrl(cs, user_base); + + // SAFETY: user mode is active; the flash aperture is the hardware-defined + // byte-stream port for SPI command traffic while user mode is held. + unsafe { + // Command phase — always single-wire. + let cmd_ctrl = (user_base & SPI_CTRL_IO_MODE_MASK) | mode.cmd_io_bits(); + self.regs.write_cs_ctrl(cs, cmd_ctrl); + spi_write_data(window, cmd); + + // Address / TX payload phase. + let addr_ctrl = (user_base & SPI_CTRL_IO_MODE_MASK) | mode.addr_io_bits(); + self.regs.write_cs_ctrl(cs, addr_ctrl); + spi_write_data(window, tx_payload); + + // RX data phase. + let data_ctrl = (user_base & SPI_CTRL_IO_MODE_MASK) | mode.data_io_bits(); + self.regs.write_cs_ctrl(cs, data_ctrl); + spi_read_data(window as *const u32, rx); + } + + // Deassert CS, then restore the pre-computed normal-read configuration + // (matches aspeed-rust deactivate_user restoring cmd_mode[cs].normal_read). + self.regs + .write_cs_ctrl(cs, user_base | ASPEED_SPI_USER_INACTIVE); + self.regs.write_cs_ctrl(cs, self.normal_read_ctrl[cs_idx]); + Ok(()) + } + + // + // MMIO access:: nor read init + // + //TODO: call from nordevice layer instead + pub fn spi_nor_read_init(&mut self, cs: ChipSelect) -> Result<(), SmcError> { + let mode: TransferMode = TransferMode::Mode114; + let dummy: u32 = 0x1; + let cs_idx = cs as usize; + let cs_capacity = self.cs_capacity_bytes(cs)?; + let use_4b_addr = spi_nor_uses_4b_addr(cs_capacity); + let read_opcode = spi_nor_qread_cmd_for_capacity(cs_capacity); + //pw_log::info!("=== spi_read_init()==="); + let read_cmd = + mode.data_io_bits() | (read_opcode << 16) | (dummy << 6) | ASPEED_SPI_NORMAL_READ; + + self.regs.write_cs_ctrl(cs, read_cmd); + let addr_width = spi_nor_addr_width_reg(self.regs.read_addr_width(), cs, use_4b_addr); + self.regs.write_addr_width(addr_width); + self.normal_read_ctrl[cs_idx] = read_cmd; + if cs != ChipSelect::Cs0 { + // CS1 calibration can fault on boards where the secondary FMC flash + // is not ready for the calibration sweep. Keep CS1 on the same + // fixed timing path used after calibration and still program its + // normal-read command/address width above. + return self.configure_timing(cs, self.cs_config(cs)?.spi_clock_mhz); + } + self.timing_calibration(cs) + } + + fn configure_timing(&mut self, cs: ChipSelect, spi_clock_mhz: u32) -> Result<(), SmcError> { + // Timing calibration is topology-aware. + // + // For BootSpi (FMC, master_idx=0): Full calibration sweep recommended. + // Boot firmware has exclusive access; full timing margin is priority. + // + // For HostSpi / NormalSpi when master_idx != 0: Shared-bus topology. + // When a secondary master shares the flash bus, calibration on CS1 may need + // to be skipped to avoid interfering with the primary master's calibration. + // Phase 3+: gate calibration logic on config.topology.master_idx(). + // + // For now, all topologies use a single divider lookup; no HCLK sweep. + // Phase 3+: add conditional calibration logic per topology and master_idx. + // pw_log::info!("=== configure_timing()==="); + //TODO: need to get this from scu register + let sysclk_mhz = 200u32; + let encoded_div = spi_freq_div(sysclk_mhz, spi_clock_mhz)?; + + let cs_idx = cs as usize; + let reg = self.regs.read_cs_ctrl(cs); + self.regs + .write_cs_ctrl(cs, (reg & !SPI_CTRL_FREQ_MASK) | encoded_div); + self.normal_read_ctrl[cs_idx] &= (!SPI_CTRL_FREQ_MASK) | encoded_div; + + Ok(()) + } + + fn timing_calibration(&mut self, cs: ChipSelect) -> Result<(), SmcError> { + let cs_cfg = self.cs_config(cs)?; + let cs_idx = cs as usize; + + if self.regs.already_calibrated(cs) { + pw_log::info!("already calibrated"); + return self.configure_timing(cs, cs_cfg.spi_clock_mhz); + } + + //SPI2 work around + if self.config.topology.master_idx() != 0 && cs_idx != 0 { + return self.configure_timing(cs, cs_cfg.spi_clock_mhz); + } + // TODO: add SPIM config + /* + * use the related low frequency to get check calibration data + * and get golden data. + */ + let ctrl_val = self.regs.read_cs_ctrl(cs) & (!SPI_CTRL_FREQ_MASK); + self.regs.write_cs_ctrl(cs, ctrl_val); + + let check_buf = unsafe { &mut *CALIBRATION_SCRATCH.0.get() }; + let window = self.flash_window_base[cs_idx] as *const u8; + // TODO: configure timing_calibration_start_offset beside be??? + let timing_offset = 0x0; + let flash_ptr = window.wrapping_add(timing_offset); + unsafe { + core::ptr::copy_nonoverlapping(flash_ptr, check_buf.as_mut_ptr(), SPI_CALIB_LEN); + } + + if !spi_calibration_enable(&check_buf[..])? { + return self.configure_timing(cs, cs_cfg.spi_clock_mhz); + } + + let gold_checksum = self.spi_dma_checksum(cs, 0, 0); + self.run_timing_sweep(cs, gold_checksum); + + self.configure_timing(cs, cs_cfg.spi_clock_mhz) + } + + fn spi_dma_checksum(&mut self, cs: ChipSelect, div: u32, delay: u32) -> u32 { + let timing_offset = 0x0; + + // Request DMA access + self.regs.acquire_dma_arbiter(); + + // Set DMA flash start address + let cs_idx = cs as usize; + let flash_addr = self.flash_window_base[cs_idx] + timing_offset; + self.regs.write_dma_flash_addr(flash_addr as u32); + // Set DMA length + self.regs.write_dma_len(SPI_CALIB_LEN as u32); + + // Configure DMA control register + let ctrl_val = SPI_DMA_ENABLE + | SPI_DMA_CALC_CKSUM + | SPI_DMA_CALIB_MODE + | (delay << 0x8) + | ((div & 0xf) << 16); + self.regs.write_dma_ctrl(ctrl_val); + + // Wait until DMA done + if self.poll_blocking_dma_completion(0x1000) == 0 { + pw_log::info!("dma timeout!"); + } + + // Read checksum result + // disable dma will clear the checksum + let checksum = self.regs.read_dma_checksum(); + // Clear DMA control and discard request + self.regs.disable_dma(); + + return checksum; + } + + fn run_timing_sweep(&mut self, cs: ChipSelect, gold_checksum: u32) { + let hclk_masks = [7u32, 14, 6, 13]; + let mut calib_res = [0u8; 6 * 17]; + let cs_cfg = self.cs_config(cs); + let mut freq_to_use = cs_cfg.unwrap().spi_clock_mhz; + let sysclk_mhz = 200u32; + + for (i, &mask) in hclk_masks.iter().enumerate() { + let div = u32::try_from(i).unwrap() + 2; + if freq_to_use < sysclk_mhz / div { + continue; + } + + freq_to_use = sysclk_mhz / div; + + self.spi_dma_checksum(cs, mask, 0); + + calib_res.fill(0); + + for hcycle in 0..=5 { + for delay_ns in 0..=0xf { + let reg_val = (1 << 3) | hcycle | (delay_ns << 4); + + let checksum = self.spi_dma_checksum(cs, mask, reg_val); + + let pass = checksum == gold_checksum; + let index = (hcycle * 17 + delay_ns) as usize; + calib_res[index] = u8::from(pass); + } + } //hcycle + + let calib_point = get_mid_point_of_longest_one(&calib_res); + if calib_point >= 0 { + let hcycle = (calib_point as u32 / 17) as u32; + let delay_ns = (calib_point as u32 % 17) as u32; + let final_delay = ((1 << 3) | hcycle | (delay_ns << 4)) << (i * 8); + + pw_log::info!( + "Final hcycle: {}, delay_ns: {} final_delay0x{:08x}", + hcycle as u32, + delay_ns as u32, + final_delay as u32 + ); + + self.regs.write_cs_timing_compensation(cs, final_delay); + return; + } else { + pw_log::info!("Cannot get good calibration point."); + } + } + } // run_timing_sweep +} + +unsafe fn spi_read_data(ahb_addr: *const u32, read_arr: &mut [u8]) { + let len = read_arr.len(); + let mut index = 0usize; + + while index + 4 <= len { + let word = unsafe { core::ptr::read_volatile(ahb_addr.add(index / 4)) }; + read_arr[index..index + 4].copy_from_slice(&word.to_le_bytes()); + index += 4; + } + + while index < len { + read_arr[index] = unsafe { core::ptr::read_volatile(ahb_addr.cast::<u8>().add(index)) }; + index += 1; + } +} + +unsafe fn spi_write_data(ahb_addr: *mut u32, write_arr: &[u8]) { + let len = write_arr.len(); + let mut index = 0usize; + + while index + 4 <= len { + let word = u32::from_le_bytes([ + write_arr[index], + write_arr[index + 1], + write_arr[index + 2], + write_arr[index + 3], + ]); + unsafe { core::ptr::write_volatile(ahb_addr.add(index / 4), word) }; + index += 4; + } + + while index < len { + unsafe { core::ptr::write_volatile(ahb_addr.cast::<u8>().add(index), write_arr[index]) }; + index += 1; + } +} + +#[cfg(test)] +mod tests { + use super::{ + spi_nor_addr_width_reg, spi_nor_qread_cmd_for_capacity, SPI_NOR_4B_READ_THRESHOLD_BYTES, + SPI_NOR_CMD_QREAD, SPI_NOR_CMD_QREAD_4B, + }; + use crate::smc::types::ChipSelect; + + #[test] + fn qread_command_uses_3b_at_or_below_16mib() { + assert_eq!( + spi_nor_qread_cmd_for_capacity(1024 * 1024), + SPI_NOR_CMD_QREAD + ); + assert_eq!( + spi_nor_qread_cmd_for_capacity(SPI_NOR_4B_READ_THRESHOLD_BYTES), + SPI_NOR_CMD_QREAD + ); + } + + #[test] + fn qread_command_uses_4b_above_16mib() { + assert_eq!( + spi_nor_qread_cmd_for_capacity(SPI_NOR_4B_READ_THRESHOLD_BYTES + 1), + SPI_NOR_CMD_QREAD_4B + ); + } + + #[test] + fn addr_width_register_sets_only_selected_cs_for_4b() { + assert_eq!(spi_nor_addr_width_reg(0, ChipSelect::Cs0, true), 0x11); + assert_eq!(spi_nor_addr_width_reg(0, ChipSelect::Cs1, true), 0x22); + } + + #[test] + fn addr_width_register_clears_only_selected_cs_for_3b() { + assert_eq!( + spi_nor_addr_width_reg(0x2a33, ChipSelect::Cs0, false), + 0x2a22 + ); + assert_eq!( + spi_nor_addr_width_reg(0x2a33, ChipSelect::Cs1, false), + 0x2a11 + ); + } +}
diff --git a/target/ast10x0/peripherals/smc/device/block_device.rs b/target/ast10x0/peripherals/smc/device/block_device.rs new file mode 100644 index 0000000..fbfbfff --- /dev/null +++ b/target/ast10x0/peripherals/smc/device/block_device.rs
@@ -0,0 +1,114 @@ +// Licensed under the Apache-2.0 license +// SPDX-License-Identifier: Apache-2.0 + +//! Contained block-device facade layered on top of `SpiNorFlash`. + +use crate::smc::device::flash::{JedecId, SpiNorFlash, SpiNorFlashDevice}; +use crate::smc::types::{FlashConfig, SmcError}; + +/// Geometry and limits exposed by the block facade. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct BlockDeviceInfo { + pub capacity_bytes: usize, + pub page_size: usize, + pub sector_size: usize, + pub block_size: usize, +} + +/// Minimal block-oriented facade over a `SpiNorFlash` device. +pub struct SpiNorBlockDevice<'a, 'b> { + flash: &'a mut SpiNorFlash<'b>, + cfg: FlashConfig, +} + +impl<'a, 'b> SpiNorBlockDevice<'a, 'b> { + /// Build a block facade from an existing `SpiNorFlash` plus known config. + pub fn from_flash( + flash: &'a mut SpiNorFlash<'b>, + cfg: FlashConfig, + ) -> Result<Self, SmcError> { + let expected = cfg_capacity_bytes(cfg)?; + let actual = SpiNorFlashDevice::capacity_bytes(flash)?; + if expected != actual { + return Err(SmcError::InvalidCapacity); + } + if cfg.page_size == 0 || cfg.sector_size == 0 || cfg.block_size == 0 { + return Err(SmcError::InvalidCapacity); + } + Ok(Self { flash, cfg }) + } + + /// Build a block facade by mapping a JEDEC ID to a known flash profile. + pub fn from_jedec_id( + flash: &'a mut SpiNorFlash<'b>, + jedec: JedecId, + ) -> Result<Self, SmcError> { + let cfg = cfg_from_jedec(jedec)?; + Self::from_flash(flash, cfg) + } + + /// Read bytes from the block device. + pub fn read_blocks(&self, address: u32, out: &mut [u8]) -> Result<usize, SmcError> { + SpiNorFlashDevice::read(self.flash, address, out) + } + + /// Program bytes using the underlying page-program path. + pub fn write_blocks(&mut self, address: u32, data: &[u8]) -> Result<usize, SmcError> { + if data.is_empty() { + return Ok(0); + } + let page = self.cfg.page_size as usize; + if (address as usize) % page != 0 { + return Err(SmcError::InvalidCapacity); + } + self.flash.program(address, data) + } + + /// Erase bytes using sector-granularity contract. + pub fn erase_blocks(&mut self, address: u32, length: u32) -> Result<(), SmcError> { + if length == 0 { + return Ok(()); + } + let sector = self.cfg.sector_size; + if !address.is_multiple_of(sector) || !length.is_multiple_of(sector) { + return Err(SmcError::InvalidCapacity); + } + self.flash.erase_range(address, length as usize) + } + + /// Return block-device geometry. + pub fn info(&self) -> Result<BlockDeviceInfo, SmcError> { + Ok(BlockDeviceInfo { + capacity_bytes: cfg_capacity_bytes(self.cfg)?, + page_size: self.cfg.page_size as usize, + sector_size: self.cfg.sector_size as usize, + block_size: self.cfg.block_size as usize, + }) + } + + /// Read JEDEC ID from the underlying flash. + pub fn jedec(&self) -> Result<JedecId, SmcError> { + self.flash.jedec() + } +} + +fn cfg_capacity_bytes(cfg: FlashConfig) -> Result<usize, SmcError> { + (cfg.capacity_mb as usize) + .checked_mul(1024 * 1024) + .ok_or(SmcError::InvalidCapacity) +} + +fn cfg_from_jedec(jedec: JedecId) -> Result<FlashConfig, SmcError> { + match (jedec.manufacturer, jedec.memory_type, jedec.capacity_code) { + (0xEF, 0x40, 0x17) => Ok(FlashConfig::winbond_w25q64()), + (0xEF, 0x40, 0x18) => Ok(FlashConfig { + capacity_mb: 16, + page_size: 256, + sector_size: 4096, + block_size: 65536, + spi_clock_mhz: 25, + }), + (0xEF, 0x40, 0x19) => Ok(FlashConfig::winbond_w25q256()), + _ => Err(SmcError::DeviceNotSupported), + } +} \ No newline at end of file
diff --git a/target/ast10x0/peripherals/smc/device/flash.rs b/target/ast10x0/peripherals/smc/device/flash.rs new file mode 100644 index 0000000..7aa2e5e --- /dev/null +++ b/target/ast10x0/peripherals/smc/device/flash.rs
@@ -0,0 +1,672 @@ +// Licensed under the Apache-2.0 license +// SPDX-License-Identifier: Apache-2.0 + +//! SPI NOR facade with shared logic for FMC and SPI1/SPI2 backends. + +use core::ops::FnMut; +use core::result::Result; +use core::result::Result::{Err, Ok}; + +use crate::smc::fmc::FmcReady; +use crate::smc::spi::SpiReady; +use crate::smc::types::{AddressWidth, ChipSelect, FlashConfig, SmcError, TransferMode}; + +/// Build a command byte array: opcode followed by address bytes selected by +/// `width`. Returns a fixed-size buffer and the valid length. +/// +/// The caller slices `&buf[..len]` to get the exact command bytes. +/// This mirrors aspeed-rust's explicit `AddressWidth` selection rather than +/// relying on implicit `to_be_bytes()[1..]` slicing. +fn encode_addr_cmd(opcode: u8, offset: u32, width: AddressWidth) -> ([u8; 5], usize) { + let be = offset.to_be_bytes(); + match width { + AddressWidth::None => { + let mut buf = [0u8; 5]; + buf[0] = opcode; + (buf, 1) + } + AddressWidth::ThreeByte => { + let mut buf = [0u8; 5]; + buf[0] = opcode; + buf[1] = be[1]; + buf[2] = be[2]; + buf[3] = be[3]; + (buf, 4) + } + AddressWidth::FourByte => { + let mut buf = [0u8; 5]; + buf[0] = opcode; + buf[1] = be[0]; + buf[2] = be[1]; + buf[3] = be[2]; + buf[4] = be[3]; + (buf, 5) + } + } +} + +/// Minimal SPI NOR flash device API. +pub trait SpiNorFlashDevice { + /// Read bytes from flash at `offset` into `buf`. + fn read(&self, offset: u32, buf: &mut [u8]) -> Result<usize, SmcError>; + + /// Return configured flash capacity in bytes. + fn capacity_bytes(&self) -> Result<usize, SmcError>; + + /// Erase one sector at `offset`. + fn erase_sector(&mut self, offset: u32) -> Result<(), SmcError>; + + /// Program one page at `offset`. + fn program_page(&mut self, offset: u32, data: &[u8]) -> Result<usize, SmcError>; + + /// Verify flash content against `expected` bytes. + fn verify(&self, offset: u32, expected: &[u8]) -> Result<bool, SmcError>; + + /// Read status register. + fn status(&self) -> Result<u8, SmcError>; + + /// Read JEDEC ID bytes (manufacturer + 2-byte device ID). + fn jedec_id(&self) -> Result<[u8; 3], SmcError>; +} + +/// Standard SPI NOR opcodes used by Phase 3B operations. +pub mod commands { + pub const WRITE_ENABLE: u8 = 0x06; + pub const ERASE_SECTOR_4K: u8 = 0x20; + pub const ERASE_SECTOR_4K_4B: u8 = 0x21; + pub const PAGE_PROGRAM: u8 = 0x02; + pub const PAGE_PROGRAM_4B: u8 = 0x12; + pub const READ_FAST: u8 = 0x0B; + pub const READ_FAST_4B: u8 = 0x0C; + pub const READ_STATUS: u8 = 0x05; + pub const READ_ID: u8 = 0x9F; +} + +/// Addressing policy for SPI NOR command transactions. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum FlashAddressingPolicy { + /// Use 3-byte addressing command set. + ThreeByteOnly, + /// Use 4-byte addressing command set. + FourByteCommands, +} + +impl FlashAddressingPolicy { + pub const fn addr_width(self) -> AddressWidth { + match self { + Self::ThreeByteOnly => AddressWidth::ThreeByte, + Self::FourByteCommands => AddressWidth::FourByte, + } + } +} + +/// SPI NOR opcode profile selected by addressing policy. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct FlashCommandProfile { + pub read_fast: u8, + pub page_program: u8, + pub erase_sector_4k: u8, + pub read_status: u8, + pub write_enable: u8, +} + +impl FlashCommandProfile { + const fn for_addressing(policy: FlashAddressingPolicy) -> Self { + match policy { + FlashAddressingPolicy::ThreeByteOnly => Self { + read_fast: commands::READ_FAST, + page_program: commands::PAGE_PROGRAM, + erase_sector_4k: commands::ERASE_SECTOR_4K, + read_status: commands::READ_STATUS, + write_enable: commands::WRITE_ENABLE, + }, + FlashAddressingPolicy::FourByteCommands => Self { + read_fast: commands::READ_FAST_4B, + page_program: commands::PAGE_PROGRAM_4B, + erase_sector_4k: commands::ERASE_SECTOR_4K_4B, + read_status: commands::READ_STATUS, + write_enable: commands::WRITE_ENABLE, + }, + } + } +} + +/// Compare `expected` against bytes produced by `read`, in chunks of at most +/// `chunk` bytes. `read(offset, dst)` fills `dst` with bytes at the given +/// device-local offset. Returns `Ok(true)` on full equality, `Ok(false)` on the +/// first mismatch, and propagates any error from `read`. Bounded scratch use: +/// the comparison is performed in stack-resident chunks (`chunk` bytes, capped +/// at 256) regardless of `expected.len()`. +fn compare_chunked<F>( + mut read: F, + offset: u32, + expected: &[u8], + chunk: usize, +) -> Result<bool, SmcError> +where + F: FnMut(u32, &mut [u8]) -> Result<usize, SmcError>, +{ + let mut scratch = [0u8; 256]; + let step = core::cmp::min(chunk, scratch.len()); + if step == 0 { + return Err(SmcError::InvalidCapacity); + } + let mut cursor = 0usize; + while cursor < expected.len() { + let n = core::cmp::min(step, expected.len() - cursor); + let chunk_offset = offset + .checked_add(cursor as u32) + .ok_or(SmcError::InvalidCapacity)?; + read(chunk_offset, &mut scratch[..n])?; + if scratch[..n] != expected[cursor..cursor + n] { + return Ok(false); + } + cursor += n; + } + Ok(true) +} + +enum FlashBackend<'a> { + Fmc(&'a FmcReady), + Spi(&'a SpiReady), +} + +/// Decoded JEDEC identifier returned by `READ_ID` (`0x9F`). +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct JedecId { + pub manufacturer: u8, + pub memory_type: u8, + pub capacity_code: u8, +} + +impl JedecId { + #[must_use] + pub const fn from_bytes(raw: [u8; 3]) -> Self { + Self { + manufacturer: raw[0], + memory_type: raw[1], + capacity_code: raw[2], + } + } + + #[must_use] + pub const fn as_bytes(self) -> [u8; 3] { + [self.manufacturer, self.memory_type, self.capacity_code] + } +} + +fn expect_jedec_match(actual: JedecId, expected: JedecId) -> Result<JedecId, SmcError> { + if actual != expected { + return Err(SmcError::HardwareError); + } + Ok(actual) +} + +/// Wrapper-aware SPI NOR flash facade. +pub struct SpiNorFlash<'a> { + backend: FlashBackend<'a>, + // Validated metadata for Phase 3B alignment/policy checks. + cfg: FlashConfig, + /// Chip select this flash device sits on. + cs: ChipSelect, + /// IO mode used for all SPI command transactions (WREN, RDSR, PP, SE). + /// Defaults to `Mode111` (single-wire cmd/addr/data). + cmd_mode: TransferMode, + /// Addressing policy selected for SPI NOR command construction. + addressing_policy: FlashAddressingPolicy, + /// Opcodes selected for the current addressing policy. + command_profile: FlashCommandProfile, +} + +impl<'a> SpiNorFlash<'a> { + /// Build a flash facade from an initialized FMC controller wrapper. + pub fn from_fmc(fmc: &'a mut FmcReady, cfg: FlashConfig) -> Result<Self, SmcError> { + Self::from_fmc_cs(fmc, cfg, ChipSelect::Cs0) + } + + /// Build a flash facade from an initialized FMC controller wrapper with explicit CS. + pub fn from_fmc_cs(fmc: &'a mut FmcReady, cfg: FlashConfig, cs: ChipSelect) -> Result<Self, SmcError> { + let addressing_policy = Self::default_addressing_for_cfg(cfg); + Self::validate_capacity_cfg(cfg, fmc.cs_config(cs)?)?; + Ok(Self { + backend: FlashBackend::Fmc(fmc), + cfg, + cs, + cmd_mode: TransferMode::Mode111, + addressing_policy, + command_profile: FlashCommandProfile::for_addressing(addressing_policy), + }) + } + + /// Build a flash facade from an initialized SPI1/SPI2 controller wrapper. + pub fn from_spi(spi: &'a mut SpiReady, cfg: FlashConfig) -> Result<Self, SmcError> { + Self::from_spi_cs(spi, cfg, ChipSelect::Cs0) + } + + /// Build a flash facade from an initialized SPI1/SPI2 controller wrapper with explicit CS. + pub fn from_spi_cs(spi: &'a mut SpiReady, cfg: FlashConfig, cs: ChipSelect) -> Result<Self, SmcError> { + let addressing_policy = Self::default_addressing_for_cfg(cfg); + Self::validate_capacity_cfg(cfg, spi.cs_config(cs)?)?; + Ok(Self { + backend: FlashBackend::Spi(spi), + cfg, + cs, + cmd_mode: TransferMode::Mode111, + addressing_policy, + command_profile: FlashCommandProfile::for_addressing(addressing_policy), + }) + } + + /// Override the IO mode used for all SPI command transactions. + /// + /// Applies to WREN, RDSR, PAGE_PROGRAM, and SECTOR_ERASE paths. + /// The memory-mapped read path always uses the segment-routed AHB window + /// and is unaffected by this setting. + pub fn with_cmd_mode(mut self, mode: TransferMode) -> Self { + self.cmd_mode = mode; + self + } + + /// Override the addressing policy used for command-profile selection. + pub fn with_addressing_policy(mut self, policy: FlashAddressingPolicy) -> Self { + self.addressing_policy = policy; + self.command_profile = FlashCommandProfile::for_addressing(policy); + self + } + + /// Read and decode the three-byte JEDEC ID tuple. + pub fn jedec(&self) -> Result<JedecId, SmcError> { + Ok(JedecId::from_bytes(self.read_jedec_id_impl()?)) + } + + /// Read JEDEC ID and require an exact match. + pub fn expect_jedec(&self, expected: JedecId) -> Result<JedecId, SmcError> { + expect_jedec_match(self.jedec()?, expected) + } + + /// Program an arbitrary-length buffer by issuing page-sized writes. + /// + /// The starting `offset` must be page-aligned. The final chunk may be + /// shorter than a full page. + pub fn program(&mut self, offset: u32, data: &[u8]) -> Result<usize, SmcError> { + if data.is_empty() { + return Ok(0); + } + + let page_size = self.cfg.page_size as usize; + if page_size == 0 || (offset as usize) % page_size != 0 { + return Err(SmcError::InvalidCapacity); + } + self.validate_range(offset, data.len())?; + + let mut written = 0usize; + while written < data.len() { + let chunk_len = core::cmp::min(page_size, data.len() - written); + let chunk_offset = offset + .checked_add(written as u32) + .ok_or(SmcError::InvalidCapacity)?; + self.program_page(chunk_offset, &data[written..written + chunk_len])?; + written += chunk_len; + } + + Ok(written) + } + + /// Erase all sectors intersecting the requested byte range. + /// + /// The erased interval is rounded outward to sector boundaries. + pub fn erase_range(&mut self, offset: u32, len: usize) -> Result<(), SmcError> { + if len == 0 { + return Ok(()); + } + + self.validate_range(offset, len)?; + + let sector_size = self.cfg.sector_size as usize; + if sector_size == 0 { + return Err(SmcError::InvalidCapacity); + } + + let start = (offset as usize / sector_size) * sector_size; + let end = (offset as usize) + .checked_add(len) + .ok_or(SmcError::InvalidCapacity)?; + let end_aligned = end + .checked_add(sector_size - 1) + .ok_or(SmcError::InvalidCapacity)? + / sector_size + * sector_size; + + let mut current = start; + while current < end_aligned { + self.erase_sector(current as u32)?; + current += sector_size; + } + + Ok(()) + } + + /// Perform a correctness-first flash update of the requested region. + /// + /// This helper erases all sectors intersecting the target range, programs + /// the supplied bytes page-by-page, then verifies the written contents. + /// Returns the number of bytes programmed on success. + pub fn update_region(&mut self, offset: u32, data: &[u8]) -> Result<usize, SmcError> { + if data.is_empty() { + return Ok(0); + } + + self.erase_range(offset, data.len())?; + let written = self.program(offset, data)?; + if !self.verify(offset, data)? { + return Err(SmcError::HardwareError); + } + + Ok(written) + } + + fn validate_capacity_cfg(cfg: FlashConfig, expected: FlashConfig) -> Result<(), SmcError> { + if cfg != expected { + return Err(SmcError::InvalidCapacity); + } + Ok(()) + } + + fn default_addressing_for_cfg(cfg: FlashConfig) -> FlashAddressingPolicy { + if cfg.capacity_mb > 16 { + FlashAddressingPolicy::FourByteCommands + } else { + FlashAddressingPolicy::ThreeByteOnly + } + } + + pub fn addr_width(&self) -> AddressWidth { + self.addressing_policy.addr_width() + } + + pub fn command_profile(&self) -> FlashCommandProfile { + self.command_profile + } + + + /// Validate a device-local offset before handing it to the controller. + /// + /// `FmcReady::read` / `SpiReady::read` already select the per-CS AHB + /// window from the chip-select argument, so offsets stay CS-local here. + fn device_to_controller_offset(&self, device_offset: u32) -> Result<u32, SmcError> { + let cs_cap = self.capacity_bytes()?; + if (device_offset as usize) >= cs_cap { + return Err(SmcError::InvalidCapacity); + } + Ok(device_offset) + } + + fn validate_range(&self, offset: u32, len: usize) -> Result<(), SmcError> { + let start = offset as usize; + let end = start.checked_add(len).ok_or(SmcError::InvalidCapacity)?; + if end > self.capacity_bytes()? { + return Err(SmcError::InvalidCapacity); + } + Ok(()) + } + + fn validate_sector_erase(&self, offset: u32) -> Result<(), SmcError> { + let sector_size = self.cfg.sector_size as usize; + if sector_size == 0 || (offset as usize) % sector_size != 0 { + return Err(SmcError::InvalidCapacity); + } + self.validate_range(offset, sector_size) + } + + fn validate_page_program(&self, offset: u32, data: &[u8]) -> Result<(), SmcError> { + let page_size = self.cfg.page_size as usize; + if page_size == 0 || data.is_empty() || data.len() > page_size { + return Err(SmcError::InvalidCapacity); + } + if (offset as usize) % page_size != 0 { + return Err(SmcError::InvalidCapacity); + } + self.validate_range(offset, data.len()) + } + + fn issue_command(&mut self, cmd: &[u8], payload: &[u8]) -> Result<(), SmcError> { + let cs = self.cs; + let mode = self.cmd_mode; + match &self.backend { + FlashBackend::Fmc(fmc) => fmc.transceive_user(cs, cmd, payload, &mut [], mode), + FlashBackend::Spi(spi) => spi.transceive_user(cs, cmd, payload, &mut [], mode), + } + } + + fn read_status_impl(&self) -> Result<u8, SmcError> { + let cs = self.cs; + let mode = self.cmd_mode; + let opcode = self.command_profile().read_status; + let mut status = [0u8; 1]; + match &self.backend { + FlashBackend::Fmc(fmc) => { + fmc.transceive_user(cs, &[opcode], &[], &mut status, mode)? + } + FlashBackend::Spi(spi) => { + spi.transceive_user(cs, &[opcode], &[], &mut status, mode)? + } + } + Ok(status[0]) + } + + fn read_jedec_id_impl(&self) -> Result<[u8; 3], SmcError> { + let cs = self.cs; + let mode = self.cmd_mode; + let mut id = [0u8; 3]; + match &self.backend { + FlashBackend::Fmc(fmc) => { + fmc.transceive_user(cs, &[commands::READ_ID], &[], &mut id, mode)? + } + FlashBackend::Spi(spi) => { + spi.transceive_user(cs, &[commands::READ_ID], &[], &mut id, mode)? + } + } + Ok(id) + } + + fn wait_write_complete(&self, max_polls: u32) -> Result<(), SmcError> { + let mut polls = 0u32; + while polls < max_polls { + let sr = self.read_status_impl()?; + if (sr & 0x01) == 0 { + return Ok(()); + } + polls += 1; + } + Err(SmcError::Timeout) + } +} + +impl SpiNorFlashDevice for SpiNorFlash<'_> { + fn read(&self, offset: u32, buf: &mut [u8]) -> Result<usize, SmcError> { + // Bounds-check against the selected CS's capacity, then translate to + // the controller-window address before issuing the segment-routed read. + self.validate_range(offset, buf.len())?; + let translated = self.device_to_controller_offset(offset)?; + let cs = self.cs; + match &self.backend { + FlashBackend::Fmc(fmc) => fmc.read(cs, translated, buf), + FlashBackend::Spi(spi) => spi.read(cs, translated, buf), + } + } + + fn capacity_bytes(&self) -> Result<usize, SmcError> { + match &self.backend { + FlashBackend::Fmc(fmc) => fmc.cs_capacity_bytes(self.cs), + FlashBackend::Spi(spi) => spi.cs_capacity_bytes(self.cs), + } + } + + fn erase_sector(&mut self, offset: u32) -> Result<(), SmcError> { + self.validate_sector_erase(offset)?; + + let profile = self.command_profile(); + let width = self.addr_width(); + self.issue_command(&[profile.write_enable], &[])?; + let (cmd, len) = encode_addr_cmd(profile.erase_sector_4k, offset, width); + self.issue_command(&cmd[..len], &[])?; + self.wait_write_complete(10_000) + } + + fn program_page(&mut self, offset: u32, data: &[u8]) -> Result<usize, SmcError> { + self.validate_page_program(offset, data)?; + + let profile = self.command_profile(); + let width = self.addr_width(); + self.issue_command(&[profile.write_enable], &[])?; + let (cmd, len) = encode_addr_cmd(profile.page_program, offset, width); + self.issue_command(&cmd[..len], data)?; + self.wait_write_complete(10_000)?; + Ok(data.len()) + } + + fn verify(&self, offset: u32, expected: &[u8]) -> Result<bool, SmcError> { + self.validate_range(offset, expected.len())?; + compare_chunked(|o, b| self.read(o, b), offset, expected, 256) + } + + fn status(&self) -> Result<u8, SmcError> { + self.read_status_impl() + } + + fn jedec_id(&self) -> Result<[u8; 3], SmcError> { + self.read_jedec_id_impl() + } +} + +#[cfg(test)] +mod tests { + use super::{ + commands, compare_chunked, encode_addr_cmd, expect_jedec_match, FlashAddressingPolicy, + FlashCommandProfile, JedecId, SpiNorFlash, + }; + use crate::smc::types::{AddressWidth, FlashConfig, SmcError}; + + #[test] + fn encode_addr_cmd_none_emits_opcode_only() { + let (buf, len) = encode_addr_cmd(0x06, 0x1234_5678, AddressWidth::None); + assert_eq!(len, 1); + assert_eq!(&buf[..len], &[0x06]); + } + + #[test] + fn encode_addr_cmd_three_byte_emits_low_24_bits() { + let (buf, len) = encode_addr_cmd(0x20, 0x1234_5678, AddressWidth::ThreeByte); + assert_eq!(len, 4); + assert_eq!(&buf[..len], &[0x20, 0x34, 0x56, 0x78]); + } + + #[test] + fn encode_addr_cmd_four_byte_emits_full_32_bits() { + let (buf, len) = encode_addr_cmd(0x13, 0x1234_5678, AddressWidth::FourByte); + assert_eq!(len, 5); + assert_eq!(&buf[..len], &[0x13, 0x12, 0x34, 0x56, 0x78]); + } + + #[test] + fn command_profile_three_byte_uses_legacy_opcodes() { + let profile = FlashCommandProfile::for_addressing(FlashAddressingPolicy::ThreeByteOnly); + assert_eq!(profile.read_fast, commands::READ_FAST); + assert_eq!(profile.page_program, commands::PAGE_PROGRAM); + assert_eq!(profile.erase_sector_4k, commands::ERASE_SECTOR_4K); + assert_eq!(profile.read_status, commands::READ_STATUS); + assert_eq!(profile.write_enable, commands::WRITE_ENABLE); + } + + #[test] + fn command_profile_four_byte_uses_4b_opcodes() { + let profile = FlashCommandProfile::for_addressing(FlashAddressingPolicy::FourByteCommands); + assert_eq!(profile.read_fast, commands::READ_FAST_4B); + assert_eq!(profile.page_program, commands::PAGE_PROGRAM_4B); + assert_eq!(profile.erase_sector_4k, commands::ERASE_SECTOR_4K_4B); + assert_eq!(profile.read_status, commands::READ_STATUS); + assert_eq!(profile.write_enable, commands::WRITE_ENABLE); + } + + #[test] + fn default_addressing_policy_derives_from_capacity() { + assert_eq!( + SpiNorFlash::default_addressing_for_cfg(FlashConfig { + capacity_mb: 8, + page_size: 256, + sector_size: 4096, + block_size: 65536, + spi_clock_mhz: 25, + }), + FlashAddressingPolicy::ThreeByteOnly + ); + + assert_eq!( + SpiNorFlash::default_addressing_for_cfg(FlashConfig { + capacity_mb: 32, + page_size: 256, + sector_size: 4096, + block_size: 65536, + spi_clock_mhz: 25, + }), + FlashAddressingPolicy::FourByteCommands + ); + } + + fn fixture_1kb() -> [u8; 1024] { + let mut out = [0u8; 1024]; + let mut i = 0; + while i < out.len() { + out[i] = (i as u8).wrapping_mul(31).wrapping_add(7); + i += 1; + } + out + } + + #[test] + fn compare_chunked_matches_buffer_above_scratch_size() { + let expected = fixture_1kb(); + let backing = expected; + let read = |offset: u32, dst: &mut [u8]| -> Result<usize, SmcError> { + let off = offset as usize; + dst.copy_from_slice(&backing[off..off + dst.len()]); + Ok(dst.len()) + }; + assert_eq!(compare_chunked(read, 0, &expected, 256), Ok(true)); + } + + #[test] + fn compare_chunked_detects_mismatch_in_later_chunk() { + let expected = fixture_1kb(); + let mut backing = expected; + backing[800] = backing[800].wrapping_add(1); + let read = |offset: u32, dst: &mut [u8]| -> Result<usize, SmcError> { + let off = offset as usize; + dst.copy_from_slice(&backing[off..off + dst.len()]); + Ok(dst.len()) + }; + assert_eq!(compare_chunked(read, 0, &expected, 256), Ok(false)); + } + + #[test] + fn compare_chunked_propagates_read_error() { + let expected = fixture_1kb(); + let read = |_offset: u32, _dst: &mut [u8]| -> Result<usize, SmcError> { + Err(SmcError::Timeout) + }; + assert_eq!(compare_chunked(read, 0, &expected, 256), Err(SmcError::Timeout)); + } + + #[test] + fn expect_jedec_match_returns_actual_on_exact_match() { + let jedec = JedecId::from_bytes([0xEF, 0x40, 0x18]); + assert_eq!(expect_jedec_match(jedec, jedec), Ok(jedec)); + } + + #[test] + fn expect_jedec_match_rejects_mismatch() { + let expected = JedecId::from_bytes([0xEF, 0x40, 0x18]); + let actual = JedecId::from_bytes([0xC2, 0x20, 0x19]); + assert_eq!(expect_jedec_match(actual, expected), Err(SmcError::HardwareError)); + } +}
diff --git a/target/ast10x0/peripherals/smc/device/mod.rs b/target/ast10x0/peripherals/smc/device/mod.rs new file mode 100644 index 0000000..f7fba1f --- /dev/null +++ b/target/ast10x0/peripherals/smc/device/mod.rs
@@ -0,0 +1,10 @@ +// Licensed under the Apache-2.0 license +// SPDX-License-Identifier: Apache-2.0 + +//! Flash device abstractions layered on top of SMC wrappers. + +mod flash; +mod block_device; + +pub use flash::{FlashAddressingPolicy, FlashCommandProfile, SpiNorFlashDevice, JedecId, SpiNorFlash}; +pub use block_device::{BlockDeviceInfo, SpiNorBlockDevice};
diff --git a/target/ast10x0/peripherals/smc/fmc.rs b/target/ast10x0/peripherals/smc/fmc.rs new file mode 100644 index 0000000..bce687f --- /dev/null +++ b/target/ast10x0/peripherals/smc/fmc.rs
@@ -0,0 +1,158 @@ +// Licensed under the Apache-2.0 license +// SPDX-License-Identifier: Apache-2.0 + +//! FMC-specialized wrapper around the generic SMC controller. +//! +//! # FMC vs SPI1/SPI2 +//! +//! This module provides an abstraction **exclusively for the FMC (Firmware Memory Controller)** +//! block. The FMC connects directly to flash without SPI-monitor interception. +//! +//! **SPI1 and SPI2** (application SPI controllers that route through SPIPF monitor) are +//! handled by the separate [`crate::smc::spi`] module, not here. +//! +//! - **FMC**: Single dedicated flash controller, no SPI-monitor support, boot-time device +//! - **SPI1/SPI2**: Multi-instance application controllers with optional SPIPF monitoring +//! +//! See [`crate::smc`] module-level documentation for the full taxonomy. + +use crate::smc::controller::{ReadySmc, UninitSmc}; +use crate::smc::interrupts::SmcInterrupt; +use crate::smc::types::{ + ChipSelect, FlashConfig, SmcConfig, SmcController, SmcError, TransferMode, +}; + +/// FMC handle before hardware initialization. +pub struct FmcUninit { + inner: UninitSmc, +} + +/// FMC handle after hardware initialization. +pub struct FmcReady { + inner: ReadySmc, +} + +impl FmcUninit { + /// Construct an uninitialized FMC controller. + /// + /// # Safety + /// Caller must ensure unique ownership of the FMC hardware block. + pub unsafe fn new(mut config: SmcConfig) -> Result<Self, SmcError> { + config.controller_id = SmcController::Fmc; + // SAFETY: Caller upholds controller ownership requirements. + let inner = unsafe { UninitSmc::new(config)? }; + Ok(Self { inner }) + } + + /// Initialize FMC hardware and transition to ready state. + pub fn init(self) -> Result<FmcReady, SmcError> { + Ok(FmcReady { + inner: self.inner.init()?, + }) + } +} + +impl FmcReady { + /// Perform a programmed I/O read via the FMC flash window. + pub fn read(&self, cs: ChipSelect, offset: u32, buf: &mut [u8]) -> Result<usize, SmcError> { + self.inner.read(cs, offset, buf) + } + + /// Initiate a DMA read operation. + pub fn dma_read( + &mut self, + cs: ChipSelect, + flash_offset: u32, + dram_addr: usize, + len: u32, + ) -> Result<(), SmcError> { + self.inner.dma_read(cs, flash_offset, dram_addr, len) + } + + /// Read raw DMA/interrupt status bits from FMC008. + pub fn dma_status(&self) -> u32 { + self.inner.dma_status() + } + + /// Clear DMA-related status bits in FMC008 (write-1-to-clear). + pub fn clear_dma_status(&self, clear_mask: u32) { + self.inner.clear_dma_status(clear_mask) + } + + /// Handle DMA completion/error from IRQ status and finalize controller state. + pub fn handle_dma_irq(&mut self) -> Result<SmcInterrupt, SmcError> { + self.inner.handle_dma_irq() + } + + /// Poll for DMA completion without requiring an IRQ. See `Smc::poll_dma_completion`. + pub fn poll_dma_completion(&mut self) -> core::task::Poll<Result<(), SmcError>> { + self.inner.poll_dma_completion() + } + + /// Check if FMC is ready for operations. + pub fn is_ready(&self) -> bool { + self.inner.is_ready() + } + + /// Program memory-mapped SPI NOR read mode for the selected chip select. + pub fn spi_nor_read_init(&mut self, cs: ChipSelect) -> Result<(), SmcError> { + self.inner.spi_nor_read_init(cs) + } + + #[doc(hidden)] + pub fn test_force_dma_in_flight(&mut self) { + self.inner.test_force_dma_in_flight(); + } + + /// Return configured flash capacity in bytes. + pub fn capacity_bytes(&self) -> Result<usize, SmcError> { + self.inner.capacity_bytes() + } + + /// Return configured flash capacity in bytes for the given chip select. + pub fn cs_capacity_bytes(&self, cs: ChipSelect) -> Result<usize, SmcError> { + self.inner.cs_capacity_bytes(cs) + } + + /// Return the configured `FlashConfig` for the requested chip select. + pub fn cs_config(&self, cs: ChipSelect) -> Result<FlashConfig, SmcError> { + self.inner.cs_config(cs) + } + + /// Execute a raw user-mode SPI transfer on the selected FMC chip select. + /// + /// `cs` selects CS0 or CS1; `mode` controls the per-phase IO width. + /// Returns `SmcError::InvalidChipSelect` if CS1 is requested but not configured. + pub fn transceive_user( + &self, + cs: ChipSelect, + cmd: &[u8], + tx_payload: &[u8], + rx: &mut [u8], + mode: TransferMode, + ) -> Result<(), SmcError> { + self.inner.transceive_user(cs, cmd, tx_payload, rx, mode) + } + + /// Convenience wrapper: execute a user-mode transfer on CS0. + pub fn transceive_user_cs0( + &self, + cmd: &[u8], + tx_payload: &[u8], + rx: &mut [u8], + mode: TransferMode, + ) -> Result<(), SmcError> { + self.inner + .transceive_user(ChipSelect::Cs0, cmd, tx_payload, rx, mode) + } + + /// Access the underlying generic ready controller. + pub fn as_inner(&self) -> &ReadySmc { + &self.inner + } + + /// Mutable access to the underlying generic ready controller. + pub fn as_inner_mut(&mut self) -> &mut ReadySmc { + &mut self.inner + } +}
diff --git a/target/ast10x0/peripherals/smc/helpers.rs b/target/ast10x0/peripherals/smc/helpers.rs new file mode 100644 index 0000000..78a889a --- /dev/null +++ b/target/ast10x0/peripherals/smc/helpers.rs
@@ -0,0 +1,432 @@ +// Licensed under the Apache-2.0 license +// SPDX-License-Identifier: Apache-2.0 + +//! Pure helper logic for SMC address and timing calculations. + +use core::convert::TryFrom; + +use crate::smc::types::ChipSelect; +use crate::smc::types::FlashConfig; +use crate::smc::types::SmcConfig; +use crate::smc::types::SmcError; + +const SMC_WINDOW_SIZE_BYTES: usize = 256 * 1024 * 1024; +const DMA_MAX_TRANSFER_LENGTH: u32 = 0x20_0000; // 32MBytes +pub(crate) const SPI_CTRL_FREQ_MASK: u32 = 0x0F00_0F00; + +/// DMA engine's base address for flash-side memory (fmc084 / spi084). +/// DMA flash address = flash_window_base[cs] - SPI_DMA_FLASH_MAP_BASE + cs_offset. +pub(crate) const SPI_DMA_FLASH_MAP_BASE: usize = 0x6000_0000; + +/// DMA engine's base address for SRAM-side memory (fmc088 / spi088). +/// DMA DRAM address = physical_sram_addr + SPI_DMA_RAM_MAP_BASE. +pub(crate) const SPI_DMA_RAM_MAP_BASE: u32 = 0x8000_0000; + +/// Written to spi080/fmc080 to request the DMA bus (sets DMAReq, bit 31). +/// On SPI1/SPI2 this asserts the hardware arbiter request line. +/// On FMC, bits 20–31 are Reserved — the write is a no-op. +/// Matches aspeed-rust `SPI_DMA_GET_REQ_MAGIC`. +pub(crate) const SPI_DMA_GET_REQ_MAGIC: u32 = 0xaeed_0000; + +/// Written to spi080/fmc080 to release the DMA bus grant (DMADiscard). +/// On SPI1/SPI2 this releases the arbiter grant after DMA completes. +/// On FMC, bits 20–31 are Reserved — the write is a no-op. +/// Matches aspeed-rust `SPI_DMA_DISCARD_REQ_MAGIC`. +pub(crate) const SPI_DMA_DISCARD_REQ_MAGIC: u32 = 0xdeea_0000; + +/// spi080 bit 31: DMA bus request is pending (SPI1/SPI2 only). +/// Reads as 0 on FMC (Reserved). +pub(crate) const SPI_DMA_REQUEST: u32 = 1 << 31; + +/// spi080 bit 30: DMA bus grant is held (SPI1/SPI2 only). +/// Reads as 0 on FMC (Reserved). +pub(crate) const SPI_DMA_GRANT: u32 = 1 << 30; + +pub(crate) const SPI_DMA_CALIB_MODE: u32 = 1 << 3; +pub(crate) const SPI_DMA_CALC_CKSUM: u32 = 1 << 2; +pub(crate) const SPI_DMA_ENABLE: u32 = 1 << 0; + +/// Validated parameters for a DMA read operation, ready to be written to hardware registers. +/// +/// Produced by [`validate_dma_read`] after bounds-checking and address translation. +/// All fields are in the format expected directly by the DMA engine registers. +pub(crate) struct ValidatedDmaRead { + /// DMA engine flash-side address (written to fmc084 / spi084). + /// + /// Computed as `flash_window_base[cs] - SPI_DMA_FLASH_MAP_BASE + cs_offset`. + pub flash_start: usize, + /// DMA engine DRAM-side address (written to fmc088 / spi088). + /// + /// Must be 4-byte aligned + pub dram_addr: u32, + /// Value to write to the DMA length register (transfer length minus one). + /// [0:24] 0x1F_FFFF:32Mbytes + pub dma_len_reg: u32, +} + +pub(crate) fn flash_capacity_bytes(config: Option<FlashConfig>) -> Result<usize, SmcError> { + match config { + Some(config) => (config.capacity_mb as usize) + .checked_mul(1024 * 1024) + .ok_or(SmcError::InvalidCapacity), + None => Ok(0), + } +} + +pub(crate) fn cs_capacity_bytes(config: &SmcConfig, cs: ChipSelect) -> Result<usize, SmcError> { + let slot = match cs { + ChipSelect::Cs0 => config.cs0, + ChipSelect::Cs1 => config.cs1, + }; + match slot { + Some(_) => flash_capacity_bytes(slot), + None => Err(SmcError::InvalidChipSelect), + } +} + +pub(crate) fn total_capacity_bytes( + cs0: Option<FlashConfig>, + cs1: Option<FlashConfig>, +) -> Result<usize, SmcError> { + let cs0_size = flash_capacity_bytes(cs0)?; + let cs1_size = flash_capacity_bytes(cs1)?; + let total = cs0_size + .checked_add(cs1_size) + .ok_or(SmcError::InvalidCapacity)?; + if total > SMC_WINDOW_SIZE_BYTES { + return Err(SmcError::InvalidCapacity); + } + Ok(total) +} + +pub(crate) fn validate_mapped_range( + offset: u32, + len: usize, + capacity_bytes: usize, +) -> Result<usize, SmcError> { + let offset = offset as usize; + let end = offset.checked_add(len).ok_or(SmcError::InvalidCapacity)?; + if end > capacity_bytes { + return Err(SmcError::InvalidCapacity); + } + Ok(offset) +} + +/// Validate a DMA read request and compute DMA register values. +/// +/// `flash_window_base`: per-CS AHB window base addresses from `Smc<Ready>`. +/// `cs0_capacity`: byte size of CS0; used to derive which CS the offset falls in. +/// +/// The chip select is never accepted as a caller argument. The controller-relative +/// `flash_offset` encodes it implicitly: any offset in `[0, cs0_capacity)` names +/// CS0; any offset in `[cs0_capacity, capacity_bytes)` names CS1. See +/// EVD-20260511-dma-flash-offset-encodes-cs for the full rationale. +pub(crate) fn validate_dma_read( + flash_offset: u32, + flash_win_base: usize, + cs_capacity: usize, + dram_addr: usize, + len: u32, +) -> Result<ValidatedDmaRead, SmcError> { + if len == 0 || len > DMA_MAX_TRANSFER_LENGTH { + return Err(SmcError::InvalidCapacity); + } + + // Flash offset must be 4-byte aligned (spec §1.3, matching aspeed-rust). + if flash_offset & 0x3 != 0 { + return Err(SmcError::InvalidCapacity); + } + + // Bounds-check the controller-relative offset. + let _ = validate_mapped_range(flash_offset, len as usize, cs_capacity)?; + + // Compute the DMA engine's flash address (written to fmc084/spi084). + // Formula from aspeed-rust fmccontroller.rs::read_dma: + // fmc084 = decode_addr[cs].start + op.address.value - SPI_DMA_FLASH_MAP_BASE + // = flash_window_base[cs] - SPI_DMA_FLASH_MAP_BASE + cs_offset + let base = flash_win_base + .checked_sub(SPI_DMA_FLASH_MAP_BASE) + .ok_or(SmcError::InvalidCapacity)?; + + let flash_start = base + .checked_add(flash_offset as usize) + .ok_or(SmcError::InvalidCapacity)?; + + let dram_addr = u32::try_from(dram_addr).map_err(|_| SmcError::InvalidCapacity)?; + if dram_addr & 0x3 != 0 { + return Err(SmcError::InvalidCapacity); + } + + Ok(ValidatedDmaRead { + flash_start, + dram_addr, + dma_len_reg: len - 1, + }) +} + +/// Encode a memory segment into hardware register format. +/// +/// Hardware uses 512 KB units for addressing. +pub(crate) fn encode_segment(start: usize, end: usize) -> Result<u32, SmcError> { + let start_512k = (start >> 19) as u32; + let end_512k = ((end >> 19) - 1) as u32; + + if start_512k > 0xFFFF || end_512k > 0xFFFF { + return Err(SmcError::InvalidCapacity); + } + + Ok((end_512k << 16) | start_512k) +} + +/// Calculate AST-compatible SPI clock divider field for CS control registers. +/// +/// Ported from aspeed-rust's silicon-tested divisor search logic. +pub(crate) fn spi_freq_div(sysclk_mhz: u32, max_freq_mhz: u32) -> Result<u32, SmcError> { + if max_freq_mhz == 0 { + return Err(SmcError::HardwareError); + } + + let div_arr = [15u32, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 0]; + + for i in 0..0x0f { + for (j, div_val) in div_arr.iter().copied().enumerate() { + if i == 0 && j == 0 { + continue; + } + + let divisor = (j as u32) + 1 + (i * 16); + let freq = sysclk_mhz / divisor; + if max_freq_mhz >= freq { + return Ok((i << 24) | (div_val << 8)); + } + } + } + + Ok(0) +} +/// Finds the midpoint of the longest consecutive sequence of 1's in a buffer. +/// +/// Returns the midpoint index if the longest run is at least length 4, +/// otherwise returns -1. +/// +/// # Arguments +/// * `buf` - slice of bytes (each should be 0 or 1). +pub(crate) fn get_mid_point_of_longest_one(buf: &[u8]) -> i32 { + let mut start = 0; + let mut mid_point = 0; + let mut max_cnt = 0; + let mut cnt = 0; + + for (i, &val) in buf.iter().enumerate() { + if val == 1 { + cnt += 1; + } else { + cnt = 0; + start = i; + } + + if cnt > max_cnt { + max_cnt = cnt; + mid_point = start + (cnt / 2); + } + } + + if max_cnt < 4 { + return -1; + } else { + return i32::try_from(mid_point).unwrap(); + } +} + +pub(crate) fn spi_calibration_enable(buf: &[u8]) -> Result<bool, SmcError> { + if buf.len() < 4 { + return Ok(false); + } + + let mut valid_count = 0; + + // Process 4 bytes at a time + for chunk in buf.chunks_exact(4) { + // Convert 4 bytes to u32 in little-endian order + let word = u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]); + + if word != 0 && word != 0xFFFF_FFFF { + valid_count += 1; + } + if valid_count > 100 { + return Ok(true); + } + } + + Ok(false) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_encode_segment() { + let seg = encode_segment(0, 16 * 1024 * 1024).unwrap(); + let start_512k = seg & 0xFFFF; + let end_512k = (seg >> 16) & 0xFFFF; + assert_eq!(start_512k, 0); + assert_eq!(end_512k, 31); + } + + #[test] + fn test_encode_segment_8mb_cs0() { + let seg = encode_segment(0, 8 * 1024 * 1024).unwrap(); + let start_512k = seg & 0xFFFF; + let end_512k = (seg >> 16) & 0xFFFF; + assert_eq!(start_512k, 0); + assert_eq!(end_512k, 15); + } + + #[test] + fn test_encode_segment_64mb_cs1_after_8mb_cs0() { + let start = 8 * 1024 * 1024; + let end = start + 64 * 1024 * 1024; + let seg = encode_segment(start, end).unwrap(); + let start_512k = seg & 0xFFFF; + let end_512k = (seg >> 16) & 0xFFFF; + assert_eq!(start_512k, 16); + assert_eq!(end_512k, 143); + } + + fn decode_divisor(encoded: u32) -> u32 { + let table = [15u32, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 0]; + let hi = (encoded >> 24) & 0x0f; + let lo = (encoded >> 8) & 0x0f; + let j = table + .iter() + .position(|&v| v == lo) + .expect("encoded lo nibble must exist in divisor table") as u32; + j + 1 + (hi * 16) + } + + #[test] + fn test_spi_freq_div_25mhz_bound() { + let encoded = spi_freq_div(200, 25).unwrap(); + let divisor = decode_divisor(encoded); + assert_eq!(200 / divisor, 25); + assert!(encoded & !SPI_CTRL_FREQ_MASK == 0); + } + + #[test] + fn test_spi_freq_div_50mhz_bound() { + let encoded = spi_freq_div(200, 50).unwrap(); + let divisor = decode_divisor(encoded); + assert_eq!(200 / divisor, 50); + assert!(encoded & !SPI_CTRL_FREQ_MASK == 0); + } + + #[test] + fn test_spi_freq_div_rejects_zero_target() { + assert!(spi_freq_div(200, 0).is_err()); + } + + #[test] + fn test_segment_overflow() { + let result = encode_segment(0, 512 * 1024 * 1024); + assert!(result.is_err()); + } + + #[test] + fn test_total_capacity_overflow() { + let result = total_capacity_bytes( + Some(FlashConfig { + capacity_mb: 128, + page_size: 256, + sector_size: 4096, + block_size: 65536, + spi_clock_mhz: 25, + }), + Some(FlashConfig { + capacity_mb: 129, + page_size: 256, + sector_size: 4096, + block_size: 65536, + spi_clock_mhz: 25, + }), + ); + assert!(result.is_err()); + } + + #[test] + fn test_validate_mapped_range_accepts_exact_fit() { + let offset = validate_mapped_range(4092, 4, 4096).unwrap(); + assert_eq!(offset, 4092); + } + + #[test] + fn test_validate_mapped_range_rejects_overflow() { + let result = validate_mapped_range(u32::MAX, 8, SMC_WINDOW_SIZE_BYTES); + assert!(result.is_err()); + } + + #[test] + fn test_validate_mapped_range_rejects_out_of_bounds() { + let result = validate_mapped_range(1024, 1, 1024); + assert!(result.is_err()); + } + + // FMC window base for tests: 0x8000_0000; SPI_DMA_FLASH_MAP_BASE: 0x6000_0000 + // Expected fmc084 for CS0 offset 0x1000: 0x8000_0000 - 0x6000_0000 + 0x1000 = 0x2000_1000 + const TEST_WINDOW: [usize; 2] = [0x8000_0000, 0x8100_0000]; // CS0=16MB, CS1 starts at +16MB + const TEST_CS0_CAP: usize = 16 * 1024 * 1024; + //const TEST_CAP: usize = 16 * 1024 * 1024; + + #[test] + fn test_validate_dma_read_accepts_valid_request() { + let validated = + validate_dma_read(0x1000, TEST_WINDOW, TEST_CS0_CAP, 0x0008_0000, 512).unwrap(); + assert_eq!(validated.flash_start, 0x2000_1000); // 0x8000_0000 - 0x6000_0000 + 0x1000 + assert_eq!(validated.dram_addr, 0x0008_0000); + assert_eq!(validated.dma_len_reg, 511); + } + + #[test] + fn test_validate_dma_read_cs1_region() { + // Offset falls in CS1 region (past 16 MB CS0) on a 32 MB dual-CS controller. + const DUAL_WINDOW: [usize; 2] = [0x8000_0000, 0x8100_0000]; + const CS0_CAP: usize = 16 * 1024 * 1024; + const TOTAL_CAP: usize = 32 * 1024 * 1024; + let cs1_offset = CS0_CAP + 0x1000; + let validated = + validate_dma_read(cs1_offset as u32, DUAL_WINDOW, CS0_CAP, 0x0008_0000, 512).unwrap(); + // fmc084 = 0x8100_0000 - 0x6000_0000 + 0x1000 = 0x2100_1000 + assert_eq!(validated.flash_start, 0x2100_1000); + assert_eq!(validated.dma_len_reg, 511); + } + + #[test] + fn test_validate_dma_read_rejects_zero_length() { + let result = validate_dma_read(0, TEST_WINDOW, TEST_CS0_CAP, 0x0008_0000, 0); + assert!(result.is_err()); + } + + #[test] + fn test_validate_dma_read_rejects_unaligned_flash_offset() { + let result = validate_dma_read(0x1001, TEST_WINDOW, TEST_CS0_CAP, 0x0008_0000, 256); + assert!(result.is_err()); + } + + #[test] + fn test_validate_dma_read_rejects_unaligned_dram() { + let result = validate_dma_read(0, TEST_WINDOW, TEST_CS0_CAP, 0x0008_0002, 256); + assert!(result.is_err()); + } + + #[test] + fn test_validate_dma_read_rejects_masked_dram_bits() { + let result = validate_dma_read(0, TEST_WINDOW, TEST_CS0_CAP, 0x1000_0000, 256); + assert!(result.is_err()); + } + + #[test] + fn test_validate_dma_read_rejects_flash_range_overflow() { + let result = validate_dma_read(0x00ff_ff00, TEST_WINDOW, TEST_CS0_CAP, 0x0008_0000, 0x200); + assert!(result.is_err()); + } +}
diff --git a/target/ast10x0/peripherals/smc/interrupts.rs b/target/ast10x0/peripherals/smc/interrupts.rs new file mode 100644 index 0000000..fae72cb --- /dev/null +++ b/target/ast10x0/peripherals/smc/interrupts.rs
@@ -0,0 +1,111 @@ +// Licensed under the Apache-2.0 license +// SPDX-License-Identifier: Apache-2.0 + +//! Safe interrupt handling +//! +//! Provides safe enums for decoding interrupts, suitable for use in ISR context. + +use super::types::SmcController; + +/// SMC interrupt types +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum SmcInterrupt { + /// DMA transfer completed successfully + DmaComplete = 0, + /// DMA transfer was aborted + DmaError = 1, + /// Command was aborted + CommandAbort = 2, + /// Write protect signal active + WriteProtected = 3, + /// Unknown or no interrupt + Unknown = 255, +} + +impl TryFrom<u8> for SmcInterrupt { + type Error = (); + + fn try_from(value: u8) -> core::result::Result<Self, Self::Error> { + match value { + 0 => Ok(SmcInterrupt::DmaComplete), + 1 => Ok(SmcInterrupt::DmaError), + 2 => Ok(SmcInterrupt::CommandAbort), + 3 => Ok(SmcInterrupt::WriteProtected), + _ => Err(()), + } + } +} + +/// Decoder for SMC interrupt status register +/// +/// Safe to call from ISR context. Returns the decoded interrupt type. +pub struct SmcInterruptDecoder; + +impl SmcInterruptDecoder { + /// Decode interrupt control register bits + pub fn decode(intr_ctrl: u32) -> SmcInterrupt { + Self::decode_with_context(intr_ctrl, true) + } + + /// Decode interrupt bits with DMA state context. + /// + /// Bit 10 indicates a command abort condition. If a DMA transfer is + /// in-flight, that abort is treated as `DmaError`; otherwise it is a + /// generic `CommandAbort`. + pub fn decode_with_context(intr_ctrl: u32, dma_in_flight: bool) -> SmcInterrupt { + // Bit fields from hardware register: + // [11] = DMA_STATUS (DMA complete) + // [10] = CMD_ABORT_STATUS (command abort / DMA abort) + // [9] = WRITE_PROTECT_STATUS + if (intr_ctrl & (1 << 11)) != 0 { + SmcInterrupt::DmaComplete + } else if (intr_ctrl & (1 << 10)) != 0 { + if dma_in_flight { + SmcInterrupt::DmaError + } else { + SmcInterrupt::CommandAbort + } + } else if (intr_ctrl & (1 << 9)) != 0 { + SmcInterrupt::WriteProtected + } else { + SmcInterrupt::Unknown + } + } +} + +/// Context passed to interrupt handler +/// +/// Safe to use in ISR; only allows non-blocking operations +pub struct SmcIsrContext { + pub controller_id: SmcController, + pub interrupt: SmcInterrupt, +} + +#[cfg(test)] +mod tests { + use super::{SmcInterrupt, SmcInterruptDecoder}; + + #[test] + fn decode_emits_dma_error_on_abort_by_default() { + let intr_ctrl = 1 << 10; + assert_eq!(SmcInterruptDecoder::decode(intr_ctrl), SmcInterrupt::DmaError); + } + + #[test] + fn decode_with_context_can_emit_command_abort() { + let intr_ctrl = 1 << 10; + assert_eq!( + SmcInterruptDecoder::decode_with_context(intr_ctrl, false), + SmcInterrupt::CommandAbort + ); + } + + #[test] + fn decode_with_context_prefers_dma_complete() { + let intr_ctrl = (1 << 11) | (1 << 10); + assert_eq!( + SmcInterruptDecoder::decode_with_context(intr_ctrl, true), + SmcInterrupt::DmaComplete + ); + } +}
diff --git a/target/ast10x0/peripherals/smc/mod.rs b/target/ast10x0/peripherals/smc/mod.rs new file mode 100644 index 0000000..4f2bc8c --- /dev/null +++ b/target/ast10x0/peripherals/smc/mod.rs
@@ -0,0 +1,29 @@ +// Licensed under the Apache-2.0 license +// SPDX-License-Identifier: Apache-2.0 + +//! Static Memory Controller (SMC) HAL +//! +//! Provides safe abstractions over the FMC (Firmware Memory Controller) +//! and SPI1/SPI2 flash controllers. + +pub mod registers; +pub mod types; +mod helpers; +pub mod controller; +pub mod fmc; +pub mod spi; +pub mod interrupts; +pub mod device; + +pub use types::{SmcError, SmcController, ChipSelect, FlashConfig, SmcConfig, SmcRetryable, TransferMode, AddressWidth, SmcTopology}; +pub use controller::{Ready, ReadySmc, Smc, UninitSmc, Uninitialized}; +pub use fmc::{FmcReady, FmcUninit}; +pub use spi::{SpiReady, SpiUninit}; +pub use interrupts::{SmcInterrupt, SmcInterruptDecoder}; +pub use device::{ + BlockDeviceInfo, FlashAddressingPolicy, FlashCommandProfile, JedecId, SpiNorBlockDevice, + SpiNorFlash, SpiNorFlashDevice, +}; + +/// Result type for SMC operations +pub type Result<T> = core::result::Result<T, SmcError>;
diff --git a/target/ast10x0/peripherals/smc/registers.rs b/target/ast10x0/peripherals/smc/registers.rs new file mode 100644 index 0000000..4328f5f --- /dev/null +++ b/target/ast10x0/peripherals/smc/registers.rs
@@ -0,0 +1,322 @@ +// Licensed under the Apache-2.0 license +// SPDX-License-Identifier: Apache-2.0 + +//! Low-level register access +//! +//! Consolidates all unsafe hardware register access into a single unsafe +//! perimeter, following the AST1060 PAC guide pattern. +//! +//! # Phase 5: Topology Logic Boundary +//! +//! **This trait is pure register abstraction. No topology logic belongs here.** +//! +//! All decisions about when to call these operations, how to interpret results +//! based on controller role, and topology-gated behaviors (decode-range sizing, +//! calibration skip, control register programming per role) live in the +//! controller layer (`controller.rs`), not in backends or this trait. +//! +//! Backends are transport only; they answer "how to read/write hardware registers." +//! The controller layer answers "what to do with the data based on the topology." + +use ast1060_pac as device; +use core::marker::PhantomData; +use core::cell::UnsafeCell; + +use crate::smc::helpers::{ + SPI_DMA_DISCARD_REQ_MAGIC, SPI_DMA_GET_REQ_MAGIC, SPI_DMA_GRANT, SPI_DMA_REQUEST, +}; + +/// Safe wrapper around SMC hardware registers +/// +/// This struct consolidates all unsafe hardware access. All register operations +/// go through this single point, making it easy to audit safety invariants. +/// +/// Register naming follows AST1060 PAC convention: methods are named by their +/// hex offsets (e.g., `fmc000()` for offset 0x00, `fmc080()` for offset 0x80). +pub struct SmcRegisters { + base: *const device::fmc::RegisterBlock, + _not_sync: PhantomData<UnsafeCell<()>>, // Prevent Sync, allow Send +} + +impl SmcRegisters { + /// Create a new register accessor + /// + /// # Safety + /// Caller must ensure: + /// - `base` points to a valid FMC register block + /// - Only one SmcRegisters instance exists per register block + /// - Caller maintains exclusive access (no concurrent mutations) + pub const unsafe fn new(base: *const device::fmc::RegisterBlock) -> Self { + Self { + base, + _not_sync: PhantomData, + } + } + + /// Access the register block (single consolidation point for unsafe) + /// + /// # Safety + /// Constructor must have ensured pointer validity and single ownership + #[inline] + fn regs(&self) -> &device::fmc::RegisterBlock { + // SAFETY: Constructor ensures pointer validity and exclusive access. + // Only one SmcRegisters instance can be created per hardware controller. + unsafe { &*self.base } + } + + // ====== Safe read/write wrappers (FMC register methods by offset) ====== + + /// FMC000: Configuration register + pub fn read_config(&self) -> u32 { + self.regs().fmc000().read().bits() + } + + pub fn write_config(&self, value: u32) { + // SAFETY: Value always valid; PAC ensures register width. + self.regs().fmc000().write(|w| unsafe { w.bits(value) }); + } + + pub fn modify_config<F>(&self, f: F) + where + F: FnOnce(&mut u32), + { + self.regs().fmc000().modify(|r, w| { + let mut bits = r.bits(); + f(&mut bits); + // SAFETY: Caller's function produces valid bits. + unsafe { w.bits(bits) } + }); + } + + /// FMC004: 4-byte mode and address width control + pub fn read_addr_width(&self) -> u32 { + self.regs().fmc004().read().bits() + } + + pub fn write_addr_width(&self, value: u32) { + self.regs().fmc004().write(|w| unsafe { w.bits(value) }); + } + + /// FMC008: DMA status + pub fn read_dma_status(&self) -> u32 { + self.regs().fmc008().read().bits() + } + + /// FMC008: Clear DMA status bits (write-1-to-clear). + pub fn clear_dma_status(&self, clear_mask: u32) { + self.regs().fmc008().write(|w| unsafe { w.bits(clear_mask) }); + } + + /// FMC008: Enable DMA interrupt (bit 3, `dmaintenbl`). + /// + /// Call at end of each DMA launch, not at init time. + pub fn enable_dma_irq(&self) { + self.regs().fmc008().modify(|_, w| w.dmaintenbl().set_bit()); + } + + /// FMC008: Disable DMA interrupt (bit 3, `dmaintenbl`). + /// + /// Call at the top of the IRQ handler before processing status bits. + pub fn disable_dma_irq(&self) { + self.regs().fmc008().modify(|_, w| w.dmaintenbl().clear_bit()); + } + + /// FMC010: CS0 control register + pub fn read_cs0_ctrl(&self) -> u32 { + self.regs().fmc010().read().bits() + } + + pub fn write_cs0_ctrl(&self, value: u32) { + self.regs().fmc010().write(|w| unsafe { w.bits(value) }); + } + + /// FMC014: CS1 control register + pub fn read_cs1_ctrl(&self) -> u32 { + self.regs().fmc014().read().bits() + } + + pub fn write_cs1_ctrl(&self, value: u32) { + self.regs().fmc014().write(|w| unsafe { w.bits(value) }); + } + + /// Dispatch CS control register read by index. + pub fn read_cs_ctrl(&self, cs: crate::smc::types::ChipSelect) -> u32 { + match cs { + crate::smc::types::ChipSelect::Cs0 => self.read_cs0_ctrl(), + crate::smc::types::ChipSelect::Cs1 => self.read_cs1_ctrl(), + } + } + + /// Dispatch CS control register write by index. + pub fn write_cs_ctrl(&self, cs: crate::smc::types::ChipSelect, value: u32) { + match cs { + crate::smc::types::ChipSelect::Cs0 => self.write_cs0_ctrl(value), + crate::smc::types::ChipSelect::Cs1 => self.write_cs1_ctrl(value), + } + } + + /// FMC030: CS0 segment register (memory mapping) + pub fn read_cs0_segment(&self) -> u32 { + self.regs().fmc030().read().bits() + } + + pub fn write_cs0_segment(&self, value: u32) { + self.regs().fmc030().write(|w| unsafe { w.bits(value) }); + } + + /// FMC034: CS1 segment register (memory mapping) + pub fn read_cs1_segment(&self) -> u32 { + self.regs().fmc034().read().bits() + } + + pub fn write_cs1_segment(&self, value: u32) { + self.regs().fmc034().write(|w| unsafe { w.bits(value) }); + } + + /// FMC06C: SPI I/O mode register + pub fn read_spi_mode(&self) -> u32 { + self.regs().fmc06c().read().bits() + } + + pub fn write_spi_mode(&self, value: u32) { + self.regs().fmc06c().write(|w| unsafe { w.bits(value) }); + } + + pub fn modify_spi_mode<F>(&self, f: F) + where + F: FnOnce(&mut u32), + { + self.regs().fmc06c().modify(|r, w| { + let mut bits = r.bits(); + f(&mut bits); + // SAFETY: Caller's function produces valid bits. + unsafe { w.bits(bits) } + }); + } + + /// FMC080: DMA control register + pub fn read_dma_ctrl(&self) -> u32 { + self.regs().fmc080().read().bits() + } + + pub fn write_dma_ctrl(&self, value: u32) { + self.regs().fmc080().write(|w| unsafe { w.bits(value) }); + } + + /// FMC080: Disable DMA — full two-write sequence matching aspeed-rust `dma_disable()`. + /// + /// 1. Write `0x0` — deasserts `DMAEnbl` and `DMADirection`. + /// 2. Write `SPI_DMA_DISCARD_REQ_MAGIC` — releases DMA bus grant on SPI1/SPI2. + /// On FMC, bits 20–31 are Reserved; the second write is a no-op. + pub fn disable_dma(&self) { + self.regs().fmc080().write(|w| unsafe { w.bits(0x0) }); + self.write_dma_ctrl(SPI_DMA_DISCARD_REQ_MAGIC); + } + + /// FMC080/SPI080: Acquire the DMA bus arbiter before programming DMA registers. + /// + /// Writes `SPI_DMA_GET_REQ_MAGIC` (0xaeed_0000) to assert `DMAReq` (bit 31), + /// then spins until `DMAGrant` (bit 30) is set. + /// + /// On FMC, bits 20–31 of `fmc080` are Reserved (AST1060 PAC: `Reserved0R`). + /// The write is ignored and bit 31 reads back 0, so the spin condition is + /// immediately false — no loop is entered. This method is safe to call on + /// all three controllers without branching on `controller_id`. + /// + /// Matches aspeed-rust `spicontroller.rs::read_dma` arbitration sequence. + pub fn acquire_dma_arbiter(&self) { + self.write_dma_ctrl(SPI_DMA_GET_REQ_MAGIC); + if self.read_dma_ctrl() & SPI_DMA_REQUEST != 0 { + while self.read_dma_ctrl() & SPI_DMA_GRANT == 0 {} + } + } + + /// FMC084: DMA flash side start address (`R_DMA_FLASH_ADDR`). + /// + /// Receives the flash-side byte offset of the DMA source window. + /// Matches aspeed-rust `fmc084` / QEMU `R_DMA_FLASH_ADDR`. + pub fn read_dma_flash_addr(&self) -> u32 { + self.regs().fmc084().read().bits() + } + + pub fn write_dma_flash_addr(&self, value: u32) { + self.regs().fmc084().write(|w| unsafe { w.bits(value) }); + } + + /// FMC088: DMA DRAM/SRAM side start address (`R_DMA_DRAM_ADDR`). + /// + /// Receives the DRAM/SRAM destination address for the DMA transfer. + /// Matches aspeed-rust `fmc088` / QEMU `R_DMA_DRAM_ADDR`. + pub fn read_dma_dram_addr(&self) -> u32 { + self.regs().fmc088().read().bits() + } + + pub fn write_dma_dram_addr(&self, value: u32) { + self.regs().fmc088().write(|w| unsafe { w.bits(value) }); + } + + /// FMC08C: DMA length register (`R_DMA_LEN`). + /// + /// Receives `transfer_length - 1`. + /// Matches aspeed-rust `fmc08c` / QEMU `R_DMA_LEN`. + pub fn write_dma_len(&self, value: u32) { + self.regs().fmc08c().write(|w| unsafe { w.bits(value) }); + } + + /// FMC080: Start a DMA read (flash → DRAM). + /// + /// Uses read-modify-write to preserve timing calibration fields (bits 8–19) + /// while setting `DMAEnbl = 1` and `DMADirection = Read`. + /// Matches aspeed-rust `fmccontroller.rs::read_dma` kick sequence. + pub fn kick_dma_read(&self) { + self.regs().fmc080().modify(|_, w| { + w.dmaenbl().enable_dma_operation(); + w.dmadirection() + .read_flash_move_from_flash_to_external_memory() + }); + } + + /// FMC090: DMA checksum (CRC) + pub fn read_dma_checksum(&self) -> u32 { + self.regs().fmc090().read().bits() + } + + /// FMC094: CS0 calibration status + pub fn read_cs0_timing_compensation(&self) -> u32 { + self.regs().fmc094().read().bits() + } + + /// FMC094: CS0 calibration status + pub fn write_cs0_timing_compensation(&self, value: u32) { + self.regs().fmc094().write(|w| unsafe { w.bits(value) }); + } + + /// FMC098: CS1 calibration status + pub fn read_cs1_timing_compensation(&self) -> u32 { + self.regs().fmc098().read().bits() + } + + /// FMC098: CS0 calibration status + pub fn write_cs1_timing_compensation(&self, value: u32) { + self.regs().fmc098().write(|w| unsafe { w.bits(value) }); + } + + pub fn write_cs_timing_compensation(&self, cs: crate::smc::types::ChipSelect, value: u32) { + match cs { + crate::smc::types::ChipSelect::Cs0 => self.write_cs0_timing_compensation(value), + crate::smc::types::ChipSelect::Cs1 => self.write_cs1_timing_compensation(value), + } + } + + pub fn already_calibrated(&self, cs: crate::smc::types::ChipSelect) -> bool { + match cs { + crate::smc::types::ChipSelect::Cs0 => { + self.read_cs0_timing_compensation() != 0 + } + + crate::smc::types::ChipSelect::Cs1 => { + self.read_cs1_timing_compensation() != 0 + } + } + } +}
diff --git a/target/ast10x0/peripherals/smc/spi.rs b/target/ast10x0/peripherals/smc/spi.rs new file mode 100644 index 0000000..6a17271 --- /dev/null +++ b/target/ast10x0/peripherals/smc/spi.rs
@@ -0,0 +1,187 @@ +// Licensed under the Apache-2.0 license +// SPDX-License-Identifier: Apache-2.0 + +//! SPI1/SPI2-specialized wrapper around the generic SMC controller. +//! +//! # Architecture: Wrapper vs. Controller +//! +//! This module provides an ergonomic construction API for SPI1/SPI2 controllers. +//! **All topology-aware behavior gating (decode-range sizing, calibration skip, +//! role-specific control programming) lives in the generic controller layer** +//! (`controller.rs`), not here. +//! +//! The wrapper's role is **construction and delegation only**: +//! - `SpiUninit::new()`: Type-check that controller_id is SPI1 or SPI2 (not FMC) +//! - `SpiReady` methods: Delegate to inner controller operations +//! +//! For BootSpi (FMC), use `Smc<FmcRegisterBackend>` directly. +//! For HostSpi/NormalSpi (SPI1/SPI2), use this wrapper. + +use crate::smc::controller::{ReadySmc, UninitSmc}; +use crate::smc::interrupts::SmcInterrupt; +use crate::smc::types::{ + ChipSelect, FlashConfig, SmcConfig, SmcController, SmcError, TransferMode, +}; + +/// SPI handle before hardware initialization. +pub struct SpiUninit { + inner: UninitSmc, +} + +/// SPI handle after hardware initialization. +/// +/// # Topology Gating +/// +/// This wrapper delegates all operations to the inner controller. Topology-specific +/// behavior (decode-range sizing, calibration skip, role-dependent control register +/// programming) is handled by the controller layer, not here. This keeps the wrapper +/// thin and the topology logic centralized. +/// +/// # Example +/// +/// ```ignore +/// let mut spi = unsafe { SpiUninit::new(SmcController::Spi1, config)? }; +/// let spi = spi.init()?; // Topology-gated behaviors in controller.init() +/// spi.read(0, &mut buf)?; +/// ``` +pub struct SpiReady { + inner: ReadySmc, +} + +impl SpiUninit { + /// Construct an uninitialized SPI controller for SPI1 or SPI2. + /// + /// # Topology Requirements + /// + /// The SPI wrapper is for HostSpi and NormalSpi topologies only. + /// BootSpi (FMC) should use the generic Smc<FmcRegisterBackend> directly. + /// + /// # Safety + /// Caller must ensure unique ownership of the selected SPI hardware block. + pub unsafe fn new( + controller_id: SmcController, + mut config: SmcConfig, + ) -> Result<Self, SmcError> { + // Phase 3: Topology-aware SPI construction check. + // + // The SPI wrapper is specialized for HostSpi and NormalSpi topologies. + // FMC (BootSpi topology) uses the generic controller with FmcRegisterBackend. + // This check enforces that constraint at construction time. + match controller_id { + SmcController::Fmc => return Err(SmcError::InvalidChipSelect), + SmcController::Spi1 | SmcController::Spi2 => {} + } + + config.controller_id = controller_id; + // SAFETY: Caller upholds controller ownership requirements. + let inner = unsafe { UninitSmc::new(config)? }; + Ok(Self { inner }) + } + + /// Initialize SPI hardware and transition to ready state. + pub fn init(self) -> Result<SpiReady, SmcError> { + Ok(SpiReady { + inner: self.inner.init()?, + }) + } +} + +impl SpiReady { + /// Perform a programmed I/O read via the SPI flash window. + pub fn read(&self, cs: ChipSelect, offset: u32, buf: &mut [u8]) -> Result<usize, SmcError> { + self.inner.read(cs, offset, buf) + } + + /// Initiate a DMA read operation. + pub fn dma_read( + &mut self, + cs: ChipSelect, + flash_offset: u32, + dram_addr: usize, + len: u32, + ) -> Result<(), SmcError> { + self.inner.dma_read(cs, flash_offset, dram_addr, len) + } + + /// Read raw DMA/interrupt status bits from FMC008. + pub fn dma_status(&self) -> u32 { + self.inner.dma_status() + } + + /// Clear DMA-related status bits in FMC008 (write-1-to-clear). + pub fn clear_dma_status(&self, clear_mask: u32) { + self.inner.clear_dma_status(clear_mask) + } + + /// Handle DMA completion/error from IRQ status and finalize controller state. + pub fn handle_dma_irq(&mut self) -> Result<SmcInterrupt, SmcError> { + self.inner.handle_dma_irq() + } + + /// Poll for DMA completion without requiring an IRQ. See `Smc::poll_dma_completion`. + pub fn poll_dma_completion(&mut self) -> core::task::Poll<Result<(), SmcError>> { + self.inner.poll_dma_completion() + } + + /// Check if SPI controller is ready for operations. + pub fn is_ready(&self) -> bool { + self.inner.is_ready() + } + + /// Program memory-mapped SPI NOR read mode for the selected chip select. + pub fn spi_nor_read_init(&mut self, cs: ChipSelect) -> Result<(), SmcError> { + self.inner.spi_nor_read_init(cs) + } + + /// Return configured flash capacity in bytes. + pub fn capacity_bytes(&self) -> Result<usize, SmcError> { + self.inner.capacity_bytes() + } + + /// Return configured flash capacity in bytes for the given chip select. + pub fn cs_capacity_bytes(&self, cs: ChipSelect) -> Result<usize, SmcError> { + self.inner.cs_capacity_bytes(cs) + } + + /// Return the configured `FlashConfig` for the requested chip select. + pub fn cs_config(&self, cs: ChipSelect) -> Result<FlashConfig, SmcError> { + self.inner.cs_config(cs) + } + + /// Execute a raw user-mode SPI transfer on the selected SPI chip select. + /// + /// `cs` selects CS0 or CS1; `mode` controls the per-phase IO width. + /// Returns `SmcError::InvalidChipSelect` if CS1 is requested but not configured. + pub fn transceive_user( + &self, + cs: ChipSelect, + cmd: &[u8], + tx_payload: &[u8], + rx: &mut [u8], + mode: TransferMode, + ) -> Result<(), SmcError> { + self.inner.transceive_user(cs, cmd, tx_payload, rx, mode) + } + + /// Convenience wrapper: execute a user-mode transfer on CS0. + pub fn transceive_user_cs0( + &self, + cmd: &[u8], + tx_payload: &[u8], + rx: &mut [u8], + mode: TransferMode, + ) -> Result<(), SmcError> { + self.inner + .transceive_user(ChipSelect::Cs0, cmd, tx_payload, rx, mode) + } + + /// Access the underlying generic ready controller. + pub fn as_inner(&self) -> &ReadySmc { + &self.inner + } + + /// Mutable access to the underlying generic ready controller. + pub fn as_inner_mut(&mut self) -> &mut ReadySmc { + &mut self.inner + } +}
diff --git a/target/ast10x0/peripherals/smc/types.rs b/target/ast10x0/peripherals/smc/types.rs new file mode 100644 index 0000000..675c8f3 --- /dev/null +++ b/target/ast10x0/peripherals/smc/types.rs
@@ -0,0 +1,288 @@ +// Licensed under the Apache-2.0 license +// SPDX-License-Identifier: Apache-2.0 + +//! Type definitions and error handling + +use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; + +/// Terminal errors: operation failed, don't retry +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum SmcError { + /// Hardware error + HardwareError, + /// Timeout waiting for operation + Timeout, + /// DMA transfer aborted + DmaAborted, + /// DMA length doesn't match expected + DmaLengthMismatch, + /// Invalid chip select number + InvalidChipSelect, + /// Invalid or unsupported capacity + InvalidCapacity, + /// Device not supported + DeviceNotSupported, + /// Flash is write-protected + WriteProtected, + /// Write operation in progress + WriteInProgress, + /// Controller is not in the Ready state; call was made at wrong lifecycle stage + ControllerNotReady, + /// DMA was requested but `SmcConfig::dma_enabled` is false for this controller + DmaNotEnabled, +} + +/// Chip select index for a controller that may have multiple attached devices. +/// +/// Matches aspeed-rust's per-CS indexing. Use `Cs0` for single-device +/// controllers; `Cs1` requires `SmcConfig.cs1` to be populated. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum ChipSelect { + /// Primary chip select (CS0) — always valid when any flash is configured. + Cs0 = 0, + /// Secondary chip select (CS1) — valid only when `SmcConfig.cs1.is_some()`. + Cs1 = 1, +} + +impl NorFlashError for SmcError { + fn kind(&self) -> NorFlashErrorKind { + NorFlashErrorKind::Other + } +} + +/// Retryable errors (returned as WouldBlock in nb::Result) +#[derive(Clone, Copy, Debug)] +pub enum SmcRetryable { + /// Controller not ready + NotReady, + /// DMA transfer still in-flight + DmaTransferPending, +} + +impl From<SmcRetryable> for nb::Error<SmcError> { + fn from(_: SmcRetryable) -> Self { + nb::Error::WouldBlock + } +} + +/// Address width used when assembling SPI NOR command byte streams. +/// +/// Matches aspeed-rust's `AddressWidth` enum. The device layer uses this when +/// building opcode+address slices for `transceive_user`, ensuring the correct +/// number of address bytes is emitted rather than relying on implicit slicing. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum AddressWidth { + /// No address bytes (e.g. WREN, RDSR). + None, + /// 24-bit (3-byte) address — standard for ≤16 MB devices. + ThreeByte, + /// 32-bit (4-byte) address — required for >16 MB devices. + FourByte, +} + +impl AddressWidth { + /// Number of address bytes this variant represents. + #[must_use] + pub const fn byte_count(self) -> usize { + match self { + Self::None => 0, + Self::ThreeByte => 3, + Self::FourByte => 4, + } + } +} +/// +/// Matches the mode naming convention used by JESD216 and aspeed-rust. +/// The IO mode bits written to the CS control register per phase are derived +/// from this value by `TransferMode::cmd_io_bits()`, `addr_io_bits()`, and +/// `data_io_bits()`. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum TransferMode { + /// Single-wire command, address, and data (standard SPI) + Mode111, + /// Single-wire command and address, dual-wire data + Mode112, + /// Single-wire command, dual-wire address and data + Mode122, + /// Single-wire command and address, quad-wire data + Mode114, + /// Single-wire command, quad-wire address and data + Mode144, +} + +impl TransferMode { + /// IO mode bits for the command phase (bits [29:28] of CS ctrl register). + #[must_use] + pub const fn cmd_io_bits(self) -> u32 { + // Command phase is always single-wire across all supported modes. + 0x0000_0000 + } + + /// IO mode bits for the address phase. + #[must_use] + pub const fn addr_io_bits(self) -> u32 { + match self { + Self::Mode111 | Self::Mode112 | Self::Mode114 => 0x0000_0000, + Self::Mode122 | Self::Mode144 => 0x2000_0000, + } + } + + /// IO mode bits for the data phase. + #[must_use] + pub const fn data_io_bits(self) -> u32 { + match self { + Self::Mode111 => 0x0000_0000, + Self::Mode112 | Self::Mode122 => 0x2000_0000, + Self::Mode114 | Self::Mode144 => 0x4000_0000, + } + } +} + +/// SMC Controller identifier +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum SmcController { + /// Firmware Memory Controller (boot flash, primary) + Fmc = 0, + /// SPI Flash Controller 1 (secondary) + Spi1 = 1, + /// SPI Flash Controller 2 (tertiary) + Spi2 = 2, +} + +impl SmcController { + /// Get the base hardware address for this controller + pub fn base_address(&self) -> usize { + match self { + Self::Fmc => 0x7E620000, + Self::Spi1 => 0x7E630000, + Self::Spi2 => 0x7E640000, + } + } + + /// Get the memory-mapped flash window address + pub fn flash_window_address(&self) -> usize { + match self { + Self::Fmc => 0x80000000, + Self::Spi1 => 0x90000000, + Self::Spi2 => 0xB0000000, + } + } + + /// Get the IRQ vector number + pub fn irq_number(&self) -> u32 { + match self { + Self::Fmc => 39, + Self::Spi1 => 65, + Self::Spi2 => 66, + } + } +} + +/// Configuration for a single flash device +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct FlashConfig { + /// Device capacity in MB + pub capacity_mb: u32, + /// Page size in bytes (typically 256) + pub page_size: u32, + /// Sector size in bytes (typically 4096) + pub sector_size: u32, + /// Block size in bytes (typically 65536) + pub block_size: u32, + /// Desired SPI clock frequency in MHz + pub spi_clock_mhz: u32, +} + +impl FlashConfig { + /// Winbond W25Q64 (8 MB) configuration + pub const fn winbond_w25q64() -> Self { + Self { + capacity_mb: 8, + page_size: 256, + sector_size: 4096, + block_size: 65536, + spi_clock_mhz: 25, + } + } + + /// Winbond W25Q256 (32 MB) configuration + pub const fn winbond_w25q256() -> Self { + Self { + capacity_mb: 32, + page_size: 256, + sector_size: 4096, + block_size: 65536, + spi_clock_mhz: 25, + } + } +} + +/// SPI controller topology: role and master index +/// +/// Mirrors aspeed-rust's `ctrl_type` and `master_idx` concepts. +/// The topology determines decode-range sizing, calibration skip rules, +/// and other controller-specific behaviors that depend on the controller's +/// role in the system and its position in multi-channel arrangements. +/// +/// Mappings follow aspeed-rust conventions: +/// - FMC -> BootSpi { master_idx: 0 } +/// - SPI1 -> HostSpi { master_idx: 0 } +/// - SPI2 -> NormalSpi { master_idx: 2 } +/// +/// # Behavioral Differences by Variant +/// +/// ## BootSpi +/// - **Decode-range sizing:** Full 256 MB range from configured capacity +/// - **Calibration:** Run full timing sweep (exclusive master) +/// - **SPIM bracketing:** Not required (direct FMC path, no arbitration) +/// - **Use case:** Boot firmware with exclusive flash access +/// +/// ## HostSpi +/// - **Decode-range sizing:** 256 MB range (assumes single master on this interface) +/// - **Calibration:** Skip if `master_idx != 0` (shared-bus topology) +/// - **SPIM bracketing:** Required when `master_idx != 0` (shared with other masters) +/// - **Use case:** Host BMC SPI access; may be muxed with other masters +/// +/// ## NormalSpi +/// - **Decode-range sizing:** Per-master sizing; when `master_idx != 0`, decode may be restricted +/// - **Calibration:** Skip if `master_idx != 0` and `cs != 0` (shared topology) +/// - **SPIM bracketing:** Required when `master_idx != 0` (shared-bus topology) +/// - **Use case:** Normal user SPI access; often on shared external SPI buses +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum SmcTopology { + /// Boot firmware SPI interface + BootSpi { master_idx: u8 }, + /// Host BMC SPI interface + HostSpi { master_idx: u8 }, + /// Normal user SPI interface + NormalSpi { master_idx: u8 }, +} + +impl SmcTopology { + /// Get the master index (multiplex/channel ID) for this topology + #[must_use] + pub const fn master_idx(self) -> u8 { + match self { + Self::BootSpi { master_idx } => master_idx, + Self::HostSpi { master_idx } => master_idx, + Self::NormalSpi { master_idx } => master_idx, + } + } +} + +/// Per-controller configuration +#[derive(Clone, Copy, Debug)] +pub struct SmcConfig { + /// Which controller to configure + pub controller_id: SmcController, + /// Optional configuration for CS0 flash device + pub cs0: Option<FlashConfig>, + /// Optional configuration for CS1 flash device + pub cs1: Option<FlashConfig>, + /// Enable DMA transfers + pub dma_enabled: bool, + /// Enable interrupt handlers + pub enable_interrupts: bool, + /// Controller topology (role and master index) + pub topology: SmcTopology, +}
diff --git a/target/ast10x0/tests/smc/BUILD.bazel b/target/ast10x0/tests/smc/BUILD.bazel new file mode 100644 index 0000000..0e61d54 --- /dev/null +++ b/target/ast10x0/tests/smc/BUILD.bazel
@@ -0,0 +1,30 @@ +# Licensed under the Apache-2.0 license +# SPDX-License-Identifier: Apache-2.0 + +exports_files( + ["target_debug.rs"], + visibility = [ + "//target/ast10x0/tests/smc/dma_irq:__pkg__", + "//target/ast10x0/tests/smc/read:__pkg__", + ], +) + +alias( + name = "smc_read_test", + actual = "//target/ast10x0/tests/smc/read:smc_read_test", +) + +alias( + name = "smc_read_evb_test", + actual = "//target/ast10x0/tests/smc/read:smc_read_evb_test", +) + +alias( + name = "smc_irq_test", + actual = "//target/ast10x0/tests/smc/dma_irq:smc_irq_test", +) + +alias( + name = "smc_irq_evb_test", + actual = "//target/ast10x0/tests/smc/dma_irq:smc_irq_evb_test", +)
diff --git a/target/ast10x0/tests/smc/README.md b/target/ast10x0/tests/smc/README.md new file mode 100644 index 0000000..68c375e --- /dev/null +++ b/target/ast10x0/tests/smc/README.md
@@ -0,0 +1,50 @@ +# AST10x0 SMC Test Package + +This package is now a compatibility layer and shared helper location. + +## Current organization + +Active SMC test flows are split into dedicated subpackages: + +- `//target/ast10x0/tests/smc/read` +- `//target/ast10x0/tests/smc/dma_irq` + +The parent package (`//target/ast10x0/tests/smc`) keeps only: + +- Compatibility aliases: + - `smc_read_test` + - `smc_read_evb_test` + - `smc_irq_test` + - `smc_irq_evb_test` +- Shared debug helper export: `target_debug.rs` + +## Canonical targets + +Use these subpackage labels as canonical: + +- Read flow image: `//target/ast10x0/tests/smc/read:smc_read_test` +- Read flow runnable EVB test: `//target/ast10x0/tests/smc/read:smc_read_evb_test` +- DMA IRQ flow image: `//target/ast10x0/tests/smc/dma_irq:smc_irq_test` +- DMA IRQ flow runnable EVB test: `//target/ast10x0/tests/smc/dma_irq:smc_irq_evb_test` + +Legacy compatibility aliases in this package resolve to the same targets. + +## Run on AST1060 EVB + +Read flow: + +```bash +AST1060_EVB_PI_HOST=<pi-hostname-or-ip> \ + bazel test --config=k_ast1060_evb \ + //target/ast10x0/tests/smc/read:smc_read_evb_test +``` + +DMA IRQ flow: + +```bash +AST1060_EVB_PI_HOST=<pi-hostname-or-ip> \ + bazel test --config=k_ast1060_evb \ + //target/ast10x0/tests/smc/dma_irq:smc_irq_evb_test +``` + +Both flows are hardware-only by design. \ No newline at end of file
diff --git a/target/ast10x0/tests/smc/dma_irq/BUILD.bazel b/target/ast10x0/tests/smc/dma_irq/BUILD.bazel new file mode 100644 index 0000000..2a98169 --- /dev/null +++ b/target/ast10x0/tests/smc/dma_irq/BUILD.bazel
@@ -0,0 +1,79 @@ +# Licensed under the Apache-2.0 license +# SPDX-License-Identifier: Apache-2.0 + +load("@pigweed//pw_kernel/tooling:system_image.bzl", "system_image", "system_image_test") +load("@pigweed//pw_kernel/tooling:target_codegen.bzl", "target_codegen") +load("@pigweed//pw_kernel/tooling:target_linker_script.bzl", "target_linker_script") +load("@pigweed//pw_kernel/tooling/panic_detector:rust_binary_no_panics_test.bzl", "rust_binary_no_panics_test") +load("@rules_rust//rust:defs.bzl", "rust_binary") +load("//target/ast10x0:defs.bzl", "TARGET_COMPATIBLE_WITH") + +filegroup( + name = "system_config", + srcs = ["system.json5"], +) + +target_codegen( + name = "codegen", + arch = "@pigweed//pw_kernel/arch/arm_cortex_m:arch_arm_cortex_m", + system_config = ":system_config", + target_compatible_with = TARGET_COMPATIBLE_WITH, +) + +target_linker_script( + name = "linker_script", + system_config = ":system_config", + tags = ["kernel"], + target_compatible_with = TARGET_COMPATIBLE_WITH, + template = "//target/ast10x0:linker_script_template", +) + +rust_binary( + name = "target", + srcs = [ + "target.rs", + "//target/ast10x0/tests/smc:target_debug.rs", + ], + edition = "2024", + tags = ["kernel"], + target_compatible_with = TARGET_COMPATIBLE_WITH, + deps = [ + ":codegen", + ":linker_script", + "//target/ast10x0:entry", + "//target/ast10x0/peripherals", + "@pigweed//pw_kernel/arch/arm_cortex_m:arch_arm_cortex_m", + "@pigweed//pw_kernel/kernel", + "@pigweed//pw_kernel/subsys/console:console_backend", + "@pigweed//pw_kernel/target:target_common", + "@pigweed//pw_log/rust:pw_log", + ], +) + +system_image( + name = "smc_irq_test", + kernel = ":target", + platform = "//target/ast10x0", + system_config = ":system_config", + tags = ["kernel"], + target_compatible_with = TARGET_COMPATIBLE_WITH, + userspace = False, + visibility = ["//visibility:public"], +) + +system_image_test( + name = "smc_irq_evb_test", + image = ":smc_irq_test", + tags = ["hardware"], + target_compatible_with = select({ + "//target/ast10x0:qemu_enabled": ["@platforms//:incompatible"], + "//conditions:default": [], + }), + visibility = ["//visibility:public"], +) + +rust_binary_no_panics_test( + name = "no_panics_test", + binary = ":smc_irq_test", + tags = ["kernel"], +)
diff --git a/target/ast10x0/tests/smc/dma_irq/README.md b/target/ast10x0/tests/smc/dma_irq/README.md new file mode 100644 index 0000000..a9de49c --- /dev/null +++ b/target/ast10x0/tests/smc/dma_irq/README.md
@@ -0,0 +1,17 @@ +# SMC DMA IRQ Test (EVB-only) + +This package contains the SMC DMA IRQ test flow split out from the parent SMC package. + +## Targets + +- Image: `//target/ast10x0/tests/smc/dma_irq:smc_irq_test` +- Runnable EVB test: `//target/ast10x0/tests/smc/dma_irq:smc_irq_evb_test` +- Panic detector: `//target/ast10x0/tests/smc/dma_irq:no_panics_test` + +## Run on AST1060 EVB + +```bash +AST1060_EVB_PI_HOST=<pi-hostname-or-ip> \ + bazel test --config=k_ast1060_evb \ + //target/ast10x0/tests/smc/dma_irq:smc_irq_evb_test +```
diff --git a/target/ast10x0/tests/smc/dma_irq/system.json5 b/target/ast10x0/tests/smc/dma_irq/system.json5 new file mode 100644 index 0000000..ed5fedc --- /dev/null +++ b/target/ast10x0/tests/smc/dma_irq/system.json5
@@ -0,0 +1,23 @@ +// Licensed under the Apache-2.0 license +// SPDX-License-Identifier: Apache-2.0 + +// AST10x0 kernel-only SMC DMA IRQ test configuration. +{ + arch: { + type: "armv7m", + vector_table_start_address: 0x00000000, + vector_table_size_bytes: 1280, + }, + kernel: { + flash_start_address: 0x00000500, + flash_size_bytes: 262144, + ram_start_address: 0x00040500, + ram_size_bytes: 393216, + interrupt_table: { + table: { + // FMC IRQ. + "39": "crate::fmc_dma_irq_handler", + }, + }, + }, +}
diff --git a/target/ast10x0/tests/smc/dma_irq/target.rs b/target/ast10x0/tests/smc/dma_irq/target.rs new file mode 100644 index 0000000..6828cb1 --- /dev/null +++ b/target/ast10x0/tests/smc/dma_irq/target.rs
@@ -0,0 +1,194 @@ +// Licensed under the Apache-2.0 license +// SPDX-License-Identifier: Apache-2.0 + +//! AST10x0 SMC DMA-read interrupt completion test target. +//! +//! Tests (in order): +//! +//! 1. **Init with DMA interrupts enabled** -- construct the FMC controller, +//! apply FMC pinmux, initialize hardware, and assert the controller is ready. +//! 2. **DMA read kick-off** -- start a valid CS0 DMA read and assert the +//! controller moves out of Ready while the transfer is in flight. +//! 3. **IRQ completion path** -- the FMC IRQ handler records that the interrupt +//! fired, then main context completes the transfer through `handle_dma_irq()` +//! rather than polling the DMA status register. +//! 4. **Ready after IRQ** -- assert the IRQ completion path clears state and +//! returns the controller to Ready. + +#![no_std] +#![no_main] + +use core::sync::atomic::{AtomicBool, AtomicU32, Ordering}; +use core::task::Poll; + +use arch_arm_cortex_m::Arch; +use ast10x0_peripherals::scu::ScuRegisters; +use ast10x0_peripherals::scu::pinctrl::PINCTRL_FMC_QUAD; +use ast10x0_peripherals::smc::{ + ChipSelect, FlashConfig, SmcConfig, SmcController, SmcError, SmcInterrupt, SmcTopology, + UninitSmc, +}; +use codegen as _; +use console_backend::console_backend_write_all; +use kernel::Arch as KernelArch; +use kernel::Kernel; +use target_common::{TargetInterface, declare_target}; +use {console_backend as _, entry as _}; + +#[path = "../target_debug.rs"] +mod target_debug; +use target_debug::{dump_smc_read, dump_smc_register}; + +pub struct Target {} + +const FLASH_CFG: FlashConfig = FlashConfig { + capacity_mb: 16, + page_size: 256, + sector_size: 4096, + block_size: 65536, + spi_clock_mhz: 50, +}; + +const DMA_FLASH_OFFSET: u32 = 0x500; +const DMA_DRAM_ADDR: usize = 0x0004_1000; +const DMA_LEN: u32 = 256; +const FMC_IRQ: u32 = 39; +const DMA_IRQ_TIMEOUT: u32 = 0x00010_0000; + +static FMC_DMA_IRQ_FIRED: AtomicBool = AtomicBool::new(false); +static FMC_DMA_IRQ_COUNT: AtomicU32 = AtomicU32::new(0); + +fn read_u32(addr: usize) -> u32 { + unsafe { core::ptr::read_volatile(addr as *const u32) } +} + +fn dump_nvic_irq_state(irq: u32) { + let word = (irq / 32) as usize; + let bit = irq % 32; + let mask = 1u32 << bit; + let iser = read_u32(0xE000_E100 + (word * 4)); + let ispr = read_u32(0xE000_E200 + (word * 4)); + let iabr = read_u32(0xE000_E300 + (word * 4)); + + pw_log::info!( + "NVIC irq={} word={} bit={} mask=0x{:08x} ISER=0x{:08x} ISPR=0x{:08x} IABR=0x{:08x}", + irq as u32, + word as u32, + bit as u32, + mask as u32, + iser as u32, + ispr as u32, + iabr as u32, + ); +} + +pub fn fmc_dma_irq_handler<K: Kernel>(_kernel: K) { + FMC_DMA_IRQ_COUNT.fetch_add(1, Ordering::AcqRel); + FMC_DMA_IRQ_FIRED.store(true, Ordering::Release); + <<Arch as KernelArch>::InterruptController as kernel::interrupt_controller::InterruptController>::disable_interrupt( + FMC_IRQ, + ); +} + +fn poll_dma_irq_completion( + controller: &mut ast10x0_peripherals::smc::ReadySmc, +) -> Poll<Result<(), SmcError>> { + if !FMC_DMA_IRQ_FIRED.swap(false, Ordering::AcqRel) { + return Poll::Pending; + } + + match controller.handle_dma_irq() { + Ok(SmcInterrupt::DmaComplete) => Poll::Ready(Ok(())), + Ok(_) => Poll::Ready(Err(SmcError::HardwareError)), + Err(err) => Poll::Ready(Err(err)), + } +} + +fn run_dma_read_irq_test() -> Result<(), SmcError> { + let scu = unsafe { ScuRegisters::new_global_unlocked() }; + scu.apply_pinctrl_group(PINCTRL_FMC_QUAD); + + let config = SmcConfig { + controller_id: SmcController::Fmc, + cs0: Some(FLASH_CFG), + cs1: None, + dma_enabled: true, + enable_interrupts: true, + topology: SmcTopology::BootSpi { master_idx: 0 }, + }; + + let uninit = unsafe { UninitSmc::new(config)? }; + let mut controller = uninit.init()?; + + controller.spi_nor_read_init(ChipSelect::Cs0)?; + + if !controller.is_ready() || controller.controller_id() != SmcController::Fmc { + return Err(SmcError::HardwareError); + } + + FMC_DMA_IRQ_FIRED.store(false, Ordering::Release); + FMC_DMA_IRQ_COUNT.store(0, Ordering::Release); + <<Arch as KernelArch>::InterruptController as kernel::interrupt_controller::InterruptController>::enable_interrupt( + FMC_IRQ, + ); + dump_nvic_irq_state(FMC_IRQ); + + pw_log::info!("SMC DMA IRQ: starting DMA read"); + dump_smc_register(0x7E62_0000, 8); + dump_smc_register(0x7E62_0080, 8); + controller.dma_read(ChipSelect::Cs0, DMA_FLASH_OFFSET, DMA_DRAM_ADDR, DMA_LEN)?; + pw_log::info!("after calling dma_read()"); + dump_smc_register(0x7E62_0000, 8); + dump_smc_register(0x7E62_0080, 8); + if controller.is_ready() { + return Err(SmcError::HardwareError); + } + + for _ in 0..DMA_IRQ_TIMEOUT { + match poll_dma_irq_completion(&mut controller) { + Poll::Ready(result) => { + result?; + if !controller.is_ready() { + return Err(SmcError::HardwareError); + } + pw_log::info!("SMC DMA IRQ: DMA read completed via IRQ"); + let dma_buf = unsafe { + core::slice::from_raw_parts(DMA_DRAM_ADDR as *const u8, DMA_LEN as usize) + }; + dump_smc_register(0x7E62_0000, 8); + dump_smc_register(0x7E62_0080, 8); + dump_smc_read(dma_buf, DMA_LEN); + return Ok(()); + } + Poll::Pending => core::hint::spin_loop(), + } + } + pw_log::info!("dma Timeout"); + pw_log::info!( + "FMC IRQ count={}", + FMC_DMA_IRQ_COUNT.load(Ordering::Acquire) as u32 + ); + pw_log::info!( + "FMC DMA status at timeout=0x{:08x}", + controller.dma_status() as u32 + ); + dump_nvic_irq_state(FMC_IRQ); + Err(SmcError::Timeout) +} + +codegen::declare_kernel_interrupt_handlers!(); +declare_target!(Target); + +impl TargetInterface for Target { + const NAME: &'static str = "AST10x0 SMC DMA Read IRQ Test"; + + fn main() -> ! { + let sentinel: &[u8] = match run_dma_read_irq_test() { + Ok(()) => b"TEST_RESULT:PASS\n", + Err(_) => b"TEST_RESULT:FAIL\n", + }; + let _ = console_backend_write_all(sentinel); + #[expect(clippy::empty_loop)] + loop {} + } +}
diff --git a/target/ast10x0/tests/smc/read/BUILD.bazel b/target/ast10x0/tests/smc/read/BUILD.bazel new file mode 100644 index 0000000..1e649f7 --- /dev/null +++ b/target/ast10x0/tests/smc/read/BUILD.bazel
@@ -0,0 +1,80 @@ +# Licensed under the Apache-2.0 license +# SPDX-License-Identifier: Apache-2.0 + +load("@pigweed//pw_kernel/tooling:system_image.bzl", "system_image", "system_image_test") +load("@pigweed//pw_kernel/tooling:target_codegen.bzl", "target_codegen") +load("@pigweed//pw_kernel/tooling:target_linker_script.bzl", "target_linker_script") +load("@pigweed//pw_kernel/tooling/panic_detector:rust_binary_no_panics_test.bzl", "rust_binary_no_panics_test") +load("@rules_rust//rust:defs.bzl", "rust_binary") +load("//target/ast10x0:defs.bzl", "TARGET_COMPATIBLE_WITH") + +filegroup( + name = "system_config", + srcs = ["system.json5"], +) + +target_codegen( + name = "codegen", + arch = "@pigweed//pw_kernel/arch/arm_cortex_m:arch_arm_cortex_m", + system_config = ":system_config", + target_compatible_with = TARGET_COMPATIBLE_WITH, +) + +target_linker_script( + name = "linker_script", + system_config = ":system_config", + tags = ["kernel"], + target_compatible_with = TARGET_COMPATIBLE_WITH, + template = "//target/ast10x0:linker_script_template", +) + +rust_binary( + name = "target", + srcs = [ + "target.rs", + "//target/ast10x0/tests/smc:target_debug.rs", + ], + edition = "2024", + tags = ["kernel"], + target_compatible_with = TARGET_COMPATIBLE_WITH, + deps = [ + ":codegen", + ":linker_script", + "//target/ast10x0:entry", + "//target/ast10x0/peripherals", + "@pigweed//pw_kernel/arch/arm_cortex_m:arch_arm_cortex_m", + "@pigweed//pw_kernel/kernel", + "@pigweed//pw_kernel/subsys/console:console_backend", + "@pigweed//pw_kernel/target:target_common", + "@pigweed//pw_log/rust:pw_log", + "@rust_crates//:cortex-m-semihosting", + ], +) + +system_image( + name = "smc_read_test", + kernel = ":target", + platform = "//target/ast10x0", + system_config = ":system_config", + tags = ["kernel"], + target_compatible_with = TARGET_COMPATIBLE_WITH, + userspace = False, + visibility = ["//visibility:public"], +) + +system_image_test( + name = "smc_read_evb_test", + image = ":smc_read_test", + tags = ["hardware"], + target_compatible_with = select({ + "//target/ast10x0:qemu_enabled": ["@platforms//:incompatible"], + "//conditions:default": [], + }), + visibility = ["//visibility:public"], +) + +rust_binary_no_panics_test( + name = "no_panics_test", + binary = ":smc_read_test", + tags = ["kernel"], +)
diff --git a/target/ast10x0/tests/smc/read/README.md b/target/ast10x0/tests/smc/read/README.md new file mode 100644 index 0000000..d4b89cb --- /dev/null +++ b/target/ast10x0/tests/smc/read/README.md
@@ -0,0 +1,17 @@ +# SMC Read Test (EVB-only) + +This package contains the SMC read path test flow split out from the parent SMC package. + +## Targets + +- Image: `//target/ast10x0/tests/smc/read:smc_read_test` +- Runnable EVB test: `//target/ast10x0/tests/smc/read:smc_read_evb_test` +- Panic detector: `//target/ast10x0/tests/smc/read:no_panics_test` + +## Run on AST1060 EVB + +```bash +AST1060_EVB_PI_HOST=<pi-hostname-or-ip> \ + bazel test --config=k_ast1060_evb \ + //target/ast10x0/tests/smc/read:smc_read_evb_test +```
diff --git a/target/ast10x0/tests/smc/read/system.json5 b/target/ast10x0/tests/smc/read/system.json5 new file mode 100644 index 0000000..ed5fedc --- /dev/null +++ b/target/ast10x0/tests/smc/read/system.json5
@@ -0,0 +1,23 @@ +// Licensed under the Apache-2.0 license +// SPDX-License-Identifier: Apache-2.0 + +// AST10x0 kernel-only SMC DMA IRQ test configuration. +{ + arch: { + type: "armv7m", + vector_table_start_address: 0x00000000, + vector_table_size_bytes: 1280, + }, + kernel: { + flash_start_address: 0x00000500, + flash_size_bytes: 262144, + ram_start_address: 0x00040500, + ram_size_bytes: 393216, + interrupt_table: { + table: { + // FMC IRQ. + "39": "crate::fmc_dma_irq_handler", + }, + }, + }, +}
diff --git a/target/ast10x0/tests/smc/read/target.rs b/target/ast10x0/tests/smc/read/target.rs new file mode 100644 index 0000000..6915acb --- /dev/null +++ b/target/ast10x0/tests/smc/read/target.rs
@@ -0,0 +1,160 @@ +// Licensed under the Apache-2.0 license +// SPDX-License-Identifier: Apache-2.0 + +//! AST10x0 SMC portable smoke test target. +//! +//! Safe to run on both QEMU and silicon. Does not assert on flash content +//! because silicon flash will not be in the erased state. +//! +//! Tests (in order): +//! +//! 1. **Init** — construct FMC controller, run hardware init, assert Ready. +//! 2. **PIO read — success path** — issue a read from offset 0; assert the +//! call succeeds and returns the expected byte count. Flash content is not +//! inspected. +//! 3. **PIO read — bounds rejection** — assert that a read past the configured +//! capacity returns `SmcError::InvalidCapacity` before touching hardware. +//! 4. **DMA disabled rejection** — assert that `dma_read` returns +//! `SmcError::DmaNotEnabled` when `SmcConfig::dma_enabled` is false. + +#![no_std] +#![no_main] +#[allow(unused_imports)] +use ast10x0_peripherals::scu::pinctrl::PINCTRL_FMC_QUAD; +use ast10x0_peripherals::scu::ScuRegisters; +use ast10x0_peripherals::smc::{ + ChipSelect, FlashConfig, SmcConfig, SmcController, SmcError, SmcTopology, UninitSmc, +}; +use console_backend::console_backend_write_all; +use target_common::{declare_target, TargetInterface}; +use {console_backend as _, entry as _}; + +#[path = "../target_debug.rs"] +mod target_debug; +use target_debug::{dump_smc_read, dump_smc_register}; + +pub struct Target {} + +#[allow(dead_code)] +fn run_smc_read_test() -> Result<(), SmcError> { + // --- 1. Init --- + // TODO:: set pinctrl in board/src/lib.rs + let scu = unsafe { ScuRegisters::new_global_unlocked() }; + scu.apply_pinctrl_group(PINCTRL_FMC_QUAD); + + let config = SmcConfig { + controller_id: SmcController::Fmc, + + cs0: Some(FlashConfig { + capacity_mb: 8, + page_size: 256, + sector_size: 4096, + block_size: 65536, + spi_clock_mhz: 50, + }), + cs1: Some(FlashConfig { + capacity_mb: 64, + page_size: 256, + sector_size: 4096, + block_size: 65536, + spi_clock_mhz: 50, + }), + dma_enabled: true, + enable_interrupts: false, + topology: SmcTopology::BootSpi { master_idx: 0 }, + }; + pw_log::info!("=== AST10x0 smc read test ==="); + let controller = unsafe { UninitSmc::new(config)? }; + let mut controller = controller.init()?; + + let _ = match controller.spi_nor_read_init(ChipSelect::Cs0) { + Ok(v) => v, + Err(e) => { + pw_log::info!("Error:: spi_nor_read_init cs0"); + return Err(e); + } + }; + let _ = match controller.spi_nor_read_init(ChipSelect::Cs1) { + Ok(v) => v, + Err(e) => { + pw_log::info!("Error:: spi_nor_read_init cs1"); + return Err(e); + } + }; + + pw_log::info!("=== Dump 0x7E62_0000 ==="); + dump_smc_register(0x7E62_0000, 16); + dump_smc_register(0x8000_0000, 16); + if !controller.is_ready() || controller.controller_id() != SmcController::Fmc { + return Err(SmcError::HardwareError); + } + + // --- 2. MMIO read — success path --- + // Confirm the call succeeds and returns the correct byte count. Flash + // content is not inspected so this is safe on both QEMU and silicon. + // TODO: need to add test CS1 + pw_log::info!("=== read test cs0==="); + let mut buf = [0u8; 64]; + let n = controller.read(ChipSelect::Cs0, 0x400, &mut buf)?; + if n != 64 { + return Err(SmcError::HardwareError); + } + dump_smc_read(&buf, 64); + + pw_log::info!("=== read test cs1==="); + let n = controller.read(ChipSelect::Cs1, 0x400, &mut buf)?; + if n != 64 { + return Err(SmcError::HardwareError); + } + dump_smc_read(&buf, 64); + + pw_log::info!("=== read dma test==="); + // --- 4. DMA --- + let tempbuf = unsafe { core::slice::from_raw_parts(0x41000 as *mut u8, 256) }; + + let _ = match controller.dma_read(ChipSelect::Cs0, 0x500, 0x41000 as usize, 256) { + Err(SmcError::InvalidCapacity) => Ok(()), + Err(other) => Err(other), + Ok(()) => Err(SmcError::HardwareError), + }; + + loop { + match controller.poll_dma_completion() { + core::task::Poll::Pending => { + // still running + } + core::task::Poll::Ready(result) => { + result?; + pw_log::info!("dma completion is ready"); + break; + } + } + } + + pw_log::info!("=== dma done= =="); + dump_smc_register(0x7E62_0000, 8); + dump_smc_register(0x7E62_0080, 8); + dump_smc_read(tempbuf, 256); + + Ok(()) +} + +impl TargetInterface for Target { + const NAME: &'static str = "AST10x0 SMC read Test"; + + fn main() -> ! { + let sentinel = if run_smc_read_test().is_ok() { + b"TEST_RESULT:PASS\n" + } else { + b"TEST_RESULT:FAIL\n" + }; + let _ = console_backend_write_all(sentinel); + + // Physical-board UART tests stop after the sentinel. Semihosting exit + // faults on silicon when no debugger handles the BKPT request. + #[expect(clippy::empty_loop)] + loop {} + } +} + +declare_target!(Target);
diff --git a/target/ast10x0/tests/smc/target_debug.rs b/target/ast10x0/tests/smc/target_debug.rs new file mode 100644 index 0000000..38e7ee8 --- /dev/null +++ b/target/ast10x0/tests/smc/target_debug.rs
@@ -0,0 +1,29 @@ +// Licensed under the Apache-2.0 license +// SPDX-License-Identifier: Apache-2.0 + +use core::ptr::read_volatile; + +#[allow(dead_code)] +pub fn dump_smc_register(addr: u32, count: u32) { + for i in 0..count { + let reg_addr = addr + (i * 4); + let reg = unsafe { read_volatile(reg_addr as *const u32) }; + + pw_log::info!("SMC[0x{:08x}] = 0x{:08x}", reg_addr as u32, reg as u32); + } +} + +#[allow(dead_code)] +pub fn dump_smc_read(buf: &[u8], count: u32) { + let count = core::cmp::min(count as usize, buf.len()); + for i in (0..count).step_by(4) { + if i + 4 > count { + break; + } + + let bytes: [u8; 4] = buf[i..i + 4].try_into().unwrap(); + let value = u32::from_le_bytes(bytes); + + pw_log::info!("[0x{:08x}] = 0x{:08x}", i as u32, value as u32); + } +}
diff --git a/third_party/crates_io/Cargo.lock b/third_party/crates_io/Cargo.lock index 8f14999..0d2e3a7 100644 --- a/third_party/crates_io/Cargo.lock +++ b/third_party/crates_io/Cargo.lock
@@ -490,6 +490,12 @@ ] [[package]] +name = "embedded-storage" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032" + +[[package]] name = "equivalent" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1295,6 +1301,7 @@ "embedded-hal-async", "embedded-hal-nb", "embedded-io", + "embedded-storage", "fugit", "futures", "heapless 0.9.2",
diff --git a/third_party/crates_io/Cargo.toml b/third_party/crates_io/Cargo.toml index 112ca9c..c878162 100644 --- a/third_party/crates_io/Cargo.toml +++ b/third_party/crates_io/Cargo.toml
@@ -45,6 +45,7 @@ embedded-hal = "1.0" embedded-hal-async = "1.0" embedded-hal-nb = "1.0" +embedded-storage = "0.3" hex-literal = "0.4" nb = "1.1" fugit = "0.3.7"