commit 1bbfc98a0afc2b8091dbd983e69f1cc5de4bc4e2 Author: Robin Mueller Date: Wed Feb 19 11:00:04 2025 +0100 init commit diff --git a/.cargo/def-config.toml b/.cargo/def-config.toml new file mode 100644 index 0000000..a2dd61b --- /dev/null +++ b/.cargo/def-config.toml @@ -0,0 +1,33 @@ +[target.armv7a-none-eabihf] +runner = "./scripts/runner.sh" + +rustflags = [ + "-Ctarget-cpu=cortex-a9", + "-Ctarget-feature=+vfp3", + "-Ctarget-feature=+neon", + "-Clink-arg=-Tlink.x", + # If this is not enabled, debugging / stepping can become problematic. + "-Cforce-frame-pointers=yes", + # Can be useful for debugging. + # "-Clink-args=-Map=app.map" +] + +# Tier 3 target, so no pre-compiled artifacts included. +[unstable] +build-std = ["core", "alloc"] + +[build] +target = "armv7a-none-eabihf" + +[env] +# The following two env variables need to be set for the supplied runner.sh script to work. + +# Absolute path to the Vitis install directory. +# AMD_TOOLS = "/tools/Xilinx/Vitis/2024.1" +# Absolute path to the PS7 initialization TCL script. +# TCL_INIT_SCRIPT = "/home/$user/$project/$sdt_dir/ps7_init.tcl" + +# Absolute path to the Zynq bitstream file, which will be flashed to the target before +# running the application. You only need to do this once for unchanged bitstream as long as you +# do not reset the whole board. +# ZYNQ_BITSTREAM = "/home/$user/$project/$sdt_dir/bitstream.bit" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cad995a --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +/target +/app.map +/xsct-output.log +/.vscode +/Cargo.lock +/.cargo/config.toml diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..8bc810b --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[workspace] +resolver = "3" +members = [ + "zynq7000-rt", + "zynq7000", + "zynq7000-hal", + "zynq7000-embassy", + "examples/simple", + "examples/embassy", + "examples/zedboard", +] +exclude = ["experiments"] diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..8311204 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Robin A. Mueller + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..c5f7ef2 --- /dev/null +++ b/NOTICE @@ -0,0 +1 @@ +This software contains code developed at the University of Stuttgart. diff --git a/README.md b/README.md new file mode 100644 index 0000000..13c32ad --- /dev/null +++ b/README.md @@ -0,0 +1,164 @@ +Zynq 7000 Bare-Metal Rust Support +========= + +This crate collection provides support to write bare-metal Rust applications for the AMD Zynq 7000 +family of SoCs. + +# List of crates + +This workspace contains the following released crates: + +- The [`zynq7000-rt`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq7000-rt) + run-time crate containing basic low-level startup code necessary to boot a Rust app on the + Zynq7000. +- The [`zynq7000`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq7000) PAC + crate containing basic low-level register definition. +- The [`zynq7000-hal`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq7000-hal) + HAL crate containing higher-level abstractions on top of the PAC register crate. +- The [`zynq7000-embassy`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq7000-embassy) + crate containing support for running the embassy-rs RTOS. + +It also contains the following helper crates: + +- The [`examples`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/examples) + folder contains various example applications crates using the HAL and the PAC. + This folder also contains dedicated example applications using the + [`embassy`](https://github.com/embassy-rs/embassy) native Rust RTOS. + +The [`zedboard-fpga-design`](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zedboard-fpga-design) +folder contains a sample FPGA design and block design which was used in +some of the provided software examples. The project was created with Vivado version 2024.1. +The folder contains a README with all the steps required to load this project from a TCL script. + +# Using the `.cargo/config.toml` file + +Use the following command to have a starting `config.toml` file + +```sh +cp .cargo/def-config.toml .cargo/config.toml +``` + +You then can adapt the `config.toml` to your needs. For example, you can configure runners +to conveniently flash with `cargo run`. + +# Using the sample VS Code files + +Use the following command to have a starting configuration for VS Code: + +```sh +cp -rT vscode .vscode +``` + +You can then adapt the files in `.vscode` to your needs. + +# Building the blinky example + +Building an application requires `nightly` to build the `core` and `alloc` library +because the `thumbv7a-none-eabihf` Rust target only has Tier 3 support +If you have not installed it yet, you can do so with + +```sh +rustup toolchain install nightly +``` + +Assuming you have the following segments inside your `.cargo/config.toml` + +```toml +[target.armv7a-none-eabihf] +rustflags = [ + "-Ctarget-cpu=cortex-a9", + "-Ctarget-feature=+vfp3", + "-Ctarget-feature=+neon", + "-Clink-arg=-Tlink.x", + # If this is not enabled, debugging / stepping can become problematic. + "-Cforce-frame-pointers=yes", + # Can be useful for debugging. + # "-Clink-args=-Map=app.map" +] + +# Tier 3 target, so no pre-compiled artifacts included. +[unstable] +build-std = ["core", "alloc"] + +[build] +target = "armv7a-none-eabihf" +``` + +You can build the blinky example app using + +```sh +cargo build --example simple +``` + + +## Flashing, running and debugging the software + +This repository was only tested with the [Zedboard](https://digilent.com/reference/programmable-logic/zedboard/start) +but should be easily adaptable to other Zynq7000 based platforms and boards. + +If you want to test and use this crate on a Zedboard, make sure that the board jumpers on the +Zedboard are configured for JTAG boot. + +### Pre-Requisites + +- [`xsct`](https://docs.amd.com/r/en-US/ug1165-zynq-embedded-design-tutorial/XSCT-Xilinx-Software-Command-Tool) + tool installation. You have to install the [Vitis tool](https://www.xilinx.com/support/download/index.html/content/xilinx/en/downloadNav/vitis.html) + to get access to this tool. You can minimize the download size by de-selecting all SoC families + that you do not require. Vitis also includes a Vivado installation which is required to do + anything with the FPGA. +- [`hw_server`](https://docs.amd.com/r/en-US/ug908-vivado-programming-debugging/Connecting-to-a-Hardware-Target-Using-hw_server) + installation which is generally included with Vitis/Vivado. This tool starts a GDB server + which will be used to connect to and debug the target board. It also allows initializing the + processing system and uploading the FPGA design via JTAG. +- A valid `ps7_init.tcl` script to configure the processing system. This is necessary to even + be able flashing application into the DDR via JTAG. There are multiple ways to generate this + startup script, but the recommended way here is to the the `sdtgen` tool included in `xsct` which + also generates a bitstream for the FPGA configuration. You can find a sample `ps7_init.tcl` + script inside the `scripts` folder. However, it is strongly recommended to get familiar with + Vivado and generate the SDT folder yourself. +- `gdb-multiarch` installation to debug applications. +- `python3` installation to use the provided tooling. + +### Programming and Debug Flow + +1. Start the `hw_server` application first. This is required for other tooling provided by this + repository as well. + +2. The provided `scripts/zynq7000-init.py` script can be used to initialize the processing system + with the `ps7_init.tcl` script, program the bitstream, and load an ELF file to the DDR. + You can run `scripts/zynq7000-init.py` to get some help and additional information. + Here is an example command to initialize the processing system without loading a bitstream + using the provided initialization script (adapt `AMD_TOOLS` to your system): + + ```sh + export AMD_TOOLS="/tools/Xilinx/Vitis/2024.1" + ./scripts/zynq7000-init.py --itcl ./scripts/ps7_init.tcl + ``` + +3. Assuming you have managed to build the blinky example, you can flash the example now + using GDB: + + ```sh + gdb-multiarch -q -x gdb.gdb target/armv7a-none-eabihf/debug/blinky + ``` + + You can use the `-tui` argument to also have a terminal UI. + This repository provides a `scripts/runner.sh` which performs all the steps specified above. + The `.cargo/def-config.toml` script contains the runner and some template environmental + variables that need to be set for this to work. The command above also loaded the app, but + this task can be performed by the `zynq7000-init.py` wrapper as well. + +# Using VS Code + +The provided VS Code configuration files can be used to perform the CLI steps specified above +in a GUI completely and to also have a graphical debugging interface. You can use this +as a starting point for your own application. You need to adapt the `options.env` variables +in `.vscode/tasks.json` for this to work. + +# Embedded Rust + +If you have not done this yet, it is recommended to read some of the excellent resources available +to learn Rust: + +- [Rust Embedded Book](https://docs.rust-embedded.org/book/) +- [Rust Discovery Book](https://docs.rust-embedded.org/discovery/) diff --git a/examples/embassy/Cargo.toml b/examples/embassy/Cargo.toml new file mode 100644 index 0000000..3d973e3 --- /dev/null +++ b/examples/embassy/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "embassy-examples" +version = "0.1.0" +authors = ["Robin Mueller "] +edition = "2024" +description = "Embassy examples for the Zynq7000 SoC" +homepage = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs" +repository = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs" +license = "MIT OR Apache-2.0" +keywords = ["no-std", "arm", "cortex-a", "amd", "zynq7000"] +categories = ["embedded", "no-std", "hardware-support"] + +[dependencies] +cortex-ar = { path = "/home/rmueller/Rust/cortex-ar/cortex-ar", features = ["critical-section-single-core"] } +zynq7000-rt = { path = "../../zynq7000-rt" } +zynq7000 = { path = "../../zynq7000" } +zynq7000-hal = { path = "../../zynq7000-hal" } +zynq7000-embassy = { path = "../../zynq7000-embassy" } +static_cell = "2" +critical-section = "1" +heapless = "0.8" +embedded-io = "0.6" +embedded-hal = "1" +fugit = "0.3" +log = "0.4" + +embassy-executor = { path = "/home/rmueller/Rust/embassy/embassy-executor", features = [ + "arch-cortex-ar", + "executor-thread", + "task-arena-size-65536" +]} +embassy-time = { path = "/home/rmueller/Rust/embassy/embassy-time", version = "0.4" } diff --git a/examples/embassy/src/bin/logger-non-blocking.rs b/examples/embassy/src/bin/logger-non-blocking.rs new file mode 100644 index 0000000..aceb583 --- /dev/null +++ b/examples/embassy/src/bin/logger-non-blocking.rs @@ -0,0 +1,151 @@ +//! Example which uses the UART1 to send log messages. +#![no_std] +#![no_main] + +use core::panic::PanicInfo; +use cortex_ar::asm::nop; +use embassy_executor::Spawner; +use embassy_time::{Duration, Ticker}; +use embedded_hal::digital::StatefulOutputPin; +use embedded_io::Write; +use log::{error, info}; +use zynq7000::PsPeripherals; +use zynq7000_hal::{ + BootMode, + clocks::Clocks, + gic::{GicConfigurator, GicInterruptHelper, Interrupt}, + gpio::{Mio7, MioPin, MioPins, Output, PinState}, + gtc::Gtc, + time::Hertz, + uart::{ClkConfigRaw, TxAsync, Uart, UartConfig, on_interrupt_tx}, +}; + +use zynq7000_rt as _; + +// Define the clock frequency as a constant +const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_300); + +/// Entry point (not called like a normal main function) +#[unsafe(no_mangle)] +pub extern "C" fn boot_core(cpu_id: u32) -> ! { + if cpu_id != 0 { + panic!("unexpected CPU ID {}", cpu_id); + } + main(); +} + +#[unsafe(export_name = "main")] +#[embassy_executor::main] +async fn main(spawner: Spawner) -> ! { + let dp = PsPeripherals::take().unwrap(); + // Clock was already initialized by PS7 Init TCL script or FSBL, we just read it. + let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap(); + // Set up the global interrupt controller. + let mut gic = GicConfigurator::new_with_init(dp.gicc, dp.gicd); + gic.enable_all_interrupts(); + gic.set_all_spi_interrupt_targets_cpu0(); + gic.enable(); + unsafe { + gic.enable_interrupts(); + } + // Set up global timer counter and embassy time driver. + let gtc = Gtc::new(dp.gtc, clocks.arm_clocks()); + zynq7000_embassy::init(clocks.arm_clocks(), gtc); + + let mio_pins = MioPins::new(dp.gpio); + + // Set up the UART, we are logging with it. + let uart_clk_config = ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200) + .unwrap() + .0; + let uart_tx = mio_pins.mio48.into_uart(); + let uart_rx = mio_pins.mio49.into_uart(); + let mut uart = Uart::new_with_mio( + dp.uart_1, + UartConfig::new_with_clk_config(uart_clk_config), + (uart_tx, uart_rx), + ) + .unwrap(); + uart.write_all(b"-- Zynq 7000 Logging example --\n\r") + .unwrap(); + uart.flush().unwrap(); + let (tx, _rx) = uart.split(); + let mut logger = TxAsync::new(tx); + + zynq7000_hal::log::rb::init(log::LevelFilter::Trace); + + let boot_mode = BootMode::new(); + info!("Boot mode: {:?}", boot_mode); + + let led = mio_pins.mio7.into_output(PinState::Low); + spawner.spawn(led_task(led)).unwrap(); + let mut log_buf: [u8; 2048] = [0; 2048]; + let frame_queue = zynq7000_hal::log::rb::get_frame_queue(); + loop { + let next_frame_len = frame_queue.receive().await; + zynq7000_hal::log::rb::read_next_frame(next_frame_len, &mut log_buf); + logger.write(&log_buf[0..next_frame_len]).await; + } +} + +#[embassy_executor::task] +async fn led_task(mut mio_led: MioPin) { + let mut ticker = Ticker::every(Duration::from_millis(1000)); + loop { + mio_led.toggle().unwrap(); + info!("Toggling LED"); + ticker.next().await; + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _irq_handler() { + let mut gic_helper = GicInterruptHelper::new(); + let irq_info = gic_helper.acknowledge_interrupt(); + match irq_info.interrupt() { + Interrupt::Sgi(_) => (), + Interrupt::Ppi(ppi_interrupt) => { + if ppi_interrupt == zynq7000_hal::gic::PpiInterrupt::GlobalTimer { + unsafe { + zynq7000_embassy::on_interrupt(); + } + } + } + Interrupt::Spi(spi_interrupt) => { + if spi_interrupt == zynq7000_hal::gic::SpiInterrupt::Uart1 { + on_interrupt_tx(zynq7000_hal::uart::UartId::Uart1); + } + } + Interrupt::Invalid(_) => (), + Interrupt::Spurious => (), + } + gic_helper.end_of_interrupt(irq_info); +} + +#[unsafe(no_mangle)] +pub extern "C" fn _abort_handler() { + loop { + nop(); + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _undefined_handler() { + loop { + nop(); + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _prefetch_handler() { + loop { + nop(); + } +} + +/// Panic handler +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + error!("Panic: {:?}", info); + loop {} +} diff --git a/examples/embassy/src/bin/pwm.rs b/examples/embassy/src/bin/pwm.rs new file mode 100644 index 0000000..14c76c9 --- /dev/null +++ b/examples/embassy/src/bin/pwm.rs @@ -0,0 +1,159 @@ +//! PWM example which uses a PWM pin routed through EMIO. +//! +//! This example puts the PWM output on the EMIO channel of TTC0 channel 0. +//! +//! On the Zedboard, the PWM waveform output will be on the W12 pin of PMOD JB1. The Zedboard +//! reference FPGA design must be flashed onto the Zedboard for this to work. +#![no_std] +#![no_main] + +use core::panic::PanicInfo; +use cortex_ar::asm::nop; +use embassy_executor::Spawner; +use embassy_time::{Duration, Ticker}; +use embedded_hal::{digital::StatefulOutputPin, pwm::SetDutyCycle}; +use embedded_io::Write; +use fugit::RateExtU32; +use log::{error, info}; +use zynq7000_hal::{ + BootMode, + clocks::Clocks, + gic::{GicConfigurator, GicInterruptHelper, Interrupt}, + gpio::{MioPins, PinState}, + gtc::Gtc, + time::Hertz, + uart::{ClkConfigRaw, Uart, UartConfig}, +}; + +use zynq7000::PsPeripherals; +use zynq7000_rt as _; + +// Define the clock frequency as a constant +const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_300); + +/// Entry point (not called like a normal main function) +#[unsafe(no_mangle)] +pub extern "C" fn boot_core(cpu_id: u32) -> ! { + if cpu_id != 0 { + panic!("unexpected CPU ID {}", cpu_id); + } + main(); +} + +#[embassy_executor::main] +#[unsafe(export_name = "main")] +async fn main(_spawner: Spawner) -> ! { + let dp = PsPeripherals::take().unwrap(); + // Clock was already initialized by PS7 Init TCL script or FSBL, we just read it. + let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap(); + // Set up the global interrupt controller. + let mut gic = GicConfigurator::new_with_init(dp.gicc, dp.gicd); + gic.enable_all_interrupts(); + gic.set_all_spi_interrupt_targets_cpu0(); + gic.enable(); + unsafe { + gic.enable_interrupts(); + } + let mio_pins = MioPins::new(dp.gpio); + + // Set up global timer counter and embassy time driver. + let gtc = Gtc::new(dp.gtc, clocks.arm_clocks()); + zynq7000_embassy::init(clocks.arm_clocks(), gtc); + + // Unwrap is okay, the address is definitely valid. + let ttc_0 = zynq7000_hal::ttc::Ttc::new(dp.ttc_0).unwrap(); + let mut pwm = + zynq7000_hal::ttc::Pwm::new_with_cpu_clk(ttc_0.ch0, clocks.arm_clocks(), 1000.Hz()) + .unwrap(); + pwm.set_duty_cycle_percent(50).unwrap(); + + // Set up the UART, we are logging with it. + let uart_clk_config = ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200) + .unwrap() + .0; + let uart_tx = mio_pins.mio48.into_uart(); + let uart_rx = mio_pins.mio49.into_uart(); + let mut uart = Uart::new_with_mio( + dp.uart_1, + UartConfig::new_with_clk_config(uart_clk_config), + (uart_tx, uart_rx), + ) + .unwrap(); + uart.write_all(b"-- Zynq 7000 Embassy Hello World --\n\r") + .unwrap(); + // Safety: We are not multi-threaded yet. + unsafe { + zynq7000_hal::log::uart_blocking::init_unsafe_single_core( + uart, + log::LevelFilter::Trace, + false, + ) + }; + + let boot_mode = BootMode::new(); + info!("Boot mode: {:?}", boot_mode); + + let mut ticker = Ticker::every(Duration::from_millis(1000)); + let mut led = mio_pins.mio7.into_output(PinState::Low); + let mut current_duty = 0; + loop { + led.toggle().unwrap(); + + pwm.set_duty_cycle_percent(current_duty).unwrap(); + info!("Setting duty cycle to {}%", current_duty); + current_duty += 5; + if current_duty > 100 { + current_duty = 0; + } + + ticker.next().await; + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _irq_handler() { + let mut gic_helper = GicInterruptHelper::new(); + let irq_info = gic_helper.acknowledge_interrupt(); + match irq_info.interrupt() { + Interrupt::Sgi(_) => (), + Interrupt::Ppi(ppi_interrupt) => { + if ppi_interrupt == zynq7000_hal::gic::PpiInterrupt::GlobalTimer { + unsafe { + zynq7000_embassy::on_interrupt(); + } + } + } + Interrupt::Spi(_spi_interrupt) => (), + Interrupt::Invalid(_) => (), + Interrupt::Spurious => (), + } + gic_helper.end_of_interrupt(irq_info); +} + +#[unsafe(no_mangle)] +pub extern "C" fn _abort_handler() { + loop { + nop(); + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _undefined_handler() { + loop { + nop(); + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _prefetch_handler() { + loop { + nop(); + } +} + +/// Panic handler +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + error!("Panic: {:?}", info); + loop {} +} diff --git a/examples/embassy/src/main.rs b/examples/embassy/src/main.rs new file mode 100644 index 0000000..a70da10 --- /dev/null +++ b/examples/embassy/src/main.rs @@ -0,0 +1,138 @@ +#![no_std] +#![no_main] + +use core::panic::PanicInfo; +use cortex_ar::asm::nop; +use embassy_executor::Spawner; +use embassy_time::{Duration, Ticker}; +use embedded_hal::digital::StatefulOutputPin; +use embedded_io::Write; +use log::{error, info}; +use zynq7000_hal::{ + BootMode, + clocks::Clocks, + gic::{GicConfigurator, GicInterruptHelper, Interrupt}, + gpio::{MioPins, PinState}, + gtc::Gtc, + time::Hertz, + uart::{ClkConfigRaw, Uart, UartConfig}, +}; + +use zynq7000::PsPeripherals; +use zynq7000_rt as _; + +// Define the clock frequency as a constant +const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_300); + +/// Entry point (not called like a normal main function) +#[unsafe(no_mangle)] +pub extern "C" fn boot_core(cpu_id: u32) -> ! { + if cpu_id != 0 { + panic!("unexpected CPU ID {}", cpu_id); + } + main(); +} + +// TODO: The export name is ignored.. +#[embassy_executor::main] +#[unsafe(export_name = "main")] +async fn main(_spawner: Spawner) -> ! { + let dp = PsPeripherals::take().unwrap(); + // Clock was already initialized by PS7 Init TCL script or FSBL, we just read it. + let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap(); + // Set up the global interrupt controller. + let mut gic = GicConfigurator::new_with_init(dp.gicc, dp.gicd); + gic.enable_all_interrupts(); + gic.set_all_spi_interrupt_targets_cpu0(); + gic.enable(); + unsafe { + gic.enable_interrupts(); + } + let mio_pins = MioPins::new(dp.gpio); + + // Set up global timer counter and embassy time driver. + let gtc = Gtc::new(dp.gtc, clocks.arm_clocks()); + zynq7000_embassy::init(clocks.arm_clocks(), gtc); + + // Set up the UART, we are logging with it. + let uart_clk_config = ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200) + .unwrap() + .0; + let uart_tx = mio_pins.mio48.into_uart(); + let uart_rx = mio_pins.mio49.into_uart(); + let mut uart = Uart::new_with_mio( + dp.uart_1, + UartConfig::new_with_clk_config(uart_clk_config), + (uart_tx, uart_rx), + ) + .unwrap(); + uart.write_all(b"-- Zynq 7000 Embassy Hello World --\n\r") + .unwrap(); + // Safety: We are not multi-threaded yet. + unsafe { + zynq7000_hal::log::uart_blocking::init_unsafe_single_core( + uart, + log::LevelFilter::Trace, + false, + ) + }; + + let boot_mode = BootMode::new(); + info!("Boot mode: {:?}", boot_mode); + + let mut ticker = Ticker::every(Duration::from_millis(1000)); + let mut led = mio_pins.mio7.into_output(PinState::Low); + loop { + info!("Hello, world!"); + led.toggle().unwrap(); + ticker.next().await; + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _irq_handler() { + let mut gic_helper = GicInterruptHelper::new(); + let irq_info = gic_helper.acknowledge_interrupt(); + match irq_info.interrupt() { + Interrupt::Sgi(_) => (), + Interrupt::Ppi(ppi_interrupt) => { + if ppi_interrupt == zynq7000_hal::gic::PpiInterrupt::GlobalTimer { + unsafe { + zynq7000_embassy::on_interrupt(); + } + } + } + Interrupt::Spi(_spi_interrupt) => (), + Interrupt::Invalid(_) => (), + Interrupt::Spurious => (), + } + gic_helper.end_of_interrupt(irq_info); +} + +#[unsafe(no_mangle)] +pub extern "C" fn _abort_handler() { + loop { + nop(); + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _undefined_handler() { + loop { + nop(); + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _prefetch_handler() { + loop { + nop(); + } +} + +/// Panic handler +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + error!("Panic: {:?}", info); + loop {} +} diff --git a/examples/simple/Cargo.toml b/examples/simple/Cargo.toml new file mode 100644 index 0000000..73f14ad --- /dev/null +++ b/examples/simple/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "blinky" +version = "0.1.0" +authors = ["Robin Mueller "] +edition = "2024" +description = "Simple examples for the Zynq7000 SoC" +homepage = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs" +repository = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs" +license = "MIT OR Apache-2.0" + +[dependencies] +cortex-ar = { git = "https://github.com/us-irs/cortex-ar.git", branch = "cortex-a-addition", features = ["critical-section-single-core"] } +zynq7000-rt = { path = "../../zynq7000-rt" } +zynq7000 = { path = "../../zynq7000" } +zynq7000-hal = { path = "../../zynq7000-hal" } +embedded-io = "0.6" +embedded-hal = "1" +fugit = "0.3" +log = "0.4" diff --git a/examples/simple/src/bin/gtc-ticks.rs b/examples/simple/src/bin/gtc-ticks.rs new file mode 100644 index 0000000..565d673 --- /dev/null +++ b/examples/simple/src/bin/gtc-ticks.rs @@ -0,0 +1,138 @@ +//! Example which uses the global timer for a simple tick counter. +#![no_std] +#![no_main] + +use core::{panic::PanicInfo, sync::atomic::AtomicU64}; +use cortex_ar::asm::nop; +use embedded_hal::digital::StatefulOutputPin; +use embedded_io::Write; +use log::{error, info}; +use zynq7000_hal::{ + clocks::Clocks, + gic::{GicConfigurator, GicInterruptHelper, Interrupt}, + gpio::{MioPins, PinState}, + gtc::Gtc, + prelude::*, + time::Hertz, + uart::{ClkConfigRaw, Uart, UartConfig}, +}; + +use zynq7000_rt as _; + +// Define the clock frequency as a constant +const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_300); + +static MS_TICKS: AtomicU64 = AtomicU64::new(0); + +/// Entry point (not called like a normal main function) +#[unsafe(no_mangle)] +pub extern "C" fn boot_core(cpu_id: u32) -> ! { + if cpu_id != 0 { + panic!("unexpected CPU ID {}", cpu_id); + } + main(); +} + +#[unsafe(export_name = "main")] +pub fn main() -> ! { + let dp = zynq7000::PsPeripherals::take().unwrap(); + // Clock was already initialized by PS7 Init TCL script or FSBL, we just read it. + let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap(); + // Set up the global interrupt controller. + let mut gic = GicConfigurator::new_with_init(dp.gicc, dp.gicd); + gic.enable_all_interrupts(); + gic.set_all_spi_interrupt_targets_cpu0(); + gic.enable(); + // Enable interrupt exception. + unsafe { gic.enable_interrupts() }; + // Set up the UART, we are logging with it. + let uart_clk_config = ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200) + .unwrap() + .0; + let mut gtc = Gtc::new(dp.gtc, clocks.arm_clocks()); + let ticks = gtc.frequency_to_ticks(1000.Hz()); + gtc.set_auto_increment_value(ticks); + gtc.set_comparator(gtc.read_timer() + ticks as u64); + gtc.enable_auto_increment(); + gtc.enable_interrupt(); + gtc.enable(); + + // This structure holds all MIO pins. + let mio_pins = MioPins::new(dp.gpio); + let uart_tx = mio_pins.mio48.into_uart(); + let uart_rx = mio_pins.mio49.into_uart(); + let mut uart = Uart::new_with_mio( + dp.uart_1, + UartConfig::new_with_clk_config(uart_clk_config), + (uart_tx, uart_rx), + ) + .unwrap(); + uart.write_all(b"-- Zynq 7000 GTC Ticks example --\n\r") + .unwrap(); + // Safety: We are not multi-threaded yet. + unsafe { + zynq7000_hal::log::uart_blocking::init_unsafe_single_core( + uart, + log::LevelFilter::Trace, + false, + ) + }; + + let mut led = mio_pins.mio7.into_output(PinState::Low); + loop { + info!( + "MS_TICKS: {}", + MS_TICKS.load(core::sync::atomic::Ordering::Relaxed) + ); + led.toggle().unwrap(); + for _ in 0..5_000_000 { + nop(); + } + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _irq_handler() { + let mut gic_helper = GicInterruptHelper::new(); + let irq_info = gic_helper.acknowledge_interrupt(); + match irq_info.interrupt() { + Interrupt::Sgi(_) => (), + Interrupt::Ppi(ppi_interrupt) => { + if ppi_interrupt == zynq7000_hal::gic::PpiInterrupt::GlobalTimer { + MS_TICKS.fetch_add(1, core::sync::atomic::Ordering::Relaxed); + } + } + Interrupt::Spi(_spi_interrupt) => (), + Interrupt::Invalid(_) => (), + Interrupt::Spurious => (), + } + gic_helper.end_of_interrupt(irq_info); +} + +#[unsafe(no_mangle)] +pub extern "C" fn _abort_handler() { + loop { + nop(); + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _undefined_handler() { + loop { + nop(); + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _prefetch_handler() { + loop { + nop(); + } +} + +/// Panic handler +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + error!("Panic: {:?}", info); + loop {} +} diff --git a/examples/simple/src/bin/logger.rs b/examples/simple/src/bin/logger.rs new file mode 100644 index 0000000..0e9a460 --- /dev/null +++ b/examples/simple/src/bin/logger.rs @@ -0,0 +1,141 @@ +//! Example which uses the UART1 to send log messages. +#![no_std] +#![no_main] + +use core::{panic::PanicInfo, sync::atomic::AtomicU64}; +use cortex_ar::asm::nop; +use embedded_hal::digital::StatefulOutputPin; +use embedded_io::Write; +use log::{error, info}; +use zynq7000_hal::{ + BootMode, + clocks::Clocks, + gic::{GicConfigurator, GicInterruptHelper, Interrupt}, + gpio::{MioPins, PinState}, + gtc::Gtc, + prelude::*, + time::Hertz, + uart::{ClkConfigRaw, Uart, UartConfig}, +}; + +use zynq7000_rt as _; + +// Define the clock frequency as a constant +const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_300); + +static MS_TICKS: AtomicU64 = AtomicU64::new(0); + +/// Entry point (not called like a normal main function) +#[unsafe(no_mangle)] +pub extern "C" fn boot_core(cpu_id: u32) -> ! { + if cpu_id != 0 { + panic!("unexpected CPU ID {}", cpu_id); + } + main(); +} + +#[unsafe(export_name = "main")] +pub fn main() -> ! { + let dp = zynq7000::PsPeripherals::take().unwrap(); + // Clock was already initialized by PS7 Init TCL script or FSBL, we just read it. + let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap(); + // Set up the global interrupt controller. + let mut gic = GicConfigurator::new_with_init(dp.gicc, dp.gicd); + gic.enable_all_interrupts(); + gic.set_all_spi_interrupt_targets_cpu0(); + gic.enable(); + // Enable interrupt exception. + unsafe { gic.enable_interrupts() }; + // Set up the UART, we are logging with it. + let uart_clk_config = ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200) + .unwrap() + .0; + let mut gtc = Gtc::new(dp.gtc, clocks.arm_clocks()); + let ticks = gtc.frequency_to_ticks(1000.Hz()); + gtc.set_auto_increment_value(ticks); + gtc.set_comparator(gtc.read_timer() + ticks as u64); + gtc.enable_auto_increment(); + gtc.enable_interrupt(); + gtc.enable(); + let mio_pins = MioPins::new(dp.gpio); + let uart_tx = mio_pins.mio48.into_uart(); + let uart_rx = mio_pins.mio49.into_uart(); + + let mut uart = Uart::new_with_mio( + dp.uart_1, + UartConfig::new_with_clk_config(uart_clk_config), + (uart_tx, uart_rx), + ) + .unwrap(); + uart.write_all(b"-- Zynq 7000 Logging example --\n\r") + .unwrap(); + // Safety: We are not multi-threaded yet. + unsafe { + zynq7000_hal::log::uart_blocking::init_unsafe_single_core( + uart, + log::LevelFilter::Trace, + false, + ) + }; + + let boot_mode = BootMode::new(); + info!("Boot mode: {:?}", boot_mode); + + let mut led = mio_pins.mio7.into_output(PinState::Low); + loop { + let gtc = gtc.read_timer(); + info!("Hello, world!"); + info!("GTC ticks: {}", gtc); + led.toggle().unwrap(); + for _ in 0..5_000_000 { + nop(); + } + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _irq_handler() { + let mut gic_helper = GicInterruptHelper::new(); + let irq_info = gic_helper.acknowledge_interrupt(); + match irq_info.interrupt() { + Interrupt::Sgi(_) => (), + Interrupt::Ppi(ppi_interrupt) => { + if ppi_interrupt == zynq7000_hal::gic::PpiInterrupt::GlobalTimer { + // TODO: Call embassy on interrupt handler here soon. + MS_TICKS.fetch_add(1, core::sync::atomic::Ordering::Relaxed); + } + } + Interrupt::Spi(_spi_interrupt) => (), + Interrupt::Invalid(_) => (), + Interrupt::Spurious => (), + } + gic_helper.end_of_interrupt(irq_info); +} + +#[unsafe(no_mangle)] +pub extern "C" fn _abort_handler() { + loop { + nop(); + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _undefined_handler() { + loop { + nop(); + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _prefetch_handler() { + loop { + nop(); + } +} + +/// Panic handler +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + error!("Panic: {:?}", info); + loop {} +} diff --git a/examples/simple/src/main.rs b/examples/simple/src/main.rs new file mode 100644 index 0000000..2dd7555 --- /dev/null +++ b/examples/simple/src/main.rs @@ -0,0 +1,90 @@ +//! Simple blinky app, showing a PAC variant and a HAL variant. +#![no_std] +#![no_main] + +use core::panic::PanicInfo; +use cortex_ar::asm::nop; +use embedded_hal::digital::StatefulOutputPin; +use zynq7000::PsPeripherals; +use zynq7000_hal::gpio::{MioPins, PinState}; +use zynq7000_rt as _; + +/// One user LED is MIO7 +const ZEDBOARD_LED_MASK: u32 = 1 << 7; + +#[derive(Debug)] +pub enum Lib { + Pac, + Hal, +} + +const LIB: Lib = Lib::Hal; + +/// Entry point (not called like a normal main function) +#[unsafe(no_mangle)] +pub extern "C" fn boot_core(cpu_id: u32) -> ! { + if cpu_id != 0 { + panic!("unexpected CPU ID {}", cpu_id); + } + main(); +} + +#[unsafe(export_name = "main")] +pub fn main() -> ! { + match LIB { + Lib::Pac => { + let mut gpio = unsafe { zynq7000::gpio::Gpio::new_mmio_fixed() }; + gpio.bank_0().modify_dirm(|v| v | ZEDBOARD_LED_MASK); + gpio.bank_0().modify_out_en(|v| v | ZEDBOARD_LED_MASK); + loop { + gpio.modify_out_0(|v| v ^ ZEDBOARD_LED_MASK); + for _ in 0..5_000_000 { + nop(); + } + } + } + Lib::Hal => { + let dp = PsPeripherals::take().unwrap(); + let mio_pins = MioPins::new(dp.gpio); + let mut led = mio_pins.mio7.into_output(PinState::High); + loop { + led.toggle().unwrap(); + for _ in 0..5_000_000 { + nop(); + } + } + } + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _irq_handler() {} + +#[unsafe(no_mangle)] +pub extern "C" fn _abort_handler() { + loop { + nop(); + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _undefined_handler() { + loop { + nop(); + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _prefetch_handler() { + loop { + nop(); + } +} + +/// Panic handler +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + loop { + nop(); + } +} diff --git a/examples/zedboard/Cargo.toml b/examples/zedboard/Cargo.toml new file mode 100644 index 0000000..16dd211 --- /dev/null +++ b/examples/zedboard/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "zedboard" +version = "0.1.0" +authors = ["Robin Mueller "] +edition = "2024" +description = "Embassy examples for the Zynq7000 SoC" +homepage = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs" +repository = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs" +license = "MIT OR Apache-2.0" +keywords = ["no-std", "arm", "cortex-a", "amd", "zynq7000"] +categories = ["embedded", "no-std", "hardware-support"] + +[dependencies] +cortex-ar = { git = "https://github.com/us-irs/cortex-ar.git", branch = "cortex-a-addition", features = ["critical-section-single-core"] } +zynq7000-rt = { path = "../../zynq7000-rt" } +zynq7000 = { path = "../../zynq7000" } +zynq7000-hal = { path = "../../zynq7000-hal" } +zynq7000-embassy = { path = "../../zynq7000-embassy" } +l3gd20 = { git = "https://github.com/us-irs/l3gd20.git", branch = "add-async-if" } +embedded-io = "0.6" +arbitrary-int = "1.3" +embedded-io-async = "0.6" +critical-section = "1" +static_cell = "2" +embedded-alloc = "0.6" +embedded-hal = "1" +embedded-hal-async = "1" +fugit = "0.3" +log = "0.4" + +embassy-executor = { path = "/home/rmueller/Rust/embassy/embassy-executor", features = [ + "arch-cortex-ar", + "executor-thread" +]} +embassy-time = { path = "/home/rmueller/Rust/embassy/embassy-time", version = "0.4" } +heapless = "0.8" +axi-uartlite = { path = "/home/rmueller/Rust/axi-uartlite-rs" } +axi-uart16550 = { path = "/home/rmueller/Rust/axi-uart16550-rs" } diff --git a/examples/zedboard/src/bin/l3gd20h-i2c-mio.rs b/examples/zedboard/src/bin/l3gd20h-i2c-mio.rs new file mode 100644 index 0000000..c6b3471 --- /dev/null +++ b/examples/zedboard/src/bin/l3gd20h-i2c-mio.rs @@ -0,0 +1,202 @@ +//! PS I2C example using a L3GD20H sensor. +//! +//! External HW connections: +//! +//! - SCK pin to JE4 (MIO 12) +//! - SDA pin to JE1 (MIO 13) +//! - SDO / SA0 pin to JE3 (MIO 11) to select I2C address. +#![no_std] +#![no_main] + +use core::panic::PanicInfo; +use cortex_ar::asm::nop; +use embassy_executor::Spawner; +use embassy_time::{Delay, Duration, Ticker}; +use embedded_hal::digital::StatefulOutputPin; +use embedded_hal_async::delay::DelayNs; +use embedded_io::Write; +use l3gd20::i2c::I2cAddr; +use log::{error, info}; +use zynq7000_hal::{ + BootMode, + clocks::Clocks, + configure_level_shifter, + gic::{GicConfigurator, GicInterruptHelper, Interrupt}, + gpio::{EmioPin, GpioPins, PinState}, + gtc::Gtc, + i2c, + time::Hertz, + uart, +}; + +use zynq7000::{PsPeripherals, slcr::LevelShifterConfig}; +use zynq7000_rt as _; + +// Define the clock frequency as a constant +const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_300); +const I2C_ADDR_SEL: I2cAddr = I2cAddr::Sa0Low; + +/// Entry point (not called like a normal main function) +#[unsafe(no_mangle)] +pub extern "C" fn boot_core(cpu_id: u32) -> ! { + if cpu_id != 0 { + panic!("unexpected CPU ID {}", cpu_id); + } + main(); +} + +#[embassy_executor::main] +#[unsafe(export_name = "main")] +async fn main(_spawner: Spawner) -> ! { + // Enable PS-PL level shifters. + configure_level_shifter(LevelShifterConfig::EnableAll); + let dp = PsPeripherals::take().unwrap(); + // Clock was already initialized by PS7 Init TCL script or FSBL, we just read it. + let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap(); + + // Set up the global interrupt controller. + let mut gic = GicConfigurator::new_with_init(dp.gicc, dp.gicd); + gic.enable_all_interrupts(); + gic.set_all_spi_interrupt_targets_cpu0(); + gic.enable(); + unsafe { + gic.enable_interrupts(); + } + + let mut gpio_pins = GpioPins::new(dp.gpio); + + // Set up global timer counter and embassy time driver. + let gtc = Gtc::new(dp.gtc, clocks.arm_clocks()); + zynq7000_embassy::init(clocks.arm_clocks(), gtc); + + // Set up the UART, we are logging with it. + let uart_clk_config = uart::ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200) + .unwrap() + .0; + let uart_tx = gpio_pins.mio.mio48.into_uart(); + let uart_rx = gpio_pins.mio.mio49.into_uart(); + let mut uart = uart::Uart::new_with_mio( + dp.uart_1, + uart::UartConfig::new_with_clk_config(uart_clk_config), + (uart_tx, uart_rx), + ) + .unwrap(); + uart.write_all(b"-- Zynq 7000 Zedboard I2C L3GD20H example --\n\r") + .unwrap(); + // Safety: We are not multi-threaded yet. + unsafe { + zynq7000_hal::log::uart_blocking::init_unsafe_single_core( + uart, + log::LevelFilter::Trace, + false, + ) + }; + + let boot_mode = BootMode::new(); + info!("Boot mode: {:?}", boot_mode); + + let sck_pin = gpio_pins.mio.mio12.into_i2c(); + let sda_pin = gpio_pins.mio.mio13.into_i2c(); + let pin_sel = match I2C_ADDR_SEL { + I2cAddr::Sa0Low => PinState::Low, + I2cAddr::Sa0High => PinState::High, + }; + let _sa0_pin = gpio_pins.mio.mio11.into_output(pin_sel); + // The CS pin must be pulled high. + let _cs_pin = gpio_pins.mio.mio10.into_output(PinState::High); + + let clk_config = i2c::calculate_divisors( + clocks.arm_clocks().cpu_1x_clk(), + i2c::I2cSpeed::Normal100kHz, + ) + .unwrap(); + let i2c = i2c::I2c::new_with_mio(dp.i2c_1, clk_config, (sck_pin, sda_pin)).unwrap(); + let mut l3gd20 = l3gd20::i2c::L3gd20::new(i2c, l3gd20::i2c::I2cAddr::Sa0Low).unwrap(); + let who_am_i = l3gd20.who_am_i().unwrap(); + info!("L3GD20 WHO_AM_I: 0x{:02X}", who_am_i); + + let mut delay = Delay; + let mut ticker = Ticker::every(Duration::from_millis(400)); + let mut mio_led = gpio_pins.mio.mio7.into_output(PinState::Low); + + let mut emio_leds: [EmioPin; 8] = [ + gpio_pins.emio.take(0).unwrap(), + gpio_pins.emio.take(1).unwrap(), + gpio_pins.emio.take(2).unwrap(), + gpio_pins.emio.take(3).unwrap(), + gpio_pins.emio.take(4).unwrap(), + gpio_pins.emio.take(5).unwrap(), + gpio_pins.emio.take(6).unwrap(), + gpio_pins.emio.take(7).unwrap(), + ]; + for (idx, led) in emio_leds.iter_mut().enumerate() { + if idx % 2 == 0 { + led.into_output(PinState::High); + } else { + led.into_output(PinState::Low); + } + } + + // Power up time for the sensor to get good readings. + delay.delay_ms(50).await; + loop { + mio_led.toggle().unwrap(); + + let measurements = l3gd20.all().unwrap(); + info!("L3GD20: {:?}", measurements); + info!("L3GD20 Temp: {:?}", measurements.temp_celcius()); + for led in emio_leds.iter_mut() { + led.toggle().unwrap(); + } + + ticker.next().await; // Wait for the next cycle of the ticker + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _irq_handler() { + let mut gic_helper = GicInterruptHelper::new(); + let irq_info = gic_helper.acknowledge_interrupt(); + match irq_info.interrupt() { + Interrupt::Sgi(_) => (), + Interrupt::Ppi(ppi_interrupt) => { + if ppi_interrupt == zynq7000_hal::gic::PpiInterrupt::GlobalTimer { + unsafe { + zynq7000_embassy::on_interrupt(); + } + } + } + Interrupt::Spi(_spi_interrupt) => (), + Interrupt::Invalid(_) => (), + Interrupt::Spurious => (), + } + gic_helper.end_of_interrupt(irq_info); +} + +#[unsafe(no_mangle)] +pub extern "C" fn _abort_handler() { + loop { + nop(); + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _undefined_handler() { + loop { + nop(); + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _prefetch_handler() { + loop { + nop(); + } +} + +/// Panic handler +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + error!("Panic: {:?}", info); + loop {} +} diff --git a/examples/zedboard/src/bin/l3gd20h-spi-mio.rs b/examples/zedboard/src/bin/l3gd20h-spi-mio.rs new file mode 100644 index 0000000..87ca3b5 --- /dev/null +++ b/examples/zedboard/src/bin/l3gd20h-spi-mio.rs @@ -0,0 +1,293 @@ +//! PS SPI example using a L3GD20H sensor. +//! +//! External HW connections: +//! +//! - SCK pin to JE4 (MIO 12) +//! - MOSI pin to JE2 (MIO 10) +//! - MISO pin to JE3 (MIO 11) +//! - SS pin to JE1 (MIO 13) +#![no_std] +#![no_main] + +use core::panic::PanicInfo; +use cortex_ar::asm::nop; +use embassy_executor::Spawner; +use embassy_time::{Delay, Duration, Ticker}; +use embedded_hal::digital::StatefulOutputPin; +use embedded_hal_async::delay::DelayNs; +use embedded_io::Write; +use log::{error, info}; +use zynq7000_hal::{ + BootMode, + clocks::Clocks, + configure_level_shifter, + gic::{GicConfigurator, GicInterruptHelper, Interrupt}, + gpio::{DynMioPin, EmioPin, GpioPins, PinState}, + gtc::Gtc, + spi::{self, SpiAsync, SpiId, SpiWithHwCs, SpiWithHwCsAsync, on_interrupt}, + time::Hertz, + uart::{self, TxAsync, on_interrupt_tx}, +}; + +use zynq7000::{PsPeripherals, slcr::LevelShifterConfig, spi::DelayControl}; +use zynq7000_rt as _; + +// Define the clock frequency as a constant +const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_300); + +const DEBUG_SPI_CLK_CONFIG: bool = false; +const BLOCKING: bool = false; + +/// Entry point (not called like a normal main function) +#[unsafe(no_mangle)] +pub extern "C" fn boot_core(cpu_id: u32) -> ! { + if cpu_id != 0 { + panic!("unexpected CPU ID {}", cpu_id); + } + main(); +} + +#[embassy_executor::main] +#[unsafe(export_name = "main")] +async fn main(spawner: Spawner) -> ! { + // Enable PS-PL level shifters. + configure_level_shifter(LevelShifterConfig::EnableAll); + let dp = PsPeripherals::take().unwrap(); + // Clock was already initialized by PS7 Init TCL script or FSBL, we just read it. + let mut clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap(); + + // SPI reference clock must be larger than the CPU 1x clock. + let spi_ref_clk_div = spi::calculate_largest_allowed_spi_ref_clk_divisor(&clocks) + .unwrap() + .value() + - 1; + spi::configure_spi_ref_clk(&mut clocks, arbitrary_int::u6::new(spi_ref_clk_div as u8)); + + // Set up the global interrupt controller. + let mut gic = GicConfigurator::new_with_init(dp.gicc, dp.gicd); + gic.enable_all_interrupts(); + gic.set_all_spi_interrupt_targets_cpu0(); + gic.enable(); + unsafe { + gic.enable_interrupts(); + } + + let mut gpio_pins = GpioPins::new(dp.gpio); + + // Set up global timer counter and embassy time driver. + let gtc = Gtc::new(dp.gtc, clocks.arm_clocks()); + zynq7000_embassy::init(clocks.arm_clocks(), gtc); + + // Set up the UART, we are logging with it. + let uart_clk_config = uart::ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200) + .unwrap() + .0; + let uart_tx = gpio_pins.mio.mio48.into_uart(); + let uart_rx = gpio_pins.mio.mio49.into_uart(); + let mut uart = uart::Uart::new_with_mio( + dp.uart_1, + uart::UartConfig::new_with_clk_config(uart_clk_config), + (uart_tx, uart_rx), + ) + .unwrap(); + uart.write_all(b"-- Zynq 7000 Zedboard SPI L3GD20H example --\n\r") + .unwrap(); + zynq7000_hal::log::rb::init(log::LevelFilter::Trace); + + let boot_mode = BootMode::new(); + info!("Boot mode: {:?}", boot_mode); + + if DEBUG_SPI_CLK_CONFIG { + info!( + "SPI Clock Information: CPU 1x: {:?}, IO Ref Clk: {:?}, SPI Ref Clk: {:?}, DIV: {:?}", + clocks.arm_clocks().cpu_1x_clk(), + clocks.io_clocks().ref_clk(), + clocks.io_clocks().spi_clk(), + spi_ref_clk_div + ); + } + let sck_pin = gpio_pins.mio.mio12.into_spi(); + let mosi_pin = gpio_pins.mio.mio10.into_spi(); + let miso_pin = gpio_pins.mio.mio11.into_spi(); + let ss_pin = gpio_pins.mio.mio13.into_spi(); + + let mut spi = spi::Spi::new_one_hw_cs( + dp.spi_1, + clocks.io_clocks(), + spi::Config::new( + // 10 MHz maximum rating of the sensor. + zynq7000::spi::BaudDivSelect::By64, + //l3gd20::MODE, + embedded_hal::spi::MODE_3, + spi::SlaveSelectConfig::AutoWithAutoStart, + ), + (sck_pin, mosi_pin, miso_pin), + ss_pin, + ) + .unwrap(); + let mod_id = spi.regs().read_mod_id(); + assert_eq!(mod_id, spi::MODULE_ID); + assert!(spi.sclk() <= Hertz::from_raw(10_000_000)); + let min_delay = (spi.sclk().raw() * 5) / 1_000_000_000; + spi.inner().configure_delays( + DelayControl::builder() + .with_inter_word_cs_deassert(0) + .with_between_cs_assertion(0) + .with_inter_word(0) + .with_cs_to_first_bit(min_delay as u8) + .build(), + ); + + let mio_led = gpio_pins.mio.mio7.into_output(PinState::Low).downgrade(); + let mut emio_leds: [EmioPin; 8] = [ + gpio_pins.emio.take(0).unwrap(), + gpio_pins.emio.take(1).unwrap(), + gpio_pins.emio.take(2).unwrap(), + gpio_pins.emio.take(3).unwrap(), + gpio_pins.emio.take(4).unwrap(), + gpio_pins.emio.take(5).unwrap(), + gpio_pins.emio.take(6).unwrap(), + gpio_pins.emio.take(7).unwrap(), + ]; + for (idx, led) in emio_leds.iter_mut().enumerate() { + if idx % 2 == 0 { + led.into_output(PinState::High); + } else { + led.into_output(PinState::Low); + } + } + spawner.spawn(logger_task(uart)).unwrap(); + if BLOCKING { + blocking_application(mio_led, emio_leds, spi).await; + } else { + non_blocking_application(mio_led, emio_leds, spi).await; + } +} + +#[embassy_executor::task] +pub async fn logger_task(uart: uart::Uart) { + let (tx, _) = uart.split(); + let mut tx_async = TxAsync::new(tx); + let frame_queue = zynq7000_hal::log::rb::get_frame_queue(); + let mut log_buf: [u8; 2048] = [0; 2048]; + loop { + let next_frame_len = frame_queue.receive().await; + zynq7000_hal::log::rb::read_next_frame(next_frame_len, &mut log_buf); + tx_async.write(&log_buf[0..next_frame_len]).await; + } +} + +pub async fn blocking_application( + mut mio_led: DynMioPin, + mut emio_leds: [EmioPin; 8], + spi: spi::Spi, +) -> ! { + let mut delay = Delay; + let spi_dev = SpiWithHwCs::new(spi, spi::ChipSelect::Slave0, delay.clone()); + let mut l3gd20 = l3gd20::spi::L3gd20::new(spi_dev).unwrap(); + let who_am_i = l3gd20.who_am_i().unwrap(); + info!("L3GD20 WHO_AM_I: 0x{:02X}", who_am_i); + + let mut ticker = Ticker::every(Duration::from_millis(400)); + + // Power up time for the sensor to get good readings. + delay.delay_ms(50).await; + loop { + mio_led.toggle().unwrap(); + + let measurements = l3gd20.all().unwrap(); + info!("L3GD20: {:?}", measurements); + info!("L3GD20 Temp: {:?}", measurements.temp_celcius()); + for led in emio_leds.iter_mut() { + led.toggle().unwrap(); + } + + ticker.next().await; // Wait for the next cycle of the ticker + } +} + +pub async fn non_blocking_application( + mut mio_led: DynMioPin, + mut emio_leds: [EmioPin; 8], + spi: spi::Spi, +) -> ! { + let mut delay = Delay; + let spi_async = SpiAsync::new(spi); + let spi_dev = SpiWithHwCsAsync::new(spi_async, spi::ChipSelect::Slave0, delay.clone()); + let mut l3gd20 = l3gd20::asynchronous::spi::L3gd20::new(spi_dev) + .await + .unwrap(); + let who_am_i = l3gd20.who_am_i().await.unwrap(); + info!("L3GD20 WHO_AM_I: 0x{:02X}", who_am_i); + + let mut ticker = Ticker::every(Duration::from_millis(400)); + + // Power up time for the sensor to get good readings. + delay.delay_ms(50).await; + loop { + mio_led.toggle().unwrap(); + + let measurements = l3gd20.all().await.unwrap(); + info!("L3GD20: {:?}", measurements); + info!("L3GD20 Temp: {:?}", measurements.temp_celcius()); + for led in emio_leds.iter_mut() { + led.toggle().unwrap(); + } + + ticker.next().await; // Wait for the next cycle of the ticker + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _irq_handler() { + let mut gic_helper = GicInterruptHelper::new(); + let irq_info = gic_helper.acknowledge_interrupt(); + match irq_info.interrupt() { + Interrupt::Sgi(_) => (), + Interrupt::Ppi(ppi_interrupt) => { + if ppi_interrupt == zynq7000_hal::gic::PpiInterrupt::GlobalTimer { + unsafe { + zynq7000_embassy::on_interrupt(); + } + } + } + Interrupt::Spi(spi_interrupt) => { + if spi_interrupt == zynq7000_hal::gic::SpiInterrupt::Spi1 { + on_interrupt(SpiId::Spi1); + } else if spi_interrupt == zynq7000_hal::gic::SpiInterrupt::Uart1 { + on_interrupt_tx(zynq7000_hal::uart::UartId::Uart1); + } + } + Interrupt::Invalid(_) => (), + Interrupt::Spurious => (), + } + gic_helper.end_of_interrupt(irq_info); +} + +#[unsafe(no_mangle)] +pub extern "C" fn _abort_handler() { + loop { + nop(); + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _undefined_handler() { + loop { + nop(); + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _prefetch_handler() { + loop { + nop(); + } +} + +/// Panic handler +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + error!("Panic: {:?}", info); + loop {} +} diff --git a/examples/zedboard/src/bin/uart-blocking.rs b/examples/zedboard/src/bin/uart-blocking.rs new file mode 100644 index 0000000..a874c6f --- /dev/null +++ b/examples/zedboard/src/bin/uart-blocking.rs @@ -0,0 +1,269 @@ +#![no_std] +#![no_main] + +use axi_uart16550::AxiUart16550; +use axi_uartlite::AxiUartlite; +use core::panic::PanicInfo; +use cortex_ar::asm::nop; +use embassy_executor::Spawner; +use embassy_time::{Duration, Ticker}; +use embedded_hal::digital::StatefulOutputPin; +use embedded_io::Write; +use fugit::RateExtU32; +use log::{error, info}; +use zedboard::PS_CLOCK_FREQUENCY; +use zynq7000_hal::{ + BootMode, + clocks::Clocks, + configure_level_shifter, + gic::{GicConfigurator, GicInterruptHelper, Interrupt}, + gpio::{EmioPin, GpioPins, PinState}, + gtc::Gtc, + uart::{ClkConfigRaw, Uart, UartConfig}, +}; + +use zynq7000::{PsPeripherals, slcr::LevelShifterConfig}; +use zynq7000_rt as _; + +const INIT_STRING: &str = "-- Zynq 7000 Zedboard blocking UART example --\n\r"; + +const AXI_UARTLITE_BASE_ADDR: u32 = 0x42C0_0000; +const AXI_UAR16550_BASE_ADDR: u32 = 0x43C0_0000; + +/// Entry point (not called like a normal main function) +#[unsafe(no_mangle)] +pub extern "C" fn boot_core(cpu_id: u32) -> ! { + if cpu_id != 0 { + panic!("unexpected CPU ID {}", cpu_id); + } + main(); +} + +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum UartSel { + Uart0 = 0b000, + Uartlite = 0b001, + Uart16550 = 0b010, + Uart0ToUartlite = 0b011, + Uart0ToUart16550 = 0b100, + UartliteToUart16550 = 0b101, +} + +pub struct UartMultiplexer { + sel_pins: [EmioPin; 3], +} + +impl UartMultiplexer { + pub fn new(mut sel_pins: [EmioPin; 3]) -> Self { + for pin in sel_pins.iter_mut() { + pin.into_output(PinState::Low); + } + Self { sel_pins } + } + + pub fn select(&mut self, sel: UartSel) { + // TODO: A pin group switcher would be nice to do this in one go. + match sel { + UartSel::Uart0 => { + self.sel_pins[2].set_low().unwrap(); + self.sel_pins[1].set_low().unwrap(); + self.sel_pins[0].set_low().unwrap(); + } + UartSel::Uartlite => { + self.sel_pins[2].set_low().unwrap(); + self.sel_pins[1].set_low().unwrap(); + self.sel_pins[0].set_high().unwrap(); + } + UartSel::Uart16550 => { + self.sel_pins[2].set_low().unwrap(); + self.sel_pins[1].set_high().unwrap(); + self.sel_pins[0].set_low().unwrap(); + } + UartSel::Uart0ToUartlite => { + self.sel_pins[2].set_low().unwrap(); + self.sel_pins[1].set_high().unwrap(); + self.sel_pins[0].set_high().unwrap(); + } + UartSel::Uart0ToUart16550 => { + self.sel_pins[2].set_high().unwrap(); + self.sel_pins[1].set_low().unwrap(); + self.sel_pins[0].set_low().unwrap(); + } + UartSel::UartliteToUart16550 => { + self.sel_pins[2].set_high().unwrap(); + self.sel_pins[1].set_low().unwrap(); + self.sel_pins[0].set_high().unwrap(); + } + } + } +} +#[embassy_executor::main] +#[unsafe(export_name = "main")] +async fn main(_spawner: Spawner) -> ! { + // Enable PS-PL level shifters. + configure_level_shifter(LevelShifterConfig::EnableAll); + let dp = PsPeripherals::take().unwrap(); + // Clock was already initialized by PS7 Init TCL script or FSBL, we just read it. + let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap(); + // Set up the global interrupt controller. + let mut gic = GicConfigurator::new_with_init(dp.gicc, dp.gicd); + gic.enable_all_interrupts(); + gic.set_all_spi_interrupt_targets_cpu0(); + gic.enable(); + unsafe { + gic.enable_interrupts(); + } + let mut gpio_pins = GpioPins::new(dp.gpio); + + // Set up global timer counter and embassy time driver. + let gtc = Gtc::new(dp.gtc, clocks.arm_clocks()); + zynq7000_embassy::init(clocks.arm_clocks(), gtc); + + // Set up the UART, we are logging with it. + let uart_clk_config = ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200) + .unwrap() + .0; + let uart_tx = gpio_pins.mio.mio48.into_uart(); + let uart_rx = gpio_pins.mio.mio49.into_uart(); + let mut log_uart = Uart::new_with_mio( + dp.uart_1, + UartConfig::new_with_clk_config(uart_clk_config), + (uart_tx, uart_rx), + ) + .unwrap(); + log_uart.write_all(INIT_STRING.as_bytes()).unwrap(); + + // Safety: Co-operative multi-tasking is used. + unsafe { + zynq7000_hal::log::uart_blocking::init_unsafe_single_core( + log_uart, + log::LevelFilter::Trace, + false, + ) + }; + + // UART0 routed through EMIO to PL pins. + let mut uart_0 = + Uart::new_with_emio(dp.uart_0, UartConfig::new_with_clk_config(uart_clk_config)).unwrap(); + // Safety: Valid address of AXI UARTLITE. + let mut uartlite = unsafe { AxiUartlite::new(AXI_UARTLITE_BASE_ADDR) }; + + // TODO: Can we determine/read the clock frequency to the FPGAs as well? + let (clk_config, error) = + axi_uart16550::ClkConfig::new_autocalc_with_error(100.MHz(), 115200).unwrap(); + assert!(error < 0.02); + let mut uart_16550 = unsafe { + AxiUart16550::new( + AXI_UAR16550_BASE_ADDR, + axi_uart16550::UartConfig::new_with_clk_config(clk_config), + ) + }; + + let boot_mode = BootMode::new(); + info!("Boot mode: {:?}", boot_mode); + + let mut ticker = Ticker::every(Duration::from_millis(1000)); + let mut mio_led = gpio_pins.mio.mio7.into_output(PinState::Low); + + let mut emio_leds: [EmioPin; 8] = [ + gpio_pins.emio.take(0).unwrap(), + gpio_pins.emio.take(1).unwrap(), + gpio_pins.emio.take(2).unwrap(), + gpio_pins.emio.take(3).unwrap(), + gpio_pins.emio.take(4).unwrap(), + gpio_pins.emio.take(5).unwrap(), + gpio_pins.emio.take(6).unwrap(), + gpio_pins.emio.take(7).unwrap(), + ]; + for led in emio_leds.iter_mut() { + led.into_output(PinState::Low); + } + + let mut uart_mux = UartMultiplexer::new([ + gpio_pins.emio.take(8).unwrap(), + gpio_pins.emio.take(9).unwrap(), + gpio_pins.emio.take(10).unwrap(), + ]); + let mut current_sel = UartSel::Uart0; + uart_mux.select(current_sel); + let mut led_idx = 0; + loop { + mio_led.toggle().unwrap(); + + emio_leds[led_idx].toggle().unwrap(); + led_idx += 1; + if led_idx >= emio_leds.len() { + led_idx = 0; + } + uart_0 + .write_all("Hello, World from UART0!\n\r".as_bytes()) + .unwrap(); + uartlite + .write_all("Hello, World from AXI UARTLITE!\n\r".as_bytes()) + .unwrap(); + uart_16550 + .write_all("Hello, World from AXI UART16550!\n\r".as_bytes()) + .unwrap(); + + uart_0.flush().unwrap(); + uartlite.flush().unwrap(); + uart_16550.flush().unwrap(); + match current_sel { + UartSel::Uart0 => current_sel = UartSel::Uartlite, + UartSel::Uartlite => current_sel = UartSel::Uart16550, + UartSel::Uart16550 => current_sel = UartSel::Uart0, + UartSel::Uart0ToUartlite | UartSel::Uart0ToUart16550 | UartSel::UartliteToUart16550 => { + } + } + uart_mux.select(current_sel); + ticker.next().await; // Wait for the next cycle of the ticker + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _irq_handler() { + let mut gic_helper = GicInterruptHelper::new(); + let irq_info = gic_helper.acknowledge_interrupt(); + match irq_info.interrupt() { + Interrupt::Sgi(_) => (), + Interrupt::Ppi(ppi_interrupt) => { + if ppi_interrupt == zynq7000_hal::gic::PpiInterrupt::GlobalTimer { + unsafe { + zynq7000_embassy::on_interrupt(); + } + } + } + Interrupt::Spi(_spi_interrupt) => (), + Interrupt::Invalid(_) => (), + Interrupt::Spurious => (), + } + gic_helper.end_of_interrupt(irq_info); +} + +#[unsafe(no_mangle)] +pub extern "C" fn _abort_handler() { + loop { + nop(); + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _undefined_handler() { + loop { + nop(); + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _prefetch_handler() { + loop { + nop(); + } +} + +/// Panic handler +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + error!("Panic: {:?}", info); + loop {} +} diff --git a/examples/zedboard/src/bin/uart-non-blocking.rs b/examples/zedboard/src/bin/uart-non-blocking.rs new file mode 100644 index 0000000..4a2e983 --- /dev/null +++ b/examples/zedboard/src/bin/uart-non-blocking.rs @@ -0,0 +1,575 @@ +//! This example application shows usage of the non-blocking APIs offered for +//! various UART peripherals which are part of the PS or the sample bitstream. +//! +//! This example ONLY works with the provided `zedboard-fpga-design`. +//! The example FPGA design contains the following components relevant for this design +//! +//! - An AXI UARTLite peripheral, with the interrupt signal connected to the PS +//! - An AXI UART16550 peripheral, with the interrupt signal connected to the PS +//! - A custom UART multiplexer component. This multiplexer has various configuration modes +//! configurable via 3 EMIO pins: +//! 1. Route UART0 RX to pin JA1 and TX to JA2. +//! 2. Route AXI UARTLite RX to pin JA1 and TX to JA2. +//! 3. Route AXI UART16550 RX to pin JA1 and TX to JA2. +//! 4. Route UART0 to AXI UARTLite. +//! 5. Route UART0 to AXI 16550. +//! 6. Route AXI UARTLite to AXI 16550. +//! - Options 4, 5 and 6 allow to test and show the non-blocking API without the need for external +//! hardware. +//! +//! This example runs one embassy task for each UART, which periodically sends variable sized +//! string content out via its TX port. Each UART peripheral also permanently listens to all +//! incoming RX data via interrupts. Received data will be sent from the interrupt handler +//! to the main thread and will be printed to the main console on UART 1. +#![no_std] +#![no_main] +extern crate alloc; + +use alloc::format; +use axi_uart16550::AxiUart16550; +use axi_uartlite::AxiUartlite; +use core::{cell::RefCell, panic::PanicInfo}; +use cortex_ar::asm::nop; +use critical_section::Mutex; +use embassy_executor::Spawner; +use embassy_time::{Duration, Ticker}; +use embedded_alloc::LlffHeap as Heap; +use embedded_hal::digital::StatefulOutputPin; +use embedded_io::Write as _; +use heapless::spsc::Queue; +use log::{error, info, warn}; +use zynq7000_hal::{ + BootMode, + clocks::Clocks, + configure_level_shifter, + gic::{GicConfigurator, GicInterruptHelper, Interrupt}, + gpio::{EmioPin, GpioPins, Mio7, MioPin, Output, PinState}, + gtc::Gtc, + time::Hertz, + uart::{ClkConfigRaw, Uart, UartConfig}, +}; + +pub enum UartMode { + Uart0ToUartlite, + Uart0ToUart16550, + UartliteToUart16550, +} + +const UART_MODE: UartMode = UartMode::Uart0ToUart16550; +const INIT_STRING: &str = "-- Zynq 7000 Zedboard non-blocking UART example --\n\r"; + +#[global_allocator] +static HEAP: Heap = Heap::empty(); + +use zynq7000::{PsPeripherals, slcr::LevelShifterConfig}; +use zynq7000_rt as _; + +// Define the clock frequency as a constant +const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_300); + +const AXI_UARTLITE_BASE_ADDR: u32 = 0x42C0_0000; +const AXI_UAR16550_BASE_ADDR: u32 = 0x43C0_0000; + +pub const UARTLITE_PL_INT_ID: usize = 0; +pub const UART16550_PL_INT_ID: usize = 1; + +const RB_SIZE: usize = 512; + +// These queues are used to send all data received in the UART interrupt handlers to the main +// processing thread. +static QUEUE_UART_0: static_cell::ConstStaticCell> = + static_cell::ConstStaticCell::new(Queue::new()); +static QUEUE_UARTLITE: static_cell::ConstStaticCell> = + static_cell::ConstStaticCell::new(Queue::new()); +static QUEUE_UART16550: static_cell::ConstStaticCell> = + static_cell::ConstStaticCell::new(Queue::new()); + +// Those are all used by the interrupt handler, so we have to do the Mutex dance. +static RX_UART_0: Mutex>> = Mutex::new(RefCell::new(None)); + +static UART_0_PROD: Mutex>>> = + Mutex::new(RefCell::new(None)); +static UARTLITE_PROD: Mutex>>> = + Mutex::new(RefCell::new(None)); +static UART16550_PROD: Mutex>>> = + Mutex::new(RefCell::new(None)); + +/// Entry point (not called like a normal main function) +#[unsafe(no_mangle)] +pub extern "C" fn boot_core(cpu_id: u32) -> ! { + if cpu_id != 0 { + panic!("unexpected CPU ID {}", cpu_id); + } + main(); +} + +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum UartSel { + Uart0 = 0b000, + Uartlite = 0b001, + Uart16550 = 0b010, + Uart0ToUartlite = 0b011, + Uart0ToUart16550 = 0b100, + UartliteToUart16550 = 0b101, +} + +pub struct UartMultiplexer { + sel_pins: [EmioPin; 3], +} + +impl UartMultiplexer { + pub fn new(mut sel_pins: [EmioPin; 3]) -> Self { + for pin in sel_pins.iter_mut() { + pin.into_output(PinState::Low); + } + Self { sel_pins } + } + + pub fn select(&mut self, sel: UartSel) { + // TODO: A pin group switcher would be nice to do this in one go. + match sel { + UartSel::Uart0 => { + self.sel_pins[2].set_low().unwrap(); + self.sel_pins[1].set_low().unwrap(); + self.sel_pins[0].set_low().unwrap(); + } + UartSel::Uartlite => { + self.sel_pins[2].set_low().unwrap(); + self.sel_pins[1].set_low().unwrap(); + self.sel_pins[0].set_high().unwrap(); + } + UartSel::Uart16550 => { + self.sel_pins[2].set_low().unwrap(); + self.sel_pins[1].set_high().unwrap(); + self.sel_pins[0].set_low().unwrap(); + } + UartSel::Uart0ToUartlite => { + self.sel_pins[2].set_low().unwrap(); + self.sel_pins[1].set_high().unwrap(); + self.sel_pins[0].set_high().unwrap(); + } + UartSel::Uart0ToUart16550 => { + self.sel_pins[2].set_high().unwrap(); + self.sel_pins[1].set_low().unwrap(); + self.sel_pins[0].set_low().unwrap(); + } + UartSel::UartliteToUart16550 => { + self.sel_pins[2].set_high().unwrap(); + self.sel_pins[1].set_low().unwrap(); + self.sel_pins[0].set_high().unwrap(); + } + } + } +} +#[embassy_executor::main] +#[unsafe(export_name = "main")] +async fn main(spawner: Spawner) -> ! { + // Enable PS-PL level shifters. + configure_level_shifter(LevelShifterConfig::EnableAll); + let dp = PsPeripherals::take().unwrap(); + // Clock was already initialized by PS7 Init TCL script or FSBL, we just read it. + let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap(); + // Set up the global interrupt controller. + let mut gic = GicConfigurator::new_with_init(dp.gicc, dp.gicd); + gic.enable_all_interrupts(); + gic.set_all_spi_interrupt_targets_cpu0(); + // AXI UARTLite documentation mentions that a rising-edge sensitive interrupt is generated, + // but the GIC configures high-level sensitivity for the PL interrupts by default. We + // need to change it to edge sensitivity. + gic.set_pl_interrupt_sensitivity(UARTLITE_PL_INT_ID, zynq7000_hal::gic::SpiSensitivity::Edge) + .unwrap(); + gic.enable(); + unsafe { + gic.enable_interrupts(); + } + let mut gpio_pins = GpioPins::new(dp.gpio); + + // Set up global timer counter and embassy time driver. + let gtc = Gtc::new(dp.gtc, clocks.arm_clocks()); + zynq7000_embassy::init(clocks.arm_clocks(), gtc); + + // Set up the UART, we are logging with it. + let uart_clk_config = ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200) + .unwrap() + .0; + let uart_tx = gpio_pins.mio.mio48.into_uart(); + let uart_rx = gpio_pins.mio.mio49.into_uart(); + let mut log_uart = Uart::new_with_mio( + dp.uart_1, + UartConfig::new_with_clk_config(uart_clk_config), + (uart_tx, uart_rx), + ) + .unwrap(); + log_uart.write_all(INIT_STRING.as_bytes()).unwrap(); + + // Initialize the allocator BEFORE you use it + { + use core::mem::MaybeUninit; + // 10 kB heap. + const HEAP_SIZE: usize = 1024 * 10; + static mut HEAP_MEM: [MaybeUninit; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE]; + unsafe { HEAP.init(&raw mut HEAP_MEM as usize, HEAP_SIZE) } + } + + // Safety: We are not multi-threaded yet. + unsafe { + zynq7000_hal::log::uart_blocking::init_unsafe_single_core( + log_uart, + log::LevelFilter::Trace, + false, + ) + }; + + // Set up UART multiplexing before creating and configuring the UARTs. + let mut uart_mux = UartMultiplexer::new([ + gpio_pins.emio.take(8).unwrap(), + gpio_pins.emio.take(9).unwrap(), + gpio_pins.emio.take(10).unwrap(), + ]); + match UART_MODE { + UartMode::Uart0ToUartlite => uart_mux.select(UartSel::Uart0ToUartlite), + UartMode::Uart0ToUart16550 => uart_mux.select(UartSel::Uart0ToUart16550), + UartMode::UartliteToUart16550 => uart_mux.select(UartSel::UartliteToUart16550), + } + + // UART0 routed through EMIO to PL pins. + let uart_0 = + Uart::new_with_emio(dp.uart_0, UartConfig::new_with_clk_config(uart_clk_config)).unwrap(); + // Safety: Valid address of AXI UARTLITE. + let mut uartlite = unsafe { AxiUartlite::new(AXI_UARTLITE_BASE_ADDR) }; + // We need to call this before splitting the structure, because the interrupt signal is + // used for both TX and RX, so the API is only exposed for this structure. + uartlite.enable_interrupt(); + + let (clk_config, error) = + axi_uart16550::ClkConfig::new_autocalc_with_error(clocks.pl_clocks()[0], 115200).unwrap(); + assert!(error < 0.02); + let _uart_16550 = unsafe { + AxiUart16550::new( + AXI_UAR16550_BASE_ADDR, + axi_uart16550::UartConfig::new_with_clk_config(clk_config), + ) + }; + + let boot_mode = BootMode::new(); + info!("Boot mode: {:?}", boot_mode); + + let mio_led = gpio_pins.mio.mio7.into_output(PinState::Low); + + let mut emio_leds: [EmioPin; 8] = [ + gpio_pins.emio.take(0).unwrap(), + gpio_pins.emio.take(1).unwrap(), + gpio_pins.emio.take(2).unwrap(), + gpio_pins.emio.take(3).unwrap(), + gpio_pins.emio.take(4).unwrap(), + gpio_pins.emio.take(5).unwrap(), + gpio_pins.emio.take(6).unwrap(), + gpio_pins.emio.take(7).unwrap(), + ]; + for led in emio_leds.iter_mut() { + led.into_output(PinState::Low); + } + + let (uart_0_tx, mut uart_0_rx) = uart_0.split(); + let (uartlite_tx, _uartlite_rx) = uartlite.split(); + let (uart_16550_tx, mut uart_16550_rx) = _uart_16550.split(); + let (uart_0_prod, mut uart_0_cons) = QUEUE_UART_0.take().split(); + let (uartlite_prod, mut uartlite_cons) = QUEUE_UARTLITE.take().split(); + let (uart16550_prod, mut uart16550_cons) = QUEUE_UART16550.take().split(); + // Use our helper function to start RX handling. + uart_0_rx.start_interrupt_driven_reception(); + // Use our helper function to start RX handling. + uart_16550_rx.start_interrupt_driven_reception(); + critical_section::with(|cs| { + UART_0_PROD.borrow(cs).borrow_mut().replace(uart_0_prod); + UARTLITE_PROD.borrow(cs).borrow_mut().replace(uartlite_prod); + UART16550_PROD + .borrow(cs) + .borrow_mut() + .replace(uart16550_prod); + RX_UART_0.borrow(cs).borrow_mut().replace(uart_0_rx); + }); + spawner.spawn(led_task(mio_led, emio_leds)).unwrap(); + + match UART_MODE { + UartMode::Uart0ToUartlite => { + spawner.spawn(uartlite_task(uartlite_tx)).unwrap(); + spawner.spawn(uart_0_task(uart_0_tx)).unwrap(); + } + UartMode::Uart0ToUart16550 => { + spawner.spawn(uart_0_task(uart_0_tx)).unwrap(); + spawner.spawn(uart_16550_task(uart_16550_tx)).unwrap(); + } + UartMode::UartliteToUart16550 => { + spawner.spawn(uartlite_task(uartlite_tx)).unwrap(); + spawner.spawn(uart_16550_task(uart_16550_tx)).unwrap(); + } + } + let mut read_buf: [u8; RB_SIZE] = [0; RB_SIZE]; + + let mut ticker = Ticker::every(Duration::from_millis(200)); + loop { + let read_bytes = uart_0_cons.len(); + (0..read_bytes).for_each(|i| { + read_buf[i] = unsafe { uart_0_cons.dequeue_unchecked() }; + }); + if read_bytes > 0 { + info!("Received {} bytes on UART0", read_bytes); + info!( + "Data: {:?}", + core::str::from_utf8(&read_buf[0..read_bytes]).unwrap() + ); + } + + let read_bytes = uartlite_cons.len(); + (0..read_bytes).for_each(|i| { + read_buf[i] = unsafe { uartlite_cons.dequeue_unchecked() }; + }); + if read_bytes > 0 { + info!("Received {} bytes on UARTLITE", read_bytes); + info!( + "Data: {:?}", + core::str::from_utf8(&read_buf[0..read_bytes]).unwrap() + ); + } + + let read_bytes = uart16550_cons.len(); + (0..read_bytes).for_each(|i| { + read_buf[i] = unsafe { uart16550_cons.dequeue_unchecked() }; + }); + if read_bytes > 0 { + info!("Received {} bytes on UART16550", read_bytes); + info!( + "Data: {:?}", + core::str::from_utf8(&read_buf[0..read_bytes]).unwrap() + ); + } + ticker.next().await; // Wait for the next cycle of the ticker + } +} + +fn build_print_string(prefix: &str, base_str: &str) -> alloc::string::String { + format!("{} {}\n\r", prefix, base_str) +} + +#[embassy_executor::task] +async fn led_task(mut mio_led: MioPin, mut emio_leds: [EmioPin; 8]) { + let mut ticker = Ticker::every(Duration::from_millis(1000)); + let mut led_idx = 0; + loop { + mio_led.toggle().unwrap(); + + emio_leds[led_idx].toggle().unwrap(); + led_idx += 1; + if led_idx >= emio_leds.len() { + led_idx = 0; + } + ticker.next().await; + } +} + +#[embassy_executor::task] +async fn uartlite_task(uartlite: axi_uartlite::Tx) { + let mut ticker = Ticker::every(Duration::from_millis(1000)); + let str0 = build_print_string("UARTLITE:", "Hello World"); + let str1 = build_print_string( + "UARTLITE:", + "Long Hello which should completely fill the FIFO", + ); + let mut idx = 0; + let print_strs = [str0.as_bytes(), str1.as_bytes()]; + let mut tx_async = axi_uartlite::tx_async::TxAsync::new(uartlite, 0).unwrap(); + loop { + tx_async.write(print_strs[idx]).await; + idx += 1; + if idx == 2 { + idx = 0; + } + ticker.next().await; + } +} + +#[embassy_executor::task] +async fn uart_0_task(uart_tx: zynq7000_hal::uart::Tx) { + let mut ticker = Ticker::every(Duration::from_millis(1000)); + let mut tx_async = zynq7000_hal::uart::TxAsync::new(uart_tx); + let str0 = build_print_string("UART0:", "Hello World"); + let str1 = build_print_string( + "UART0:", + "Long Hello which should completely fill the 64 byte FIFO of the UART0 peripheral", + ); + let mut idx = 0; + let print_strs = [str0.as_bytes(), str1.as_bytes()]; + loop { + tx_async.write(print_strs[idx]).await; + idx += 1; + if idx == 2 { + idx = 0; + } + + ticker.next().await; + } +} + +#[embassy_executor::task] +async fn uart_16550_task(uart_tx: axi_uart16550::Tx) { + let mut ticker = Ticker::every(Duration::from_millis(1000)); + let mut tx_async = axi_uart16550::TxAsync::new(uart_tx, 0, embassy_time::Delay).unwrap(); + let str0 = build_print_string("UART16550:", "Hello World"); + let str1 = build_print_string( + "UART16550:", + "Long Hello which should completely fill the FIFO", + ); + let mut idx = 0; + let print_strs = [str0.as_bytes(), str1.as_bytes()]; + loop { + tx_async.write(print_strs[idx]).await; + idx += 1; + if idx == 2 { + idx = 0; + } + + ticker.next().await; + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _irq_handler() { + let mut gic_helper = GicInterruptHelper::new(); + let irq_info = gic_helper.acknowledge_interrupt(); + + match irq_info.interrupt() { + Interrupt::Sgi(_) => (), + Interrupt::Ppi(ppi_interrupt) => { + if ppi_interrupt == zynq7000_hal::gic::PpiInterrupt::GlobalTimer { + unsafe { + zynq7000_embassy::on_interrupt(); + } + } + } + Interrupt::Spi(spi_interrupt) => match spi_interrupt { + zynq7000_hal::gic::SpiInterrupt::Pl0 => { + on_interrupt_axi_uartlite(); + } + zynq7000_hal::gic::SpiInterrupt::Pl1 => { + on_interrupt_axi_16550(); + } + zynq7000_hal::gic::SpiInterrupt::Uart0 => { + on_interrupt_uart_0(); + } + + _ => (), + }, + Interrupt::Invalid(_) => (), + Interrupt::Spurious => (), + } + gic_helper.end_of_interrupt(irq_info); +} + +pub fn on_interrupt_axi_uartlite() { + let mut buf = [0; axi_uartlite::FIFO_DEPTH]; + let mut rx = unsafe { axi_uartlite::Rx::steal(AXI_UARTLITE_BASE_ADDR as usize) }; + // Handle RX first: Empty the FIFO content into local buffer. + let read_bytes = rx.on_interrupt_rx(&mut buf); + // Handle TX next: Handle pending asynchronous TX operations. + let mut tx = unsafe { axi_uartlite::Tx::steal(AXI_UARTLITE_BASE_ADDR as usize) }; + axi_uartlite::on_interrupt_tx(&mut tx, 0); + // Send received RX data to main task. + if read_bytes > 0 { + critical_section::with(|cs| { + let mut prod_ref_mut = UARTLITE_PROD.borrow(cs).borrow_mut(); + let prod = prod_ref_mut.as_mut().unwrap(); + (0..read_bytes).for_each(|i| { + prod.enqueue(buf[i]).expect("failed to enqueue byte"); + }); + }); + } +} + +pub fn on_interrupt_axi_16550() { + let mut buf = [0; axi_uart16550::FIFO_DEPTH]; + let mut read_bytes = 0; + let mut rx = unsafe { axi_uart16550::Rx::steal(AXI_UAR16550_BASE_ADDR as usize) }; + let iir = rx.read_iir(); + if let Ok(int_id) = iir.int_id() { + match int_id { + axi_uart16550::registers::IntId2::ReceiverLineStatus => { + let errors = rx.on_interrupt_receiver_line_status(iir); + warn!("Receiver line status error: {:?}", errors); + } + axi_uart16550::registers::IntId2::RxDataAvailable + | axi_uart16550::registers::IntId2::CharTimeout => { + read_bytes = rx.on_interrupt_data_available_or_char_timeout(int_id, &mut buf); + } + axi_uart16550::registers::IntId2::ThrEmpty => { + let mut tx = unsafe { axi_uart16550::Tx::steal(AXI_UAR16550_BASE_ADDR as usize) }; + axi_uart16550::tx_async::on_interrupt_tx(&mut tx, 0); + } + axi_uart16550::registers::IntId2::ModemStatus => (), + } + } + // Send received RX data to main task. + if read_bytes > 0 { + critical_section::with(|cs| { + let mut prod_ref_mut = UART16550_PROD.borrow(cs).borrow_mut(); + let prod = prod_ref_mut.as_mut().unwrap(); + (0..read_bytes).for_each(|i| { + prod.enqueue(buf[i]).expect("failed to enqueue byte"); + }); + }); + } +} + +fn on_interrupt_uart_0() { + let mut buf = [0; zynq7000_hal::uart::FIFO_DEPTH]; + let mut read_bytes = 0; + // Handle RX first: Empty the FIFO content into local buffer. + critical_section::with(|cs| { + let mut uart0 = RX_UART_0.borrow(cs).borrow_mut(); + read_bytes = uart0 + .as_mut() + .unwrap() + .on_interrupt(&mut buf, true) + .read_bytes(); + }); + // Handle TX next: Handle pending asynchronous TX operations. + zynq7000_hal::uart::on_interrupt_tx(zynq7000_hal::uart::UartId::Uart0); + // Send received RX data to main task. + if read_bytes > 0 { + critical_section::with(|cs| { + let mut prod_ref_mut = UART_0_PROD.borrow(cs).borrow_mut(); + let prod = prod_ref_mut.as_mut().unwrap(); + (0..read_bytes).for_each(|i| { + prod.enqueue(buf[i]).expect("failed to enqueue byte"); + }); + }); + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _abort_handler() { + loop { + nop(); + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _undefined_handler() { + loop { + nop(); + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _prefetch_handler() { + loop { + nop(); + } +} + +/// Panic handler +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + error!("Panic: {:?}", info); + loop {} +} diff --git a/examples/zedboard/src/lib.rs b/examples/zedboard/src/lib.rs new file mode 100644 index 0000000..4d22d59 --- /dev/null +++ b/examples/zedboard/src/lib.rs @@ -0,0 +1,5 @@ +#![no_std] +use zynq7000_hal::time::Hertz; + +// Define the clock frequency as a constant +pub const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_300); diff --git a/examples/zedboard/src/main.rs b/examples/zedboard/src/main.rs new file mode 100644 index 0000000..9d43c7f --- /dev/null +++ b/examples/zedboard/src/main.rs @@ -0,0 +1,158 @@ +#![no_std] +#![no_main] + +use core::panic::PanicInfo; +use cortex_ar::asm::nop; +use embassy_executor::Spawner; +use embassy_time::{Duration, Ticker}; +use embedded_hal::digital::StatefulOutputPin; +use embedded_io::Write; +use log::{error, info}; +use zedboard::PS_CLOCK_FREQUENCY; +use zynq7000_hal::{ + BootMode, + clocks::Clocks, + configure_level_shifter, + gic::{GicConfigurator, GicInterruptHelper, Interrupt}, + gpio::{EmioPin, GpioPins, PinState}, + gtc::Gtc, + uart::{ClkConfigRaw, Uart, UartConfig}, +}; + +use zynq7000::{PsPeripherals, slcr::LevelShifterConfig}; +use zynq7000_rt as _; + +const INIT_STRING: &str = "-- Zynq 7000 Zedboard GPIO blinky example --\n\r"; + +/// Entry point (not called like a normal main function) +#[unsafe(no_mangle)] +pub extern "C" fn boot_core(cpu_id: u32) -> ! { + if cpu_id != 0 { + panic!("unexpected CPU ID {}", cpu_id); + } + main(); +} + +#[embassy_executor::main] +#[unsafe(export_name = "main")] +async fn main(_spawner: Spawner) -> ! { + // Enable PS-PL level shifters. + configure_level_shifter(LevelShifterConfig::EnableAll); + let dp = PsPeripherals::take().unwrap(); + // Clock was already initialized by PS7 Init TCL script or FSBL, we just read it. + let clocks = Clocks::new_from_regs(PS_CLOCK_FREQUENCY).unwrap(); + // Set up the global interrupt controller. + let mut gic = GicConfigurator::new_with_init(dp.gicc, dp.gicd); + gic.enable_all_interrupts(); + gic.set_all_spi_interrupt_targets_cpu0(); + gic.enable(); + unsafe { + gic.enable_interrupts(); + } + let mut gpio_pins = GpioPins::new(dp.gpio); + + // Set up global timer counter and embassy time driver. + let gtc = Gtc::new(dp.gtc, clocks.arm_clocks()); + zynq7000_embassy::init(clocks.arm_clocks(), gtc); + + // Set up the UART, we are logging with it. + let uart_clk_config = ClkConfigRaw::new_autocalc_with_error(clocks.io_clocks(), 115200) + .unwrap() + .0; + let uart_tx = gpio_pins.mio.mio48.into_uart(); + let uart_rx = gpio_pins.mio.mio49.into_uart(); + let mut uart = Uart::new_with_mio( + dp.uart_1, + UartConfig::new_with_clk_config(uart_clk_config), + (uart_tx, uart_rx), + ) + .unwrap(); + uart.write_all(INIT_STRING.as_bytes()).unwrap(); + // Safety: We are not multi-threaded yet. + unsafe { + zynq7000_hal::log::uart_blocking::init_unsafe_single_core( + uart, + log::LevelFilter::Trace, + false, + ) + }; + + let boot_mode = BootMode::new(); + info!("Boot mode: {:?}", boot_mode); + + let mut ticker = Ticker::every(Duration::from_millis(200)); + let mut mio_led = gpio_pins.mio.mio7.into_output(PinState::Low); + + let mut emio_leds: [EmioPin; 8] = [ + gpio_pins.emio.take(0).unwrap(), + gpio_pins.emio.take(1).unwrap(), + gpio_pins.emio.take(2).unwrap(), + gpio_pins.emio.take(3).unwrap(), + gpio_pins.emio.take(4).unwrap(), + gpio_pins.emio.take(5).unwrap(), + gpio_pins.emio.take(6).unwrap(), + gpio_pins.emio.take(7).unwrap(), + ]; + for led in emio_leds.iter_mut() { + led.into_output(PinState::Low); + } + loop { + mio_led.toggle().unwrap(); + + // Create a wave pattern for emio_leds + for led in emio_leds.iter_mut() { + led.toggle().unwrap(); + ticker.next().await; // Wait for the next ticker for each toggle + } + + ticker.next().await; // Wait for the next cycle of the ticker + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _irq_handler() { + let mut gic_helper = GicInterruptHelper::new(); + let irq_info = gic_helper.acknowledge_interrupt(); + match irq_info.interrupt() { + Interrupt::Sgi(_) => (), + Interrupt::Ppi(ppi_interrupt) => { + if ppi_interrupt == zynq7000_hal::gic::PpiInterrupt::GlobalTimer { + unsafe { + zynq7000_embassy::on_interrupt(); + } + } + } + Interrupt::Spi(_spi_interrupt) => (), + Interrupt::Invalid(_) => (), + Interrupt::Spurious => (), + } + gic_helper.end_of_interrupt(irq_info); +} + +#[unsafe(no_mangle)] +pub extern "C" fn _abort_handler() { + loop { + nop(); + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _undefined_handler() { + loop { + nop(); + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn _prefetch_handler() { + loop { + nop(); + } +} + +/// Panic handler +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + error!("Panic: {:?}", info); + loop {} +} diff --git a/experiments/.cargo/config.toml b/experiments/.cargo/config.toml new file mode 100644 index 0000000..a7b19c9 --- /dev/null +++ b/experiments/.cargo/config.toml @@ -0,0 +1 @@ +[build] diff --git a/experiments/.gitignore b/experiments/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/experiments/.gitignore @@ -0,0 +1 @@ +/target diff --git a/experiments/Cargo.lock b/experiments/Cargo.lock new file mode 100644 index 0000000..bc77523 --- /dev/null +++ b/experiments/Cargo.lock @@ -0,0 +1,171 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "arbitrary-int" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "825297538d77367557b912770ca3083f778a196054b3ee63b22673c4a3cae0a5" + +[[package]] +name = "bitbybit" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d317eeca82e7d88d606419a430590d83552bdceb899cb29904f63d694344b7fc" +dependencies = [ + "arbitrary-int", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "derive-mmio" +version = "0.3.0" +dependencies = [ + "derive-mmio-macro", + "rustversion", +] + +[[package]] +name = "derive-mmio-macro" +version = "0.3.0" +dependencies = [ + "proc-macro-error2", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "experiments" +version = "0.1.0" +dependencies = [ + "derive-mmio", + "static_assertions", + "zynq7000", +] + +[[package]] +name = "once_cell" +version = "1.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" +dependencies = [ + "critical-section", + "portable-atomic", +] + +[[package]] +name = "portable-atomic" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "syn" +version = "2.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe" + +[[package]] +name = "zynq7000" +version = "0.1.0" +dependencies = [ + "arbitrary-int", + "bitbybit", + "derive-mmio", + "once_cell", + "static_assertions", + "thiserror", +] diff --git a/experiments/Cargo.toml b/experiments/Cargo.toml new file mode 100644 index 0000000..a19b1e7 --- /dev/null +++ b/experiments/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "experiments" +version = "0.1.0" +edition = "2024" + +[dependencies] +static_assertions = "1.1" +derive-mmio = { path = "../../derive-mmio", default-features = false } +zynq7000 = { path = "../zynq7000", default-features = false } diff --git a/experiments/src/main.rs b/experiments/src/main.rs new file mode 100644 index 0000000..3249366 --- /dev/null +++ b/experiments/src/main.rs @@ -0,0 +1,11 @@ +use zynq7000::slcr::{ClockControl, Slcr}; + + +fn main() { + let size = core::mem::size_of::(); + println!("Size of ClockControl: {}", size); + let size = core::mem::size_of::(); + println!("Size of SLCR: {}", size); + + println!("Hello, world!"); +} diff --git a/gdb.gdb b/gdb.gdb new file mode 100644 index 0000000..d1f48a2 --- /dev/null +++ b/gdb.gdb @@ -0,0 +1,8 @@ +target remote localhost:3000 + +# *try* to stop at the user entry point (it might be gone due to inlining) +break main + +load + +continue diff --git a/memory.x b/memory.x new file mode 100644 index 0000000..8a65966 --- /dev/null +++ b/memory.x @@ -0,0 +1,8 @@ + +MEMORY +{ + /* Zedboard: 512 MB DDR3. Only use 256 MB for now, should be plenty for a bare-metal app. */ + CODE(rx) : ORIGIN = 0x00100000, LENGTH = 256M +} + +REGION_ALIAS("DATA", CODE); diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..0e3c7a9 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +# channel = "stable" +channel = "nightly" diff --git a/scripts/.gitignore b/scripts/.gitignore new file mode 100644 index 0000000..ce99428 --- /dev/null +++ b/scripts/.gitignore @@ -0,0 +1 @@ +/xsct-output.log diff --git a/scripts/ps7_init.tcl b/scripts/ps7_init.tcl new file mode 100644 index 0000000..ee6fb61 --- /dev/null +++ b/scripts/ps7_init.tcl @@ -0,0 +1,847 @@ +proc ps7_pll_init_data_3_0 {} { + mwr -force 0XF8000008 0x0000DF0D + mask_write 0XF8000110 0x003FFFF0 0x000FA220 + mask_write 0XF8000100 0x0007F000 0x00027000 + mask_write 0XF8000100 0x00000010 0x00000010 + mask_write 0XF8000100 0x00000001 0x00000001 + mask_write 0XF8000100 0x00000001 0x00000000 + mask_poll 0XF800010C 0x00000001 + mask_write 0XF8000100 0x00000010 0x00000000 + mask_write 0XF8000120 0x1F003F30 0x1F000200 + mask_write 0XF8000114 0x003FFFF0 0x0012C220 + mask_write 0XF8000104 0x0007F000 0x00020000 + mask_write 0XF8000104 0x00000010 0x00000010 + mask_write 0XF8000104 0x00000001 0x00000001 + mask_write 0XF8000104 0x00000001 0x00000000 + mask_poll 0XF800010C 0x00000002 + mask_write 0XF8000104 0x00000010 0x00000000 + mask_write 0XF8000124 0xFFF00003 0x0C200003 + mask_write 0XF8000118 0x003FFFF0 0x001452C0 + mask_write 0XF8000108 0x0007F000 0x0001E000 + mask_write 0XF8000108 0x00000010 0x00000010 + mask_write 0XF8000108 0x00000001 0x00000001 + mask_write 0XF8000108 0x00000001 0x00000000 + mask_poll 0XF800010C 0x00000004 + mask_write 0XF8000108 0x00000010 0x00000000 + mwr -force 0XF8000004 0x0000767B +} +proc ps7_clock_init_data_3_0 {} { + mwr -force 0XF8000008 0x0000DF0D + mask_write 0XF8000128 0x03F03F01 0x00700F01 + mask_write 0XF8000138 0x00000011 0x00000001 + mask_write 0XF8000140 0x03F03F71 0x00100801 + mask_write 0XF800014C 0x00003F31 0x00000501 + mask_write 0XF8000150 0x00003F33 0x00001401 + mask_write 0XF8000154 0x00003F33 0x00000A03 + mask_write 0XF8000168 0x00003F31 0x00000501 + mask_write 0XF8000170 0x03F03F30 0x00200500 + mask_write 0XF80001C4 0x00000001 0x00000001 + mask_write 0XF800012C 0x01FFCCCD 0x01FC044D + mwr -force 0XF8000004 0x0000767B +} +proc ps7_ddr_init_data_3_0 {} { + mask_write 0XF8006000 0x0001FFFF 0x00000080 + mask_write 0XF8006004 0x0007FFFF 0x00001082 + mask_write 0XF8006008 0x03FFFFFF 0x03C0780F + mask_write 0XF800600C 0x03FFFFFF 0x02001001 + mask_write 0XF8006010 0x03FFFFFF 0x00014001 + mask_write 0XF8006014 0x001FFFFF 0x0004159B + mask_write 0XF8006018 0xF7FFFFFF 0x44E458D3 + mask_write 0XF800601C 0xFFFFFFFF 0x7282BCE5 + mask_write 0XF8006020 0x7FDFFFFC 0x270872D0 + mask_write 0XF8006024 0x0FFFFFC3 0x00000000 + mask_write 0XF8006028 0x00003FFF 0x00002007 + mask_write 0XF800602C 0xFFFFFFFF 0x00000008 + mask_write 0XF8006030 0xFFFFFFFF 0x00040B30 + mask_write 0XF8006034 0x13FF3FFF 0x000116D4 + mask_write 0XF8006038 0x00000003 0x00000000 + mask_write 0XF800603C 0x000FFFFF 0x00000777 + mask_write 0XF8006040 0xFFFFFFFF 0xFFF00000 + mask_write 0XF8006044 0x0FFFFFFF 0x0FF66666 + mask_write 0XF8006048 0x0003F03F 0x0003C008 + mask_write 0XF8006050 0xFF0F8FFF 0x77010800 + mask_write 0XF8006058 0x00010000 0x00000000 + mask_write 0XF800605C 0x0000FFFF 0x00005003 + mask_write 0XF8006060 0x000017FF 0x0000003E + mask_write 0XF8006064 0x00021FE0 0x00020000 + mask_write 0XF8006068 0x03FFFFFF 0x00284141 + mask_write 0XF800606C 0x0000FFFF 0x00001610 + mask_write 0XF8006078 0x03FFFFFF 0x00466111 + mask_write 0XF800607C 0x000FFFFF 0x00032222 + mask_write 0XF80060A4 0xFFFFFFFF 0x10200802 + mask_write 0XF80060A8 0x0FFFFFFF 0x0690CB73 + mask_write 0XF80060AC 0x000001FF 0x000001FE + mask_write 0XF80060B0 0x1FFFFFFF 0x1CFFFFFF + mask_write 0XF80060B4 0x00000200 0x00000200 + mask_write 0XF80060B8 0x01FFFFFF 0x00200066 + mask_write 0XF80060C4 0x00000003 0x00000000 + mask_write 0XF80060C8 0x000000FF 0x00000000 + mask_write 0XF80060DC 0x00000001 0x00000000 + mask_write 0XF80060F0 0x0000FFFF 0x00000000 + mask_write 0XF80060F4 0x0000000F 0x00000008 + mask_write 0XF8006114 0x000000FF 0x00000000 + mask_write 0XF8006118 0x7FFFFFCF 0x40000001 + mask_write 0XF800611C 0x7FFFFFCF 0x40000001 + mask_write 0XF8006120 0x7FFFFFCF 0x40000001 + mask_write 0XF8006124 0x7FFFFFCF 0x40000001 + mask_write 0XF800612C 0x000FFFFF 0x00024000 + mask_write 0XF8006130 0x000FFFFF 0x00022C00 + mask_write 0XF8006134 0x000FFFFF 0x00023000 + mask_write 0XF8006138 0x000FFFFF 0x00024C00 + mask_write 0XF8006140 0x000FFFFF 0x00000035 + mask_write 0XF8006144 0x000FFFFF 0x00000035 + mask_write 0XF8006148 0x000FFFFF 0x00000035 + mask_write 0XF800614C 0x000FFFFF 0x00000035 + mask_write 0XF8006154 0x000FFFFF 0x00000077 + mask_write 0XF8006158 0x000FFFFF 0x0000007C + mask_write 0XF800615C 0x000FFFFF 0x0000007C + mask_write 0XF8006160 0x000FFFFF 0x00000075 + mask_write 0XF8006168 0x001FFFFF 0x000000E5 + mask_write 0XF800616C 0x001FFFFF 0x000000E0 + mask_write 0XF8006170 0x001FFFFF 0x000000E1 + mask_write 0XF8006174 0x001FFFFF 0x000000E8 + mask_write 0XF800617C 0x000FFFFF 0x000000B7 + mask_write 0XF8006180 0x000FFFFF 0x000000BC + mask_write 0XF8006184 0x000FFFFF 0x000000BC + mask_write 0XF8006188 0x000FFFFF 0x000000B5 + mask_write 0XF8006190 0x6FFFFEFE 0x00040080 + mask_write 0XF8006194 0x000FFFFF 0x0001FC82 + mask_write 0XF8006204 0xFFFFFFFF 0x00000000 + mask_write 0XF8006208 0x000703FF 0x000003FF + mask_write 0XF800620C 0x000703FF 0x000003FF + mask_write 0XF8006210 0x000703FF 0x000003FF + mask_write 0XF8006214 0x000703FF 0x000003FF + mask_write 0XF8006218 0x000F03FF 0x000003FF + mask_write 0XF800621C 0x000F03FF 0x000003FF + mask_write 0XF8006220 0x000F03FF 0x000003FF + mask_write 0XF8006224 0x000F03FF 0x000003FF + mask_write 0XF80062A8 0x00000FF5 0x00000000 + mask_write 0XF80062AC 0xFFFFFFFF 0x00000000 + mask_write 0XF80062B0 0x003FFFFF 0x00005125 + mask_write 0XF80062B4 0x0003FFFF 0x000012A8 + mask_poll 0XF8000B74 0x00002000 + mask_write 0XF8006000 0x0001FFFF 0x00000081 + mask_poll 0XF8006054 0x00000007 +} +proc ps7_mio_init_data_3_0 {} { + mwr -force 0XF8000008 0x0000DF0D + mask_write 0XF8000B00 0x00000071 0x00000001 + mask_write 0XF8000B40 0x00000FFF 0x00000600 + mask_write 0XF8000B44 0x00000FFF 0x00000600 + mask_write 0XF8000B48 0x00000FFF 0x00000672 + mask_write 0XF8000B4C 0x00000FFF 0x00000672 + mask_write 0XF8000B50 0x00000FFF 0x00000674 + mask_write 0XF8000B54 0x00000FFF 0x00000674 + mask_write 0XF8000B58 0x00000FFF 0x00000600 + mask_write 0XF8000B5C 0xFFFFFFFF 0x0018C61C + mask_write 0XF8000B60 0xFFFFFFFF 0x00F9861C + mask_write 0XF8000B64 0xFFFFFFFF 0x00F9861C + mask_write 0XF8000B68 0xFFFFFFFF 0x00F9861C + mask_write 0XF8000B6C 0x00007FFF 0x00000260 + mask_write 0XF8000B70 0x00000001 0x00000001 + mask_write 0XF8000B70 0x00000021 0x00000020 + mask_write 0XF8000B70 0x07FEFFFF 0x00000823 + mask_write 0XF8000700 0x00003FFF 0x00001600 + mask_write 0XF8000704 0x00003FFF 0x00000702 + mask_write 0XF8000708 0x00003FFF 0x00000702 + mask_write 0XF800070C 0x00003FFF 0x00000702 + mask_write 0XF8000710 0x00003FFF 0x00000702 + mask_write 0XF8000714 0x00003FFF 0x00000702 + mask_write 0XF8000718 0x00003FFF 0x00000702 + mask_write 0XF800071C 0x00003FFF 0x00000600 + mask_write 0XF8000720 0x00003FFF 0x00000702 + mask_write 0XF8000724 0x00003FFF 0x00001600 + mask_write 0XF8000728 0x00003FFF 0x00001600 + mask_write 0XF800072C 0x00003FFF 0x00001600 + mask_write 0XF8000730 0x00003FFF 0x00001600 + mask_write 0XF8000734 0x00003FFF 0x00001600 + mask_write 0XF8000738 0x00003FFF 0x00001600 + mask_write 0XF800073C 0x00003FFF 0x00001600 + mask_write 0XF8000740 0x00003FFF 0x00002902 + mask_write 0XF8000744 0x00003FFF 0x00002902 + mask_write 0XF8000748 0x00003FFF 0x00002902 + mask_write 0XF800074C 0x00003FFF 0x00002902 + mask_write 0XF8000750 0x00003FFF 0x00002902 + mask_write 0XF8000754 0x00003FFF 0x00002902 + mask_write 0XF8000758 0x00003FFF 0x00000903 + mask_write 0XF800075C 0x00003FFF 0x00000903 + mask_write 0XF8000760 0x00003FFF 0x00000903 + mask_write 0XF8000764 0x00003FFF 0x00000903 + mask_write 0XF8000768 0x00003FFF 0x00000903 + mask_write 0XF800076C 0x00003FFF 0x00000903 + mask_write 0XF8000770 0x00003FFF 0x00000304 + mask_write 0XF8000774 0x00003FFF 0x00000305 + mask_write 0XF8000778 0x00003FFF 0x00000304 + mask_write 0XF800077C 0x00003FFF 0x00000305 + mask_write 0XF8000780 0x00003FFF 0x00000304 + mask_write 0XF8000784 0x00003FFF 0x00000304 + mask_write 0XF8000788 0x00003FFF 0x00000304 + mask_write 0XF800078C 0x00003FFF 0x00000304 + mask_write 0XF8000790 0x00003FFF 0x00000305 + mask_write 0XF8000794 0x00003FFF 0x00000304 + mask_write 0XF8000798 0x00003FFF 0x00000304 + mask_write 0XF800079C 0x00003FFF 0x00000304 + mask_write 0XF80007A0 0x00003FFF 0x00000380 + mask_write 0XF80007A4 0x00003FFF 0x00000380 + mask_write 0XF80007A8 0x00003FFF 0x00000380 + mask_write 0XF80007AC 0x00003FFF 0x00000380 + mask_write 0XF80007B0 0x00003FFF 0x00000380 + mask_write 0XF80007B4 0x00003FFF 0x00000380 + mask_write 0XF80007B8 0x00003FFF 0x00001200 + mask_write 0XF80007BC 0x00003F01 0x00000201 + mask_write 0XF80007C0 0x00003FFF 0x000002E0 + mask_write 0XF80007C4 0x00003FFF 0x000002E1 + mask_write 0XF80007C8 0x00003FFF 0x00000200 + mask_write 0XF80007CC 0x00003FFF 0x00000200 + mask_write 0XF80007D0 0x00003FFF 0x00000200 + mask_write 0XF80007D4 0x00003FFF 0x00000200 + mask_write 0XF8000830 0x003F003F 0x002F0037 + mwr -force 0XF8000004 0x0000767B +} +proc ps7_peripherals_init_data_3_0 {} { + mwr -force 0XF8000008 0x0000DF0D + mask_write 0XF8000B48 0x00000180 0x00000180 + mask_write 0XF8000B4C 0x00000180 0x00000180 + mask_write 0XF8000B50 0x00000180 0x00000180 + mask_write 0XF8000B54 0x00000180 0x00000180 + mwr -force 0XF8000004 0x0000767B + mask_write 0XE0001034 0x000000FF 0x00000006 + mask_write 0XE0001018 0x0000FFFF 0x0000007C + mask_write 0XE0001000 0x000001FF 0x00000017 + mask_write 0XE0001004 0x000003FF 0x00000020 + mask_write 0XE0000034 0x000000FF 0x00000006 + mask_write 0XE0000018 0x0000FFFF 0x0000007C + mask_write 0XE0000000 0x000001FF 0x00000017 + mask_write 0XE0000004 0x000003FF 0x00000020 + mask_write 0XE000D000 0x00080000 0x00080000 + mask_write 0XF8007000 0x20000000 0x00000000 + mask_write 0XE000A244 0x003FFFFF 0x00004000 + mask_write 0XE000A008 0xFFFFFFFF 0xBFFF4000 + mask_write 0XE000A248 0x003FFFFF 0x00004000 + mask_write 0XE000A008 0xFFFFFFFF 0xBFFF0000 + mask_delay 0XF8F00200 1 + mask_write 0XE000A008 0xFFFFFFFF 0xBFFF4000 +} +proc ps7_post_config_3_0 {} { + mwr -force 0XF8000008 0x0000DF0D + mask_write 0XF8000900 0x0000000F 0x0000000F + mask_write 0XF8000240 0xFFFFFFFF 0x00000000 + mwr -force 0XF8000004 0x0000767B +} +proc ps7_debug_3_0 {} { + mwr -force 0XF8898FB0 0xC5ACCE55 + mwr -force 0XF8899FB0 0xC5ACCE55 + mwr -force 0XF8809FB0 0xC5ACCE55 +} +proc ps7_pll_init_data_2_0 {} { + mwr -force 0XF8000008 0x0000DF0D + mask_write 0XF8000110 0x003FFFF0 0x000FA220 + mask_write 0XF8000100 0x0007F000 0x00027000 + mask_write 0XF8000100 0x00000010 0x00000010 + mask_write 0XF8000100 0x00000001 0x00000001 + mask_write 0XF8000100 0x00000001 0x00000000 + mask_poll 0XF800010C 0x00000001 + mask_write 0XF8000100 0x00000010 0x00000000 + mask_write 0XF8000120 0x1F003F30 0x1F000200 + mask_write 0XF8000114 0x003FFFF0 0x0012C220 + mask_write 0XF8000104 0x0007F000 0x00020000 + mask_write 0XF8000104 0x00000010 0x00000010 + mask_write 0XF8000104 0x00000001 0x00000001 + mask_write 0XF8000104 0x00000001 0x00000000 + mask_poll 0XF800010C 0x00000002 + mask_write 0XF8000104 0x00000010 0x00000000 + mask_write 0XF8000124 0xFFF00003 0x0C200003 + mask_write 0XF8000118 0x003FFFF0 0x001452C0 + mask_write 0XF8000108 0x0007F000 0x0001E000 + mask_write 0XF8000108 0x00000010 0x00000010 + mask_write 0XF8000108 0x00000001 0x00000001 + mask_write 0XF8000108 0x00000001 0x00000000 + mask_poll 0XF800010C 0x00000004 + mask_write 0XF8000108 0x00000010 0x00000000 + mwr -force 0XF8000004 0x0000767B +} +proc ps7_clock_init_data_2_0 {} { + mwr -force 0XF8000008 0x0000DF0D + mask_write 0XF8000128 0x03F03F01 0x00700F01 + mask_write 0XF8000138 0x00000011 0x00000001 + mask_write 0XF8000140 0x03F03F71 0x00100801 + mask_write 0XF800014C 0x00003F31 0x00000501 + mask_write 0XF8000150 0x00003F33 0x00001401 + mask_write 0XF8000154 0x00003F33 0x00000A03 + mask_write 0XF8000168 0x00003F31 0x00000501 + mask_write 0XF8000170 0x03F03F30 0x00200500 + mask_write 0XF80001C4 0x00000001 0x00000001 + mask_write 0XF800012C 0x01FFCCCD 0x01FC044D + mwr -force 0XF8000004 0x0000767B +} +proc ps7_ddr_init_data_2_0 {} { + mask_write 0XF8006000 0x0001FFFF 0x00000080 + mask_write 0XF8006004 0x1FFFFFFF 0x00081082 + mask_write 0XF8006008 0x03FFFFFF 0x03C0780F + mask_write 0XF800600C 0x03FFFFFF 0x02001001 + mask_write 0XF8006010 0x03FFFFFF 0x00014001 + mask_write 0XF8006014 0x001FFFFF 0x0004159B + mask_write 0XF8006018 0xF7FFFFFF 0x44E458D3 + mask_write 0XF800601C 0xFFFFFFFF 0x7282BCE5 + mask_write 0XF8006020 0xFFFFFFFC 0x272872D0 + mask_write 0XF8006024 0x0FFFFFFF 0x0000003C + mask_write 0XF8006028 0x00003FFF 0x00002007 + mask_write 0XF800602C 0xFFFFFFFF 0x00000008 + mask_write 0XF8006030 0xFFFFFFFF 0x00040B30 + mask_write 0XF8006034 0x13FF3FFF 0x000116D4 + mask_write 0XF8006038 0x00001FC3 0x00000000 + mask_write 0XF800603C 0x000FFFFF 0x00000777 + mask_write 0XF8006040 0xFFFFFFFF 0xFFF00000 + mask_write 0XF8006044 0x0FFFFFFF 0x0FF66666 + mask_write 0XF8006048 0x3FFFFFFF 0x0003C248 + mask_write 0XF8006050 0xFF0F8FFF 0x77010800 + mask_write 0XF8006058 0x0001FFFF 0x00000101 + mask_write 0XF800605C 0x0000FFFF 0x00005003 + mask_write 0XF8006060 0x000017FF 0x0000003E + mask_write 0XF8006064 0x00021FE0 0x00020000 + mask_write 0XF8006068 0x03FFFFFF 0x00284141 + mask_write 0XF800606C 0x0000FFFF 0x00001610 + mask_write 0XF8006078 0x03FFFFFF 0x00466111 + mask_write 0XF800607C 0x000FFFFF 0x00032222 + mask_write 0XF80060A0 0x00FFFFFF 0x00008000 + mask_write 0XF80060A4 0xFFFFFFFF 0x10200802 + mask_write 0XF80060A8 0x0FFFFFFF 0x0690CB73 + mask_write 0XF80060AC 0x000001FF 0x000001FE + mask_write 0XF80060B0 0x1FFFFFFF 0x1CFFFFFF + mask_write 0XF80060B4 0x000007FF 0x00000200 + mask_write 0XF80060B8 0x01FFFFFF 0x00200066 + mask_write 0XF80060C4 0x00000003 0x00000000 + mask_write 0XF80060C8 0x000000FF 0x00000000 + mask_write 0XF80060DC 0x00000001 0x00000000 + mask_write 0XF80060F0 0x0000FFFF 0x00000000 + mask_write 0XF80060F4 0x0000000F 0x00000008 + mask_write 0XF8006114 0x000000FF 0x00000000 + mask_write 0XF8006118 0x7FFFFFFF 0x40000001 + mask_write 0XF800611C 0x7FFFFFFF 0x40000001 + mask_write 0XF8006120 0x7FFFFFFF 0x40000001 + mask_write 0XF8006124 0x7FFFFFFF 0x40000001 + mask_write 0XF800612C 0x000FFFFF 0x00024000 + mask_write 0XF8006130 0x000FFFFF 0x00022C00 + mask_write 0XF8006134 0x000FFFFF 0x00023000 + mask_write 0XF8006138 0x000FFFFF 0x00024C00 + mask_write 0XF8006140 0x000FFFFF 0x00000035 + mask_write 0XF8006144 0x000FFFFF 0x00000035 + mask_write 0XF8006148 0x000FFFFF 0x00000035 + mask_write 0XF800614C 0x000FFFFF 0x00000035 + mask_write 0XF8006154 0x000FFFFF 0x00000077 + mask_write 0XF8006158 0x000FFFFF 0x0000007C + mask_write 0XF800615C 0x000FFFFF 0x0000007C + mask_write 0XF8006160 0x000FFFFF 0x00000075 + mask_write 0XF8006168 0x001FFFFF 0x000000E5 + mask_write 0XF800616C 0x001FFFFF 0x000000E0 + mask_write 0XF8006170 0x001FFFFF 0x000000E1 + mask_write 0XF8006174 0x001FFFFF 0x000000E8 + mask_write 0XF800617C 0x000FFFFF 0x000000B7 + mask_write 0XF8006180 0x000FFFFF 0x000000BC + mask_write 0XF8006184 0x000FFFFF 0x000000BC + mask_write 0XF8006188 0x000FFFFF 0x000000B5 + mask_write 0XF8006190 0xFFFFFFFF 0x10040080 + mask_write 0XF8006194 0x000FFFFF 0x0001FC82 + mask_write 0XF8006204 0xFFFFFFFF 0x00000000 + mask_write 0XF8006208 0x000F03FF 0x000803FF + mask_write 0XF800620C 0x000F03FF 0x000803FF + mask_write 0XF8006210 0x000F03FF 0x000803FF + mask_write 0XF8006214 0x000F03FF 0x000803FF + mask_write 0XF8006218 0x000F03FF 0x000003FF + mask_write 0XF800621C 0x000F03FF 0x000003FF + mask_write 0XF8006220 0x000F03FF 0x000003FF + mask_write 0XF8006224 0x000F03FF 0x000003FF + mask_write 0XF80062A8 0x00000FF7 0x00000000 + mask_write 0XF80062AC 0xFFFFFFFF 0x00000000 + mask_write 0XF80062B0 0x003FFFFF 0x00005125 + mask_write 0XF80062B4 0x0003FFFF 0x000012A8 + mask_poll 0XF8000B74 0x00002000 + mask_write 0XF8006000 0x0001FFFF 0x00000081 + mask_poll 0XF8006054 0x00000007 +} +proc ps7_mio_init_data_2_0 {} { + mwr -force 0XF8000008 0x0000DF0D + mask_write 0XF8000B00 0x00000303 0x00000001 + mask_write 0XF8000B40 0x00000FFF 0x00000600 + mask_write 0XF8000B44 0x00000FFF 0x00000600 + mask_write 0XF8000B48 0x00000FFF 0x00000672 + mask_write 0XF8000B4C 0x00000FFF 0x00000672 + mask_write 0XF8000B50 0x00000FFF 0x00000674 + mask_write 0XF8000B54 0x00000FFF 0x00000674 + mask_write 0XF8000B58 0x00000FFF 0x00000600 + mask_write 0XF8000B5C 0xFFFFFFFF 0x0018C61C + mask_write 0XF8000B60 0xFFFFFFFF 0x00F9861C + mask_write 0XF8000B64 0xFFFFFFFF 0x00F9861C + mask_write 0XF8000B68 0xFFFFFFFF 0x00F9861C + mask_write 0XF8000B6C 0x00007FFF 0x00000260 + mask_write 0XF8000B70 0x00000021 0x00000021 + mask_write 0XF8000B70 0x00000021 0x00000020 + mask_write 0XF8000B70 0x07FFFFFF 0x00000823 + mask_write 0XF8000700 0x00003FFF 0x00001600 + mask_write 0XF8000704 0x00003FFF 0x00000702 + mask_write 0XF8000708 0x00003FFF 0x00000702 + mask_write 0XF800070C 0x00003FFF 0x00000702 + mask_write 0XF8000710 0x00003FFF 0x00000702 + mask_write 0XF8000714 0x00003FFF 0x00000702 + mask_write 0XF8000718 0x00003FFF 0x00000702 + mask_write 0XF800071C 0x00003FFF 0x00000600 + mask_write 0XF8000720 0x00003FFF 0x00000702 + mask_write 0XF8000724 0x00003FFF 0x00001600 + mask_write 0XF8000728 0x00003FFF 0x00001600 + mask_write 0XF800072C 0x00003FFF 0x00001600 + mask_write 0XF8000730 0x00003FFF 0x00001600 + mask_write 0XF8000734 0x00003FFF 0x00001600 + mask_write 0XF8000738 0x00003FFF 0x00001600 + mask_write 0XF800073C 0x00003FFF 0x00001600 + mask_write 0XF8000740 0x00003FFF 0x00002902 + mask_write 0XF8000744 0x00003FFF 0x00002902 + mask_write 0XF8000748 0x00003FFF 0x00002902 + mask_write 0XF800074C 0x00003FFF 0x00002902 + mask_write 0XF8000750 0x00003FFF 0x00002902 + mask_write 0XF8000754 0x00003FFF 0x00002902 + mask_write 0XF8000758 0x00003FFF 0x00000903 + mask_write 0XF800075C 0x00003FFF 0x00000903 + mask_write 0XF8000760 0x00003FFF 0x00000903 + mask_write 0XF8000764 0x00003FFF 0x00000903 + mask_write 0XF8000768 0x00003FFF 0x00000903 + mask_write 0XF800076C 0x00003FFF 0x00000903 + mask_write 0XF8000770 0x00003FFF 0x00000304 + mask_write 0XF8000774 0x00003FFF 0x00000305 + mask_write 0XF8000778 0x00003FFF 0x00000304 + mask_write 0XF800077C 0x00003FFF 0x00000305 + mask_write 0XF8000780 0x00003FFF 0x00000304 + mask_write 0XF8000784 0x00003FFF 0x00000304 + mask_write 0XF8000788 0x00003FFF 0x00000304 + mask_write 0XF800078C 0x00003FFF 0x00000304 + mask_write 0XF8000790 0x00003FFF 0x00000305 + mask_write 0XF8000794 0x00003FFF 0x00000304 + mask_write 0XF8000798 0x00003FFF 0x00000304 + mask_write 0XF800079C 0x00003FFF 0x00000304 + mask_write 0XF80007A0 0x00003FFF 0x00000380 + mask_write 0XF80007A4 0x00003FFF 0x00000380 + mask_write 0XF80007A8 0x00003FFF 0x00000380 + mask_write 0XF80007AC 0x00003FFF 0x00000380 + mask_write 0XF80007B0 0x00003FFF 0x00000380 + mask_write 0XF80007B4 0x00003FFF 0x00000380 + mask_write 0XF80007B8 0x00003FFF 0x00001200 + mask_write 0XF80007BC 0x00003F01 0x00000201 + mask_write 0XF80007C0 0x00003FFF 0x000002E0 + mask_write 0XF80007C4 0x00003FFF 0x000002E1 + mask_write 0XF80007C8 0x00003FFF 0x00000200 + mask_write 0XF80007CC 0x00003FFF 0x00000200 + mask_write 0XF80007D0 0x00003FFF 0x00000200 + mask_write 0XF80007D4 0x00003FFF 0x00000200 + mask_write 0XF8000830 0x003F003F 0x002F0037 + mwr -force 0XF8000004 0x0000767B +} +proc ps7_peripherals_init_data_2_0 {} { + mwr -force 0XF8000008 0x0000DF0D + mask_write 0XF8000B48 0x00000180 0x00000180 + mask_write 0XF8000B4C 0x00000180 0x00000180 + mask_write 0XF8000B50 0x00000180 0x00000180 + mask_write 0XF8000B54 0x00000180 0x00000180 + mwr -force 0XF8000004 0x0000767B + mask_write 0XE0001034 0x000000FF 0x00000006 + mask_write 0XE0001018 0x0000FFFF 0x0000007C + mask_write 0XE0001000 0x000001FF 0x00000017 + mask_write 0XE0001004 0x00000FFF 0x00000020 + mask_write 0XE0000034 0x000000FF 0x00000006 + mask_write 0XE0000018 0x0000FFFF 0x0000007C + mask_write 0XE0000000 0x000001FF 0x00000017 + mask_write 0XE0000004 0x00000FFF 0x00000020 + mask_write 0XE000D000 0x00080000 0x00080000 + mask_write 0XF8007000 0x20000000 0x00000000 + mask_write 0XE000A244 0x003FFFFF 0x00004000 + mask_write 0XE000A008 0xFFFFFFFF 0xBFFF4000 + mask_write 0XE000A248 0x003FFFFF 0x00004000 + mask_write 0XE000A008 0xFFFFFFFF 0xBFFF0000 + mask_delay 0XF8F00200 1 + mask_write 0XE000A008 0xFFFFFFFF 0xBFFF4000 +} +proc ps7_post_config_2_0 {} { + mwr -force 0XF8000008 0x0000DF0D + mask_write 0XF8000900 0x0000000F 0x0000000F + mask_write 0XF8000240 0xFFFFFFFF 0x00000000 + mwr -force 0XF8000004 0x0000767B +} +proc ps7_debug_2_0 {} { + mwr -force 0XF8898FB0 0xC5ACCE55 + mwr -force 0XF8899FB0 0xC5ACCE55 + mwr -force 0XF8809FB0 0xC5ACCE55 +} +proc ps7_pll_init_data_1_0 {} { + mwr -force 0XF8000008 0x0000DF0D + mask_write 0XF8000110 0x003FFFF0 0x000FA220 + mask_write 0XF8000100 0x0007F000 0x00027000 + mask_write 0XF8000100 0x00000010 0x00000010 + mask_write 0XF8000100 0x00000001 0x00000001 + mask_write 0XF8000100 0x00000001 0x00000000 + mask_poll 0XF800010C 0x00000001 + mask_write 0XF8000100 0x00000010 0x00000000 + mask_write 0XF8000120 0x1F003F30 0x1F000200 + mask_write 0XF8000114 0x003FFFF0 0x0012C220 + mask_write 0XF8000104 0x0007F000 0x00020000 + mask_write 0XF8000104 0x00000010 0x00000010 + mask_write 0XF8000104 0x00000001 0x00000001 + mask_write 0XF8000104 0x00000001 0x00000000 + mask_poll 0XF800010C 0x00000002 + mask_write 0XF8000104 0x00000010 0x00000000 + mask_write 0XF8000124 0xFFF00003 0x0C200003 + mask_write 0XF8000118 0x003FFFF0 0x001452C0 + mask_write 0XF8000108 0x0007F000 0x0001E000 + mask_write 0XF8000108 0x00000010 0x00000010 + mask_write 0XF8000108 0x00000001 0x00000001 + mask_write 0XF8000108 0x00000001 0x00000000 + mask_poll 0XF800010C 0x00000004 + mask_write 0XF8000108 0x00000010 0x00000000 + mwr -force 0XF8000004 0x0000767B +} +proc ps7_clock_init_data_1_0 {} { + mwr -force 0XF8000008 0x0000DF0D + mask_write 0XF8000128 0x03F03F01 0x00700F01 + mask_write 0XF8000138 0x00000011 0x00000001 + mask_write 0XF8000140 0x03F03F71 0x00100801 + mask_write 0XF800014C 0x00003F31 0x00000501 + mask_write 0XF8000150 0x00003F33 0x00001401 + mask_write 0XF8000154 0x00003F33 0x00000A03 + mask_write 0XF8000168 0x00003F31 0x00000501 + mask_write 0XF8000170 0x03F03F30 0x00200500 + mask_write 0XF80001C4 0x00000001 0x00000001 + mask_write 0XF800012C 0x01FFCCCD 0x01FC044D + mwr -force 0XF8000004 0x0000767B +} +proc ps7_ddr_init_data_1_0 {} { + mask_write 0XF8006000 0x0001FFFF 0x00000080 + mask_write 0XF8006004 0x1FFFFFFF 0x00081082 + mask_write 0XF8006008 0x03FFFFFF 0x03C0780F + mask_write 0XF800600C 0x03FFFFFF 0x02001001 + mask_write 0XF8006010 0x03FFFFFF 0x00014001 + mask_write 0XF8006014 0x001FFFFF 0x0004159B + mask_write 0XF8006018 0xF7FFFFFF 0x44E458D3 + mask_write 0XF800601C 0xFFFFFFFF 0x7282BCE5 + mask_write 0XF8006020 0xFFFFFFFC 0x272872D0 + mask_write 0XF8006024 0x0FFFFFFF 0x0000003C + mask_write 0XF8006028 0x00003FFF 0x00002007 + mask_write 0XF800602C 0xFFFFFFFF 0x00000008 + mask_write 0XF8006030 0xFFFFFFFF 0x00040B30 + mask_write 0XF8006034 0x13FF3FFF 0x000116D4 + mask_write 0XF8006038 0x00001FC3 0x00000000 + mask_write 0XF800603C 0x000FFFFF 0x00000777 + mask_write 0XF8006040 0xFFFFFFFF 0xFFF00000 + mask_write 0XF8006044 0x0FFFFFFF 0x0FF66666 + mask_write 0XF8006048 0x3FFFFFFF 0x0003C248 + mask_write 0XF8006050 0xFF0F8FFF 0x77010800 + mask_write 0XF8006058 0x0001FFFF 0x00000101 + mask_write 0XF800605C 0x0000FFFF 0x00005003 + mask_write 0XF8006060 0x000017FF 0x0000003E + mask_write 0XF8006064 0x00021FE0 0x00020000 + mask_write 0XF8006068 0x03FFFFFF 0x00284141 + mask_write 0XF800606C 0x0000FFFF 0x00001610 + mask_write 0XF80060A0 0x00FFFFFF 0x00008000 + mask_write 0XF80060A4 0xFFFFFFFF 0x10200802 + mask_write 0XF80060A8 0x0FFFFFFF 0x0690CB73 + mask_write 0XF80060AC 0x000001FF 0x000001FE + mask_write 0XF80060B0 0x1FFFFFFF 0x1CFFFFFF + mask_write 0XF80060B4 0x000007FF 0x00000200 + mask_write 0XF80060B8 0x01FFFFFF 0x00200066 + mask_write 0XF80060C4 0x00000003 0x00000000 + mask_write 0XF80060C8 0x000000FF 0x00000000 + mask_write 0XF80060DC 0x00000001 0x00000000 + mask_write 0XF80060F0 0x0000FFFF 0x00000000 + mask_write 0XF80060F4 0x0000000F 0x00000008 + mask_write 0XF8006114 0x000000FF 0x00000000 + mask_write 0XF8006118 0x7FFFFFFF 0x40000001 + mask_write 0XF800611C 0x7FFFFFFF 0x40000001 + mask_write 0XF8006120 0x7FFFFFFF 0x40000001 + mask_write 0XF8006124 0x7FFFFFFF 0x40000001 + mask_write 0XF800612C 0x000FFFFF 0x00024000 + mask_write 0XF8006130 0x000FFFFF 0x00022C00 + mask_write 0XF8006134 0x000FFFFF 0x00023000 + mask_write 0XF8006138 0x000FFFFF 0x00024C00 + mask_write 0XF8006140 0x000FFFFF 0x00000035 + mask_write 0XF8006144 0x000FFFFF 0x00000035 + mask_write 0XF8006148 0x000FFFFF 0x00000035 + mask_write 0XF800614C 0x000FFFFF 0x00000035 + mask_write 0XF8006154 0x000FFFFF 0x00000077 + mask_write 0XF8006158 0x000FFFFF 0x0000007C + mask_write 0XF800615C 0x000FFFFF 0x0000007C + mask_write 0XF8006160 0x000FFFFF 0x00000075 + mask_write 0XF8006168 0x001FFFFF 0x000000E5 + mask_write 0XF800616C 0x001FFFFF 0x000000E0 + mask_write 0XF8006170 0x001FFFFF 0x000000E1 + mask_write 0XF8006174 0x001FFFFF 0x000000E8 + mask_write 0XF800617C 0x000FFFFF 0x000000B7 + mask_write 0XF8006180 0x000FFFFF 0x000000BC + mask_write 0XF8006184 0x000FFFFF 0x000000BC + mask_write 0XF8006188 0x000FFFFF 0x000000B5 + mask_write 0XF8006190 0xFFFFFFFF 0x10040080 + mask_write 0XF8006194 0x000FFFFF 0x0001FC82 + mask_write 0XF8006204 0xFFFFFFFF 0x00000000 + mask_write 0XF8006208 0x000F03FF 0x000803FF + mask_write 0XF800620C 0x000F03FF 0x000803FF + mask_write 0XF8006210 0x000F03FF 0x000803FF + mask_write 0XF8006214 0x000F03FF 0x000803FF + mask_write 0XF8006218 0x000F03FF 0x000003FF + mask_write 0XF800621C 0x000F03FF 0x000003FF + mask_write 0XF8006220 0x000F03FF 0x000003FF + mask_write 0XF8006224 0x000F03FF 0x000003FF + mask_write 0XF80062A8 0x00000FF7 0x00000000 + mask_write 0XF80062AC 0xFFFFFFFF 0x00000000 + mask_write 0XF80062B0 0x003FFFFF 0x00005125 + mask_write 0XF80062B4 0x0003FFFF 0x000012A8 + mask_poll 0XF8000B74 0x00002000 + mask_write 0XF8006000 0x0001FFFF 0x00000081 + mask_poll 0XF8006054 0x00000007 +} +proc ps7_mio_init_data_1_0 {} { + mwr -force 0XF8000008 0x0000DF0D + mask_write 0XF8000B00 0x00000303 0x00000001 + mask_write 0XF8000B40 0x00000FFF 0x00000600 + mask_write 0XF8000B44 0x00000FFF 0x00000600 + mask_write 0XF8000B48 0x00000FFF 0x00000672 + mask_write 0XF8000B4C 0x00000FFF 0x00000672 + mask_write 0XF8000B50 0x00000FFF 0x00000674 + mask_write 0XF8000B54 0x00000FFF 0x00000674 + mask_write 0XF8000B58 0x00000FFF 0x00000600 + mask_write 0XF8000B5C 0xFFFFFFFF 0x0018C61C + mask_write 0XF8000B60 0xFFFFFFFF 0x00F9861C + mask_write 0XF8000B64 0xFFFFFFFF 0x00F9861C + mask_write 0XF8000B68 0xFFFFFFFF 0x00F9861C + mask_write 0XF8000B6C 0x000073FF 0x00000260 + mask_write 0XF8000B70 0x00000021 0x00000021 + mask_write 0XF8000B70 0x00000021 0x00000020 + mask_write 0XF8000B70 0x07FFFFFF 0x00000823 + mask_write 0XF8000700 0x00003FFF 0x00001600 + mask_write 0XF8000704 0x00003FFF 0x00000702 + mask_write 0XF8000708 0x00003FFF 0x00000702 + mask_write 0XF800070C 0x00003FFF 0x00000702 + mask_write 0XF8000710 0x00003FFF 0x00000702 + mask_write 0XF8000714 0x00003FFF 0x00000702 + mask_write 0XF8000718 0x00003FFF 0x00000702 + mask_write 0XF800071C 0x00003FFF 0x00000600 + mask_write 0XF8000720 0x00003FFF 0x00000702 + mask_write 0XF8000724 0x00003FFF 0x00001600 + mask_write 0XF8000728 0x00003FFF 0x00001600 + mask_write 0XF800072C 0x00003FFF 0x00001600 + mask_write 0XF8000730 0x00003FFF 0x00001600 + mask_write 0XF8000734 0x00003FFF 0x00001600 + mask_write 0XF8000738 0x00003FFF 0x00001600 + mask_write 0XF800073C 0x00003FFF 0x00001600 + mask_write 0XF8000740 0x00003FFF 0x00002902 + mask_write 0XF8000744 0x00003FFF 0x00002902 + mask_write 0XF8000748 0x00003FFF 0x00002902 + mask_write 0XF800074C 0x00003FFF 0x00002902 + mask_write 0XF8000750 0x00003FFF 0x00002902 + mask_write 0XF8000754 0x00003FFF 0x00002902 + mask_write 0XF8000758 0x00003FFF 0x00000903 + mask_write 0XF800075C 0x00003FFF 0x00000903 + mask_write 0XF8000760 0x00003FFF 0x00000903 + mask_write 0XF8000764 0x00003FFF 0x00000903 + mask_write 0XF8000768 0x00003FFF 0x00000903 + mask_write 0XF800076C 0x00003FFF 0x00000903 + mask_write 0XF8000770 0x00003FFF 0x00000304 + mask_write 0XF8000774 0x00003FFF 0x00000305 + mask_write 0XF8000778 0x00003FFF 0x00000304 + mask_write 0XF800077C 0x00003FFF 0x00000305 + mask_write 0XF8000780 0x00003FFF 0x00000304 + mask_write 0XF8000784 0x00003FFF 0x00000304 + mask_write 0XF8000788 0x00003FFF 0x00000304 + mask_write 0XF800078C 0x00003FFF 0x00000304 + mask_write 0XF8000790 0x00003FFF 0x00000305 + mask_write 0XF8000794 0x00003FFF 0x00000304 + mask_write 0XF8000798 0x00003FFF 0x00000304 + mask_write 0XF800079C 0x00003FFF 0x00000304 + mask_write 0XF80007A0 0x00003FFF 0x00000380 + mask_write 0XF80007A4 0x00003FFF 0x00000380 + mask_write 0XF80007A8 0x00003FFF 0x00000380 + mask_write 0XF80007AC 0x00003FFF 0x00000380 + mask_write 0XF80007B0 0x00003FFF 0x00000380 + mask_write 0XF80007B4 0x00003FFF 0x00000380 + mask_write 0XF80007B8 0x00003FFF 0x00001200 + mask_write 0XF80007BC 0x00003F01 0x00000201 + mask_write 0XF80007C0 0x00003FFF 0x000002E0 + mask_write 0XF80007C4 0x00003FFF 0x000002E1 + mask_write 0XF80007C8 0x00003FFF 0x00000200 + mask_write 0XF80007CC 0x00003FFF 0x00000200 + mask_write 0XF80007D0 0x00003FFF 0x00000200 + mask_write 0XF80007D4 0x00003FFF 0x00000200 + mask_write 0XF8000830 0x003F003F 0x002F0037 + mwr -force 0XF8000004 0x0000767B +} +proc ps7_peripherals_init_data_1_0 {} { + mwr -force 0XF8000008 0x0000DF0D + mask_write 0XF8000B48 0x00000180 0x00000180 + mask_write 0XF8000B4C 0x00000180 0x00000180 + mask_write 0XF8000B50 0x00000180 0x00000180 + mask_write 0XF8000B54 0x00000180 0x00000180 + mwr -force 0XF8000004 0x0000767B + mask_write 0XE0001034 0x000000FF 0x00000006 + mask_write 0XE0001018 0x0000FFFF 0x0000007C + mask_write 0XE0001000 0x000001FF 0x00000017 + mask_write 0XE0001004 0x00000FFF 0x00000020 + mask_write 0XE0000034 0x000000FF 0x00000006 + mask_write 0XE0000018 0x0000FFFF 0x0000007C + mask_write 0XE0000000 0x000001FF 0x00000017 + mask_write 0XE0000004 0x00000FFF 0x00000020 + mask_write 0XE000D000 0x00080000 0x00080000 + mask_write 0XF8007000 0x20000000 0x00000000 + mask_write 0XE000A244 0x003FFFFF 0x00004000 + mask_write 0XE000A008 0xFFFFFFFF 0xBFFF4000 + mask_write 0XE000A248 0x003FFFFF 0x00004000 + mask_write 0XE000A008 0xFFFFFFFF 0xBFFF0000 + mask_delay 0XF8F00200 1 + mask_write 0XE000A008 0xFFFFFFFF 0xBFFF4000 +} +proc ps7_post_config_1_0 {} { + mwr -force 0XF8000008 0x0000DF0D + mask_write 0XF8000900 0x0000000F 0x0000000F + mask_write 0XF8000240 0xFFFFFFFF 0x00000000 + mwr -force 0XF8000004 0x0000767B +} +proc ps7_debug_1_0 {} { + mwr -force 0XF8898FB0 0xC5ACCE55 + mwr -force 0XF8899FB0 0xC5ACCE55 + mwr -force 0XF8809FB0 0xC5ACCE55 +} +set PCW_SILICON_VER_1_0 "0x0" +set PCW_SILICON_VER_2_0 "0x1" +set PCW_SILICON_VER_3_0 "0x2" +set APU_FREQ 650000000 + + + +proc mask_poll { addr mask } { + set count 1 + set curval "0x[string range [mrd $addr] end-8 end]" + set maskedval [expr {$curval & $mask}] + while { $maskedval == 0 } { + set curval "0x[string range [mrd $addr] end-8 end]" + set maskedval [expr {$curval & $mask}] + set count [ expr { $count + 1 } ] + if { $count == 100000000 } { + puts "Timeout Reached. Mask poll failed at ADDRESS: $addr MASK: $mask" + break + } + } +} + + + +proc mask_delay { addr val } { + set delay [ get_number_of_cycles_for_delay $val ] + perf_reset_and_start_timer + set curval "0x[string range [mrd $addr] end-8 end]" + set maskedval [expr {$curval < $delay}] + while { $maskedval == 1 } { + set curval "0x[string range [mrd $addr] end-8 end]" + set maskedval [expr {$curval < $delay}] + } + perf_reset_clock +} + +proc ps_version { } { + set si_ver "0x[string range [mrd 0xF8007080] end-8 end]" + set mask_sil_ver "0x[expr {$si_ver >> 28}]" + return $mask_sil_ver; +} + +proc ps7_post_config {} { + set saved_mode [configparams force-mem-accesses] + configparams force-mem-accesses 1 + + variable PCW_SILICON_VER_1_0 + variable PCW_SILICON_VER_2_0 + variable PCW_SILICON_VER_3_0 + set sil_ver [ps_version] + + if { $sil_ver == $PCW_SILICON_VER_1_0} { + ps7_post_config_1_0 + } elseif { $sil_ver == $PCW_SILICON_VER_2_0 } { + ps7_post_config_2_0 + } else { + ps7_post_config_3_0 + } + configparams force-mem-accesses $saved_mode +} + +proc ps7_debug {} { + variable PCW_SILICON_VER_1_0 + variable PCW_SILICON_VER_2_0 + variable PCW_SILICON_VER_3_0 + set sil_ver [ps_version] + + if { $sil_ver == $PCW_SILICON_VER_1_0} { + ps7_debug_1_0 + } elseif { $sil_ver == $PCW_SILICON_VER_2_0 } { + ps7_debug_2_0 + } else { + ps7_debug_3_0 + } +} +proc ps7_init {} { + variable PCW_SILICON_VER_1_0 + variable PCW_SILICON_VER_2_0 + variable PCW_SILICON_VER_3_0 + set sil_ver [ps_version] + if { $sil_ver == $PCW_SILICON_VER_1_0} { + ps7_mio_init_data_1_0 + ps7_pll_init_data_1_0 + ps7_clock_init_data_1_0 + ps7_ddr_init_data_1_0 + ps7_peripherals_init_data_1_0 + #puts "PCW Silicon Version : 1.0" + } elseif { $sil_ver == $PCW_SILICON_VER_2_0 } { + ps7_mio_init_data_2_0 + ps7_pll_init_data_2_0 + ps7_clock_init_data_2_0 + ps7_ddr_init_data_2_0 + ps7_peripherals_init_data_2_0 + #puts "PCW Silicon Version : 2.0" + } else { + ps7_mio_init_data_3_0 + ps7_pll_init_data_3_0 + ps7_clock_init_data_3_0 + ps7_ddr_init_data_3_0 + ps7_peripherals_init_data_3_0 + #puts "PCW Silicon Version : 3.0" + } +} + + +# For delay calculation using global timer + +# start timer + proc perf_start_clock { } { + + #writing SCU_GLOBAL_TIMER_CONTROL register + + mask_write 0xF8F00208 0x00000109 0x00000009 +} + +# stop timer and reset timer count regs + proc perf_reset_clock { } { + perf_disable_clock + mask_write 0xF8F00200 0xFFFFFFFF 0x00000000 + mask_write 0xF8F00204 0xFFFFFFFF 0x00000000 +} + +# Compute mask for given delay in miliseconds +proc get_number_of_cycles_for_delay { delay } { + + # GTC is always clocked at 1/2 of the CPU frequency (CPU_3x2x) + variable APU_FREQ + return [ expr ($delay * $APU_FREQ /(2 * 1000))] +} + + +# stop timer +proc perf_disable_clock {} { + mask_write 0xF8F00208 0xFFFFFFFF 0x00000000 +} + +proc perf_reset_and_start_timer {} { + perf_reset_clock + perf_start_clock +} + + diff --git a/scripts/runner.sh b/scripts/runner.sh new file mode 100755 index 0000000..49e7049 --- /dev/null +++ b/scripts/runner.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +# Exit if no arguments are provided +if [ "$#" -eq 0 ]; then + echo "Error: No arguments provided." + echo "Usage: run.sh " + exit 1 +fi + +# Get the absolute path to the `scripts/` directory +SCRIPT_DIR="$(cd -- "$(dirname -- "$0")" && pwd)" + +# Get the absolute path to the project root +ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" + +# Run the initialization script +"$SCRIPT_DIR/zynq7000-init.py" + +# Run the GDB debugger in GUI mode. +gdb-multiarch -q -x gdb.gdb "$@" -tui \ No newline at end of file diff --git a/scripts/unittest.sh b/scripts/unittest.sh new file mode 100755 index 0000000..f3dab7d --- /dev/null +++ b/scripts/unittest.sh @@ -0,0 +1,3 @@ +#!/bin/bash +cargo +stable test --target $(rustc -vV | grep host | cut -d ' ' -f2) -p zynq7000-hal +cargo +stable test --target $(rustc -vV | grep host | cut -d ' ' -f2) -p zynq7000 diff --git a/scripts/xsct-init.tcl b/scripts/xsct-init.tcl new file mode 100644 index 0000000..946332f --- /dev/null +++ b/scripts/xsct-init.tcl @@ -0,0 +1,86 @@ +if {[info exists env(ip_address_hw_server)]} { + set ip $env(ip_address_hw_server) +} else { + set ip "localhost" +} + +set init_tcl "" +if {[llength $argv] >= 1} { + set init_tcl [lindex $argv 0] +} else { + puts "error: missing required first argument pointing to initialization TCL script" + exit 1 +} + +if {![file exists $init_tcl]} { + puts "the ps init tcl script '$init_tcl' does not exist" + exit 0 +} + +# parse command-line arguments +set bitstream "" +if {[llength $argv] >= 2} { + set bitstream [lindex $argv 1] +} + +puts "Hardware server IP address: $ip" +connect -url tcp:$ip:3121 + +set devices [targets] + +set apu_line [string trim [targets -nocase -filter {name =~ "APU"}]] +set arm_core_0_line [string trim [targets -nocase -filter {name =~ "ARM Cortex-A9 MPCore #0"}]] +set fpga_line [string trim [targets -nocase -filter {name =~ "xc7z020"}]] + +set apu_device_num [string index $apu_line 0] +set arm_core_0_num [string index $arm_core_0_line 0] +set fpga_device_num [string index $fpga_line 0] + +puts "Select ps target with number: $apu_device_num" + +# Select the target +target $apu_device_num + +# Resetting the target involved problems when an image is stored on the flash. +# It has turned out that it is not essential to reset the system before loading +# the software components into the device. +puts "Reset target" +# TODO: Make the reset optional/configurable via input argument. +# Reset the target +rst + +# Check if bitstream is set and the file exists before programming FPGA +if {$bitstream eq ""} { + puts "Skipping bitstream programming (bitstream argument not set)" +} elseif {![file exists $bitstream]} { + puts "Error: The bitstream file '$bitstream' does not exist" +} else { + puts "Set FPGA target with number: $fpga_device_num" + target $fpga_device_num + + # Without this delay, the FPGA programming may fail + after 1500 + + puts "Programming FPGA with bitstream: $bitstream" + fpga -f $bitstream +} + +puts "Set ps target with device number: $arm_core_0_num" +targets $arm_core_0_num + +puts "Initialize processing system" +# Init processing system +source $init_tcl + +ps7_init +ps7_post_config + +puts "Set arm core 0 target with number: $arm_core_0_num" +target $arm_core_0_num + +if {[info exists env(APP)] && [file exists $env(APP)]} { + puts "Download app $env(APP) to target" + dow $env(APP) +} + +puts "Successful" diff --git a/scripts/zynq7000-init.py b/scripts/zynq7000-init.py new file mode 100755 index 0000000..b293ada --- /dev/null +++ b/scripts/zynq7000-init.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python3 +import shlex +import argparse +import os +import subprocess +import sys +from pathlib import Path + +# Define the default values +TCL_SCRIPT_NAME = "xsct-init.tcl" +SCRIPTS_DIR = "scripts" +DEFAULT_IP_ADDRESS_HW_SERVER = "localhost" + + +def main(): + parser = argparse.ArgumentParser( + description="Wrapper script for xsct-init.tcl\n" + "It launches xsct, initialize and prepare the processing system for debugging and " + "allows loading a bitstream and/or bare-metal application to the board.", + formatter_class=argparse.RawTextHelpFormatter, # This preserves line breaks + ) + parser.add_argument( + "-t", + "--tools", + # Required only if env var is not set + required=not bool(os.getenv("AMD_TOOLS")), + # Use env var if set + default=os.getenv("AMD_TOOLS"), + help="The path to the tool to use. Must point to a valid Vivado tools installation which" + "also provides xsct, for example a Vitis installation.\nThe directory where the path " + "points to should contain a shell script named settings64.sh.\nYou can also set the " + "AMD_TOOLS env variable to set this.", + ) + parser.add_argument( + "--sdt", + dest="sdt", + help="Path to a SDT output folder which contains a PS7 init TCL script and a bitstream.", + ) + parser.add_argument( + "--no-bit", + dest="no_bit", + action="store_true", + help="No bitstream flashing for initialization with SDT.", + ) + parser.add_argument("-a", "--app", dest="app", help="Path to the app to program") + parser.add_argument( + "-i", + "--ip", + default=DEFAULT_IP_ADDRESS_HW_SERVER, + help="The IP address of the hardware server (default: localhost)", + ) + parser.add_argument( + "--itcl", + dest="init_tcl", + default=os.getenv("TCL_INIT_SCRIPT"), + help="Path to the ps7 initialization TCL file to prepare the processing system.\n" + "You can also set the TCL_INIT_SCRIPT env variable to set this.\n" + "It is also set implicitely when specifying the SDT folder with --sdt" + ) + parser.add_argument( + "-b", + "--bit", + dest="bit", + default=os.getenv("ZYNQ_BITSTREAM"), + help="Optional path to the bitstream which will also be programed to the device. It is" + " also searched automatically if the --sdt option is used.\n" + ) + + args = parser.parse_args() + + settings_script = os.path.join(args.tools, "settings64.sh") + + if not os.path.isfile(settings_script): + print(f"Invalid tool path {args.tools}, did not find settings file.") + sys.exit(1) + + # Source the settings script and check for xsdb availability + command = f"source {settings_script} && command -v xsct" + result = subprocess.run( + command, + shell=True, + capture_output=True, + executable="/bin/bash", + ) + + if result.returncode != 0: + print("Error: 'xsct' could not be found after sourcing settings64.sh.") + sys.exit(1) + + if args.app and not os.path.isfile(args.app): + print(f"The app '{args.app}' does not exist") + sys.exit(1) + + # Export environment variables + if args.app: + os.environ["APP"] = args.app + os.environ["IP_ADDRESS_HW_SERVER"] = args.ip + init_tcl = None + bitstream = None + if args.bit: + bitstream = args.bit + if args.sdt: + sdt_path = Path(args.sdt) + # CLI bitstream argument overrides implicit SDT bitstream. + if not args.no_bit and not bitstream: + # Search for .bit files in the SDT folder + bit_files = list(sdt_path.glob("*.bit")) + if len(bit_files) == 0: + print("Error: No .bit file found in the SDT folder.") + elif len(bit_files) > 1: + print("Error: Multiple .bit files found in the SDT folder.") + bitstream = str(bit_files[0]) + # Search for the ps7_init.tcl file + init_script = sdt_path / "ps7_init.tcl" + if not init_script.exists(): + sys.exit("Error: ps7_init.tcl file not found in the SDT folder.") + + init_tcl = str(init_script) + else: + if not args.init_tcl: + print("Error: No ps7_init.tcl file specified.") + sys.exit(1) + if args.bit: + bitstream = args.bit + init_tcl = args.init_tcl + + xsct_script = Path(TCL_SCRIPT_NAME) + + if not xsct_script.exists(): + xsct_script = Path(os.path.join(SCRIPTS_DIR, TCL_SCRIPT_NAME)) + if not xsct_script.exists(): + print(f"Could not find the xsct initialization script {TCL_SCRIPT_NAME}") + sys.exit(1) + + # Launch xsct with the initialization script + # Prepare tcl_args as a list to avoid manual string concatenation issues + cmd_list = ["xsct", str(xsct_script), init_tcl] + if bitstream: + cmd_list.append(bitstream) + + # Join safely for shell execution + xsct_cmd = shlex.join(cmd_list) + print(f"Running xsct command: {xsct_cmd}") + command = f"bash -c 'source {settings_script} && {xsct_cmd} | tee xsct-output.log'" + subprocess.run( + command, + shell=True, + check=True, + ) + + +if __name__ == "__main__": + main() diff --git a/vscode/launch.json b/vscode/launch.json new file mode 100644 index 0000000..df219ab --- /dev/null +++ b/vscode/launch.json @@ -0,0 +1,155 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug Blinky Example", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/target/armv7a-none-eabihf/debug/simple", + "miDebuggerServerAddress": "localhost:3000", + "miDebuggerPath": "/usr/bin/gdb-multiarch", + "stopAtEntry": true, + "useExtendedRemote": true, + "cwd": "${workspaceFolder}", + "externalConsole": false, + "MIMode": "gdb", + "launchCompleteCommand": "None", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "Load symbols for the program", + "text": "symbol-file ${workspaceFolder}/target/armv7a-none-eabihf/debug/simple", + "ignoreFailures": false + }, + { + "text": "set output-radix 16" + } + ], + "preLaunchTask": "flash-blinky" + }, + { + "name": "Debug Logger Example", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/target/armv7a-none-eabihf/debug/logger", + "miDebuggerServerAddress": "localhost:3000", + "miDebuggerPath": "/usr/bin/gdb-multiarch", + "stopAtEntry": true, + "useExtendedRemote": true, + "cwd": "${workspaceFolder}", + "externalConsole": false, + "MIMode": "gdb", + "launchCompleteCommand": "None", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "Load symbols for the program", + "text": "symbol-file ${workspaceFolder}/target/armv7a-none-eabihf/debug/logger", + "ignoreFailures": false + }, + { + "text": "set output-radix 16" + } + ], + "preLaunchTask": "flash-logger" + }, + { + "name": "Debug Embassy Example", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/target/armv7a-none-eabihf/debug/embassy-examples", + "miDebuggerServerAddress": "localhost:3000", + "miDebuggerPath": "/usr/bin/gdb-multiarch", + "stopAtEntry": true, + "useExtendedRemote": true, + "cwd": "${workspaceFolder}", + "externalConsole": false, + "MIMode": "gdb", + "launchCompleteCommand": "None", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "Load symbols for the program", + "text": "symbol-file ${workspaceFolder}/target/armv7a-none-eabihf/debug/embassy-examples", + "ignoreFailures": false + }, + { + "text": "set output-radix 16" + } + ], + "preLaunchTask": "flash-embassy" + }, + { + "name": "Debug Zedboard GPIOs", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/target/armv7a-none-eabihf/debug/zedboard", + "miDebuggerServerAddress": "localhost:3000", + "miDebuggerPath": "/usr/bin/gdb-multiarch", + "stopAtEntry": true, + "useExtendedRemote": true, + "cwd": "${workspaceFolder}", + "externalConsole": false, + "MIMode": "gdb", + "launchCompleteCommand": "None", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "Load symbols for the program", + "text": "symbol-file ${workspaceFolder}/target/armv7a-none-eabihf/debug/zedboard", + "ignoreFailures": false + }, + { + "text": "set output-radix 16" + } + ], + "preLaunchTask": "flash-zed-gpios" + }, + { + "name": "Debug UART Non-Blocking", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/target/armv7a-none-eabihf/debug/uart-non-blocking", + "miDebuggerServerAddress": "localhost:3000", + "miDebuggerPath": "/usr/bin/gdb-multiarch", + "stopAtEntry": true, + "useExtendedRemote": true, + "cwd": "${workspaceFolder}", + "externalConsole": false, + "MIMode": "gdb", + "launchCompleteCommand": "None", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "Load symbols for the program", + "text": "symbol-file ${workspaceFolder}/target/armv7a-none-eabihf/debug/uart-non-blocking", + "ignoreFailures": false + }, + { + "text": "set output-radix 16" + } + ], + "preLaunchTask": "flash-uart-non-blocking" + } + ] +} \ No newline at end of file diff --git a/vscode/tasks.json b/vscode/tasks.json new file mode 100644 index 0000000..575c02e --- /dev/null +++ b/vscode/tasks.json @@ -0,0 +1,163 @@ +{ + "version": "2.0.0", + "options": { + "env": { + // Pass environment variables to the zynq7000-init.py script. + "AMD_TOOLS": "/tools/Xilinx/Vitis/2024.1", + "TCL_INIT_SCRIPT": "${workspaceFolder}/zedboard-fpga-design/sdt_out/ps7_init.tcl", + // Leading _, otherwise the Python script will always flash it. + "_ZYNQ_BITSTREAM": "${workspaceFolder}/zedboard-fpga-design/sdt_out/zedboard-rust.bit" + } + }, + "tasks": [ + { + "label": "zedboard-init", + "type": "shell", + "command": "${workspaceFolder}/scripts/zynq7000-init.py", + "args": [ + "--bit", + "${BITSTREAM}" + ], + "problemMatcher": [] + }, + { + "label": "flash-blinky", + "type": "shell", + "command": "${workspaceFolder}/scripts/zynq7000-init.py", + "args": [ + "-a", + "${workspaceFolder}/target/armv7a-none-eabihf/debug/simple" + ], + "dependsOn": [ + "build-blinky" + ], + "problemMatcher": [] + }, + { + "label": "build-blinky", + "type": "shell", + "command": "~/.cargo/bin/cargo", // note: full path to the cargo + "args": [ + "build", + "-p", + "simple" + ], + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "flash-logger", + "type": "shell", + "command": "${workspaceFolder}/scripts/zynq7000-init.py", + "args": [ + "-a", + "${workspaceFolder}/target/armv7a-none-eabihf/debug/logger" + ], + "dependsOn": [ + "build-logger" + ], + "problemMatcher": [] + }, + { + "label": "build-logger", + "type": "shell", + "command": "~/.cargo/bin/cargo", // note: full path to the cargo + "args": [ + "build", + "--bin", + "logger" + ], + "group": { + "kind": "build" + } + }, + { + "label": "flash-embassy", + "type": "shell", + "command": "${workspaceFolder}/scripts/zynq7000-init.py", + "args": [ + "-a", + "${workspaceFolder}/target/armv7a-none-eabihf/debug/embassy-examples" + ], + "dependsOn": [ + "build-embassy" + ], + "problemMatcher": [] + }, + { + "label": "build-embassy", + "type": "shell", + "command": "~/.cargo/bin/cargo", // note: full path to the cargo + "args": [ + "build", + "-p", + "embassy-examples" + ], + "group": { + "kind": "build" + } + }, + { + "label": "flash-zed-gpios", + "type": "shell", + "command": "${workspaceFolder}/scripts/zynq7000-init.py", + "args": [ + "-a", + "${workspaceFolder}/target/armv7a-none-eabihf/debug/zedboard", + // The bitstream does not necesarilly need to be flashed each time, but doing so here requires one + // less extra step to prepare the system. + "--bit", + "${_ZYNQ_BITSTREAM}" + ], + "dependsOn": [ + "build-zed-gpios" + ], + "problemMatcher": [] + }, + { + "label": "build-zed-gpios", + "type": "shell", + "command": "~/.cargo/bin/cargo", // note: full path to the cargo + "args": [ + "build", + "--bin", + "zedboard" + ], + "group": { + "kind": "build" + } + }, + { + "label": "flash-uart-non-blocking", + "type": "shell", + "command": "${workspaceFolder}/scripts/zynq7000-init.py", + "args": [ + "-a", + "${workspaceFolder}/target/armv7a-none-eabihf/debug/uart-non-blocking", + // The bitstream does not necesarilly need to be flashed each time, but doing so here requires one + // less extra step to prepare the system. + "--bit", + "${_ZYNQ_BITSTREAM}" + ], + "dependsOn": [ + "build-uart-non-blocking" + ], + "problemMatcher": [] + }, + { + "label": "build-uart-non-blocking", + "type": "shell", + "command": "~/.cargo/bin/cargo", // note: full path to the cargo + "args": [ + "build", + "--bin", + "uart-non-blocking" + ], + "group": { + "kind": "build" + } + } + ] +} \ No newline at end of file diff --git a/zedboard-fpga-design/.gitignore b/zedboard-fpga-design/.gitignore new file mode 100644 index 0000000..3e4ed20 --- /dev/null +++ b/zedboard-fpga-design/.gitignore @@ -0,0 +1,5 @@ +/zedboard-rust +/.Xil +/vivado* +/sdt_out +/xsct-output.log diff --git a/zedboard-fpga-design/README.md b/zedboard-fpga-design/README.md new file mode 100644 index 0000000..2e4d5f6 --- /dev/null +++ b/zedboard-fpga-design/README.md @@ -0,0 +1,40 @@ +Zedboard FPGA design for Rust +======= + +This is an example/reference design which was used to verify various components provided +by this library. To minimize the amount of HW designs required, one project is provided. +The design was kept as generic as possible. In principle, it should be possible to adapt the +hardware design to other boards with modifications. + +# Pre-Requisites + +- [Vivado installation](https://www.xilinx.com/support/download/index.html/content/xilinx/en/downloadNav/vivado-design-tools.html) + or [Vitis installation](https://www.xilinx.com/support/download/index.html/content/xilinx/en/downloadNav/vitis.html) + which includes Vivado. This example design was created with/for Vivado 2024.1, but also might work + for newer versions. +- [Zedboard board files](https://github.com/Digilent/vivado-boards) added to the Vivado installation. + +# Loading the project and the block design with the GUI + +You can load the project using the batch mode of `vivado` inside the folder where you want to +create the `zedboard-rust` project: + +```sh +vivado -mode batch -source -tclargs --overwrite +``` + +for example, to create the directory directly insdie this directory: + +```sh +vivado -mode batch -source zedboard-rust.tcl -tclargs --overwrite +``` + +This should create a `zedboard-rust` Vivado project folder containing a `zedboard-rust.xpr` +project file. You can load this project file with Vivado: + +```sh +vivado zedboard-rust.xpr +``` + +You can perform all the steps specified in the Vivado GUI as well using `Execute TCL script` and +`Load Project`. diff --git a/zedboard-fpga-design/export-hw.tcl b/zedboard-fpga-design/export-hw.tcl new file mode 100644 index 0000000..1ed9209 --- /dev/null +++ b/zedboard-fpga-design/export-hw.tcl @@ -0,0 +1,2 @@ +set hw_file "[get_property DIRECTORY [current_project]]/zedboard-rust.xsa" +write_hw_platform -fixed -include_bit -force -file $hw_file diff --git a/zedboard-fpga-design/sdtgen.py b/zedboard-fpga-design/sdtgen.py new file mode 100755 index 0000000..87357e4 --- /dev/null +++ b/zedboard-fpga-design/sdtgen.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +import argparse +import os +import subprocess +import sys + + +def main(): + parser = argparse.ArgumentParser( + description="Script to generate SDT files from a XSA file" + ) + parser.add_argument( + "-t", + "--tools", + # Required only if env var is not set + required=not bool(os.getenv("AMD_TOOLS")), + # Use env var if set + default=os.getenv("AMD_TOOLS"), + help="The path to the tool to use. Must point to a valid Vivado tools installation which" + "also provides xsct, for example a Vitis installation.\nThe directory where the path " + "points to should contain a shell script named settings64.sh.\n You can also set the " + "AMD_TOOLS env variable to set this.", + ) + parser.add_argument( + "-x", + "--xsa", + help="Path to the input XSA file", + default="zedboard-rust/zedboard-rust.xsa", + ) + parser.add_argument( + "-o", + "--out", + default="sdt_out", + help="Directory to store the generated SDT files", + ) + + args = parser.parse_args() + + settings_script = os.path.join(args.tools, "settings64.sh") + + if not os.path.isfile(settings_script): + print(f"Invalid tool path {args.tools}, did not find settings file.") + sys.exit(1) + + # Source the settings script and check for xsdb availability + command = f"source {settings_script} && command -v xsct" + result = subprocess.run( + command, + shell=True, + capture_output=True, + executable="/bin/bash", + ) + + if result.returncode != 0: + print("Error: 'xsct' could not be found after sourcing settings64.sh.") + sys.exit(1) + + xsct_script = "sdtgen.tcl" + + command = f"bash -c 'source {settings_script} && xsct {xsct_script} {args.xsa} {args.out} | tee xsct-output.log'" + subprocess.run( + command, + shell=True, + check=True, + ) + + +if __name__ == "__main__": + main() diff --git a/zedboard-fpga-design/sdtgen.tcl b/zedboard-fpga-design/sdtgen.tcl new file mode 100644 index 0000000..2c8bbbd --- /dev/null +++ b/zedboard-fpga-design/sdtgen.tcl @@ -0,0 +1,4 @@ + set outdir [lindex $argv 1] + set xsa [lindex $argv 0] + sdtgen set_dt_param -xsa $xsa -dir $outdir -board_dts zedboard + sdtgen generate_sdt diff --git a/zedboard-fpga-design/src/uart_mux.vhd b/zedboard-fpga-design/src/uart_mux.vhd new file mode 100644 index 0000000..e502b06 --- /dev/null +++ b/zedboard-fpga-design/src/uart_mux.vhd @@ -0,0 +1,88 @@ +---------------------------------------------------------------------------------- +-- Company: Institute of Space Systems, University of Stuttgart +-- Engineer: Robin Mueller +-- +-- Description: +-- The module multiplexes three UART modules. +-- It can be used to select between UART0 through EMIO, UARTLITE or UART16550. +---------------------------------------------------------------------------------- + + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; + +entity uart_mux is +port( + sys_clk : in std_logic; + + uart_0_tx : in std_logic; + uart_0_rx : out std_logic; + + uart_1_tx : in std_logic; + uart_1_rx : out std_logic; + + uart_2_tx : in std_logic; + uart_2_rx : out std_logic; + + tx_out: out std_logic; + rx_in: in std_logic; + + -- "000" -> UART0 + -- "001" -> UART1 + -- "010" -> UART2 + -- "011" -> UART0 to UART1 + -- "100" -> UART0 to UART2 + -- "101" -> UART1 to UART2 + sel : in std_logic_vector(2 downto 0) + + ); +end uart_mux; + +architecture Behavioral of uart_mux is + +begin + +switch : process(sys_clk) +begin + if rising_edge(sys_clk) then + case sel is + when "000" => + tx_out <= uart_0_tx; + uart_0_rx <= rx_in; + uart_1_rx <= '1'; + uart_2_rx <= '1'; + when "001" => + tx_out <= uart_1_tx; + uart_1_rx <= rx_in; + uart_2_rx <= '1'; + uart_0_rx <= '1'; + when "010" => + tx_out <= uart_2_tx; + uart_2_rx <= rx_in; + uart_1_rx <= '1'; + uart_0_rx <= '1'; + when "011" => + tx_out <= '1'; + uart_1_rx <= uart_0_tx; + uart_0_rx <= uart_1_tx; + uart_2_rx <= '1'; + when "100" => + tx_out <= '1'; + uart_2_rx <= uart_0_tx; + uart_0_rx <= uart_2_tx; + uart_1_rx <= '1'; + when "101" => + tx_out <= '1'; + uart_1_rx <= uart_2_tx; + uart_2_rx <= uart_1_tx; + uart_0_rx <= '1'; + when others => + tx_out <= '1'; + uart_0_rx <= '1'; + uart_1_rx <= '1'; + uart_2_rx <= '1'; + end case; + end if; +end process; -- switch + +end Behavioral; diff --git a/zedboard-fpga-design/src/zedboard-bd.tcl b/zedboard-fpga-design/src/zedboard-bd.tcl new file mode 100644 index 0000000..d5a3fdd --- /dev/null +++ b/zedboard-fpga-design/src/zedboard-bd.tcl @@ -0,0 +1,698 @@ + +################################################################ +# This is a generated script based on design: zedboard +# +# Though there are limitations about the generated script, +# the main purpose of this utility is to make learning +# IP Integrator Tcl commands easier. +################################################################ + +namespace eval _tcl { +proc get_script_folder {} { + set script_path [file normalize [info script]] + set script_folder [file dirname $script_path] + return $script_folder +} +} +variable script_folder +set script_folder [_tcl::get_script_folder] + +################################################################ +# Check if script is running in correct Vivado version. +################################################################ +set scripts_vivado_version 2024.1 +set current_vivado_version [version -short] + +if { [string first $scripts_vivado_version $current_vivado_version] == -1 } { + puts "" + if { [string compare $scripts_vivado_version $current_vivado_version] > 0 } { + catch {common::send_gid_msg -ssname BD::TCL -id 2042 -severity "ERROR" " This script was generated using Vivado <$scripts_vivado_version> and is being run in <$current_vivado_version> of Vivado. Sourcing the script failed since it was created with a future version of Vivado."} + + } else { + catch {common::send_gid_msg -ssname BD::TCL -id 2041 -severity "ERROR" "This script was generated using Vivado <$scripts_vivado_version> and is being run in <$current_vivado_version> of Vivado. Please run the script in Vivado <$scripts_vivado_version> then open the design in Vivado <$current_vivado_version>. Upgrade the design by running \"Tools => Report => Report IP Status...\", then run write_bd_tcl to create an updated script."} + + } + + return 1 +} + +################################################################ +# START +################################################################ + +# To test this script, run the following commands from Vivado Tcl console: +# source zedboard_script.tcl + + +# The design that will be created by this Tcl script contains the following +# module references: +# uart_mux + +# Please add the sources of those modules before sourcing this Tcl script. + +# If there is no project opened, this script will create a +# project, but make sure you do not have an existing project +# <./myproj/project_1.xpr> in the current working folder. + +set list_projs [get_projects -quiet] +if { $list_projs eq "" } { + create_project project_1 myproj -part xc7z020clg484-1 + set_property BOARD_PART digilentinc.com:zedboard:part0:1.1 [current_project] +} + + +# CHANGE DESIGN NAME HERE +variable design_name +set design_name zedboard + +# If you do not already have an existing IP Integrator design open, +# you can create a design using the following command: +# create_bd_design $design_name + +# Creating design if needed +set errMsg "" +set nRet 0 + +set cur_design [current_bd_design -quiet] +set list_cells [get_bd_cells -quiet] + +if { ${design_name} eq "" } { + # USE CASES: + # 1) Design_name not set + + set errMsg "Please set the variable to a non-empty value." + set nRet 1 + +} elseif { ${cur_design} ne "" && ${list_cells} eq "" } { + # USE CASES: + # 2): Current design opened AND is empty AND names same. + # 3): Current design opened AND is empty AND names diff; design_name NOT in project. + # 4): Current design opened AND is empty AND names diff; design_name exists in project. + + if { $cur_design ne $design_name } { + common::send_gid_msg -ssname BD::TCL -id 2001 -severity "INFO" "Changing value of from <$design_name> to <$cur_design> since current design is empty." + set design_name [get_property NAME $cur_design] + } + common::send_gid_msg -ssname BD::TCL -id 2002 -severity "INFO" "Constructing design in IPI design <$cur_design>..." + +} elseif { ${cur_design} ne "" && $list_cells ne "" && $cur_design eq $design_name } { + # USE CASES: + # 5) Current design opened AND has components AND same names. + + set errMsg "Design <$design_name> already exists in your project, please set the variable to another value." + set nRet 1 +} elseif { [get_files -quiet ${design_name}.bd] ne "" } { + # USE CASES: + # 6) Current opened design, has components, but diff names, design_name exists in project. + # 7) No opened design, design_name exists in project. + + set errMsg "Design <$design_name> already exists in your project, please set the variable to another value." + set nRet 2 + +} else { + # USE CASES: + # 8) No opened design, design_name not in project. + # 9) Current opened design, has components, but diff names, design_name not in project. + + common::send_gid_msg -ssname BD::TCL -id 2003 -severity "INFO" "Currently there is no design <$design_name> in project, so creating one..." + + create_bd_design $design_name + + common::send_gid_msg -ssname BD::TCL -id 2004 -severity "INFO" "Making design <$design_name> as current_bd_design." + current_bd_design $design_name + +} + +common::send_gid_msg -ssname BD::TCL -id 2005 -severity "INFO" "Currently the variable is equal to \"$design_name\"." + +if { $nRet != 0 } { + catch {common::send_gid_msg -ssname BD::TCL -id 2006 -severity "ERROR" $errMsg} + return $nRet +} + +set bCheckIPsPassed 1 +################################################################## +# CHECK IPs +################################################################## +set bCheckIPs 1 +if { $bCheckIPs == 1 } { + set list_check_ips "\ +xilinx.com:ip:processing_system7:5.5\ +xilinx.com:ip:axi_uartlite:2.0\ +xilinx.com:ip:proc_sys_reset:5.0\ +xilinx.com:ip:axi_uart16550:2.0\ +xilinx.com:ip:xlconcat:2.1\ +xilinx.com:ip:xlslice:1.0\ +xilinx.com:ip:xlconstant:1.1\ +" + + set list_ips_missing "" + common::send_gid_msg -ssname BD::TCL -id 2011 -severity "INFO" "Checking if the following IPs exist in the project's IP catalog: $list_check_ips ." + + foreach ip_vlnv $list_check_ips { + set ip_obj [get_ipdefs -all $ip_vlnv] + if { $ip_obj eq "" } { + lappend list_ips_missing $ip_vlnv + } + } + + if { $list_ips_missing ne "" } { + catch {common::send_gid_msg -ssname BD::TCL -id 2012 -severity "ERROR" "The following IPs are not found in the IP Catalog:\n $list_ips_missing\n\nResolution: Please add the repository containing the IP(s) to the project." } + set bCheckIPsPassed 0 + } + +} + +################################################################## +# CHECK Modules +################################################################## +set bCheckModules 1 +if { $bCheckModules == 1 } { + set list_check_mods "\ +uart_mux\ +" + + set list_mods_missing "" + common::send_gid_msg -ssname BD::TCL -id 2020 -severity "INFO" "Checking if the following modules exist in the project's sources: $list_check_mods ." + + foreach mod_vlnv $list_check_mods { + if { [can_resolve_reference $mod_vlnv] == 0 } { + lappend list_mods_missing $mod_vlnv + } + } + + if { $list_mods_missing ne "" } { + catch {common::send_gid_msg -ssname BD::TCL -id 2021 -severity "ERROR" "The following module(s) are not found in the project: $list_mods_missing" } + common::send_gid_msg -ssname BD::TCL -id 2022 -severity "INFO" "Please add source files for the missing module(s) above." + set bCheckIPsPassed 0 + } +} + +if { $bCheckIPsPassed != 1 } { + common::send_gid_msg -ssname BD::TCL -id 2023 -severity "WARNING" "Will not continue with creation of design due to the error(s) above." + return 3 +} + +################################################################## +# DESIGN PROCs +################################################################## + + + +# Procedure to create entire design; Provide argument to make +# procedure reusable. If parentCell is "", will use root. +proc create_root_design { parentCell } { + + variable script_folder + variable design_name + + if { $parentCell eq "" } { + set parentCell [get_bd_cells /] + } + + # Get object for parentCell + set parentObj [get_bd_cells $parentCell] + if { $parentObj == "" } { + catch {common::send_gid_msg -ssname BD::TCL -id 2090 -severity "ERROR" "Unable to find parent cell <$parentCell>!"} + return + } + + # Make sure parentObj is hier blk + set parentType [get_property TYPE $parentObj] + if { $parentType ne "hier" } { + catch {common::send_gid_msg -ssname BD::TCL -id 2091 -severity "ERROR" "Parent <$parentObj> has TYPE = <$parentType>. Expected to be ."} + return + } + + # Save current instance; Restore later + set oldCurInst [current_bd_instance .] + + # Set parent object as current + current_bd_instance $parentObj + + + # Create interface ports + set DDR [ create_bd_intf_port -mode Master -vlnv xilinx.com:interface:ddrx_rtl:1.0 DDR ] + + set FIXED_IO [ create_bd_intf_port -mode Master -vlnv xilinx.com:display_processing_system7:fixedio_rtl:1.0 FIXED_IO ] + + + # Create ports + set LEDS [ create_bd_port -dir O -from 7 -to 0 LEDS ] + set SWITCHES [ create_bd_port -dir I -from 7 -to 0 SWITCHES ] + set BTTNS [ create_bd_port -dir I -from 4 -to 0 BTTNS ] + set UART_txd [ create_bd_port -dir O UART_txd ] + set UART_rxd [ create_bd_port -dir I UART_rxd ] + set TTC0_WAVEOUT [ create_bd_port -dir O TTC0_WAVEOUT ] + + # Create instance: processing_system7_0, and set properties + set processing_system7_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:processing_system7:5.5 processing_system7_0 ] + set_property -dict [list \ + CONFIG.PCW_ACT_APU_PERIPHERAL_FREQMHZ {650.000000} \ + CONFIG.PCW_ACT_CAN_PERIPHERAL_FREQMHZ {10.000000} \ + CONFIG.PCW_ACT_DCI_PERIPHERAL_FREQMHZ {10.158730} \ + CONFIG.PCW_ACT_ENET0_PERIPHERAL_FREQMHZ {125.000000} \ + CONFIG.PCW_ACT_ENET1_PERIPHERAL_FREQMHZ {10.000000} \ + CONFIG.PCW_ACT_FPGA0_PERIPHERAL_FREQMHZ {100.000000} \ + CONFIG.PCW_ACT_FPGA1_PERIPHERAL_FREQMHZ {10.000000} \ + CONFIG.PCW_ACT_FPGA2_PERIPHERAL_FREQMHZ {10.000000} \ + CONFIG.PCW_ACT_FPGA3_PERIPHERAL_FREQMHZ {10.000000} \ + CONFIG.PCW_ACT_PCAP_PERIPHERAL_FREQMHZ {200.000000} \ + CONFIG.PCW_ACT_QSPI_PERIPHERAL_FREQMHZ {200.000000} \ + CONFIG.PCW_ACT_SDIO_PERIPHERAL_FREQMHZ {50.000000} \ + CONFIG.PCW_ACT_SMC_PERIPHERAL_FREQMHZ {10.000000} \ + CONFIG.PCW_ACT_SPI_PERIPHERAL_FREQMHZ {10.000000} \ + CONFIG.PCW_ACT_TPIU_PERIPHERAL_FREQMHZ {200.000000} \ + CONFIG.PCW_ACT_TTC0_CLK0_PERIPHERAL_FREQMHZ {108.333336} \ + CONFIG.PCW_ACT_TTC0_CLK1_PERIPHERAL_FREQMHZ {108.333336} \ + CONFIG.PCW_ACT_TTC0_CLK2_PERIPHERAL_FREQMHZ {108.333336} \ + CONFIG.PCW_ACT_TTC1_CLK0_PERIPHERAL_FREQMHZ {108.333336} \ + CONFIG.PCW_ACT_TTC1_CLK1_PERIPHERAL_FREQMHZ {108.333336} \ + CONFIG.PCW_ACT_TTC1_CLK2_PERIPHERAL_FREQMHZ {108.333336} \ + CONFIG.PCW_ACT_UART_PERIPHERAL_FREQMHZ {100.000000} \ + CONFIG.PCW_ACT_WDT_PERIPHERAL_FREQMHZ {108.333336} \ + CONFIG.PCW_APU_PERIPHERAL_FREQMHZ {650} \ + CONFIG.PCW_CLK0_FREQ {100000000} \ + CONFIG.PCW_CLK1_FREQ {10000000} \ + CONFIG.PCW_CLK2_FREQ {10000000} \ + CONFIG.PCW_CLK3_FREQ {10000000} \ + CONFIG.PCW_CORE0_FIQ_INTR {0} \ + CONFIG.PCW_CRYSTAL_PERIPHERAL_FREQMHZ {33.333333} \ + CONFIG.PCW_DDR_RAM_HIGHADDR {0x1FFFFFFF} \ + CONFIG.PCW_ENET0_ENET0_IO {MIO 16 .. 27} \ + CONFIG.PCW_ENET0_GRP_MDIO_ENABLE {1} \ + CONFIG.PCW_ENET0_GRP_MDIO_IO {EMIO} \ + CONFIG.PCW_ENET0_PERIPHERAL_ENABLE {1} \ + CONFIG.PCW_ENET0_PERIPHERAL_FREQMHZ {1000 Mbps} \ + CONFIG.PCW_ENET0_RESET_ENABLE {0} \ + CONFIG.PCW_ENET_RESET_ENABLE {1} \ + CONFIG.PCW_ENET_RESET_SELECT {Share reset pin} \ + CONFIG.PCW_EN_EMIO_GPIO {1} \ + CONFIG.PCW_EN_EMIO_TTC0 {1} \ + CONFIG.PCW_EN_EMIO_TTC1 {0} \ + CONFIG.PCW_EN_EMIO_UART0 {1} \ + CONFIG.PCW_EN_EMIO_WP_SDIO0 {1} \ + CONFIG.PCW_EN_ENET0 {1} \ + CONFIG.PCW_EN_GPIO {1} \ + CONFIG.PCW_EN_QSPI {1} \ + CONFIG.PCW_EN_SDIO0 {1} \ + CONFIG.PCW_EN_TTC0 {1} \ + CONFIG.PCW_EN_TTC1 {0} \ + CONFIG.PCW_EN_UART0 {1} \ + CONFIG.PCW_EN_UART1 {1} \ + CONFIG.PCW_EN_USB0 {1} \ + CONFIG.PCW_FPGA0_PERIPHERAL_FREQMHZ {100} \ + CONFIG.PCW_FPGA_FCLK0_ENABLE {1} \ + CONFIG.PCW_GPIO_EMIO_GPIO_ENABLE {1} \ + CONFIG.PCW_GPIO_EMIO_GPIO_IO {64} \ + CONFIG.PCW_GPIO_EMIO_GPIO_WIDTH {64} \ + CONFIG.PCW_GPIO_MIO_GPIO_ENABLE {1} \ + CONFIG.PCW_GPIO_MIO_GPIO_IO {MIO} \ + CONFIG.PCW_I2C_RESET_ENABLE {1} \ + CONFIG.PCW_IRQ_F2P_INTR {1} \ + CONFIG.PCW_MIO_0_IOTYPE {LVCMOS 3.3V} \ + CONFIG.PCW_MIO_0_PULLUP {enabled} \ + CONFIG.PCW_MIO_0_SLEW {slow} \ + CONFIG.PCW_MIO_10_IOTYPE {LVCMOS 3.3V} \ + CONFIG.PCW_MIO_10_PULLUP {enabled} \ + CONFIG.PCW_MIO_10_SLEW {slow} \ + CONFIG.PCW_MIO_11_IOTYPE {LVCMOS 3.3V} \ + CONFIG.PCW_MIO_11_PULLUP {enabled} \ + CONFIG.PCW_MIO_11_SLEW {slow} \ + CONFIG.PCW_MIO_12_IOTYPE {LVCMOS 3.3V} \ + CONFIG.PCW_MIO_12_PULLUP {enabled} \ + CONFIG.PCW_MIO_12_SLEW {slow} \ + CONFIG.PCW_MIO_13_IOTYPE {LVCMOS 3.3V} \ + CONFIG.PCW_MIO_13_PULLUP {enabled} \ + CONFIG.PCW_MIO_13_SLEW {slow} \ + CONFIG.PCW_MIO_14_IOTYPE {LVCMOS 3.3V} \ + CONFIG.PCW_MIO_14_PULLUP {enabled} \ + CONFIG.PCW_MIO_14_SLEW {slow} \ + CONFIG.PCW_MIO_15_IOTYPE {LVCMOS 3.3V} \ + CONFIG.PCW_MIO_15_PULLUP {enabled} \ + CONFIG.PCW_MIO_15_SLEW {slow} \ + CONFIG.PCW_MIO_16_IOTYPE {HSTL 1.8V} \ + CONFIG.PCW_MIO_16_PULLUP {disabled} \ + CONFIG.PCW_MIO_16_SLEW {fast} \ + CONFIG.PCW_MIO_17_IOTYPE {HSTL 1.8V} \ + CONFIG.PCW_MIO_17_PULLUP {disabled} \ + CONFIG.PCW_MIO_17_SLEW {fast} \ + CONFIG.PCW_MIO_18_IOTYPE {HSTL 1.8V} \ + CONFIG.PCW_MIO_18_PULLUP {disabled} \ + CONFIG.PCW_MIO_18_SLEW {fast} \ + CONFIG.PCW_MIO_19_IOTYPE {HSTL 1.8V} \ + CONFIG.PCW_MIO_19_PULLUP {disabled} \ + CONFIG.PCW_MIO_19_SLEW {fast} \ + CONFIG.PCW_MIO_1_IOTYPE {LVCMOS 3.3V} \ + CONFIG.PCW_MIO_1_PULLUP {disabled} \ + CONFIG.PCW_MIO_1_SLEW {fast} \ + CONFIG.PCW_MIO_20_IOTYPE {HSTL 1.8V} \ + CONFIG.PCW_MIO_20_PULLUP {disabled} \ + CONFIG.PCW_MIO_20_SLEW {fast} \ + CONFIG.PCW_MIO_21_IOTYPE {HSTL 1.8V} \ + CONFIG.PCW_MIO_21_PULLUP {disabled} \ + CONFIG.PCW_MIO_21_SLEW {fast} \ + CONFIG.PCW_MIO_22_IOTYPE {HSTL 1.8V} \ + CONFIG.PCW_MIO_22_PULLUP {disabled} \ + CONFIG.PCW_MIO_22_SLEW {fast} \ + CONFIG.PCW_MIO_23_IOTYPE {HSTL 1.8V} \ + CONFIG.PCW_MIO_23_PULLUP {disabled} \ + CONFIG.PCW_MIO_23_SLEW {fast} \ + CONFIG.PCW_MIO_24_IOTYPE {HSTL 1.8V} \ + CONFIG.PCW_MIO_24_PULLUP {disabled} \ + CONFIG.PCW_MIO_24_SLEW {fast} \ + CONFIG.PCW_MIO_25_IOTYPE {HSTL 1.8V} \ + CONFIG.PCW_MIO_25_PULLUP {disabled} \ + CONFIG.PCW_MIO_25_SLEW {fast} \ + CONFIG.PCW_MIO_26_IOTYPE {HSTL 1.8V} \ + CONFIG.PCW_MIO_26_PULLUP {disabled} \ + CONFIG.PCW_MIO_26_SLEW {fast} \ + CONFIG.PCW_MIO_27_IOTYPE {HSTL 1.8V} \ + CONFIG.PCW_MIO_27_PULLUP {disabled} \ + CONFIG.PCW_MIO_27_SLEW {fast} \ + CONFIG.PCW_MIO_28_IOTYPE {LVCMOS 1.8V} \ + CONFIG.PCW_MIO_28_PULLUP {disabled} \ + CONFIG.PCW_MIO_28_SLEW {fast} \ + CONFIG.PCW_MIO_29_IOTYPE {LVCMOS 1.8V} \ + CONFIG.PCW_MIO_29_PULLUP {disabled} \ + CONFIG.PCW_MIO_29_SLEW {fast} \ + CONFIG.PCW_MIO_2_IOTYPE {LVCMOS 3.3V} \ + CONFIG.PCW_MIO_2_SLEW {fast} \ + CONFIG.PCW_MIO_30_IOTYPE {LVCMOS 1.8V} \ + CONFIG.PCW_MIO_30_PULLUP {disabled} \ + CONFIG.PCW_MIO_30_SLEW {fast} \ + CONFIG.PCW_MIO_31_IOTYPE {LVCMOS 1.8V} \ + CONFIG.PCW_MIO_31_PULLUP {disabled} \ + CONFIG.PCW_MIO_31_SLEW {fast} \ + CONFIG.PCW_MIO_32_IOTYPE {LVCMOS 1.8V} \ + CONFIG.PCW_MIO_32_PULLUP {disabled} \ + CONFIG.PCW_MIO_32_SLEW {fast} \ + CONFIG.PCW_MIO_33_IOTYPE {LVCMOS 1.8V} \ + CONFIG.PCW_MIO_33_PULLUP {disabled} \ + CONFIG.PCW_MIO_33_SLEW {fast} \ + CONFIG.PCW_MIO_34_IOTYPE {LVCMOS 1.8V} \ + CONFIG.PCW_MIO_34_PULLUP {disabled} \ + CONFIG.PCW_MIO_34_SLEW {fast} \ + CONFIG.PCW_MIO_35_IOTYPE {LVCMOS 1.8V} \ + CONFIG.PCW_MIO_35_PULLUP {disabled} \ + CONFIG.PCW_MIO_35_SLEW {fast} \ + CONFIG.PCW_MIO_36_IOTYPE {LVCMOS 1.8V} \ + CONFIG.PCW_MIO_36_PULLUP {disabled} \ + CONFIG.PCW_MIO_36_SLEW {fast} \ + CONFIG.PCW_MIO_37_IOTYPE {LVCMOS 1.8V} \ + CONFIG.PCW_MIO_37_PULLUP {disabled} \ + CONFIG.PCW_MIO_37_SLEW {fast} \ + CONFIG.PCW_MIO_38_IOTYPE {LVCMOS 1.8V} \ + CONFIG.PCW_MIO_38_PULLUP {disabled} \ + CONFIG.PCW_MIO_38_SLEW {fast} \ + CONFIG.PCW_MIO_39_IOTYPE {LVCMOS 1.8V} \ + CONFIG.PCW_MIO_39_PULLUP {disabled} \ + CONFIG.PCW_MIO_39_SLEW {fast} \ + CONFIG.PCW_MIO_3_IOTYPE {LVCMOS 3.3V} \ + CONFIG.PCW_MIO_3_SLEW {fast} \ + CONFIG.PCW_MIO_40_IOTYPE {LVCMOS 1.8V} \ + CONFIG.PCW_MIO_40_PULLUP {disabled} \ + CONFIG.PCW_MIO_40_SLEW {fast} \ + CONFIG.PCW_MIO_41_IOTYPE {LVCMOS 1.8V} \ + CONFIG.PCW_MIO_41_PULLUP {disabled} \ + CONFIG.PCW_MIO_41_SLEW {fast} \ + CONFIG.PCW_MIO_42_IOTYPE {LVCMOS 1.8V} \ + CONFIG.PCW_MIO_42_PULLUP {disabled} \ + CONFIG.PCW_MIO_42_SLEW {fast} \ + CONFIG.PCW_MIO_43_IOTYPE {LVCMOS 1.8V} \ + CONFIG.PCW_MIO_43_PULLUP {disabled} \ + CONFIG.PCW_MIO_43_SLEW {fast} \ + CONFIG.PCW_MIO_44_IOTYPE {LVCMOS 1.8V} \ + CONFIG.PCW_MIO_44_PULLUP {disabled} \ + CONFIG.PCW_MIO_44_SLEW {fast} \ + CONFIG.PCW_MIO_45_IOTYPE {LVCMOS 1.8V} \ + CONFIG.PCW_MIO_45_PULLUP {disabled} \ + CONFIG.PCW_MIO_45_SLEW {fast} \ + CONFIG.PCW_MIO_46_IOTYPE {LVCMOS 1.8V} \ + CONFIG.PCW_MIO_46_PULLUP {enabled} \ + CONFIG.PCW_MIO_46_SLEW {slow} \ + CONFIG.PCW_MIO_47_IOTYPE {LVCMOS 1.8V} \ + CONFIG.PCW_MIO_47_PULLUP {disabled} \ + CONFIG.PCW_MIO_47_SLEW {slow} \ + CONFIG.PCW_MIO_48_IOTYPE {LVCMOS 1.8V} \ + CONFIG.PCW_MIO_48_PULLUP {disabled} \ + CONFIG.PCW_MIO_48_SLEW {slow} \ + CONFIG.PCW_MIO_49_IOTYPE {LVCMOS 1.8V} \ + CONFIG.PCW_MIO_49_PULLUP {disabled} \ + CONFIG.PCW_MIO_49_SLEW {slow} \ + CONFIG.PCW_MIO_4_IOTYPE {LVCMOS 3.3V} \ + CONFIG.PCW_MIO_4_SLEW {fast} \ + CONFIG.PCW_MIO_50_IOTYPE {LVCMOS 1.8V} \ + CONFIG.PCW_MIO_50_PULLUP {disabled} \ + CONFIG.PCW_MIO_50_SLEW {slow} \ + CONFIG.PCW_MIO_51_IOTYPE {LVCMOS 1.8V} \ + CONFIG.PCW_MIO_51_PULLUP {disabled} \ + CONFIG.PCW_MIO_51_SLEW {slow} \ + CONFIG.PCW_MIO_52_IOTYPE {LVCMOS 1.8V} \ + CONFIG.PCW_MIO_52_PULLUP {disabled} \ + CONFIG.PCW_MIO_52_SLEW {slow} \ + CONFIG.PCW_MIO_53_IOTYPE {LVCMOS 1.8V} \ + CONFIG.PCW_MIO_53_PULLUP {disabled} \ + CONFIG.PCW_MIO_53_SLEW {slow} \ + CONFIG.PCW_MIO_5_IOTYPE {LVCMOS 3.3V} \ + CONFIG.PCW_MIO_5_SLEW {fast} \ + CONFIG.PCW_MIO_6_IOTYPE {LVCMOS 3.3V} \ + CONFIG.PCW_MIO_6_SLEW {fast} \ + CONFIG.PCW_MIO_7_IOTYPE {LVCMOS 3.3V} \ + CONFIG.PCW_MIO_7_SLEW {slow} \ + CONFIG.PCW_MIO_8_IOTYPE {LVCMOS 3.3V} \ + CONFIG.PCW_MIO_8_SLEW {fast} \ + CONFIG.PCW_MIO_9_IOTYPE {LVCMOS 3.3V} \ + CONFIG.PCW_MIO_9_PULLUP {enabled} \ + CONFIG.PCW_MIO_9_SLEW {slow} \ + CONFIG.PCW_MIO_TREE_PERIPHERALS {GPIO#Quad SPI Flash#Quad SPI Flash#Quad SPI Flash#Quad SPI Flash#Quad SPI Flash#Quad SPI Flash#GPIO#Quad SPI Flash#GPIO#GPIO#GPIO#GPIO#GPIO#GPIO#GPIO#Enet 0#Enet 0#Enet\ +0#Enet 0#Enet 0#Enet 0#Enet 0#Enet 0#Enet 0#Enet 0#Enet 0#Enet 0#USB 0#USB 0#USB 0#USB 0#USB 0#USB 0#USB 0#USB 0#USB 0#USB 0#USB 0#USB 0#SD 0#SD 0#SD 0#SD 0#SD 0#SD 0#USB Reset#SD 0#UART 1#UART 1#GPIO#GPIO#GPIO#GPIO}\ +\ + CONFIG.PCW_MIO_TREE_SIGNALS {gpio[0]#qspi0_ss_b#qspi0_io[0]#qspi0_io[1]#qspi0_io[2]#qspi0_io[3]/HOLD_B#qspi0_sclk#gpio[7]#qspi_fbclk#gpio[9]#gpio[10]#gpio[11]#gpio[12]#gpio[13]#gpio[14]#gpio[15]#tx_clk#txd[0]#txd[1]#txd[2]#txd[3]#tx_ctl#rx_clk#rxd[0]#rxd[1]#rxd[2]#rxd[3]#rx_ctl#data[4]#dir#stp#nxt#data[0]#data[1]#data[2]#data[3]#clk#data[5]#data[6]#data[7]#clk#cmd#data[0]#data[1]#data[2]#data[3]#reset#cd#tx#rx#gpio[50]#gpio[51]#gpio[52]#gpio[53]}\ +\ + CONFIG.PCW_PRESET_BANK1_VOLTAGE {LVCMOS 1.8V} \ + CONFIG.PCW_QSPI_GRP_FBCLK_ENABLE {1} \ + CONFIG.PCW_QSPI_GRP_FBCLK_IO {MIO 8} \ + CONFIG.PCW_QSPI_GRP_IO1_ENABLE {0} \ + CONFIG.PCW_QSPI_GRP_SINGLE_SS_ENABLE {1} \ + CONFIG.PCW_QSPI_GRP_SINGLE_SS_IO {MIO 1 .. 6} \ + CONFIG.PCW_QSPI_GRP_SS1_ENABLE {0} \ + CONFIG.PCW_QSPI_PERIPHERAL_ENABLE {1} \ + CONFIG.PCW_QSPI_PERIPHERAL_FREQMHZ {200} \ + CONFIG.PCW_QSPI_QSPI_IO {MIO 1 .. 6} \ + CONFIG.PCW_SD0_GRP_CD_ENABLE {1} \ + CONFIG.PCW_SD0_GRP_CD_IO {MIO 47} \ + CONFIG.PCW_SD0_GRP_POW_ENABLE {0} \ + CONFIG.PCW_SD0_GRP_WP_ENABLE {1} \ + CONFIG.PCW_SD0_GRP_WP_IO {EMIO} \ + CONFIG.PCW_SD0_PERIPHERAL_ENABLE {1} \ + CONFIG.PCW_SD0_SD0_IO {MIO 40 .. 45} \ + CONFIG.PCW_SDIO_PERIPHERAL_FREQMHZ {50} \ + CONFIG.PCW_SDIO_PERIPHERAL_VALID {1} \ + CONFIG.PCW_SINGLE_QSPI_DATA_MODE {x4} \ + CONFIG.PCW_TTC0_PERIPHERAL_ENABLE {1} \ + CONFIG.PCW_TTC0_TTC0_IO {EMIO} \ + CONFIG.PCW_TTC1_PERIPHERAL_ENABLE {0} \ + CONFIG.PCW_TTC_PERIPHERAL_FREQMHZ {50} \ + CONFIG.PCW_UART0_GRP_FULL_ENABLE {0} \ + CONFIG.PCW_UART0_PERIPHERAL_ENABLE {1} \ + CONFIG.PCW_UART0_UART0_IO {EMIO} \ + CONFIG.PCW_UART1_GRP_FULL_ENABLE {0} \ + CONFIG.PCW_UART1_PERIPHERAL_ENABLE {1} \ + CONFIG.PCW_UART1_UART1_IO {MIO 48 .. 49} \ + CONFIG.PCW_UART_PERIPHERAL_FREQMHZ {100} \ + CONFIG.PCW_UART_PERIPHERAL_VALID {1} \ + CONFIG.PCW_UIPARAM_ACT_DDR_FREQ_MHZ {533.333374} \ + CONFIG.PCW_UIPARAM_DDR_BOARD_DELAY0 {0.176} \ + CONFIG.PCW_UIPARAM_DDR_BOARD_DELAY1 {0.159} \ + CONFIG.PCW_UIPARAM_DDR_BOARD_DELAY2 {0.162} \ + CONFIG.PCW_UIPARAM_DDR_BOARD_DELAY3 {0.187} \ + CONFIG.PCW_UIPARAM_DDR_DQS_TO_CLK_DELAY_0 {-0.073} \ + CONFIG.PCW_UIPARAM_DDR_DQS_TO_CLK_DELAY_1 {-0.034} \ + CONFIG.PCW_UIPARAM_DDR_DQS_TO_CLK_DELAY_2 {-0.03} \ + CONFIG.PCW_UIPARAM_DDR_DQS_TO_CLK_DELAY_3 {-0.082} \ + CONFIG.PCW_UIPARAM_DDR_FREQ_MHZ {525} \ + CONFIG.PCW_UIPARAM_DDR_PARTNO {MT41K128M16 JT-125} \ + CONFIG.PCW_UIPARAM_DDR_TRAIN_DATA_EYE {1} \ + CONFIG.PCW_UIPARAM_DDR_TRAIN_READ_GATE {1} \ + CONFIG.PCW_UIPARAM_DDR_TRAIN_WRITE_LEVEL {1} \ + CONFIG.PCW_USB0_PERIPHERAL_ENABLE {1} \ + CONFIG.PCW_USB0_RESET_ENABLE {1} \ + CONFIG.PCW_USB0_RESET_IO {MIO 46} \ + CONFIG.PCW_USB0_USB0_IO {MIO 28 .. 39} \ + CONFIG.PCW_USB_RESET_ENABLE {1} \ + CONFIG.PCW_USB_RESET_SELECT {Share reset pin} \ + CONFIG.PCW_USE_FABRIC_INTERRUPT {1} \ + ] $processing_system7_0 + + + # Create instance: axi_uartlite_0, and set properties + set axi_uartlite_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_uartlite:2.0 axi_uartlite_0 ] + set_property -dict [list \ + CONFIG.C_BAUDRATE {115200} \ + CONFIG.UARTLITE_BOARD_INTERFACE {Custom} \ + CONFIG.USE_BOARD_FLOW {true} \ + ] $axi_uartlite_0 + + + # Create instance: ps7_0_axi_periph, and set properties + set ps7_0_axi_periph [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_interconnect:2.1 ps7_0_axi_periph ] + set_property CONFIG.NUM_MI {2} $ps7_0_axi_periph + + + # Create instance: rst_ps7_0_100M, and set properties + set rst_ps7_0_100M [ create_bd_cell -type ip -vlnv xilinx.com:ip:proc_sys_reset:5.0 rst_ps7_0_100M ] + + # Create instance: axi_uart16550_0, and set properties + set axi_uart16550_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_uart16550:2.0 axi_uart16550_0 ] + set_property -dict [list \ + CONFIG.UART_BOARD_INTERFACE {Custom} \ + CONFIG.USE_BOARD_FLOW {true} \ + ] $axi_uart16550_0 + + + # Create instance: IRQ_F2P, and set properties + set IRQ_F2P [ create_bd_cell -type ip -vlnv xilinx.com:ip:xlconcat:2.1 IRQ_F2P ] + + # Create instance: LEDS, and set properties + set LEDS [ create_bd_cell -type ip -vlnv xilinx.com:ip:xlslice:1.0 LEDS ] + set_property -dict [list \ + CONFIG.DIN_FROM {7} \ + CONFIG.DIN_WIDTH {16} \ + ] $LEDS + + + # Create instance: EMIO_O_0, and set properties + set EMIO_O_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:xlslice:1.0 EMIO_O_0 ] + set_property -dict [list \ + CONFIG.DIN_FROM {15} \ + CONFIG.DIN_WIDTH {64} \ + ] $EMIO_O_0 + + + # Create instance: EMIO_O_1, and set properties + set EMIO_O_1 [ create_bd_cell -type ip -vlnv xilinx.com:ip:xlslice:1.0 EMIO_O_1 ] + set_property -dict [list \ + CONFIG.DIN_FROM {47} \ + CONFIG.DIN_TO {32} \ + CONFIG.DIN_WIDTH {64} \ + ] $EMIO_O_1 + + + # Create instance: EMIO_I, and set properties + set EMIO_I [ create_bd_cell -type ip -vlnv xilinx.com:ip:xlconcat:2.1 EMIO_I ] + set_property -dict [list \ + CONFIG.IN0_WIDTH {16} \ + CONFIG.IN1_WIDTH {16} \ + CONFIG.IN2_WIDTH {16} \ + CONFIG.IN3_WIDTH {16} \ + CONFIG.NUM_PORTS {4} \ + ] $EMIO_I + + + # Create instance: EMIO_I_0, and set properties + set EMIO_I_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:xlconcat:2.1 EMIO_I_0 ] + set_property -dict [list \ + CONFIG.IN0_WIDTH {8} \ + CONFIG.IN1_WIDTH {5} \ + CONFIG.IN2_WIDTH {3} \ + CONFIG.NUM_PORTS {3} \ + ] $EMIO_I_0 + + + # Create instance: xlconstant_0, and set properties + set xlconstant_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:xlconstant:1.1 xlconstant_0 ] + set_property -dict [list \ + CONFIG.CONST_VAL {0} \ + CONFIG.CONST_WIDTH {3} \ + ] $xlconstant_0 + + + # Create instance: EMIO_I_1, and set properties + set EMIO_I_1 [ create_bd_cell -type ip -vlnv xilinx.com:ip:xlconstant:1.1 EMIO_I_1 ] + set_property -dict [list \ + CONFIG.CONST_VAL {0} \ + CONFIG.CONST_WIDTH {16} \ + ] $EMIO_I_1 + + + # Create instance: uart_mux_0, and set properties + set block_name uart_mux + set block_cell_name uart_mux_0 + if { [catch {set uart_mux_0 [create_bd_cell -type module -reference $block_name $block_cell_name] } errmsg] } { + catch {common::send_gid_msg -ssname BD::TCL -id 2095 -severity "ERROR" "Unable to add referenced block <$block_name>. Please add the files for ${block_name}'s definition into the project."} + return 1 + } elseif { $uart_mux_0 eq "" } { + catch {common::send_gid_msg -ssname BD::TCL -id 2096 -severity "ERROR" "Unable to referenced block <$block_name>. Please add the files for ${block_name}'s definition into the project."} + return 1 + } + + # Create instance: UART_MUX, and set properties + set UART_MUX [ create_bd_cell -type ip -vlnv xilinx.com:ip:xlslice:1.0 UART_MUX ] + set_property -dict [list \ + CONFIG.DIN_FROM {10} \ + CONFIG.DIN_TO {8} \ + CONFIG.DIN_WIDTH {16} \ + ] $UART_MUX + + + # Create instance: xlconstant_1, and set properties + set xlconstant_1 [ create_bd_cell -type ip -vlnv xilinx.com:ip:xlconstant:1.1 xlconstant_1 ] + + # Create interface connections + connect_bd_intf_net -intf_net processing_system7_0_DDR [get_bd_intf_ports DDR] [get_bd_intf_pins processing_system7_0/DDR] + connect_bd_intf_net -intf_net processing_system7_0_FIXED_IO [get_bd_intf_ports FIXED_IO] [get_bd_intf_pins processing_system7_0/FIXED_IO] + connect_bd_intf_net -intf_net processing_system7_0_M_AXI_GP0 [get_bd_intf_pins processing_system7_0/M_AXI_GP0] [get_bd_intf_pins ps7_0_axi_periph/S00_AXI] + connect_bd_intf_net -intf_net ps7_0_axi_periph_M00_AXI [get_bd_intf_pins ps7_0_axi_periph/M00_AXI] [get_bd_intf_pins axi_uartlite_0/S_AXI] + connect_bd_intf_net -intf_net ps7_0_axi_periph_M01_AXI [get_bd_intf_pins ps7_0_axi_periph/M01_AXI] [get_bd_intf_pins axi_uart16550_0/S_AXI] + + # Create port connections + connect_bd_net -net EMIO_O_1_Dout [get_bd_pins EMIO_O_1/Dout] [get_bd_pins EMIO_I/In2] + connect_bd_net -net In0_0_1 [get_bd_ports SWITCHES] [get_bd_pins EMIO_I_0/In0] + connect_bd_net -net In1_0_1 [get_bd_ports BTTNS] [get_bd_pins EMIO_I_0/In1] + connect_bd_net -net axi_uart16550_0_ip2intc_irpt [get_bd_pins axi_uart16550_0/ip2intc_irpt] [get_bd_pins IRQ_F2P/In1] + connect_bd_net -net axi_uart16550_0_sout [get_bd_pins axi_uart16550_0/sout] [get_bd_pins uart_mux_0/uart_2_tx] + connect_bd_net -net axi_uartlite_0_interrupt [get_bd_pins axi_uartlite_0/interrupt] [get_bd_pins IRQ_F2P/In0] + connect_bd_net -net axi_uartlite_0_tx [get_bd_pins axi_uartlite_0/tx] [get_bd_pins uart_mux_0/uart_1_tx] + connect_bd_net -net processing_system7_0_FCLK_CLK0 [get_bd_pins processing_system7_0/FCLK_CLK0] [get_bd_pins processing_system7_0/M_AXI_GP0_ACLK] [get_bd_pins ps7_0_axi_periph/S00_ACLK] [get_bd_pins rst_ps7_0_100M/slowest_sync_clk] [get_bd_pins axi_uartlite_0/s_axi_aclk] [get_bd_pins ps7_0_axi_periph/M00_ACLK] [get_bd_pins ps7_0_axi_periph/ACLK] [get_bd_pins axi_uart16550_0/s_axi_aclk] [get_bd_pins ps7_0_axi_periph/M01_ACLK] [get_bd_pins uart_mux_0/sys_clk] + connect_bd_net -net processing_system7_0_FCLK_RESET0_N [get_bd_pins processing_system7_0/FCLK_RESET0_N] [get_bd_pins rst_ps7_0_100M/ext_reset_in] + connect_bd_net -net processing_system7_0_GPIO_O [get_bd_pins processing_system7_0/GPIO_O] [get_bd_pins EMIO_O_0/Din] [get_bd_pins EMIO_O_1/Din] + connect_bd_net -net processing_system7_0_TTC0_WAVE0_OUT [get_bd_pins processing_system7_0/TTC0_WAVE0_OUT] [get_bd_ports TTC0_WAVEOUT] + connect_bd_net -net processing_system7_0_UART0_TX [get_bd_pins processing_system7_0/UART0_TX] [get_bd_pins uart_mux_0/uart_0_tx] + connect_bd_net -net rst_ps7_0_100M_peripheral_aresetn [get_bd_pins rst_ps7_0_100M/peripheral_aresetn] [get_bd_pins ps7_0_axi_periph/S00_ARESETN] [get_bd_pins axi_uartlite_0/s_axi_aresetn] [get_bd_pins ps7_0_axi_periph/M00_ARESETN] [get_bd_pins ps7_0_axi_periph/ARESETN] [get_bd_pins axi_uart16550_0/s_axi_aresetn] [get_bd_pins ps7_0_axi_periph/M01_ARESETN] + connect_bd_net -net rx_in_0_1 [get_bd_ports UART_rxd] [get_bd_pins uart_mux_0/rx_in] + connect_bd_net -net uart_mux_0_tx_out [get_bd_pins uart_mux_0/tx_out] [get_bd_ports UART_txd] + connect_bd_net -net uart_mux_0_uart_0_rx [get_bd_pins uart_mux_0/uart_0_rx] [get_bd_pins processing_system7_0/UART0_RX] + connect_bd_net -net uart_mux_0_uart_1_rx [get_bd_pins uart_mux_0/uart_1_rx] [get_bd_pins axi_uartlite_0/rx] + connect_bd_net -net uart_mux_0_uart_2_rx [get_bd_pins uart_mux_0/uart_2_rx] [get_bd_pins axi_uart16550_0/sin] + connect_bd_net -net xlconcat_0_dout [get_bd_pins IRQ_F2P/dout] [get_bd_pins processing_system7_0/IRQ_F2P] + connect_bd_net -net xlconcat_1_dout [get_bd_pins EMIO_I/dout] [get_bd_pins processing_system7_0/GPIO_I] + connect_bd_net -net xlconcat_1_dout1 [get_bd_pins EMIO_I_0/dout] [get_bd_pins EMIO_I/In1] + connect_bd_net -net xlconstant_0_dout [get_bd_pins xlconstant_0/dout] [get_bd_pins EMIO_I_0/In2] + connect_bd_net -net xlconstant_1_dout [get_bd_pins EMIO_I_1/dout] [get_bd_pins EMIO_I/In3] + connect_bd_net -net xlconstant_1_dout1 [get_bd_pins xlconstant_1/dout] [get_bd_pins axi_uart16550_0/rin] [get_bd_pins axi_uart16550_0/dsrn] [get_bd_pins axi_uart16550_0/ctsn] [get_bd_pins axi_uart16550_0/dcdn] + connect_bd_net -net xlslice_0_Dout [get_bd_pins LEDS/Dout] [get_bd_ports LEDS] + connect_bd_net -net xlslice_0_Dout1 [get_bd_pins UART_MUX/Dout] [get_bd_pins uart_mux_0/sel] + connect_bd_net -net xlslice_1_Dout [get_bd_pins EMIO_O_0/Dout] [get_bd_pins LEDS/Din] [get_bd_pins EMIO_I/In0] [get_bd_pins UART_MUX/Din] + + # Create address segments + assign_bd_address -offset 0x43C00000 -range 0x00010000 -target_address_space [get_bd_addr_spaces processing_system7_0/Data] [get_bd_addr_segs axi_uart16550_0/S_AXI/Reg] -force + assign_bd_address -offset 0x42C00000 -range 0x00010000 -target_address_space [get_bd_addr_spaces processing_system7_0/Data] [get_bd_addr_segs axi_uartlite_0/S_AXI/Reg] -force + + + # Restore current instance + current_bd_instance $oldCurInst + + validate_bd_design + save_bd_design +} +# End of create_root_design() + + +################################################################## +# MAIN FLOW +################################################################## + +create_root_design "" + + diff --git a/zedboard-fpga-design/src/zedboard.xdc b/zedboard-fpga-design/src/zedboard.xdc new file mode 100644 index 0000000..001e72e --- /dev/null +++ b/zedboard-fpga-design/src/zedboard.xdc @@ -0,0 +1,75 @@ +# Zedboard LD0 +set_property PACKAGE_PIN T22 [get_ports {LEDS[0]}] +set_property IOSTANDARD LVCMOS33 [get_ports {LEDS[0]}] +# Zedboard LD1 +set_property PACKAGE_PIN T21 [get_ports {LEDS[1]}] +set_property IOSTANDARD LVCMOS33 [get_ports {LEDS[1]}] +# Zedboard LD2 +set_property PACKAGE_PIN U22 [get_ports {LEDS[2]}] +set_property IOSTANDARD LVCMOS33 [get_ports {LEDS[2]}] +# Zedboard LD3 +set_property PACKAGE_PIN U21 [get_ports {LEDS[3]}] +set_property IOSTANDARD LVCMOS33 [get_ports {LEDS[3]}] +# Zedboard LD4 +set_property PACKAGE_PIN V22 [get_ports {LEDS[4]}] +set_property IOSTANDARD LVCMOS33 [get_ports {LEDS[4]}] +# Zedboard LD5 +set_property PACKAGE_PIN W22 [get_ports {LEDS[5]}] +set_property IOSTANDARD LVCMOS33 [get_ports {LEDS[5]}] +# Zedboard LD6 +set_property PACKAGE_PIN U19 [get_ports {LEDS[6]}] +set_property IOSTANDARD LVCMOS33 [get_ports {LEDS[6]}] +# Zedboard LD7 +set_property PACKAGE_PIN U14 [get_ports {LEDS[7]}] +set_property IOSTANDARD LVCMOS33 [get_ports {LEDS[7]}] + +# Zedboard SW0 +set_property PACKAGE_PIN F22 [get_ports {SWITCHES[0]}] +set_property IOSTANDARD LVCMOS33 [get_ports {SWITCHES[0]}] +# Zedboard SW1 +set_property PACKAGE_PIN G22 [get_ports {SWITCHES[1]}] +set_property IOSTANDARD LVCMOS33 [get_ports {SWITCHES[1]}] +# Zedboard SW2 +set_property PACKAGE_PIN H22 [get_ports {SWITCHES[2]}] +set_property IOSTANDARD LVCMOS33 [get_ports {SWITCHES[2]}] +# Zedboard SW3 +set_property PACKAGE_PIN F21 [get_ports {SWITCHES[3]}] +set_property IOSTANDARD LVCMOS33 [get_ports {SWITCHES[3]}] +# Zedboard SW4 +set_property PACKAGE_PIN H19 [get_ports {SWITCHES[4]}] +set_property IOSTANDARD LVCMOS33 [get_ports {SWITCHES[4]}] +# Zedboard SW5 +set_property PACKAGE_PIN H18 [get_ports {SWITCHES[5]}] +set_property IOSTANDARD LVCMOS33 [get_ports {SWITCHES[5]}] +# Zedboard SW6 +set_property PACKAGE_PIN H17 [get_ports {SWITCHES[6]}] +set_property IOSTANDARD LVCMOS33 [get_ports {SWITCHES[6]}] +# Zedboard SW7 +set_property PACKAGE_PIN M15 [get_ports {SWITCHES[7]}] +set_property IOSTANDARD LVCMOS33 [get_ports {SWITCHES[7]}] + +# Zedboard BTNC +set_property PACKAGE_PIN P16 [get_ports {BTTNS[0]}] +set_property IOSTANDARD LVCMOS33 [get_ports {BTTNS[0]}] +# Zedboard BTND +set_property PACKAGE_PIN R16 [get_ports {BTTNS[1]}] +set_property IOSTANDARD LVCMOS33 [get_ports {BTTNS[1]}] +# Zedboard BTNL +set_property PACKAGE_PIN N15 [get_ports {BTTNS[2]}] +set_property IOSTANDARD LVCMOS33 [get_ports {BTTNS[2]}] +# Zedboard BTNR +set_property PACKAGE_PIN R18 [get_ports {BTTNS[3]}] +set_property IOSTANDARD LVCMOS33 [get_ports {BTTNS[3]}] +# Zedboard BTNU +set_property PACKAGE_PIN T18 [get_ports {BTTNS[4]}] +set_property IOSTANDARD LVCMOS33 [get_ports {BTTNS[4]}] + +# UART +set_property PACKAGE_PIN Y11 [get_ports UART_rxd] +set_property IOSTANDARD LVCMOS33 [get_ports UART_rxd] +set_property PACKAGE_PIN AA11 [get_ports UART_txd] +set_property IOSTANDARD LVCMOS33 [get_ports UART_txd] + +# TTC0 Wave Out +set_property PACKAGE_PIN W12 [get_ports {TTC0_WAVEOUT}] +set_property IOSTANDARD LVCMOS33 [get_ports {TTC0_WAVEOUT}] \ No newline at end of file diff --git a/zedboard-fpga-design/zedboard-rust.tcl b/zedboard-fpga-design/zedboard-rust.tcl new file mode 100644 index 0000000..a2e5b83 --- /dev/null +++ b/zedboard-fpga-design/zedboard-rust.tcl @@ -0,0 +1,528 @@ +#***************************************************************************************** +# Vivado (TM) v2024.1 (64-bit) +# +# zedboard-rust.tcl: Tcl script for re-creating project 'zedboard-rust' +# +# Generated by Vivado on Fri Mar 14 13:10:19 CET 2025 +# IP Build 5075265 on Wed May 22 21:45:21 MDT 2024 +# +# This file contains the Vivado Tcl commands for re-creating the project to the state* +# when this script was generated. In order to re-create the project, please source this +# file in the Vivado Tcl Shell. +# +# * Note that the runs in the created project will be configured the same way as the +# original project, however they will not be launched automatically. To regenerate the +# run results please launch the synthesis/implementation runs as needed. +# +#***************************************************************************************** +# NOTE: In order to use this script for source control purposes, please make sure that the +# following files are added to the source control system:- +# +# 1. This project restoration tcl script (zedboard-rust.tcl) that was generated. +# 2. Constraints file in src directory +# 3. BD export file in src directory +# +#***************************************************************************************** + +# Set the reference directory for source file relative paths (by default the value is script directory path) +set script_dir [file dirname [info script]] +set origin_dir "." + +set constr_file [file normalize "$script_dir/src/zedboard.xdc"] +set bd_file [file normalize "$script_dir/src/zedboard-bd.tcl"] + +set uart_mux_file [file normalize "$script_dir/src/uart_mux.vhd"] + +# Check file required for this script exists +proc checkRequiredFiles { origin_dir} { + set status true + set files [list \ + "[file normalize $constr_file]"\ + "[file normalize $bd_file]"\ + ] + foreach ifile $files { + if { ![file isfile $ifile] } { + puts " Could not find local file $ifile " + set status false + } + } + + return $status +} + +# Use origin directory path location variable, if specified in the tcl shell +if { [info exists ::origin_dir_loc] } { + set origin_dir $::origin_dir_loc +} + +# Set the project name +set _xil_proj_name_ "zedboard-rust" + +# Use project name variable, if specified in the tcl shell +if { [info exists ::user_project_name] } { + set _xil_proj_name_ $::user_project_name +} + +variable script_file +set script_file "zedboard-rust.tcl" + +# Help information for this script +proc print_help {} { + variable script_file + puts "\nDescription:" + puts "Recreate a Vivado project from this script. The created project will be" + puts "functionally equivalent to the original project for which this script was" + puts "generated. The script contains commands for creating a project, filesets," + puts "runs, adding/importing sources and setting properties on various objects.\n" + puts "Syntax:" + puts "$script_file" + puts "$script_file -tclargs \[--origin_dir \]" + puts "$script_file -tclargs \[--project_name \]" + puts "$script_file -tclargs \[--help\]\n" + puts "$script_file -tclargs \[--overwrite\]\n" + puts "Usage:" + puts "Name Description" + puts "-------------------------------------------------------------------------" + puts "\[--origin_dir \] Determine source file paths wrt this path. Default" + puts " origin_dir path value is \".\", otherwise, the value" + puts " that was set with the \"-paths_relative_to\" switch" + puts " when this script was generated.\n" + puts "\[--project_name \] Create project with the specified name. Default" + puts " name is the name of the project from where this" + puts " script was generated.\n" + puts "\[--help\] Print help information for this script" + puts "\[--overwrite\] Ovewrite the existing project if it exists" + puts "-------------------------------------------------------------------------\n" + exit 0 +} + +set _force "" + +if { $::argc > 0 } { + for {set i 0} {$i < $::argc} {incr i} { + set option [string trim [lindex $::argv $i]] + switch -regexp -- $option { + "--origin_dir" { incr i; set origin_dir [lindex $::argv $i] } + "--project_name" { incr i; set _xil_proj_name_ [lindex $::argv $i] } + "--overwrite" { incr i; set _force "-force"} + "--help" { print_help } + default { + if { [regexp {^-} $option] } { + puts "ERROR: Unknown option '$option' specified, please type '$script_file -tclargs --help' for usage info.\n" + return 1 + } + } + } + } +} + +# Create project +if { $_force ne "" } { + create_project ${_xil_proj_name_} ${origin_dir}/${_xil_proj_name_} -part xc7z020clg484-1 $_force +} else { + create_project ${_xil_proj_name_} ${origin_dir}/${_xil_proj_name_} -part xc7z020clg484-1 +} + +# Set the directory path for the new project +set proj_dir [get_property directory [current_project]] + +# Reconstruct message rules +# None + +# Set project properties +set obj [current_project] +set_property -name "board_part" -value "digilentinc.com:zedboard:part0:1.1" -objects $obj +set_property -name "default_lib" -value "xil_defaultlib" -objects $obj +set_property -name "enable_resource_estimation" -value "0" -objects $obj +set_property -name "enable_vhdl_2008" -value "1" -objects $obj +set_property -name "ip_cache_permissions" -value "read write" -objects $obj +set_property -name "ip_output_repo" -value "$proj_dir/${_xil_proj_name_}.cache/ip" -objects $obj +set_property -name "mem.enable_memory_map_generation" -value "1" -objects $obj +set_property -name "platform.board_id" -value "zedboard" -objects $obj +set_property -name "revised_directory_structure" -value "1" -objects $obj +set_property -name "sim.central_dir" -value "$proj_dir/${_xil_proj_name_}.ip_user_files" -objects $obj +set_property -name "sim.ip.auto_export_scripts" -value "1" -objects $obj +set_property -name "simulator_language" -value "Mixed" -objects $obj +set_property -name "sim_compile_state" -value "1" -objects $obj + +# Create 'sources_1' fileset (if not found) +if {[string equal [get_filesets -quiet sources_1] ""]} { + create_fileset -srcset sources_1 +} + +# Set 'sources_1' fileset object +set obj [get_filesets sources_1] +set files [list \ + $uart_mux_file \ +] +add_files -norecurse -fileset $obj $files + +set_property file_type "VHDL" [get_files $uart_mux_file] + +# Set 'sources_1' fileset file properties for remote files +# None + +# Set 'sources_1' fileset file properties for local files + +# Create 'constrs_1' fileset (if not found) +if {[string equal [get_filesets -quiet constrs_1] ""]} { + create_fileset -constrset constrs_1 +} +add_files -fileset constrs_1 -norecurse $constr_file + +# Retrieve the file object correctly +set file_obj [get_files -of_objects [get_filesets constrs_1]] +# Set the file type property +set_property -name "file_type" -value "XDC" -objects $file_obj +# Set as target constraints file. +# set_property -name "target_constrs_file" -value $constr_file -objects $file_obj +set_property target_constrs_file $constr_file [current_fileset -constrset] +set_property target_ucf $constr_file [current_fileset -constrset] + +# Load block design. +set ret [source $bd_file] +if {$ret != ""} { + error "Failed to generate block design with return value $ret" +} +set design_name [get_bd_designs] +make_wrapper -files [get_files $design_name.bd] -top -import + +# Create 'sim_1' fileset (if not found) +if {[string equal [get_filesets -quiet sim_1] ""]} { + create_fileset -simset sim_1 +} + +# Set 'sim_1' fileset object +set obj [get_filesets sim_1] +# Empty (no sources present) + +# Set 'sim_1' fileset properties +set obj [get_filesets sim_1] +set_property -name "top" -value "zedboard_wrapper" -objects $obj +set_property -name "top_lib" -value "xil_defaultlib" -objects $obj + +# Set 'utils_1' fileset object +set obj [get_filesets utils_1] + +# Set 'utils_1' fileset file properties for remote files +# None + +# Set 'utils_1' fileset file properties for local files +# None + +# Set 'utils_1' fileset properties +set obj [get_filesets utils_1] + +set idrFlowPropertiesConstraints "" +catch { + set idrFlowPropertiesConstraints [get_param runs.disableIDRFlowPropertyConstraints] + set_param runs.disableIDRFlowPropertyConstraints 1 +} + +# Create 'synth_1' run (if not found) +if {[string equal [get_runs -quiet synth_1] ""]} { + create_run -name synth_1 -part xc7z020clg484-1 -flow {Vivado Synthesis 2024} -strategy "Vivado Synthesis Defaults" -report_strategy {No Reports} -constrset constrs_1 +} else { + set_property strategy "Vivado Synthesis Defaults" [get_runs synth_1] + set_property flow "Vivado Synthesis 2024" [get_runs synth_1] +} +set obj [get_runs synth_1] +set_property set_report_strategy_name 1 $obj +set_property report_strategy {Vivado Synthesis Default Reports} $obj +set_property set_report_strategy_name 0 $obj +# Create 'synth_1_synth_report_utilization_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs synth_1] synth_1_synth_report_utilization_0] "" ] } { + create_report_config -report_name synth_1_synth_report_utilization_0 -report_type report_utilization:1.0 -steps synth_design -runs synth_1 +} +set obj [get_report_configs -of_objects [get_runs synth_1] synth_1_synth_report_utilization_0] +if { $obj != "" } { + +} +set obj [get_runs synth_1] +set_property -name "needs_refresh" -value "1" -objects $obj +set_property -name "auto_incremental_checkpoint" -value "1" -objects $obj +set_property -name "strategy" -value "Vivado Synthesis Defaults" -objects $obj + +# set the current synth run +current_run -synthesis [get_runs synth_1] + +# Create 'impl_1' run (if not found) +if {[string equal [get_runs -quiet impl_1] ""]} { + create_run -name impl_1 -part xc7z020clg484-1 -flow {Vivado Implementation 2024} -strategy "Vivado Implementation Defaults" -report_strategy {No Reports} -constrset constrs_1 -parent_run synth_1 +} else { + set_property strategy "Vivado Implementation Defaults" [get_runs impl_1] + set_property flow "Vivado Implementation 2024" [get_runs impl_1] +} +set obj [get_runs impl_1] +set_property set_report_strategy_name 1 $obj +set_property report_strategy {Vivado Implementation Default Reports} $obj +set_property set_report_strategy_name 0 $obj +# Create 'impl_1_init_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_init_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_init_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps init_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_init_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "options.max_paths" -value "10" -objects $obj +set_property -name "options.report_unconstrained" -value "1" -objects $obj + +} +# Create 'impl_1_opt_report_drc_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_drc_0] "" ] } { + create_report_config -report_name impl_1_opt_report_drc_0 -report_type report_drc:1.0 -steps opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_drc_0] +if { $obj != "" } { + +} +# Create 'impl_1_opt_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "options.max_paths" -value "10" -objects $obj +set_property -name "options.report_unconstrained" -value "1" -objects $obj + +} +# Create 'impl_1_power_opt_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_power_opt_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_power_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps power_opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_power_opt_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "options.max_paths" -value "10" -objects $obj +set_property -name "options.report_unconstrained" -value "1" -objects $obj + +} +# Create 'impl_1_place_report_io_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_io_0] "" ] } { + create_report_config -report_name impl_1_place_report_io_0 -report_type report_io:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_io_0] +if { $obj != "" } { + +} +# Create 'impl_1_place_report_utilization_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_utilization_0] "" ] } { + create_report_config -report_name impl_1_place_report_utilization_0 -report_type report_utilization:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_utilization_0] +if { $obj != "" } { + +} +# Create 'impl_1_place_report_control_sets_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_control_sets_0] "" ] } { + create_report_config -report_name impl_1_place_report_control_sets_0 -report_type report_control_sets:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_control_sets_0] +if { $obj != "" } { +set_property -name "options.verbose" -value "1" -objects $obj + +} +# Create 'impl_1_place_report_incremental_reuse_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_0] "" ] } { + create_report_config -report_name impl_1_place_report_incremental_reuse_0 -report_type report_incremental_reuse:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj + +} +# Create 'impl_1_place_report_incremental_reuse_1' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_1] "" ] } { + create_report_config -report_name impl_1_place_report_incremental_reuse_1 -report_type report_incremental_reuse:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_1] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj + +} +# Create 'impl_1_place_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_place_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "options.max_paths" -value "10" -objects $obj +set_property -name "options.report_unconstrained" -value "1" -objects $obj + +} +# Create 'impl_1_post_place_power_opt_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_place_power_opt_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_post_place_power_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps post_place_power_opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_place_power_opt_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "options.max_paths" -value "10" -objects $obj +set_property -name "options.report_unconstrained" -value "1" -objects $obj + +} +# Create 'impl_1_phys_opt_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_phys_opt_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_phys_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps phys_opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_phys_opt_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "options.max_paths" -value "10" -objects $obj +set_property -name "options.report_unconstrained" -value "1" -objects $obj + +} +# Create 'impl_1_route_report_drc_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_drc_0] "" ] } { + create_report_config -report_name impl_1_route_report_drc_0 -report_type report_drc:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_drc_0] +if { $obj != "" } { + +} +# Create 'impl_1_route_report_methodology_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_methodology_0] "" ] } { + create_report_config -report_name impl_1_route_report_methodology_0 -report_type report_methodology:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_methodology_0] +if { $obj != "" } { + +} +# Create 'impl_1_route_report_power_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_power_0] "" ] } { + create_report_config -report_name impl_1_route_report_power_0 -report_type report_power:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_power_0] +if { $obj != "" } { + +} +# Create 'impl_1_route_report_route_status_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_route_status_0] "" ] } { + create_report_config -report_name impl_1_route_report_route_status_0 -report_type report_route_status:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_route_status_0] +if { $obj != "" } { + +} +# Create 'impl_1_route_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_route_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_timing_summary_0] +if { $obj != "" } { +set_property -name "options.max_paths" -value "10" -objects $obj +set_property -name "options.report_unconstrained" -value "1" -objects $obj + +} +# Create 'impl_1_route_report_incremental_reuse_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_incremental_reuse_0] "" ] } { + create_report_config -report_name impl_1_route_report_incremental_reuse_0 -report_type report_incremental_reuse:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_incremental_reuse_0] +if { $obj != "" } { + +} +# Create 'impl_1_route_report_clock_utilization_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_clock_utilization_0] "" ] } { + create_report_config -report_name impl_1_route_report_clock_utilization_0 -report_type report_clock_utilization:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_clock_utilization_0] +if { $obj != "" } { + +} +# Create 'impl_1_route_report_bus_skew_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_bus_skew_0] "" ] } { + create_report_config -report_name impl_1_route_report_bus_skew_0 -report_type report_bus_skew:1.1 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_bus_skew_0] +if { $obj != "" } { +set_property -name "options.warn_on_violation" -value "1" -objects $obj + +} +# Create 'impl_1_post_route_phys_opt_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_post_route_phys_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps post_route_phys_opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_timing_summary_0] +if { $obj != "" } { +set_property -name "options.max_paths" -value "10" -objects $obj +set_property -name "options.report_unconstrained" -value "1" -objects $obj +set_property -name "options.warn_on_violation" -value "1" -objects $obj + +} +# Create 'impl_1_post_route_phys_opt_report_bus_skew_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_bus_skew_0] "" ] } { + create_report_config -report_name impl_1_post_route_phys_opt_report_bus_skew_0 -report_type report_bus_skew:1.1 -steps post_route_phys_opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_bus_skew_0] +if { $obj != "" } { +set_property -name "options.warn_on_violation" -value "1" -objects $obj + +} +set obj [get_runs impl_1] +set_property -name "needs_refresh" -value "1" -objects $obj +set_property -name "strategy" -value "Vivado Implementation Defaults" -objects $obj +set_property -name "steps.write_bitstream.args.readback_file" -value "0" -objects $obj +set_property -name "steps.write_bitstream.args.verbose" -value "0" -objects $obj + +# set the current impl run +current_run -implementation [get_runs impl_1] +catch { + if { $idrFlowPropertiesConstraints != {} } { + set_param runs.disableIDRFlowPropertyConstraints $idrFlowPropertiesConstraints + } +} + +puts "INFO: Project created:${_xil_proj_name_}" +# Create 'drc_1' gadget (if not found) +if {[string equal [get_dashboard_gadgets [ list "drc_1" ] ] ""]} { +create_dashboard_gadget -name {drc_1} -type drc +} +set obj [get_dashboard_gadgets [ list "drc_1" ] ] +set_property -name "reports" -value "impl_1#impl_1_route_report_drc_0" -objects $obj + +# Create 'methodology_1' gadget (if not found) +if {[string equal [get_dashboard_gadgets [ list "methodology_1" ] ] ""]} { +create_dashboard_gadget -name {methodology_1} -type methodology +} +set obj [get_dashboard_gadgets [ list "methodology_1" ] ] +set_property -name "reports" -value "impl_1#impl_1_route_report_methodology_0" -objects $obj + +# Create 'power_1' gadget (if not found) +if {[string equal [get_dashboard_gadgets [ list "power_1" ] ] ""]} { +create_dashboard_gadget -name {power_1} -type power +} +set obj [get_dashboard_gadgets [ list "power_1" ] ] +set_property -name "reports" -value "impl_1#impl_1_route_report_power_0" -objects $obj + +# Create 'timing_1' gadget (if not found) +if {[string equal [get_dashboard_gadgets [ list "timing_1" ] ] ""]} { +create_dashboard_gadget -name {timing_1} -type timing +} +set obj [get_dashboard_gadgets [ list "timing_1" ] ] +set_property -name "reports" -value "impl_1#impl_1_route_report_timing_summary_0" -objects $obj + +# Create 'utilization_1' gadget (if not found) +if {[string equal [get_dashboard_gadgets [ list "utilization_1" ] ] ""]} { +create_dashboard_gadget -name {utilization_1} -type utilization +} +set obj [get_dashboard_gadgets [ list "utilization_1" ] ] +set_property -name "reports" -value "synth_1#synth_1_synth_report_utilization_0" -objects $obj +set_property -name "run.step" -value "synth_design" -objects $obj +set_property -name "run.type" -value "synthesis" -objects $obj + +# Create 'utilization_2' gadget (if not found) +if {[string equal [get_dashboard_gadgets [ list "utilization_2" ] ] ""]} { +create_dashboard_gadget -name {utilization_2} -type utilization +} +set obj [get_dashboard_gadgets [ list "utilization_2" ] ] +set_property -name "reports" -value "impl_1#impl_1_place_report_utilization_0" -objects $obj + +move_dashboard_gadget -name {utilization_1} -row 0 -col 0 +move_dashboard_gadget -name {power_1} -row 1 -col 0 +move_dashboard_gadget -name {drc_1} -row 2 -col 0 +move_dashboard_gadget -name {timing_1} -row 0 -col 1 +move_dashboard_gadget -name {utilization_2} -row 1 -col 1 +move_dashboard_gadget -name {methodology_1} -row 2 -col 1 diff --git a/zynq7000-embassy/Cargo.toml b/zynq7000-embassy/Cargo.toml new file mode 100644 index 0000000..38a523d --- /dev/null +++ b/zynq7000-embassy/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "zynq7000-embassy" +version = "0.1.0" +authors = ["Robin Mueller "] +edition = "2024" +description = "Embassy-rs support for the Zynq7000 family of SoCs" +homepage = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs" +repository = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs" +license = "MIT OR Apache-2.0" +keywords = ["no-std", "arm", "embassy", "amd", "zynq7000"] +categories = ["embedded", "no-std", "hardware-support"] + +[dependencies] +critical-section = "1" +once_cell = { version = "1", default-features = false, features = ["critical-section"] } +zynq7000-hal = { path = "../zynq7000-hal" } + +embassy-time-driver = { path = "/home/rmueller/Rust/embassy/embassy-time-driver", version = "0.2" } +embassy-time-queue-utils = { path = "/home/rmueller/Rust/embassy/embassy-time-queue-utils", version = "0.1" } diff --git a/zynq7000-embassy/LICENSE-APACHE b/zynq7000-embassy/LICENSE-APACHE new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/zynq7000-embassy/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/zynq7000-embassy/LICENSE-MIT b/zynq7000-embassy/LICENSE-MIT new file mode 100644 index 0000000..8311204 --- /dev/null +++ b/zynq7000-embassy/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Robin A. Mueller + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/zynq7000-embassy/README.md b/zynq7000-embassy/README.md new file mode 100644 index 0000000..1231e19 --- /dev/null +++ b/zynq7000-embassy/README.md @@ -0,0 +1,8 @@ +# Embassy-rs support for the AMD Zynq7000 SoC family + +This repository contains the [embassy-rs](https://github.com/embassy-rs/embassy) support for the +AMD Zynq7000 SoC family. Currently, it contains the time driver to allow using embassy-rs. It +currently provides one driver using the global timer peripheral provided by the Zynq7000 PS for +this purpose. + +The documentation contains more information on how to use this crate. diff --git a/zynq7000-embassy/src/lib.rs b/zynq7000-embassy/src/lib.rs new file mode 100644 index 0000000..b480376 --- /dev/null +++ b/zynq7000-embassy/src/lib.rs @@ -0,0 +1,176 @@ +#![no_std] +use core::cell::{Cell, RefCell}; + +use critical_section::{CriticalSection, Mutex}; +use embassy_time_driver::{Driver, TICK_HZ, time_driver_impl}; +use embassy_time_queue_utils::Queue; +use once_cell::sync::OnceCell; + +use zynq7000_hal::{clocks::ArmClocks, gtc::Gtc, time::Hertz}; + +static SCALE: OnceCell = OnceCell::new(); +static CPU_3X2X_CLK: OnceCell = OnceCell::new(); + +struct AlarmState { + timestamp: Cell, +} + +impl AlarmState { + const fn new() -> Self { + Self { + timestamp: Cell::new(u64::MAX), + } + } +} + +unsafe impl Send for AlarmState {} + +/// This is the initialization method for the embassy time driver. +/// +/// It should be called ONCE at system initialization. +pub fn init(arm_clocks: &ArmClocks, gtc: Gtc) { + if SCALE.get().is_some() || CPU_3X2X_CLK.get().is_some() { + return; + } + unsafe { GTC_TIME_DRIVER.init(arm_clocks, gtc) }; +} + +/// This interrupt handler should be called ONCE in the interrupt handler on global timer +/// interrupts. +/// +/// # Safety +/// +/// Needs to be called once in the global timer interrupt. +pub unsafe fn on_interrupt() { + unsafe { GTC_TIME_DRIVER.on_interrupt() }; +} + +pub struct GtcTimerDriver { + gtc: Mutex>, + // Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. + alarms: Mutex, + queue: Mutex>, +} + +impl GtcTimerDriver { + /// This is the initialization method for the embassy time driver. + /// + /// # Safety + /// + /// This has to be called ONCE at system initialization. + pub unsafe fn init(&'static self, arm_clock: &ArmClocks, mut gtc: Gtc) { + CPU_3X2X_CLK.set(arm_clock.cpu_3x2x_clk()).unwrap(); + SCALE + .set(arm_clock.cpu_3x2x_clk().raw() as u64 / TICK_HZ) + .unwrap(); + gtc.set_cpu_3x2x_clock(arm_clock.cpu_3x2x_clk()); + gtc.set_prescaler(0); + gtc.enable(); + } + + /// Should be called inside the IRQ handler if the IRQ ID is equal to + /// [crate::hal::gic::PpiInterrupt::GlobalTimer]. + /// + /// # Safety + /// + /// This function has to be called once for interrupt ID + /// [crate::hal::gic::PpiInterrupt::GlobalTimer]. + pub unsafe fn on_interrupt(&self) { + critical_section::with(|cs| { + self.trigger_alarm(cs); + }) + } + + fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool { + if SCALE.get().is_none() { + return false; + } + let mut gtc = self.gtc.borrow(cs).borrow_mut(); + let alarm = &self.alarms.borrow(cs); + alarm.timestamp.set(timestamp); + + let t = self.now(); + if timestamp <= t { + gtc.disable_interrupt(); + alarm.timestamp.set(u64::MAX); + return false; + } + + // If it hasn't triggered yet, setup the relevant reset value, regardless of whether + // the interrupts are enabled or not. When they are enabled at a later point, the + // right value is already set. + + // If the timestamp is in the next few ticks, add a bit of buffer to be sure the alarm + // is not missed. + // + // This means that an alarm can be delayed for up to 2 ticks (from t+1 to t+3), but this is allowed + // by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time, + // and we don't do that here. + let safe_timestamp = timestamp.max(t + 3); + let opt_comparator = safe_timestamp.checked_mul(*SCALE.get().unwrap()); + if opt_comparator.is_none() { + return true; + } + gtc.set_comparator(opt_comparator.unwrap()); + gtc.enable_interrupt(); + true + } + + fn trigger_alarm(&self, cs: CriticalSection) { + let mut gtc = self.gtc.borrow(cs).borrow_mut(); + gtc.disable_interrupt(); + drop(gtc); + + let alarm = &self.alarms.borrow(cs); + // Setting the maximum value disables the alarm. + alarm.timestamp.set(u64::MAX); + + // Call after clearing alarm, so the callback can set another alarm. + let mut next = self + .queue + .borrow(cs) + .borrow_mut() + .next_expiration(self.now()); + while !self.set_alarm(cs, next) { + next = self + .queue + .borrow(cs) + .borrow_mut() + .next_expiration(self.now()); + } + } +} +impl Driver for GtcTimerDriver { + #[inline] + fn now(&self) -> u64 { + if SCALE.get().is_none() { + return 0; + } + // This is okay, we only read the GTC and do not re-configure it, avoids the + // need for a lock. + let gtc = unsafe { Gtc::steal_fixed(Some(*CPU_3X2X_CLK.get().unwrap())) }; + + gtc.read_timer() / SCALE.get().unwrap() + } + + fn schedule_wake(&self, at: u64, waker: &core::task::Waker) { + critical_section::with(|cs| { + let mut queue = self.queue.borrow(cs).borrow_mut(); + + if queue.schedule_wake(at, waker) { + let mut next = queue.next_expiration(self.now()); + while !self.set_alarm(cs, next) { + next = queue.next_expiration(self.now()); + } + } + }) + } +} + +time_driver_impl!( + // We assume ownership of the GTC, so it is okay to steal here. + static GTC_TIME_DRIVER: GtcTimerDriver = GtcTimerDriver { + gtc: Mutex::new(RefCell::new(unsafe { Gtc::steal_fixed(None)})), + alarms: Mutex::new(AlarmState::new()), + queue: Mutex::new(RefCell::new(Queue::new())), +}); diff --git a/zynq7000-hal/Cargo.toml b/zynq7000-hal/Cargo.toml new file mode 100644 index 0000000..e3bb7a2 --- /dev/null +++ b/zynq7000-hal/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "zynq7000-hal" +version = "0.1.0" +authors = ["Robin Mueller "] +edition = "2024" +description = "HAL for the Zynq7000 family of SoCs" +homepage = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs" +repository = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs" +license = "MIT OR Apache-2.0" +keywords = ["no-std", "hal", "amd", "zynq7000", "xilinx", "bare-metal"] +categories = ["embedded", "no-std", "hardware-support"] + +[dependencies] +cortex-ar = { path = "../../../Rust/cortex-ar/cortex-ar" } +zynq7000 = { path = "../zynq7000" } + +arbitrary-int = "1.3" +thiserror = { version = "2", default-features = false } +num_enum = { version = "0.7", default-features = false } +ringbuf = { version = "0.4.8", default-features = false } +embedded-hal-nb = "1" +embedded-io = "0.6" +embedded-hal = "1" +embedded-hal-async = "1" +heapless = "0.8" +static_cell = "2" +delegate = "0.13" +paste = "1" +nb = "1" +fugit = "0.3" +critical-section = "1" +libm = "0.2" +log = "0.4" +embassy-sync = "0.6" +raw-slice = { git = "https://egit.irs.uni-stuttgart.de/rust/raw-slice.git" } +embedded-io-async = "0.6" + +[features] +std = ["thiserror/std", "alloc"] +alloc = [] +# These devices have a lower pin count. +7z010-7z007s-clg225 = [] + +[dev-dependencies] +approx = "0.5" diff --git a/zynq7000-hal/LICENSE-APACHE b/zynq7000-hal/LICENSE-APACHE new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/zynq7000-hal/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/zynq7000-hal/LICENSE-MIT b/zynq7000-hal/LICENSE-MIT new file mode 100644 index 0000000..8311204 --- /dev/null +++ b/zynq7000-hal/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Robin A. Mueller + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/zynq7000-hal/README.md b/zynq7000-hal/README.md new file mode 100644 index 0000000..f01e919 --- /dev/null +++ b/zynq7000-hal/README.md @@ -0,0 +1,12 @@ +# HAL for the AMD Zynq 7000 SoC family + +This repository contains the **H**ardware **A**bstraction **L**ayer (HAL), which is an additional +hardware abstraction on top of the [peripheral access API](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq7000). + +It is the result of reading the datasheet for the device and encoding a type-safe layer over the +raw PAC. This crate also implements traits specified by the +[embedded-hal](https://github.com/rust-embedded/embedded-hal) project, making it compatible with +various drivers in the embedded rust ecosystem. + +The [top-level README](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs) and the documentation +contain more information on how to use this crate. diff --git a/zynq7000-hal/src/clocks.rs b/zynq7000-hal/src/clocks.rs new file mode 100644 index 0000000..3a6feb2 --- /dev/null +++ b/zynq7000-hal/src/clocks.rs @@ -0,0 +1,466 @@ +//! Clock module. +use arbitrary_int::Number; + +use zynq7000::slcr::{ + ClockControl, + clocks::{ + ClockRatioSelect, DualCommonPeriphIoClkCtrl, FpgaClkControl, GigEthClkCtrl, + SingleCommonPeriphIoClkCtrl, + }, +}; + +use super::time::Hertz; + +#[derive(Debug)] +pub struct ArmClocks { + ref_clk: Hertz, + cpu_1x_clk: Hertz, + cpu_2x_clk: Hertz, + cpu_3x2x_clk: Hertz, + cpu_6x4x_clk: Hertz, +} + +impl ArmClocks { + /// Reference clock provided by ARM PLL which is used to calculate all other clock frequencies. + pub const fn ref_clk(&self) -> Hertz { + self.ref_clk + } + + pub const fn cpu_1x_clk(&self) -> Hertz { + self.cpu_1x_clk + } + + pub const fn cpu_2x_clk(&self) -> Hertz { + self.cpu_2x_clk + } + + pub const fn cpu_3x2x_clk(&self) -> Hertz { + self.cpu_3x2x_clk + } + + pub const fn cpu_6x4x_clk(&self) -> Hertz { + self.cpu_6x4x_clk + } +} + +#[derive(Debug)] +pub struct DdrClocks { + ref_clk: Hertz, + ddr_3x_clk: Hertz, + ddr_2x_clk: Hertz, +} + +impl DdrClocks { + /// Reference clock provided by DDR PLL which is used to calculate all other clock frequencies. + pub const fn ref_clk(&self) -> Hertz { + self.ref_clk + } + + pub fn ddr_3x_clk(&self) -> Hertz { + self.ddr_3x_clk + } + + pub fn ddr_2x_clk(&self) -> Hertz { + self.ddr_2x_clk + } +} + +#[derive(Debug)] +pub struct IoClocks { + /// Reference clock provided by IO PLL which is used to calculate all other clock frequencies. + ref_clk: Hertz, + smc_clk: Hertz, + qspi_clk: Hertz, + sdio_clk: Hertz, + uart_clk: Hertz, + spi_clk: Hertz, + can_clk: Hertz, + pcap_2x_clk: Hertz, + trace_clk: Option, +} + +impl IoClocks { + pub const fn ref_clk(&self) -> Hertz { + self.ref_clk + } + + pub const fn smc_clk(&self) -> Hertz { + self.smc_clk + } + + pub fn update_smc_clk(&mut self, clk: Hertz) { + self.smc_clk = clk + } + + pub const fn qspi_clk(&self) -> Hertz { + self.qspi_clk + } + + pub fn update_qspi_clk(&mut self, clk: Hertz) { + self.qspi_clk = clk + } + + pub const fn sdio_clk(&self) -> Hertz { + self.sdio_clk + } + + pub fn update_sdio_clk(&mut self, clk: Hertz) { + self.sdio_clk = clk + } + + pub const fn uart_clk(&self) -> Hertz { + self.uart_clk + } + + pub fn update_uart_clk(&mut self, clk: Hertz) { + self.uart_clk = clk + } + + pub const fn spi_clk(&self) -> Hertz { + self.spi_clk + } + + pub fn update_spi_clk(&mut self, clk: Hertz) { + self.spi_clk = clk + } + + pub fn can_clk(&self) -> Hertz { + self.can_clk + } + + pub fn update_can_clk(&mut self, clk: Hertz) { + self.can_clk = clk + } + + pub fn pcap_2x_clk(&self) -> Hertz { + self.pcap_2x_clk + } + + pub fn update_pcap_2x_clk(&mut self, clk: Hertz) { + self.pcap_2x_clk = clk + } + + /// Returns [None] if the trace clock is configured to use the EMIO trace clock. + pub fn trace_clk(&self) -> Option { + self.trace_clk + } +} + +#[derive(Debug)] +pub struct Clocks { + ps_clk: Hertz, + arm_pll_out: Hertz, + io_pll_out: Hertz, + ddr_pll_out: Hertz, + arm: ArmClocks, + ddr: DdrClocks, + io: IoClocks, + pl: [Hertz; 4], +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ClockModuleId { + Ddr, + Arm, + Smc, + Qspi, + Sdio, + Uart, + Spi, + Pcap, + Can, + Fpga, + Trace, + Gem0, + Gem1, +} + +#[derive(Debug)] +pub struct DivisorZero(pub ClockModuleId); + +#[derive(Debug)] +pub enum ClockReadError { + /// The feedback value for the PLL clock output calculation is zero. + PllFeedbackZero, + /// Detected a divisor of zero. + DivisorZero(DivisorZero), + /// Detected a divisor that is not even. + DivisorNotEven, +} + +impl Clocks { + /// Processing system clock, which is generally dependent on the board and the used crystal. + pub fn ps_clk(&self) -> Hertz { + self.ps_clk + } + + /// This generates the clock configuration by reading the SLCR clock registers. + /// + /// It assumes that the clock already has been configured, for example by a first-stage + /// bootloader, or the PS7 initialization script. + pub fn new_from_regs(ps_clk_freq: Hertz) -> Result { + let mut clk_regs = unsafe { ClockControl::new_mmio_fixed() }; + + let arm_pll_cfg = clk_regs.read_arm_pll(); + let io_pll_cfg = clk_regs.read_io_pll(); + let ddr_pll_cfg = clk_regs.read_ddr_pll(); + + if arm_pll_cfg.fdiv().as_u32() == 0 + || io_pll_cfg.fdiv().as_u32() == 0 + || ddr_pll_cfg.fdiv().as_u32() == 0 + { + return Err(ClockReadError::PllFeedbackZero); + } + let arm_pll_out = ps_clk_freq * arm_pll_cfg.fdiv().into(); + let io_pll_out = ps_clk_freq * io_pll_cfg.fdiv().into(); + let ddr_pll_out = ps_clk_freq * ddr_pll_cfg.fdiv().into(); + + let arm_clk_ctrl = clk_regs.read_arm_clk_ctrl(); + let arm_base_clk = match arm_clk_ctrl.srcsel() { + zynq7000::slcr::clocks::SrcSelArm::ArmPll + | zynq7000::slcr::clocks::SrcSelArm::ArmPllAlt => arm_pll_out, + zynq7000::slcr::clocks::SrcSelArm::DdrPll => ddr_pll_out, + zynq7000::slcr::clocks::SrcSelArm::IoPll => io_pll_out, + }; + let clk_sel = clk_regs.read_clk_621_true(); + if arm_clk_ctrl.divisor().as_u32() == 0 { + return Err(ClockReadError::DivisorZero(DivisorZero(ClockModuleId::Arm))); + } + let arm_clk_divided = arm_base_clk / arm_clk_ctrl.divisor().as_u32(); + let arm_clks = match clk_sel.sel() { + ClockRatioSelect::FourToTwoToOne => ArmClocks { + ref_clk: arm_pll_out, + cpu_1x_clk: arm_clk_divided / 4, + cpu_2x_clk: arm_clk_divided / 2, + cpu_3x2x_clk: arm_clk_divided / 2, + cpu_6x4x_clk: arm_clk_divided, + }, + ClockRatioSelect::SixToTwoToOne => ArmClocks { + ref_clk: arm_pll_out, + cpu_1x_clk: arm_clk_divided / 6, + cpu_2x_clk: arm_clk_divided / 3, + cpu_3x2x_clk: arm_clk_divided / 2, + cpu_6x4x_clk: arm_clk_divided, + }, + }; + + let ddr_clk_ctrl = clk_regs.read_ddr_clk_ctrl(); + if ddr_clk_ctrl.div_3x_clk().as_u32() == 0 || ddr_clk_ctrl.div_2x_clk().as_u32() == 0 { + return Err(ClockReadError::DivisorZero(DivisorZero(ClockModuleId::Ddr))); + } + let ddr_clks = DdrClocks { + ref_clk: ddr_pll_out, + ddr_3x_clk: ddr_pll_out / ddr_clk_ctrl.div_3x_clk().as_u32(), + ddr_2x_clk: ddr_pll_out / ddr_clk_ctrl.div_2x_clk().as_u32(), + }; + + let handle_common_single_clock_config = |single_block: SingleCommonPeriphIoClkCtrl, + id: ClockModuleId| + -> Result { + if single_block.divisor().as_u32() == 0 { + return Err(ClockReadError::DivisorZero(DivisorZero(id))); + } + Ok(match single_block.srcsel() { + zynq7000::slcr::clocks::SrcSelIo::IoPll + | zynq7000::slcr::clocks::SrcSelIo::IoPllAlt => { + io_pll_out / single_block.divisor().as_u32() + } + zynq7000::slcr::clocks::SrcSelIo::ArmPll => { + arm_pll_out / single_block.divisor().as_u32() + } + zynq7000::slcr::clocks::SrcSelIo::DdrPll => { + ddr_pll_out / single_block.divisor().as_u32() + } + }) + }; + let handle_common_dual_clock_config = |dual_block: DualCommonPeriphIoClkCtrl, + id: ClockModuleId| + -> Result { + if dual_block.divisor().as_u32() == 0 { + return Err(ClockReadError::DivisorZero(DivisorZero(id))); + } + Ok(match dual_block.srcsel() { + zynq7000::slcr::clocks::SrcSelIo::IoPll + | zynq7000::slcr::clocks::SrcSelIo::IoPllAlt => { + io_pll_out / dual_block.divisor().as_u32() + } + zynq7000::slcr::clocks::SrcSelIo::ArmPll => { + arm_pll_out / dual_block.divisor().as_u32() + } + zynq7000::slcr::clocks::SrcSelIo::DdrPll => { + ddr_pll_out / dual_block.divisor().as_u32() + } + }) + }; + + let smc_clk = + handle_common_single_clock_config(clk_regs.read_smc_clk_ctrl(), ClockModuleId::Smc)?; + let qspi_clk = + handle_common_single_clock_config(clk_regs.read_lqspi_clk_ctrl(), ClockModuleId::Qspi)?; + let sdio_clk = + handle_common_dual_clock_config(clk_regs.read_sdio_clk_ctrl(), ClockModuleId::Sdio)?; + let uart_clk = + handle_common_dual_clock_config(clk_regs.read_uart_clk_ctrl(), ClockModuleId::Uart)?; + let spi_clk = + handle_common_dual_clock_config(clk_regs.read_spi_clk_ctrl(), ClockModuleId::Spi)?; + let pcap_2x_clk = + handle_common_single_clock_config(clk_regs.read_pcap_clk_ctrl(), ClockModuleId::Pcap)?; + let can_clk_ctrl = clk_regs.read_can_clk_ctrl(); + let can_clk_ref_clk = match can_clk_ctrl.srcsel() { + zynq7000::slcr::clocks::SrcSelIo::IoPll + | zynq7000::slcr::clocks::SrcSelIo::IoPllAlt => io_pll_out, + zynq7000::slcr::clocks::SrcSelIo::ArmPll => arm_pll_out, + zynq7000::slcr::clocks::SrcSelIo::DdrPll => ddr_pll_out, + }; + if can_clk_ctrl.divisor_0().as_u32() == 0 || can_clk_ctrl.divisor_1().as_u32() == 0 { + return Err(ClockReadError::DivisorZero(DivisorZero(ClockModuleId::Can))); + } + let can_clk = + can_clk_ref_clk / can_clk_ctrl.divisor_0().as_u32() / can_clk_ctrl.divisor_1().as_u32(); + + let trace_clk_ctrl = clk_regs.read_dbg_clk_ctrl(); + if trace_clk_ctrl.divisor().as_u32() == 0 { + return Err(ClockReadError::DivisorZero(DivisorZero( + ClockModuleId::Trace, + ))); + } + let trace_clk = match trace_clk_ctrl.srcsel() { + zynq7000::slcr::clocks::SrcSelTpiu::IoPll + | zynq7000::slcr::clocks::SrcSelTpiu::IoPllAlt => { + Some(io_pll_out / trace_clk_ctrl.divisor().as_u32()) + } + zynq7000::slcr::clocks::SrcSelTpiu::ArmPll => { + Some(arm_pll_out / trace_clk_ctrl.divisor().as_u32()) + } + zynq7000::slcr::clocks::SrcSelTpiu::DdrPll => { + Some(ddr_pll_out / trace_clk_ctrl.divisor().as_u32()) + } + zynq7000::slcr::clocks::SrcSelTpiu::EmioTraceClk + | zynq7000::slcr::clocks::SrcSelTpiu::EmioTraceClkAlt0 + | zynq7000::slcr::clocks::SrcSelTpiu::EmioTraceClkAlt1 + | zynq7000::slcr::clocks::SrcSelTpiu::EmioTraceClkAlt2 => None, + }; + let calculate_fpga_clk = |fpga_clk_ctrl: FpgaClkControl| -> Result { + if fpga_clk_ctrl.divisor_0().as_u32() == 0 || fpga_clk_ctrl.divisor_1().as_u32() == 0 { + return Err(ClockReadError::DivisorZero(DivisorZero( + ClockModuleId::Fpga, + ))); + } + Ok(match fpga_clk_ctrl.srcsel() { + zynq7000::slcr::clocks::SrcSelIo::IoPll + | zynq7000::slcr::clocks::SrcSelIo::IoPllAlt => { + io_pll_out + / fpga_clk_ctrl.divisor_0().as_u32() + / fpga_clk_ctrl.divisor_1().as_u32() + } + zynq7000::slcr::clocks::SrcSelIo::ArmPll => { + arm_pll_out + / fpga_clk_ctrl.divisor_0().as_u32() + / fpga_clk_ctrl.divisor_1().as_u32() + } + zynq7000::slcr::clocks::SrcSelIo::DdrPll => { + ddr_pll_out + / fpga_clk_ctrl.divisor_0().as_u32() + / fpga_clk_ctrl.divisor_1().as_u32() + } + }) + }; + + Ok(Self { + ps_clk: ps_clk_freq, + io_pll_out, + ddr_pll_out, + arm_pll_out, + arm: arm_clks, + ddr: ddr_clks, + io: IoClocks { + ref_clk: io_pll_out, + smc_clk, + qspi_clk, + sdio_clk, + uart_clk, + spi_clk, + can_clk, + pcap_2x_clk, + trace_clk, + }, + // TODO: There should be a mut and a non-mut getter for an inner block. We only do pure + // reads with the inner block here. + pl: [ + calculate_fpga_clk(clk_regs.fpga_0_clk_ctrl().read_clk_ctrl())?, + calculate_fpga_clk(clk_regs.fpga_1_clk_ctrl().read_clk_ctrl())?, + calculate_fpga_clk(clk_regs.fpga_2_clk_ctrl().read_clk_ctrl())?, + calculate_fpga_clk(clk_regs.fpga_3_clk_ctrl().read_clk_ctrl())?, + ], + }) + } + + pub fn arm_clocks(&self) -> &ArmClocks { + &self.arm + } + + pub fn ddr_clocks(&self) -> &DdrClocks { + &self.ddr + } + + pub fn io_clocks(&self) -> &IoClocks { + &self.io + } + + pub fn io_clocks_mut(&mut self) -> &mut IoClocks { + &mut self.io + } + + /// Programmable Logic (PL) FCLK clocks. + pub fn pl_clocks(&self) -> &[Hertz; 4] { + &self.pl + } + + fn calculate_gem_ref_clock( + &self, + reg: GigEthClkCtrl, + module: ClockModuleId, + ) -> Result { + let source_clk = match reg.srcsel() { + zynq7000::slcr::clocks::SrcSelIo::IoPll + | zynq7000::slcr::clocks::SrcSelIo::IoPllAlt => self.io_pll_out, + zynq7000::slcr::clocks::SrcSelIo::ArmPll => self.arm_pll_out, + zynq7000::slcr::clocks::SrcSelIo::DdrPll => self.ddr_pll_out, + }; + let div0 = reg.divisor_0().as_u32(); + if div0 == 0 { + return Err(DivisorZero(module)); + } + let div1 = reg.divisor_1().as_u32(); + if div1 == 0 { + return Err(DivisorZero(module)); + } + Ok(source_clk / reg.divisor_0().as_u32() / reg.divisor_1().as_u32()) + } + + /// Calculate the reference clock for GEM0. + /// + /// The divisor 1 of the GEM is 0 on reset. You have to properly initialize the clock + /// configuration before calling this function. + /// + /// It should be noted that the GEM has a separate TX and RX clock. + /// The reference clock will only be the RX clock in loopback mode. For the TX block, + /// the reference clock is used if the EMIO enable bit `GEM{0,1}_CLK_CTRL[6]` is set to 0. + pub fn calculate_gem_0_ref_clock(&self) -> Result { + let clk_regs = unsafe { ClockControl::new_mmio_fixed() }; + self.calculate_gem_ref_clock(clk_regs.read_gem_0_clk_ctrl(), ClockModuleId::Gem0) + } + + /// Calculate the reference clock for GEM1. + /// + /// The divisor 1 of the GEM is 0 on reset. You have to properly initialize the clock + /// configuration before calling this function. + /// + /// It should be noted that the GEM has a separate TX and RX clock. + /// The reference clock will only be the RX clock in loopback mode. For the TX block, + /// the reference clock is used if the EMIO enable bit `GEM{0,1}_CLK_CTRL[6]` is set to 0. + pub fn calculate_gem_1_ref_clock(&self) -> Result { + let clk_regs = unsafe { ClockControl::new_mmio_fixed() }; + self.calculate_gem_ref_clock(clk_regs.read_gem_0_clk_ctrl(), ClockModuleId::Gem1) + } +} diff --git a/zynq7000-hal/src/gic.rs b/zynq7000-hal/src/gic.rs new file mode 100644 index 0000000..516d09c --- /dev/null +++ b/zynq7000-hal/src/gic.rs @@ -0,0 +1,528 @@ +//! Global Interrupt Controller (GIC) module. +//! +//! The primary interface to configure and allow handling the interrupts are the +//! [GicConfigurator] and the [GicInterruptHelper] structures. +//! +//! # Examples +//! +//! - [GTC ticks](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/examples/simple/src/bin/gtc-ticks.rs) +use arbitrary_int::Number; + +use cortex_ar::interrupt; +use zynq7000::gic::{ + Dcr, Gicc, Gicd, Icr, InterruptSignalRegister, MmioGicc, MmioGicd, PriorityRegister, +}; + +const SPURIOUS_INTERRUPT_ID: u32 = 1023; + +pub const HIGHEST_PRIORITY: u8 = 0; +pub const LOWEST_PRIORITY: u8 = 31; + +/// These fixed values must be programmed according to the Zynq7000 TRM p.236. +/// Configures #32 to #47. +pub const ICFR_2_FIXED_VALUE: u32 = 0b01010101010111010101010001011111; +/// These fixed values must be programmed according to the Zynq7000 TRM p.236. +/// This configures `PL[2:0]` to high-level sensitivity. +/// Configures #48 to #63. +pub const ICFR_3_FIXED_VALUE: u32 = 0b01010101010101011101010101010101; +/// These fixed values must be programmed according to the Zynq7000 TRM p.236. +/// This configures `PL[7:3]` to high-level sensitivity. +/// Configures #64 to #79. +pub const ICFR_4_FIXED_VALUE: u32 = 0b01110101010101010101010101010101; +/// These fixed values must be programmed according to the Zynq7000 TRM p.236. +/// This configures `PL[15:8]` to high-level sensitivity. +/// Configures #80 to #95. +pub const ICFR_5_FIXED_VALUE: u32 = 0b00000011010101010101010101010101; + +/// Helper value to target all interrupts which can be targetted to CPU 0 +pub const TARGETS_ALL_CPU_0_IPTR_VAL: u32 = 0x01010101; +/// Helper value to target all interrupts which can be targetted to CPU 1 +pub const TARGETS_ALL_CPU_1_IPTR_VAL: u32 = 0x02020202; + +pub const ACTIVATE_ALL_SGIS_MASK_ISER: u32 = 0x0000_FFFF; +pub const ACTIVATE_ALL_PPIS_MASK_ISER: u32 = 0xF800_0000; + +pub enum SpiSensitivity { + Level = 0b01, + Edge = 0b11, +} + +pub enum TargetCpu { + None = 0b00, + Cpu0 = 0b01, + Cpu1 = 0b10, + Both = 0b11, +} + +/// Private Peripheral Interrupt (PPI) which are private to the CPU. +#[derive(Debug, Eq, PartialEq, Clone, Copy, num_enum::TryFromPrimitive)] +#[repr(u8)] +pub enum PpiInterrupt { + GlobalTimer = 27, + // Interrupt signal from the PL. CPU0: `IRQF2P[18]` and CPU1: `IRQF2P[19]` + NFiq = 28, + CpuPrivateTimer = 29, + /// AWDT0 and AWDT1 for each CPU. + Awdt = 30, + // Interrupt signal from the PL. CPU0: `IRQF2P[16]` and CPU1: `IRQF2P[17]` + NIrq = 31, +} + +/// Shared Peripheral Interrupt IDs. +#[derive(Debug, Eq, PartialEq, Clone, Copy, num_enum::TryFromPrimitive)] +#[repr(u8)] +pub enum SpiInterrupt { + Cpu0 = 32, + Cpu1 = 33, + L2Cache = 34, + Ocm = 35, + _Reserved0 = 36, + Pmu0 = 37, + Pmu1 = 38, + Xadc = 39, + DevC = 40, + Swdt = 41, + Ttc00 = 42, + Ttc01 = 43, + Ttc02 = 44, + DmacAbort = 45, + Dmac0 = 46, + Dmac1 = 47, + Dmac2 = 48, + Dmac3 = 49, + Smc = 50, + Qspi = 51, + Gpio = 52, + Usb0 = 53, + Eth0 = 54, + Eth0Wakeup = 55, + Sdio0 = 56, + I2c0 = 57, + Spi0 = 58, + Uart0 = 59, + Can0 = 60, + Pl0 = 61, + Pl1 = 62, + Pl2 = 63, + Pl3 = 64, + Pl4 = 65, + Pl5 = 66, + Pl6 = 67, + Pl7 = 68, + Ttc10 = 69, + Ttc11 = 70, + Ttc12 = 71, + Dmac4 = 72, + Dmac5 = 73, + Dmac6 = 74, + Dmac7 = 75, + Usb1 = 76, + Eth1 = 77, + Eth1Wakeup = 78, + Sdio1 = 79, + I2c1 = 80, + Spi1 = 81, + Uart1 = 82, + Can1 = 83, + Pl8 = 84, + Pl9 = 85, + Pl10 = 86, + Pl11 = 87, + Pl12 = 88, + Pl13 = 89, + Pl14 = 90, + Pl15 = 91, + ScuParity = 92, +} + +/// Interrupt ID wrapper. +#[derive(Debug, Clone, Copy)] +pub enum Interrupt { + Sgi(usize), + Ppi(PpiInterrupt), + Spi(SpiInterrupt), + /// Detects an invalid interrupt ID. + Invalid(usize), + /// Spurious interrupt (ID# 1023). + Spurious, +} + +#[derive(Debug)] +pub struct InterruptInfo { + raw_reg: InterruptSignalRegister, + interrupt: Interrupt, + cpu_id: u8, +} + +impl InterruptInfo { + pub fn raw_reg(&self) -> InterruptSignalRegister { + self.raw_reg + } + + pub fn cpu_id(&self) -> u8 { + self.cpu_id + } + + pub fn interrupt(&self) -> Interrupt { + self.interrupt + } +} + +#[derive(Debug, thiserror::Error)] +#[error("Invalid priority value {0}, range is [0, 31]")] +pub struct InvalidPriorityValue(pub u8); + +#[derive(Debug, thiserror::Error)] +#[error("Invalid PL interrupt ID {0}")] +pub struct InvalidPlInterruptId(pub usize); + +/// Invalid Shared Peripheral Interrupt (SPI) ID. +#[derive(Debug, thiserror::Error)] +#[error("Invalid SPI interrupt ID {0}")] +pub struct InvalidSpiInterruptId(pub usize); + +/// Invalid Software Generated Interrupt (SGI) ID. +#[derive(Debug, thiserror::Error)] +#[error("Invalid SGI interrupt ID {0}")] +pub struct InvalidSgiInterruptId(pub usize); + +/// Higher-level GIC controller for the Zynq70000 SoC. +/// +/// The flow of using this controller is as follows: +/// +/// 1. Create the controller using [Self::new_with_init]. You can use the [zynq7000::PsPeripherals] +/// structure or the [zynq7000::gic::Gicc::new_mmio] and [zynq7000::gic::Gicd::new_mmio] +/// functions to create the MMIO instances. The constructor configures all PL interrupts +/// sensivities to high-level sensitivity and configures all sensitivities which are expected +/// to have a certain value. It also sets the priority mask to 0xff by calling +/// [Self::set_priority_mask] to prevent masking of the interrupts. +/// 2. Perform the configuration of the interrupt targets and the interrupt sensitivities. +/// The CPU targets are encoded with [TargetCpu] while the sensitivities are encoded by +/// the [SpiSensitivity] enum. You can use the following (helper) API to configure the +/// interrupts: +/// +/// - [Self::set_spi_interrupt_cpu_target] +/// - [Self::set_all_spi_interrupt_targets_cpu0] +/// - [Self::set_pl_interrupt_sensitivity] +/// +/// 3. Enable all required interrupts. The following API can be used for this: +/// +/// - [Self::enable_sgi_interrupt] +/// - [Self::enable_ppi_interrupt] +/// - [Self::enable_spi_interrupt] +/// - [Self::enable_all_spi_interrupts] +/// - [Self::enable_all_ppi_interrupts] +/// - [Self::enable_all_sgi_interrupts] +/// - [Self::enable_all_interrupts] +/// +/// You might also chose to enable these interrupts at run-time after the GIC was started. +/// 4. Start the GIC by calling [Self::update_ctrl_regs] with the required settings or +/// with [Self::enable] which assumes a certain configuration. +/// 5. Enable interrupts for the Cortex-AR core by calling [Self::enable_interrupts]. +/// +/// For the handling of the interrupts, you can use the [GicInterruptHelper] which assumes a +/// properly configured GIC. +pub struct GicConfigurator { + pub gicc: MmioGicc<'static>, + pub gicd: MmioGicd<'static>, +} + +impl GicConfigurator { + /// Create a new GIC controller instance and calls [Self::initialize] to perform + /// strongly recommended initialization routines for the GIC. + #[inline] + pub fn new_with_init(gicc: MmioGicc<'static>, gicd: MmioGicd<'static>) -> Self { + let mut gic = GicConfigurator { gicc, gicd }; + gic.initialize(); + gic + } + + /// Create a new GIC controller instance without performing any initialization routines. + /// + /// # Safety + /// + /// This creates the GIC without performing any of the initialization routines necessary + /// for proper operation. It also circumvents ownership checks. It is mainly intended to be + /// used inside the interrupt handler. + #[inline] + pub unsafe fn steal() -> Self { + GicConfigurator { + gicc: unsafe { Gicc::new_mmio_fixed() }, + gicd: unsafe { Gicd::new_mmio_fixed() }, + } + } + + /// Sets up the GIC by configuring the required sensitivites for the shared peripheral + /// interrupts. + /// + /// With a few exeception, the GIC expects software to set up the sensitivities + /// to fixed values. The only exceptions are the interupts coming from the programmable + /// logic. These are configured to high level sensitivity by this function. + /// If you need a different sensitivity, you need to update the bits using the + /// [Self::set_pl_interrupt_sensitivity] function. + #[inline] + pub fn initialize(&mut self) { + self.gicd.write_icfr_2_spi(ICFR_2_FIXED_VALUE); + self.gicd.write_icfr_3_spi(ICFR_3_FIXED_VALUE); + self.gicd.write_icfr_4_spi(ICFR_4_FIXED_VALUE); + self.gicd.write_icfr_5_spi(ICFR_5_FIXED_VALUE); + self.set_priority_mask(0xff); + } + + /// Set the priority mask for the CPU. + /// + /// Only interrupts with a higher priority than the mask will be accepted. + /// A lower numerical number means a higher priority. This means that the reset value 0x0 + /// will mask all interrupts to the CPU while 0xff will unmask all interrupts. + /// + /// Please note that the highest priority mask will NOT be necessarily the number of priority + /// levels: The IPRn register always sets the priority level number to the upper bits of the + /// 8-bit bitfield. See p.83 of the ARM GICv1 architecture specification. + pub fn set_priority_mask(&mut self, mask: u8) { + self.gicc + .write_pmr(PriorityRegister::new_with_raw_value(mask as u32)); + } + + /// Set the sensitivity of a the Programmable Logic SPI interrupts. + /// + /// These are the only interrupt IDs which are configurable for SPI. They are set + /// to high-level sensitivity by default by the [Self::initialize] function. You can + /// use this method to override certain sensitivies. + #[inline] + pub fn set_pl_interrupt_sensitivity( + &mut self, + pl_int_id: usize, + sensitivity: SpiSensitivity, + ) -> Result<(), InvalidPlInterruptId> { + if pl_int_id >= 16 { + return Err(InvalidPlInterruptId(pl_int_id)); + } + match pl_int_id { + 0..=2 => { + let pos = 26 + (pl_int_id * 2); + let mask = 0b11 << pos; + self.gicd + .modify_icfr_3_spi(|v| (v & !mask) | ((sensitivity as u32) << pos)); + } + 3..=7 => { + let pos = pl_int_id * 2; + let mask = 0b11 << pos; + self.gicd + .modify_icfr_4_spi(|v| (v & !mask) | ((sensitivity as u32) << pos)); + } + 8..=15 => { + let pos = 8 + (pl_int_id * 2); + let mask = 0b11 << pos; + self.gicd + .modify_icfr_5_spi(|v| (v & !mask) | ((sensitivity as u32) << pos)); + } + _ => unreachable!(), + } + Ok(()) + } + + /// Set the CPU target for a SPI interrupt. + /// + /// See [Self::set_all_spi_interrupt_targets_cpu0] for a utility method to handle all + /// interrupts with one core. + #[inline] + pub fn set_spi_interrupt_cpu_target(&mut self, spi_int: SpiInterrupt, target: TargetCpu) { + let spi_int_raw = spi_int as u32; + let spi_offset_to_0 = spi_int_raw as usize - 32; + // Unwrap okay, calculated index is always valid. + self.gicd + .write_iptr_spi( + spi_offset_to_0 / 4, + (target as u32) << ((spi_offset_to_0 % 4) * 8), + ) + .unwrap(); + } + + /// Utility function to set all SGI interrupt targets to CPU0. + /// + /// This is useful if only CPU0 is active in a system, or if CPU0 handles most interrupts in + /// the system. + #[inline] + pub fn set_all_spi_interrupt_targets_cpu0(&mut self) { + for i in 0..0x10 { + self.gicd + .write_iptr_spi(i, TARGETS_ALL_CPU_0_IPTR_VAL) + .unwrap(); + } + } + + #[inline] + pub fn enable_sgi_interrupt(&mut self, int_id: usize) -> Result<(), InvalidSpiInterruptId> { + if int_id >= 16 { + return Err(InvalidSpiInterruptId(int_id)); + } + unsafe { self.gicd.write_iser_unchecked(0, 1 << int_id) }; + Ok(()) + } + + #[inline] + pub fn enable_all_sgi_interrupts(&mut self) { + // Unwrap okay, index is valid. + self.gicd + .modify_iser(0, |mut v| { + v |= ACTIVATE_ALL_SGIS_MASK_ISER; + v + }) + .unwrap(); + } + + #[inline] + pub fn enable_ppi_interrupt(&mut self, ppi_int: PpiInterrupt) { + // Unwrap okay, index is valid. + self.gicd + .modify_iser(0, |mut v| { + v |= 1 << (ppi_int as u32); + v + }) + .unwrap(); + } + + #[inline] + pub fn enable_all_ppi_interrupts(&mut self) { + unsafe { + self.gicd.modify_iser_unchecked(0, |mut v| { + v |= ACTIVATE_ALL_PPIS_MASK_ISER; + v + }) + }; + } + + #[inline] + pub fn enable_spi_interrupt(&mut self, spi_int: SpiInterrupt) { + let spi_int_raw = spi_int as u32; + match spi_int_raw { + 32..=63 => { + let bit_pos = spi_int_raw - 32; + // Unwrap okay, valid index. + self.gicd.write_iser(1, 1 << bit_pos).unwrap(); + } + 64..=92 => { + let bit_pos = spi_int_raw - 64; + // Unwrap okay, valid index. + self.gicd.write_iser(2, 1 << bit_pos).unwrap(); + } + _ => unreachable!(), + } + } + + #[inline] + pub fn enable_all_spi_interrupts(&mut self) { + self.gicd.write_iser(1, 0xFFFF_FFFF).unwrap(); + self.gicd.write_iser(2, 0xFFFF_FFFF).unwrap(); + } + + /// Enables all interrupts by calling [Self::enable_all_sgi_interrupts], + /// [Self::enable_all_ppi_interrupts] and [Self::enable_all_spi_interrupts]. + pub fn enable_all_interrupts(&mut self) { + self.enable_all_sgi_interrupts(); + self.enable_all_ppi_interrupts(); + self.enable_all_spi_interrupts(); + } + + /// Enable the GIC assuming a possibly non-secure configuration. + /// + /// This function will NOT configure and enable the various interrupt sources. You need to + /// set the interrupt sensitivities and targets before calling this function. + /// This function configured the control registers with the following settings: + /// + /// - CPU interface: Secure and non-secure interrupts are enabled. SBPR, FIQen and AckCtrl + /// fields set to default value 0. + /// - Distributor interface: Both non-secure and secure interrupt distribution enabled. + /// + /// It calls [Self::update_ctrl_regs] to update the control registers. + /// If you need custom settings, you can call [Self::update_ctrl_regs] with your required + /// settings. + /// + /// This will not enable the interrupt exception for the Cortex-AR core. You might also have + /// to call [Self::enable_interrupts] for interrupts to work. + pub fn enable(&mut self) { + self.update_ctrl_regs( + Icr::builder() + .with_sbpr(false) + .with_fiq_en(false) + .with_ack_ctrl(false) + .with_enable_non_secure(true) + .with_enable_secure(true) + .build(), + Dcr::builder() + .with_enable_non_secure(true) + .with_enable_secure(true) + .build(), + ); + } + + /// Enable the regular interrupt exceprion for the Cortex-A core by calling the + /// [interrupt::enable] function. You also need to [Self::enable] the GIC for interrupts to + /// work. + /// + /// # Safety + /// + /// Do not call this in a critical section. + pub unsafe fn enable_interrupts(&self) { + unsafe { + interrupt::enable(); + } + } + + /// Enable the interrupts for the Cortex-A core by calling the [interrupt::enable] module. + pub fn disable_interrupts(&self) { + interrupt::disable(); + } + + /// Update the control registers which control the safety configuration and which also enable + /// the GIC. + pub fn update_ctrl_regs(&mut self, icr: Icr, dcr: Dcr) { + self.gicc.write_icr(icr); + self.gicd.write_dcr(dcr); + } +} + +/// Helper structure which should only be used inside the interrupt handler once the GIC has +/// been configured with the [GicConfigurator]. +pub struct GicInterruptHelper(MmioGicc<'static>); + +impl GicInterruptHelper { + /// Create the interrupt helper with the fixed GICC MMIO instance. + pub const fn new() -> Self { + GicInterruptHelper(unsafe { Gicc::new_mmio_fixed() }) + } + + /// Acknowledges an interrupt by reading the IAR register and returning the interrupt context + /// information structure. + /// + /// This should be called at the start of an interrupt handler. + pub fn acknowledge_interrupt(&mut self) -> InterruptInfo { + let iar = self.0.read_iar(); + let int_id = iar.ack_int_id().as_u32(); + let interrupt = match int_id { + 0..=15 => Interrupt::Sgi(int_id as usize), + 27..=31 => Interrupt::Ppi(PpiInterrupt::try_from(int_id as u8).unwrap()), + 32..=92 => Interrupt::Spi(SpiInterrupt::try_from(int_id as u8).unwrap()), + SPURIOUS_INTERRUPT_ID => Interrupt::Spurious, + _ => Interrupt::Invalid(int_id as usize), + }; + InterruptInfo { + interrupt, + cpu_id: iar.cpu_id().as_u8(), + raw_reg: iar, + } + } + + /// Acknowledges the end of an interrupt by writing the EOIR register of the GICC. + /// + /// This should be called at the end of an interrupt handler. + pub fn end_of_interrupt(&mut self, irq_info: InterruptInfo) { + self.0.write_eoir(irq_info.raw_reg()) + } +} + +impl Default for GicInterruptHelper { + fn default() -> Self { + Self::new() + } +} diff --git a/zynq7000-hal/src/gpio/dyn_mio.rs b/zynq7000-hal/src/gpio/dyn_mio.rs new file mode 100644 index 0000000..0c3d1db --- /dev/null +++ b/zynq7000-hal/src/gpio/dyn_mio.rs @@ -0,0 +1,420 @@ +//! Dynamic MIO pin module. +//! +//! This provides the type-erased MIO pin support. +use arbitrary_int::{u2, u3}; +use zynq7000::gpio::{Gpio, MaskedOutput, MmioGpio}; + +pub use crate::gpio::PinState; +use crate::slcr::Slcr; + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct MuxConf { + l3: u3, + l2: u2, + l1: bool, + l0: bool, +} + +impl From for MuxConf { + fn from(value: zynq7000::slcr::mio::Config) -> Self { + Self::new( + value.l0_sel(), + value.l1_sel(), + value.l2_sel(), + value.l3_sel(), + ) + } +} + +impl MuxConf { + #[inline] + pub const fn new(l0: bool, l1: bool, l2: u2, l3: u3) -> Self { + Self { l3, l2, l1, l0 } + } + + pub const fn new_with_l3(l3: u3) -> Self { + Self::new(false, false, u2::new(0b00), l3) + } + + pub const fn new_for_gpio() -> Self { + Self::new(false, false, u2::new(0), u3::new(0)) + } + + #[inline] + pub const fn l0_sel(&self) -> bool { + self.l0 + } + + #[inline] + pub const fn l1_sel(&self) -> bool { + self.l1 + } + + #[inline] + pub const fn l2_sel(&self) -> u2 { + self.l2 + } + + #[inline] + pub const fn l3_sel(&self) -> u3 { + self.l3 + } +} + +#[derive(Debug, Copy, Clone)] +pub enum DynPinModeMio { + Output, + InputFloating, + InputPullUp, + IoPeriph(MuxConf), +} + +#[derive(Debug, thiserror::Error)] +#[error("invalid pin mode for MIO pin: {0:?}")] +pub struct InvalidPinModeMio(pub DynPinModeMio); + +impl embedded_hal::digital::Error for InvalidPinModeMio { + fn kind(&self) -> embedded_hal::digital::ErrorKind { + embedded_hal::digital::ErrorKind::Other + } +} + +pub trait MioPinProvider { + fn mode(&self) -> &DynPinModeMio; + + fn offset(&self) -> usize; + + #[inline] + fn is_input(&self) -> bool { + matches!( + self.mode(), + DynPinModeMio::InputFloating | DynPinModeMio::InputPullUp + ) + } + #[inline] + fn is_output(&self) -> bool { + matches!(self.mode(), DynPinModeMio::Output) + } + #[inline] + fn is_io_periph(&self) -> bool { + matches!(self.mode(), DynPinModeMio::IoPeriph(_)) + } +} + +pub struct DynMioPin { + offset: usize, + dyn_mode: DynPinModeMio, + regs: MmioGpio<'static>, +} + +impl MioPinProvider for DynMioPin { + #[inline] + fn mode(&self) -> &DynPinModeMio { + &self.dyn_mode + } + #[inline] + fn offset(&self) -> usize { + self.offset + } +} + +#[derive(Debug, thiserror::Error)] +#[error("MIO pins 7 and 8 can only be output pins")] +pub struct PinIsOutputOnly; + +impl DynMioPin { + #[inline] + pub(crate) const fn new(offset: usize, dyn_mode: DynPinModeMio) -> Self { + Self { + offset, + dyn_mode, + regs: unsafe { Gpio::new_mmio_fixed() }, + } + } + + /// Convert the pin into an output pin. + pub fn into_output(&mut self, init_level: PinState) { + self.dyn_mode = DynPinModeMio::Output; + // The Pullup config does not matter for Output. Tri-state bit must be 0 for the + // output driver to work. + self.reconfigure_slcr_mio_cfg(false, None, Some(MuxConf::new_for_gpio())); + match self.offset { + 0..=31 => { + self.regs.bank_0().modify_dirm(|v| v | (1 << self.offset)); + self.regs.bank_0().modify_out_en(|v| v | (1 << self.offset)); + } + 32..=53 => { + self.regs + .bank_1() + .modify_dirm(|v| v | 1 << (self.offset - 32)); + self.regs + .bank_1() + .modify_out_en(|v| v | 1 << (self.offset - 32)); + } + _ => panic!("invalid GPIO pin offset"), + } + // Unwrap okay, just set mode. + self.write_state(self.offset, init_level).unwrap(); + } + + /// Convert the pin into a floating input pin. + pub fn into_input_floating(&mut self) -> Result<(), PinIsOutputOnly> { + if self.offset == 7 || self.offset == 8 { + return Err(PinIsOutputOnly); + } + self.reconfigure_slcr_mio_cfg(true, Some(false), Some(MuxConf::new_for_gpio())); + self.configure_input_pin(); + self.dyn_mode = DynPinModeMio::InputFloating; + Ok(()) + } + + /// Convert the pin into an input pin with a pull up. + pub fn into_input_pull_up(&mut self) -> Result<(), PinIsOutputOnly> { + if self.offset == 7 || self.offset == 8 { + return Err(PinIsOutputOnly); + } + self.reconfigure_slcr_mio_cfg(true, Some(true), Some(MuxConf::new_for_gpio())); + self.configure_input_pin(); + self.dyn_mode = DynPinModeMio::InputPullUp; + Ok(()) + } + + /// Convert the pin into an IO peripheral pin. + pub fn into_io_periph_pin(&mut self, mux_conf: MuxConf, pullup: Option) { + self.reconfigure_slcr_mio_cfg(false, pullup, Some(mux_conf)); + self.dyn_mode = DynPinModeMio::IoPeriph(mux_conf); + } + + pub fn is_low(&self) -> Result { + if !self.is_input() { + return Err(InvalidPinModeMio(self.dyn_mode)); + } + Ok(self.is_low_unchecked()) + } + + /// This variant does not check whether the [DynPinModeMio] is correct. + #[inline] + pub fn is_low_unchecked(&self) -> bool { + match self.offset { + 0..=31 => ((self.regs.read_in_0() >> self.offset) & 0b1) == 0, + 32..=53 => ((self.regs.read_in_1() >> (self.offset - 32)) & 0b1) == 0, + _ => panic!("invalid GPIO pin offset"), + } + } + + #[inline] + pub fn is_high(&self) -> Result { + self.is_low().map(|v| !v) + } + + /// This variant does not check whether the [DynPinModeMio] is correct. + #[inline] + pub fn is_high_unchecked(&self) -> bool { + !self.is_low_unchecked() + } + + #[inline] + pub fn is_set_low(&self) -> Result { + if !self.is_output() { + return Err(InvalidPinModeMio(self.dyn_mode)); + } + Ok(self.is_set_low_unchecked()) + } + + /// This variant does not check whether the [DynPinModeMio] is correct. + #[inline] + pub fn is_set_low_unchecked(&self) -> bool { + match self.offset { + 0..=31 => ((self.regs.read_out_0() >> self.offset) & 0b1) == 0, + 32..=53 => ((self.regs.read_out_1() >> (self.offset - 32)) & 0b1) == 0, + _ => panic!("invalid GPIO pin offset"), + } + } + + #[inline] + pub fn is_set_high(&self) -> Result { + self.is_set_low().map(|v| !v) + } + + /// This variant does not check whether the [DynPinModeMio] is correct. + #[inline] + pub fn is_set_high_unchecked(&self) -> bool { + !self.is_set_low_unchecked() + } + + #[inline] + pub fn set_low(&mut self) -> Result<(), InvalidPinModeMio> { + self.write_state(self.offset, PinState::Low) + } + + /// This variant does not check whether the [DynPinModeMio] is correct. + #[inline] + pub fn set_low_unchecked(&mut self) { + self.write_state_unchecked(self.offset, PinState::Low) + } + + #[inline] + pub fn set_high(&mut self) -> Result<(), InvalidPinModeMio> { + self.write_state(self.offset, PinState::High) + } + + /// This variant does not check whether the [DynPinModeMio] is correct. + #[inline] + pub fn set_high_unchecked(&mut self) { + self.write_state_unchecked(self.offset, PinState::High) + } + + #[inline(always)] + fn offset_to_masked_out_ptr_and_ptr_offset( + &mut self, + offset: usize, + ) -> (usize, *mut MaskedOutput) { + match offset { + 0..=15 => (offset, self.regs.pointer_to_masked_out_0_lsw()), + 16..=31 => (offset - 16, self.regs.pointer_to_masked_out_0_msw()), + 32..=47 => (offset - 32, self.regs.pointer_to_masked_out_1_lsw()), + 48..=53 => (offset - 48, self.regs.pointer_to_masked_out_1_msw()), + _ => unreachable!(), + } + } + + #[inline] + fn write_state(&mut self, offset: usize, level: PinState) -> Result<(), InvalidPinModeMio> { + if !self.is_output() { + return Err(InvalidPinModeMio(self.dyn_mode)); + } + self.write_state_unchecked(offset, level); + Ok(()) + } + + #[inline] + fn write_state_unchecked(&mut self, offset: usize, level: PinState) { + let (offset_in_reg, masked_out_ptr) = self.offset_to_masked_out_ptr_and_ptr_offset(offset); + unsafe { + core::ptr::write_volatile( + masked_out_ptr, + MaskedOutput::builder() + .with_mask(!(1 << offset_in_reg)) + .with_output((level as u16) << offset_in_reg) + .build(), + ); + } + } + + #[inline] + fn is_low_mut(&mut self) -> Result { + self.is_low() + } + + #[inline] + fn is_high_mut(&mut self) -> Result { + self.is_high() + } + + #[inline] + fn is_set_low_mut(&mut self) -> Result { + self.is_set_low() + } + + #[inline] + fn is_set_high_mut(&mut self) -> Result { + self.is_set_high() + } + + fn reconfigure_slcr_mio_cfg( + &mut self, + tristate: bool, + pullup: Option, + mux_conf: Option, + ) { + // Safety: We only modify the MIO config of the pin. + let mut slcr_wrapper = unsafe { Slcr::steal() }; + // We read first, because writing also required unlocking the SLCR. + // This allows the user to configure the SLCR themselves to avoid unnecessary + // re-configuration which might also be potentially unsafe at run-time. + let mio_cfg = slcr_wrapper.regs().read_mio_pins(self.offset).unwrap(); + if (pullup.is_some() && mio_cfg.pullup() != pullup.unwrap()) + || (mux_conf.is_some() && MuxConf::from(mio_cfg) != mux_conf.unwrap()) + || tristate != mio_cfg.tri_enable() + { + slcr_wrapper.modify(|mut_slcr| { + mut_slcr + .modify_mio_pins(self.offset, |mut val| { + if let Some(pullup) = pullup { + val.set_pullup(pullup); + } + if let Some(mux_conf) = mux_conf { + val.set_l0_sel(mux_conf.l0_sel()); + val.set_l1_sel(mux_conf.l1_sel()); + val.set_l2_sel(mux_conf.l2_sel()); + val.set_l3_sel(mux_conf.l3_sel()); + } + val.set_tri_enable(tristate); + val + }) + .unwrap(); + }); + } + } + + fn configure_input_pin(&mut self) { + match self.offset { + 0..=31 => { + self.regs.bank_0().modify_dirm(|mut v| { + v &= !(1 << self.offset); + v + }); + self.regs.bank_0().modify_out_en(|mut v| { + v &= !(1 << self.offset); + v + }); + } + 32..=53 => { + self.regs.bank_1().modify_dirm(|mut v| { + v &= !(1 << (self.offset - 32)); + v + }); + self.regs.bank_1().modify_out_en(|mut v| { + v &= !(1 << (self.offset - 32)); + v + }); + } + _ => panic!("invalid GPIO pin offset"), + } + } +} + +impl embedded_hal::digital::ErrorType for DynMioPin { + type Error = InvalidPinModeMio; +} + +impl embedded_hal::digital::OutputPin for DynMioPin { + fn set_low(&mut self) -> Result<(), Self::Error> { + self.set_low()?; + Ok(()) + } + fn set_high(&mut self) -> Result<(), Self::Error> { + self.set_high()?; + Ok(()) + } +} + +impl embedded_hal::digital::StatefulOutputPin for DynMioPin { + fn is_set_high(&mut self) -> Result { + self.is_set_high_mut() + } + + fn is_set_low(&mut self) -> Result { + self.is_set_low_mut() + } +} + +impl embedded_hal::digital::InputPin for DynMioPin { + fn is_high(&mut self) -> Result { + self.is_high_mut() + } + + fn is_low(&mut self) -> Result { + self.is_low_mut() + } +} diff --git a/zynq7000-hal/src/gpio/emio.rs b/zynq7000-hal/src/gpio/emio.rs new file mode 100644 index 0000000..9af24f2 --- /dev/null +++ b/zynq7000-hal/src/gpio/emio.rs @@ -0,0 +1,290 @@ +//! EMIO (Extended Multiplexed I/O) module. +use zynq7000::gpio::{Gpio, MaskedOutput, MmioGpio}; + +pub use crate::gpio::PinState; + +#[derive(Debug, thiserror::Error)] +#[error("invalid pin mode for MIO pin: {0:?}")] +pub struct InvalidPinModeEmio(pub DynPinModeEmio); + +impl embedded_hal::digital::Error for InvalidPinModeEmio { + fn kind(&self) -> embedded_hal::digital::ErrorKind { + embedded_hal::digital::ErrorKind::Other + } +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub enum DynPinModeEmio { + Output, + Input, +} + +pub struct EmioPin { + regs: MmioGpio<'static>, + mode: DynPinModeEmio, + offset: usize, +} + +impl EmioPin { + /// Unsafely steal an EMIO input pin. + /// + /// Unless you have no other option, it is recommended to use the [EmioPins::take] method + /// to retrieve the pins safely. Returns [None] if the offset is larger than 63. + /// + /// # Safety + /// + /// This allows potentially creating multiple input pin structures for the same GPIO + /// peripheral which can cause data races. + #[inline] + pub const unsafe fn steal(offset: usize) -> Option { + if offset >= 64 { + return None; + } + Some(Self { + regs: unsafe { Gpio::new_mmio_fixed() }, + mode: DynPinModeEmio::Input, + offset: 0, + }) + } + + pub fn into_input(&mut self) { + self.mode = DynPinModeEmio::Input; + match self.offset { + 0..=31 => { + self.regs + .bank_2() + .modify_dirm(|val| val & !(1 << self.offset)); + } + 32..=63 => { + self.regs + .bank_3() + .modify_dirm(|val| val & !(1 << self.offset)); + } + _ => unreachable!(), + } + } + + pub fn into_output(&mut self, init_level: PinState) { + self.mode = DynPinModeEmio::Output; + match self.offset { + 0..=31 => { + self.regs + .bank_2() + .modify_dirm(|val| val | (1 << self.offset)); + self.regs + .bank_2() + .modify_out_en(|val| val | (1 << self.offset)); + } + 32..=63 => { + self.regs + .bank_3() + .modify_dirm(|val| val | (1 << self.offset)); + self.regs + .bank_2() + .modify_out_en(|val| val | (1 << self.offset)); + } + _ => unreachable!(), + } + // Unwrap okay, just set mode. + self.write_state(self.offset, init_level).unwrap(); + } + + #[inline] + pub fn is_low(&self) -> Result { + if self.mode == DynPinModeEmio::Output { + return Err(InvalidPinModeEmio(self.mode)); + } + Ok(self.is_low_unchecked()) + } + + /// This variant does not check whether the [DynPinModeEmio] is correct. + #[inline] + pub fn is_low_unchecked(&self) -> bool { + match self.offset { + 0..=31 => ((self.regs.read_in_0() >> self.offset) & 0b1) == 0, + 32..=63 => ((self.regs.read_in_1() >> (self.offset - 32)) & 0b1) == 0, + _ => panic!("invalid GPIO pin offset"), + } + } + + #[inline] + pub fn is_high(&self) -> Result { + self.is_low().map(|v| !v) + } + + /// This variant does not check whether the [DynPinModeEmio] is correct. + #[inline] + pub fn is_high_unchecked(&self) -> bool { + !self.is_low_unchecked() + } + + #[inline(always)] + fn offset_to_masked_out_ptr_and_ptr_offset( + &mut self, + offset: usize, + ) -> (usize, *mut MaskedOutput) { + match offset { + 0..=15 => (offset, self.regs.pointer_to_masked_out_2_lsw()), + 16..=31 => (offset - 16, self.regs.pointer_to_masked_out_2_msw()), + 32..=47 => (offset - 32, self.regs.pointer_to_masked_out_3_lsw()), + 48..=63 => (offset - 48, self.regs.pointer_to_masked_out_3_msw()), + _ => unreachable!(), + } + } + + #[inline] + fn write_state(&mut self, offset: usize, level: PinState) -> Result<(), InvalidPinModeEmio> { + if self.mode == DynPinModeEmio::Input { + return Err(InvalidPinModeEmio(self.mode)); + } + self.write_state_unchecked(offset, level); + Ok(()) + } + + #[inline] + fn write_state_unchecked(&mut self, offset: usize, level: PinState) { + let (offset_in_reg, masked_out_ptr) = self.offset_to_masked_out_ptr_and_ptr_offset(offset); + unsafe { + core::ptr::write_volatile( + masked_out_ptr, + MaskedOutput::builder() + .with_mask(!(1 << offset_in_reg)) + .with_output((level as u16) << offset_in_reg) + .build(), + ); + } + } + + #[inline] + pub fn is_set_low(&mut self) -> Result { + if self.mode == DynPinModeEmio::Input { + return Err(InvalidPinModeEmio(self.mode)); + } + Ok(self.is_set_low_unchecked()) + } + + /// This variant does not check whether the [DynPinModeEmio] is correct. + #[inline] + pub fn is_set_low_unchecked(&mut self) -> bool { + match self.offset { + 0..=31 => ((self.regs.read_out_2() >> self.offset) & 0b1) == 0, + 32..=64 => ((self.regs.read_out_3() >> (self.offset - 32)) & 0b1) == 0, + _ => panic!("invalid GPIO pin offset"), + } + } + + #[inline] + pub fn is_set_high(&mut self) -> Result { + self.is_set_low().map(|v| !v) + } + + /// This variant does not check whether the [DynPinModeEmio] is correct. + #[inline] + pub fn is_set_high_unchecked(&mut self) -> bool { + !self.is_set_low_unchecked() + } + + #[inline] + pub fn set_high(&mut self) -> Result<(), InvalidPinModeEmio> { + self.write_state(self.offset, PinState::High) + } + + /// This variant does not check whether the [DynPinModeEmio] is correct. + #[inline] + pub fn set_high_unchecked(&mut self) { + self.write_state_unchecked(self.offset, PinState::High) + } + + #[inline] + pub fn set_low(&mut self) -> Result<(), InvalidPinModeEmio> { + self.write_state(self.offset, PinState::Low) + } + + /// This variant does not check whether the [DynPinModeEmio] is correct. + #[inline] + pub fn set_low_unchecked(&mut self) { + self.write_state_unchecked(self.offset, PinState::Low) + } + + #[inline] + fn is_high_mut(&mut self) -> Result { + self.is_high() + } + + #[inline] + fn is_low_mut(&mut self) -> Result { + self.is_low() + } +} + +impl embedded_hal::digital::ErrorType for EmioPin { + type Error = InvalidPinModeEmio; +} + +impl embedded_hal::digital::InputPin for EmioPin { + #[inline] + fn is_high(&mut self) -> Result { + self.is_high_mut() + } + #[inline] + fn is_low(&mut self) -> Result { + self.is_low_mut() + } +} + +impl embedded_hal::digital::OutputPin for EmioPin { + #[inline] + fn set_high(&mut self) -> Result<(), Self::Error> { + self.set_high() + } + #[inline] + fn set_low(&mut self) -> Result<(), Self::Error> { + self.set_low() + } +} + +impl embedded_hal::digital::StatefulOutputPin for EmioPin { + fn is_set_high(&mut self) -> Result { + self.is_set_high() + } + + fn is_set_low(&mut self) -> Result { + self.is_set_low() + } +} + +pub struct EmioPins { + emios: [Option; 64], +} + +impl EmioPins { + /// Create a new EMIO pin structure. + /// + /// This structure is supposed to be used as a singleton. It will configure all + /// EMIO pins as inputs. If you want to retrieve individual pins without this structure, + /// use [EmioPin::steal] instead. + pub fn new(mut mmio: MmioGpio) -> Self { + let mut emios = [const { None }; 64]; + // Configure all EMIO pins as inputs. + mmio.bank_2().write_dirm(0); + mmio.bank_3().write_dirm(0); + + (0..64).for_each(|i| { + let mmio = unsafe { Gpio::new_mmio_fixed() }; + emios[i] = Some(EmioPin { + regs: mmio, + mode: DynPinModeEmio::Input, + offset: i, + }); + }); + Self { emios } + } + + pub fn take(&mut self, offset: usize) -> Option { + self.emios[offset].take() + } + + pub fn give(&mut self, emio: EmioPin) { + self.emios[emio.offset].replace(emio); + } +} diff --git a/zynq7000-hal/src/gpio/mio.rs b/zynq7000-hal/src/gpio/mio.rs new file mode 100644 index 0000000..dc3b1b6 --- /dev/null +++ b/zynq7000-hal/src/gpio/mio.rs @@ -0,0 +1,475 @@ +//! Multiplexed I/O (MIO) module. +//! +//! This module provides a type-state API for all MIO pins. This also allows associating +//! the pins, their modes and their IDs to the peripherals they are able to serve. +//! +//! The pins can be type-erased for easier handling, which also incurs some more run-time checks. +//! +//! # Examples +//! +//! - [Blinky](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/examples/simple/src/main.rs) +//! - [Logger example](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/examples/simple/src/bin/logger.rs) +//! which uses MIO pins for the UART. +use embedded_hal::digital::InputPin; +use zynq7000::gpio::MmioGpio; + +use crate::sealed; + +use super::{DynMioPin, DynPinModeMio, MioPinProvider, MuxConf, PinIsOutputOnly, PinState}; + +pub trait PinMode: sealed::Sealed {} +pub trait InputMode: sealed::Sealed {} + +pub struct Output; + +impl PinMode for Output {} +impl sealed::Sealed for Output {} + +pub struct Input(core::marker::PhantomData); + +impl PinMode for Input {} +impl sealed::Sealed for Input {} + +pub struct PullUp; +pub struct Floating; + +impl InputMode for PullUp {} +impl sealed::Sealed for PullUp {} +impl InputMode for Floating {} +impl sealed::Sealed for Floating {} + +pub struct IoPeriph; +impl sealed::Sealed for IoPeriph {} +impl PinMode for IoPeriph {} + +pub type Reset = Input; + +pub trait PinId { + const OFFSET: usize; +} + +macro_rules! pin_id { + ($Id:ident, $num:literal) => { + // Need paste macro to use ident in doc attribute + paste::paste! { + #[doc = "Pin ID representing pin " $Id] + #[derive(Debug)] + pub enum $Id {} + impl $crate::sealed::Sealed for $Id {} + impl PinId for $Id { + const OFFSET: usize = $num; + } + } + }; +} + +pin_id!(Mio0, 0); +pin_id!(Mio1, 1); +pin_id!(Mio2, 2); +pin_id!(Mio3, 3); +pin_id!(Mio4, 4); +pin_id!(Mio5, 5); +pin_id!(Mio6, 6); +pin_id!(Mio7, 7); +pin_id!(Mio8, 8); +pin_id!(Mio9, 9); +pin_id!(Mio10, 10); +pin_id!(Mio11, 11); +pin_id!(Mio12, 12); +pin_id!(Mio13, 13); +pin_id!(Mio14, 14); +pin_id!(Mio15, 15); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +pin_id!(Mio16, 16); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +pin_id!(Mio17, 17); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +pin_id!(Mio18, 18); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +pin_id!(Mio19, 19); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +pin_id!(Mio20, 20); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +pin_id!(Mio21, 21); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +pin_id!(Mio22, 22); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +pin_id!(Mio23, 23); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +pin_id!(Mio24, 24); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +pin_id!(Mio25, 25); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +pin_id!(Mio26, 26); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +pin_id!(Mio27, 27); +pin_id!(Mio28, 28); +pin_id!(Mio29, 29); +pin_id!(Mio30, 30); +pin_id!(Mio31, 31); + +pin_id!(Mio32, 32); +pin_id!(Mio33, 33); +pin_id!(Mio34, 34); +pin_id!(Mio35, 35); +pin_id!(Mio36, 36); +pin_id!(Mio37, 37); +pin_id!(Mio38, 38); +pin_id!(Mio39, 39); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +pin_id!(Mio40, 40); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +pin_id!(Mio41, 41); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +pin_id!(Mio42, 42); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +pin_id!(Mio43, 43); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +pin_id!(Mio44, 44); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +pin_id!(Mio45, 45); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +pin_id!(Mio46, 46); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +pin_id!(Mio47, 47); +pin_id!(Mio48, 48); +pin_id!(Mio49, 49); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +pin_id!(Mio50, 50); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +pin_id!(Mio51, 51); +pin_id!(Mio52, 52); +pin_id!(Mio53, 53); + +pub struct MioPin { + inner: DynMioPin, + phantom: core::marker::PhantomData<(I, S)>, +} + +pub trait IoPeriphPin { + fn mux_conf(&self) -> MuxConf; +} + +impl MioPinProvider for MioPin { + delegate::delegate! { + to self.inner { + fn mode(&self) -> &DynPinModeMio; + fn offset(&self) -> usize; + } + } +} + +impl MioPin { + #[inline] + const unsafe fn new() -> Self { + Self { + inner: DynMioPin::new(I::OFFSET, DynPinModeMio::InputPullUp), + phantom: core::marker::PhantomData, + } + } + + /// Steal a typed MIO pin. + /// + /// Usually, you can just use the MIO pin members of the [MioPins] structure. + /// However, if you pass the pins into a consuming peripheral driver which performs + /// immediate type erasure, and you require the pins for/after a re-configuration + /// of the system, you can unsafely steal the pin. This function will NOT perform any + /// re-configuration. + /// + /// # Safety + /// + /// This allows to create multiple instances of the same pin, which can lead to + /// data races on concurrent access. + #[inline] + pub const unsafe fn steal() -> Self { + unsafe { Self::new() } + } + + /// Convert the pin to the requested [`PinMode`] + #[inline] + pub fn into_mode(self) -> MioPin { + // Safe because we drop the existing Pin + MioPin { + inner: self.inner, + phantom: core::marker::PhantomData, + } + } + + pub fn into_floating_input(mut self) -> Result>, PinIsOutputOnly> { + self.inner.into_input_floating()?; + Ok(self.into_mode()) + } + + pub fn into_pull_up_input(mut self) -> Result>, PinIsOutputOnly> { + self.inner.into_input_pull_up()?; + Ok(self.into_mode()) + } + + pub fn into_output(mut self, init_level: PinState) -> MioPin { + self.inner.into_output(init_level); + self.into_mode() + } + + pub fn into_io_periph( + mut self, + mux_conf: MuxConf, + pullup: Option, + ) -> MioPin { + self.inner.into_io_periph_pin(mux_conf, pullup); + self.into_mode() + } + + /// Type-erase the pin. + #[inline] + pub const fn downgrade(self) -> DynMioPin { + self.inner + } +} + +impl MioPin { + #[inline] + pub fn set_high(&mut self) { + self.inner.set_high_unchecked(); + } + + #[inline] + pub fn set_low(&mut self) { + self.inner.set_low_unchecked(); + } + + #[inline] + pub fn is_set_high(&self) { + self.inner.is_set_high_unchecked(); + } + + #[inline] + pub fn is_set_low(&self) { + self.inner.is_set_low_unchecked(); + } +} + +impl IoPeriphPin for MioPin { + #[inline] + fn mux_conf(&self) -> MuxConf { + if let DynPinModeMio::IoPeriph(mux_conf) = self.inner.mode() { + *mux_conf + } else { + // This should never happen due to type state guarantees. + panic!("unexpected pin state"); + } + } +} + +impl MioPin { + #[inline] + pub fn is_high(&self) -> bool { + self.inner.is_high_unchecked() + } + + #[inline] + pub fn is_low(&self) -> bool { + self.inner.is_low_unchecked() + } +} + +pub struct MioPins { + pub mio0: MioPin, + pub mio1: MioPin, + pub mio2: MioPin, + pub mio3: MioPin, + pub mio4: MioPin, + pub mio5: MioPin, + pub mio6: MioPin, + pub mio7: MioPin, + pub mio8: MioPin, + pub mio9: MioPin, + pub mio10: MioPin, + pub mio11: MioPin, + pub mio12: MioPin, + pub mio13: MioPin, + pub mio14: MioPin, + pub mio15: MioPin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio16: MioPin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio17: MioPin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio18: MioPin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio19: MioPin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio20: MioPin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio21: MioPin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio22: MioPin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio23: MioPin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio24: MioPin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio25: MioPin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio26: MioPin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio27: MioPin, + pub mio28: MioPin, + pub mio29: MioPin, + pub mio30: MioPin, + pub mio31: MioPin, + + pub mio32: MioPin, + pub mio33: MioPin, + pub mio34: MioPin, + pub mio35: MioPin, + pub mio36: MioPin, + pub mio37: MioPin, + pub mio38: MioPin, + pub mio39: MioPin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio40: MioPin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio41: MioPin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio42: MioPin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio43: MioPin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio44: MioPin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio45: MioPin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio46: MioPin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio47: MioPin, + pub mio48: MioPin, + pub mio49: MioPin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio50: MioPin, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + pub mio51: MioPin, + pub mio52: MioPin, + pub mio53: MioPin, +} + +impl MioPins { + pub const fn new(_mmio: MmioGpio) -> Self { + Self { + mio0: unsafe { MioPin::new() }, + mio1: unsafe { MioPin::new() }, + mio2: unsafe { MioPin::new() }, + mio3: unsafe { MioPin::new() }, + mio4: unsafe { MioPin::new() }, + mio5: unsafe { MioPin::new() }, + mio6: unsafe { MioPin::new() }, + mio7: unsafe { MioPin::new() }, + mio8: unsafe { MioPin::new() }, + mio9: unsafe { MioPin::new() }, + mio10: unsafe { MioPin::new() }, + mio11: unsafe { MioPin::new() }, + mio12: unsafe { MioPin::new() }, + mio13: unsafe { MioPin::new() }, + mio14: unsafe { MioPin::new() }, + mio15: unsafe { MioPin::new() }, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + mio16: unsafe { MioPin::new() }, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + mio17: unsafe { MioPin::new() }, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + mio18: unsafe { MioPin::new() }, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + mio19: unsafe { MioPin::new() }, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + mio20: unsafe { MioPin::new() }, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + mio21: unsafe { MioPin::new() }, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + mio22: unsafe { MioPin::new() }, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + mio23: unsafe { MioPin::new() }, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + mio24: unsafe { MioPin::new() }, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + mio25: unsafe { MioPin::new() }, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + mio26: unsafe { MioPin::new() }, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + mio27: unsafe { MioPin::new() }, + mio28: unsafe { MioPin::new() }, + mio29: unsafe { MioPin::new() }, + mio30: unsafe { MioPin::new() }, + mio31: unsafe { MioPin::new() }, + + mio32: unsafe { MioPin::new() }, + mio33: unsafe { MioPin::new() }, + mio34: unsafe { MioPin::new() }, + mio35: unsafe { MioPin::new() }, + mio36: unsafe { MioPin::new() }, + mio37: unsafe { MioPin::new() }, + mio38: unsafe { MioPin::new() }, + mio39: unsafe { MioPin::new() }, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + mio40: unsafe { MioPin::new() }, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + mio41: unsafe { MioPin::new() }, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + mio42: unsafe { MioPin::new() }, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + mio43: unsafe { MioPin::new() }, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + mio44: unsafe { MioPin::new() }, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + mio45: unsafe { MioPin::new() }, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + mio46: unsafe { MioPin::new() }, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + mio47: unsafe { MioPin::new() }, + mio48: unsafe { MioPin::new() }, + mio49: unsafe { MioPin::new() }, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + mio50: unsafe { MioPin::new() }, + #[cfg(not(feature = "7z010-7z007s-clg225"))] + mio51: unsafe { MioPin::new() }, + mio52: unsafe { MioPin::new() }, + mio53: unsafe { MioPin::new() }, + } + } +} + +impl embedded_hal::digital::ErrorType for MioPin { + type Error = core::convert::Infallible; +} + +impl embedded_hal::digital::OutputPin for MioPin { + #[inline] + fn set_low(&mut self) -> Result<(), Self::Error> { + self.inner.set_low_unchecked(); + Ok(()) + } + #[inline] + fn set_high(&mut self) -> Result<(), Self::Error> { + self.inner.set_high_unchecked(); + Ok(()) + } +} + +impl embedded_hal::digital::StatefulOutputPin for MioPin { + fn is_set_high(&mut self) -> Result { + Ok(self.inner.is_set_high_unchecked()) + } + + fn is_set_low(&mut self) -> Result { + Ok(self.inner.is_set_low_unchecked()) + } +} + +impl embedded_hal::digital::InputPin for MioPin { + fn is_high(&mut self) -> Result { + Ok(self.inner.is_high_unchecked()) + } + + fn is_low(&mut self) -> Result { + Ok(self.inner.is_low_unchecked()) + } +} diff --git a/zynq7000-hal/src/gpio/mod.rs b/zynq7000-hal/src/gpio/mod.rs new file mode 100644 index 0000000..ac1cf6e --- /dev/null +++ b/zynq7000-hal/src/gpio/mod.rs @@ -0,0 +1,42 @@ +//! GPIO support module for the Zynq7000 SoC. +pub mod dyn_mio; +pub mod emio; +pub mod mio; + +use crate::{enable_amba_peripheral_clock, slcr::Slcr}; +pub use dyn_mio::*; +pub use emio::*; +pub use mio::*; + +pub use embedded_hal::digital::PinState; +use zynq7000::{gpio::MmioGpio, slcr::reset::GpioClockReset}; + +pub struct GpioPins { + pub mio: MioPins, + pub emio: EmioPins, +} + +impl GpioPins { + pub fn new(gpio: MmioGpio) -> Self { + enable_amba_peripheral_clock(crate::PeripheralSelect::Gpio); + Self { + mio: MioPins::new(unsafe { gpio.clone() }), + emio: EmioPins::new(gpio), + } + } +} + +/// Reset the GPIO peripheral using the SLCR reset register for GPIO. +#[inline] +pub fn reset() { + unsafe { + Slcr::with(|regs| { + regs.reset_ctrl() + .write_gpio(GpioClockReset::builder().with_gpio_cpu1x_rst(true).build()); + // Keep it in reset for one cycle.. not sure if this is necessary. + cortex_ar::asm::nop(); + regs.reset_ctrl() + .write_gpio(GpioClockReset::builder().with_gpio_cpu1x_rst(false).build()); + }); + } +} diff --git a/zynq7000-hal/src/gtc.rs b/zynq7000-hal/src/gtc.rs new file mode 100644 index 0000000..782c45a --- /dev/null +++ b/zynq7000-hal/src/gtc.rs @@ -0,0 +1,169 @@ +//! Global timer counter driver module. +//! +//! # Examples +//! +//! - [GTC ticks example](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/examples/simple/src/bin/gtc-ticks.rs) +//! - [Embassy Timer Driver](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq7000-embassy/src/lib.rs) +use zynq7000::gtc::MmioGtc; + +use crate::{clocks::ArmClocks, time::Hertz}; + +/// High level GTC driver. +/// +/// This structure also allows an optional clock member, which is required for the +/// [frequency_to_ticks] function and the [embedded_hal::delay::DelayNs] implementation +/// to work. +pub struct Gtc { + regs: MmioGtc<'static>, + cpu_3x2x_clock: Option, +} + +unsafe impl Send for Gtc {} + +pub const fn frequency_to_ticks(clock: Hertz, frequency: Hertz) -> u32 { + clock.raw().div_ceil(frequency.raw()) +} + +impl Gtc { + /// Create a peripheral driver from a MMIO GTC block. + #[inline] + pub const fn new(_regs: MmioGtc<'static>, clocks: &ArmClocks) -> Self { + unsafe { Self::steal_fixed(Some(clocks.cpu_3x2x_clk())) } + } + + /// Steal the GTC from the PAC. + /// + /// This function still expect the GTC clock, which is the CPU 3x2x clock frequency. + /// + /// # Safety + /// + /// This function allows creating an arbitrary amount of memory-mapped peripheral drivers. + /// See the [zynq7000::gtc::Gtc::new_mmio] docs for more safety information. + #[inline] + pub const unsafe fn steal_fixed(cpu_3x2x_clk: Option) -> Self { + Self { + regs: unsafe { zynq7000::gtc::Gtc::new_mmio_fixed() }, + cpu_3x2x_clock: cpu_3x2x_clk, + } + } + + #[inline] + pub fn set_cpu_3x2x_clock(&mut self, clock: Hertz) { + self.cpu_3x2x_clock = Some(clock); + } + + // TODO: Change this API once pure-reads work. + /// Read the 64-bit timer. + #[inline] + pub fn read_timer(&self) -> u64 { + // Safety: We require interior mutability here because even reads are unsafe. + // But we want to avoid a RefCell which would incur a run-time cost solely to make this + // function non-mut, so we steal the GTC here. Ownership is guaranteed or mandated + // by constructor. + let upper = self.regs.read_count_upper(); + loop { + let lower = self.regs.read_count_lower(); + if self.regs.read_count_upper() == upper { + return ((upper as u64) << 32) | (lower as u64); + } + // Overflow, read upper again. + } + } + + /// Set the comparator which can be used to trigger an interrupt in the future. + #[inline] + pub fn set_comparator(&mut self, comparator: u64) { + self.regs.modify_ctrl(|mut ctrl| { + ctrl.set_comparator_enable(false); + ctrl + }); + self.regs.write_comparator_upper((comparator >> 32) as u32); + self.regs.write_comparator_lower(comparator as u32); + self.regs.modify_ctrl(|mut ctrl| { + ctrl.set_comparator_enable(true); + ctrl + }); + } + + pub fn frequency_to_ticks(&self, frequency: Hertz) -> u32 { + if self.cpu_3x2x_clock.is_none() { + return 0; + } + frequency_to_ticks(self.cpu_3x2x_clock.unwrap(), frequency) + } + + /// Set the auto-increment value which will be used by the hardware to automatically + /// increment the comparator value on a comparator interrupt, if the auto-increment is enabled. + #[inline] + pub fn set_auto_increment_value(&mut self, value: u32) { + self.regs.write_auto_increment(value); + } + + #[inline] + pub fn set_auto_increment_value_for_frequency(&mut self, frequency: Hertz) { + self.regs + .write_auto_increment(self.frequency_to_ticks(frequency)); + } + + #[inline] + pub fn enable(&mut self) { + self.regs.modify_ctrl(|mut ctrl| { + ctrl.set_enable(true); + ctrl + }); + } + + #[inline] + pub fn enable_auto_increment(&mut self) { + self.regs.modify_ctrl(|mut ctrl| { + ctrl.set_auto_increment(true); + ctrl + }); + } + + #[inline] + pub fn set_prescaler(&mut self, prescaler: u8) { + self.regs.modify_ctrl(|mut ctrl| { + ctrl.set_prescaler(prescaler); + ctrl + }); + } + + #[inline] + pub fn disable(&mut self) { + self.regs.modify_ctrl(|mut ctrl| { + ctrl.set_enable(false); + ctrl + }); + } + + /// Enable the comparator interrupt. + #[inline] + pub fn enable_interrupt(&mut self) { + self.regs.modify_ctrl(|mut ctrl| { + ctrl.set_irq_enable(true); + ctrl + }); + } + + /// Disable the comparator interrupt. + #[inline] + pub fn disable_interrupt(&mut self) { + self.regs.modify_ctrl(|mut ctrl| { + ctrl.set_irq_enable(false); + ctrl + }); + } +} + +/// GTC can be used for blocking delays. +impl embedded_hal::delay::DelayNs for Gtc { + fn delay_ns(&mut self, ns: u32) { + if self.cpu_3x2x_clock.is_none() { + return; + } + let end_of_delay = self.read_timer() + + (((ns as u64) * self.cpu_3x2x_clock.unwrap().raw() as u64) / 1_000_000_000); + while self.read_timer() < end_of_delay {} + } +} diff --git a/zynq7000-hal/src/i2c.rs b/zynq7000-hal/src/i2c.rs new file mode 100644 index 0000000..7f6e523 --- /dev/null +++ b/zynq7000-hal/src/i2c.rs @@ -0,0 +1,707 @@ +use arbitrary_int::{u2, u3, u6}; +use embedded_hal::i2c::NoAcknowledgeSource; +use zynq7000::{ + i2c::{Control, I2C_0_BASE_ADDR, I2C_1_BASE_ADDR, InterruptStatus, MmioI2c, TransferSize}, + slcr::reset::DualClockReset, +}; + +#[cfg(not(feature = "7z010-7z007s-clg225"))] +use crate::gpio::{ + Mio16, Mio17, Mio18, Mio19, Mio20, Mio21, Mio22, Mio23, Mio24, Mio25, Mio26, Mio27, Mio40, + Mio41, Mio42, Mio43, Mio44, Mio45, Mio46, Mio47, Mio50, Mio51, +}; +use crate::{ + enable_amba_peripheral_clock, + gpio::{ + IoPeriph, IoPeriphPin, Mio10, Mio11, Mio12, Mio13, Mio14, Mio15, Mio28, Mio29, Mio30, + Mio31, Mio32, Mio33, Mio34, Mio35, Mio36, Mio37, Mio38, Mio39, Mio48, Mio49, Mio52, Mio53, + MioPin, MuxConf, PinMode, + }, + slcr::Slcr, + time::Hertz, +}; + +pub const I2C_MUX_CONF: MuxConf = MuxConf::new_with_l3(u3::new(0b010)); +pub const FIFO_DEPTH: usize = 16; +/// Maximum read size in one read operation. +pub const MAX_READ_SIZE: usize = 255; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum I2cId { + I2c0 = 0, + I2c1 = 1, +} + +pub trait PsI2c { + fn reg_block(&self) -> MmioI2c<'static>; + fn id(&self) -> Option; +} + +impl PsI2c for MmioI2c<'static> { + #[inline] + fn reg_block(&self) -> MmioI2c<'static> { + unsafe { self.clone() } + } + + #[inline] + fn id(&self) -> Option { + let base_addr = unsafe { self.ptr() } as usize; + if base_addr == I2C_0_BASE_ADDR { + return Some(I2cId::I2c0); + } else if base_addr == I2C_1_BASE_ADDR { + return Some(I2cId::I2c1); + } + None + } +} + +pub trait SdaPin: IoPeriphPin { + const ID: I2cId; +} + +pub trait SckPin: IoPeriphPin { + const ID: I2cId; +} + +pub trait I2cPins {} + +macro_rules! into_i2c { + ($($Mio:ident),+) => { + $( + impl MioPin<$Mio, M> { + /// Convert the pin into I2C pins by configuring the pin routing via the + /// MIO multiplexer bits. Also enables pull-ups for the pins. + pub fn into_i2c(self) -> MioPin<$Mio, IoPeriph> { + // Enable pull-ups for the I2C pins. + self.into_io_periph(I2C_MUX_CONF, Some(true)) + } + } + )+ + }; +} + +macro_rules! i2c_pin_impls { + ($Id: path, $SckMio:ident, $SdaMio:ident) => { + impl SckPin for MioPin<$SckMio, IoPeriph> { + const ID: I2cId = $Id; + } + + impl SdaPin for MioPin<$SdaMio, IoPeriph> { + const ID: I2cId = $Id; + } + + impl I2cPins for (MioPin<$SckMio, IoPeriph>, MioPin<$SdaMio, IoPeriph>) {} + }; +} + +into_i2c!( + Mio10, Mio11, Mio14, Mio15, Mio30, Mio31, Mio34, Mio35, Mio38, Mio39, Mio12, Mio13, Mio28, + Mio29, Mio32, Mio33, Mio36, Mio37, Mio48, Mio49, Mio52, Mio53 +); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +into_i2c!( + Mio18, Mio19, Mio22, Mio23, Mio26, Mio27, Mio42, Mio43, Mio46, Mio47, Mio50, Mio51, Mio16, + Mio17, Mio20, Mio21, Mio24, Mio25, Mio40, Mio41, Mio44, Mio45 +); + +i2c_pin_impls!(I2cId::I2c0, Mio10, Mio11); +i2c_pin_impls!(I2cId::I2c0, Mio14, Mio15); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +i2c_pin_impls!(I2cId::I2c0, Mio18, Mio19); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +i2c_pin_impls!(I2cId::I2c0, Mio22, Mio23); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +i2c_pin_impls!(I2cId::I2c0, Mio26, Mio27); +i2c_pin_impls!(I2cId::I2c0, Mio30, Mio31); +i2c_pin_impls!(I2cId::I2c0, Mio34, Mio35); +i2c_pin_impls!(I2cId::I2c0, Mio38, Mio39); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +i2c_pin_impls!(I2cId::I2c0, Mio42, Mio43); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +i2c_pin_impls!(I2cId::I2c0, Mio46, Mio47); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +i2c_pin_impls!(I2cId::I2c0, Mio50, Mio51); + +i2c_pin_impls!(I2cId::I2c1, Mio12, Mio13); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +i2c_pin_impls!(I2cId::I2c1, Mio16, Mio17); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +i2c_pin_impls!(I2cId::I2c1, Mio20, Mio21); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +i2c_pin_impls!(I2cId::I2c1, Mio24, Mio25); +i2c_pin_impls!(I2cId::I2c1, Mio28, Mio29); +i2c_pin_impls!(I2cId::I2c1, Mio32, Mio33); +i2c_pin_impls!(I2cId::I2c1, Mio36, Mio37); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +i2c_pin_impls!(I2cId::I2c1, Mio40, Mio41); +#[cfg(not(feature = "7z010-7z007s-clg225"))] +i2c_pin_impls!(I2cId::I2c1, Mio44, Mio45); +i2c_pin_impls!(I2cId::I2c1, Mio48, Mio49); +i2c_pin_impls!(I2cId::I2c1, Mio52, Mio53); + +#[derive(Debug, Clone, Copy)] +pub enum I2cSpeed { + Normal100kHz, + HighSpeed400KHz, +} + +impl I2cSpeed { + pub fn frequency_full_number(&self) -> Hertz { + Hertz::from_raw(match self { + I2cSpeed::Normal100kHz => 100_000, + I2cSpeed::HighSpeed400KHz => 400_000, + }) + } + + /// From Xilinx embeddedsw + /// If frequency 400KHz is selected, 384.6KHz should be set. + /// If frequency 100KHz is selected, 90KHz should be set. + /// This is due to a hardware limitation. + pub fn frequency_for_calculation(&self) -> Hertz { + Hertz::from_raw(match self { + I2cSpeed::Normal100kHz => 90_000, + I2cSpeed::HighSpeed400KHz => 384_600, + }) + } +} + +#[derive(Debug, thiserror::Error)] +#[error("I2C speed not attainable")] +pub struct I2cSpeedNotAttainable; + +#[derive(Debug, thiserror::Error)] +pub enum I2cTxError { + #[error("arbitration lost")] + ArbitrationLoss, + #[error("transfer not acknowledged: {0}")] + Nack(NoAcknowledgeSource), + #[error("TX overflow")] + TxOverflow, + #[error("timeout of transfer")] + Timeout, +} + +#[derive(Debug, thiserror::Error)] +pub enum I2cRxError { + #[error("arbitration lost")] + ArbitrationLoss, + #[error("transfer not acknowledged")] + Nack(NoAcknowledgeSource), + #[error("RX underflow")] + RxUnderflow, + #[error("RX overflow")] + RxOverflow, + #[error("timeout of transfer")] + Timeout, + #[error("read data exceeds maximum allowed 255 bytes per transfer")] + ReadDataLenTooLarge, +} + +#[derive(Debug, thiserror::Error)] +pub enum I2cError { + #[error("arbitration lost")] + ArbitrationLoss, + #[error("transfer not acknowledged: {0}")] + Nack(NoAcknowledgeSource), + #[error("TX overflow")] + TxOverflow, + #[error("RX underflow")] + RxUnderflow, + #[error("RX overflow")] + RxOverflow, + #[error("timeout of transfer")] + Timeout, + #[error("read data exceeds maximum allowed 255 bytes per transfer")] + ReadDataLenTooLarge, +} + +impl From for I2cError { + fn from(err: I2cRxError) -> Self { + match err { + I2cRxError::ArbitrationLoss => I2cError::ArbitrationLoss, + I2cRxError::Nack(nack) => I2cError::Nack(nack), + I2cRxError::RxUnderflow => I2cError::RxUnderflow, + I2cRxError::RxOverflow => I2cError::RxOverflow, + I2cRxError::Timeout => I2cError::Timeout, + I2cRxError::ReadDataLenTooLarge => I2cError::ReadDataLenTooLarge, + } + } +} + +impl From for I2cError { + fn from(err: I2cTxError) -> Self { + match err { + I2cTxError::ArbitrationLoss => I2cError::ArbitrationLoss, + I2cTxError::Nack(nack) => I2cError::Nack(nack), + I2cTxError::TxOverflow => I2cError::TxOverflow, + I2cTxError::Timeout => I2cError::Timeout, + } + } +} + +#[inline] +pub fn calculate_i2c_speed(cpu_1x_clk: Hertz, clk_config: ClockConfig) -> Hertz { + cpu_1x_clk / (22 * (clk_config.div_a as u32 + 1) * (clk_config.div_b as u32 + 1)) +} + +pub fn calculate_divisors( + cpu_1x_clk: Hertz, + speed: I2cSpeed, +) -> Result { + let target_speed = speed.frequency_for_calculation(); + if cpu_1x_clk > 22 * 64 * 4 * target_speed { + return Err(I2cSpeedNotAttainable); + } + let mut smallest_deviation = u32::MAX; + let mut best_div_a = 1; + let mut best_div_b = 1; + for divisor_a in 1..=4 { + for divisor_b in 1..=64 { + let i2c_clock = cpu_1x_clk / (22 * divisor_a * divisor_b); + let deviation = (target_speed.raw() as i32 - i2c_clock.raw() as i32).unsigned_abs(); + if deviation < smallest_deviation { + smallest_deviation = deviation; + best_div_a = divisor_a; + best_div_b = divisor_b; + } + } + } + Ok(ClockConfig::new(best_div_a as u8 - 1, best_div_b as u8 - 1)) +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub struct ClockConfig { + div_a: u8, + div_b: u8, +} + +impl ClockConfig { + pub fn new(div_a: u8, div_b: u8) -> Self { + Self { div_a, div_b } + } + + pub fn div_a(&self) -> u8 { + self.div_a + } + + pub fn div_b(&self) -> u8 { + self.div_b + } +} + +#[derive(Debug, thiserror::Error)] +#[error("invalid I2C ID")] +pub struct InvalidPsI2cError; + +#[derive(Debug, thiserror::Error)] +pub enum I2cConstructionError { + #[error("invalid I2C ID {0}")] + InvalidPsI2c(#[from] InvalidPsI2cError), + #[error("pin invalid for I2C ID")] + PinInvalidForI2cId, + #[error("invalid pin configuration for I2C")] + InvalidPinConf, +} +pub struct I2c { + regs: MmioI2c<'static>, +} + +impl I2c { + pub fn new_with_mio( + i2c: impl PsI2c, + clk_cfg: ClockConfig, + i2c_pins: (Sck, Sda), + ) -> Result { + if i2c.id().is_none() { + return Err(InvalidPsI2cError.into()); + } + if Sck::ID != Sda::ID { + return Err(I2cConstructionError::PinInvalidForI2cId); + } + if i2c_pins.0.mux_conf() != I2C_MUX_CONF || i2c_pins.1.mux_conf() != I2C_MUX_CONF { + return Err(I2cConstructionError::InvalidPinConf); + } + Ok(Self::new_generic( + i2c.id().unwrap(), + i2c.reg_block(), + clk_cfg, + )) + } + + pub fn new_with_emio(i2c: impl PsI2c, clk_cfg: ClockConfig) -> Result { + if i2c.id().is_none() { + return Err(InvalidPsI2cError); + } + Ok(Self::new_generic( + i2c.id().unwrap(), + i2c.reg_block(), + clk_cfg, + )) + } + + pub fn new_generic(id: I2cId, mut regs: MmioI2c<'static>, clk_cfg: ClockConfig) -> Self { + let periph_sel = match id { + I2cId::I2c0 => crate::PeripheralSelect::I2c0, + I2cId::I2c1 => crate::PeripheralSelect::I2c1, + }; + enable_amba_peripheral_clock(periph_sel); + //reset(id); + regs.write_cr( + Control::builder() + .with_div_a(u2::new(clk_cfg.div_a())) + .with_div_b(u6::new(clk_cfg.div_b())) + .with_clear_fifo(true) + .with_slv_mon(false) + .with_hold_bus(false) + .with_acken(false) + .with_addressing(true) + .with_mode(zynq7000::i2c::Mode::Master) + .with_dir(zynq7000::i2c::Direction::Transmitter) + .build(), + ); + Self { regs } + } + + /// Start the transfer by writing the I2C address. + #[inline] + fn start_transfer(&mut self, address: u8) { + self.regs + .write_addr(zynq7000::i2c::Addr::new_with_raw_value(address as u32)); + } + + #[inline] + pub fn set_hold_bit(&mut self) { + self.regs.modify_cr(|mut cr| { + cr.set_hold_bus(true); + cr + }); + } + + #[inline] + pub fn clear_hold_bit(&mut self) { + self.regs.modify_cr(|mut cr| { + cr.set_hold_bus(false); + cr + }); + } + + pub fn write_transfer_blocking( + &mut self, + addr: u8, + data: &[u8], + generate_stop: bool, + ) -> Result<(), I2cTxError> { + self.regs.modify_cr(|mut cr| { + cr.set_acken(true); + cr.set_mode(zynq7000::i2c::Mode::Master); + cr.set_clear_fifo(true); + cr.set_dir(zynq7000::i2c::Direction::Transmitter); + if !generate_stop { + cr.set_hold_bus(true); + } + cr + }); + let mut first_write_cycle = true; + let mut addr_set = false; + let mut written = 0; + // Clear the interrupt status register before using it to monitor the transfer. + self.regs.modify_isr(|isr| isr); + loop { + let bytes_to_write = core::cmp::min( + FIFO_DEPTH - self.regs.read_transfer_size().size() as usize, + data.len() - written, + ); + (0..bytes_to_write).for_each(|_| { + self.regs + .write_data(zynq7000::i2c::Fifo::new_with_raw_value( + data[written] as u32, + )); + written += 1; + }); + if !addr_set { + self.start_transfer(addr); + addr_set = true; + } + let mut status = self.regs.read_sr(); + // While the hardware is busy sending out data, we poll for errors. + while status.tx_busy() { + let isr = self.regs.read_isr(); + self.check_and_handle_tx_errors(isr, first_write_cycle, bytes_to_write)?; + // Re-read for next check. + status = self.regs.read_sr(); + } + first_write_cycle = false; + // Just need to poll to completion now. + if written == data.len() { + break; + } + } + // Poll to completion. + while !self.regs.read_isr().complete() { + let isr = self.regs.read_isr(); + self.check_and_handle_tx_errors(isr, first_write_cycle, data.len())?; + } + if generate_stop { + self.clear_hold_bit(); + } + Ok(()) + } + + fn check_and_handle_tx_errors( + &mut self, + isr: InterruptStatus, + first_write_cycle: bool, + first_chunk_len: usize, + ) -> Result<(), I2cTxError> { + if isr.tx_overflow() { + self.clean_up_after_transfer_or_on_error(); + return Err(I2cTxError::TxOverflow); + } + if isr.arbitration_lost() { + self.clean_up_after_transfer_or_on_error(); + return Err(I2cTxError::ArbitrationLoss); + } + if isr.nack() { + self.clean_up_after_transfer_or_on_error(); + // I have no tested this yet, but if no data was sent yet, this is probably + // an address NACK. + if first_write_cycle + && self.regs.read_transfer_size().size() as usize + 1 == first_chunk_len + { + return Err(I2cTxError::Nack(NoAcknowledgeSource::Address)); + } else { + return Err(I2cTxError::Nack(NoAcknowledgeSource::Data)); + } + } + if isr.timeout() { + // Timeout / Stall condition. + self.clean_up_after_transfer_or_on_error(); + return Err(I2cTxError::Timeout); + } + Ok(()) + } + + pub fn clean_up_after_transfer_or_on_error(&mut self) { + self.regs.modify_cr(|mut cr| { + cr.set_acken(false); + cr.set_clear_fifo(true); + cr + }); + } + + pub fn read_transfer_blocking(&mut self, addr: u8, data: &mut [u8]) -> Result<(), I2cRxError> { + self.regs.modify_cr(|mut cr| { + cr.set_acken(true); + cr.set_mode(zynq7000::i2c::Mode::Master); + cr.set_clear_fifo(true); + cr.set_dir(zynq7000::i2c::Direction::Receiver); + if data.len() > FIFO_DEPTH { + cr.set_hold_bus(true); + } + cr + }); + let mut read = 0; + if data.len() > MAX_READ_SIZE { + return Err(I2cRxError::ReadDataLenTooLarge); + } + // Clear the interrupt status register before using it to monitor the transfer. + self.regs.modify_isr(|isr| isr); + self.regs + .write_transfer_size(TransferSize::new_with_raw_value(data.len() as u32)); + self.start_transfer(addr); + loop { + let mut status = self.regs.read_sr(); + loop { + let isr = self.regs.read_isr(); + self.check_and_handle_rx_errors(read, isr)?; + if status.rx_valid() { + break; + } + // Re-read for next check. + status = self.regs.read_sr(); + } + // Data to be read. + while self.regs.read_sr().rx_valid() { + data[read] = self.regs.read_data().data(); + read += 1; + } + // The outstading read size is smaller than the FIFO. Clear the HOLD register as + // specified in TRM p.649 polled read step 6. + if self.regs.read_transfer_size().size() as usize <= FIFO_DEPTH { + self.clear_hold_bit(); + } + // Read everything, just need to poll to completion now. + if read == data.len() { + break; + } + } + + // Poll to completion. + while !self.regs.read_isr().complete() { + let isr = self.regs.read_isr(); + self.check_and_handle_rx_errors(read, isr)? + } + self.clear_hold_bit(); + self.clean_up_after_transfer_or_on_error(); + Ok(()) + } + + fn check_and_handle_rx_errors( + &mut self, + read_count: usize, + isr: InterruptStatus, + ) -> Result<(), I2cRxError> { + if isr.rx_overflow() { + self.clean_up_after_transfer_or_on_error(); + return Err(I2cRxError::RxOverflow); + } + if isr.rx_underflow() { + self.clean_up_after_transfer_or_on_error(); + return Err(I2cRxError::RxUnderflow); + } + if isr.nack() { + self.clean_up_after_transfer_or_on_error(); + // I have no tested this yet, but if no data was sent yet, this is probably + // an address NACK. + if read_count == 0 { + return Err(I2cRxError::Nack(NoAcknowledgeSource::Address)); + } else { + return Err(I2cRxError::Nack(NoAcknowledgeSource::Data)); + } + } + if isr.timeout() { + // Timeout / Stall condition. + self.clean_up_after_transfer_or_on_error(); + return Err(I2cRxError::Timeout); + } + Ok(()) + } +} + +impl embedded_hal::i2c::ErrorType for I2c { + type Error = I2cError; +} + +impl embedded_hal::i2c::Error for I2cError { + fn kind(&self) -> embedded_hal::i2c::ErrorKind { + match self { + I2cError::ArbitrationLoss => embedded_hal::i2c::ErrorKind::ArbitrationLoss, + I2cError::Nack(nack_kind) => embedded_hal::i2c::ErrorKind::NoAcknowledge(*nack_kind), + I2cError::RxOverflow => embedded_hal::i2c::ErrorKind::Overrun, + I2cError::TxOverflow => embedded_hal::i2c::ErrorKind::Other, + I2cError::RxUnderflow => embedded_hal::i2c::ErrorKind::Other, + I2cError::Timeout | I2cError::ReadDataLenTooLarge => { + embedded_hal::i2c::ErrorKind::Other + } + } + } +} + +impl embedded_hal::i2c::I2c for I2c { + fn transaction( + &mut self, + address: u8, + operations: &mut [embedded_hal::i2c::Operation<'_>], + ) -> Result<(), Self::Error> { + for op in operations { + match op { + embedded_hal::i2c::Operation::Read(items) => { + self.read_transfer_blocking(address, items)? + } + embedded_hal::i2c::Operation::Write(items) => { + self.write_transfer_blocking(address, items, true)? + } + } + } + Ok(()) + } + + fn write_read( + &mut self, + address: u8, + write: &[u8], + read: &mut [u8], + ) -> Result<(), Self::Error> { + // I have never tested this, so I am not sure whether the master still generates a stop + // condition somehow.. which might break the trait contract. + self.write_transfer_blocking(address, write, false)?; + Ok(self.read_transfer_blocking(address, read)?) + } +} + +/// Reset the SPI peripheral using the SLCR reset register for SPI. +/// +/// Please note that this function will interfere with an already configured +/// SPI instance. +#[inline] +pub fn reset(id: I2cId) { + let assert_reset = match id { + I2cId::I2c0 => DualClockReset::builder() + .with_periph1_cpu1x_rst(false) + .with_periph0_cpu1x_rst(true) + .build(), + I2cId::I2c1 => DualClockReset::builder() + .with_periph1_cpu1x_rst(true) + .with_periph0_cpu1x_rst(false) + .build(), + }; + unsafe { + Slcr::with(|regs| { + regs.reset_ctrl().write_i2c(assert_reset); + // Keep it in reset for some cycles.. The TMR just mentions some small delay, + // no idea what is meant with that. + for _ in 0..3 { + cortex_ar::asm::nop(); + } + regs.reset_ctrl().write_i2c(DualClockReset::DEFAULT); + }); + } +} + +#[cfg(test)] +mod tests { + extern crate std; + use super::*; + use fugit::RateExtU32; + use std::println; + + #[test] + fn example_test() { + let clk_cfg = calculate_divisors(111.MHz(), I2cSpeed::Normal100kHz).unwrap(); + assert_eq!(clk_cfg.div_a(), 0); + assert_eq!(clk_cfg.div_b(), 55); + let speed = calculate_i2c_speed(111.MHz(), clk_cfg); + assert!(speed.raw() < 100_000); + assert!(speed.raw() > 85_000); + } + + #[test] + fn example_test_2() { + let clk_cfg = calculate_divisors(111.MHz(), I2cSpeed::HighSpeed400KHz).unwrap(); + assert_eq!(clk_cfg.div_a(), 0); + assert_eq!(clk_cfg.div_b(), 12); + let speed = calculate_i2c_speed(111.MHz(), clk_cfg); + assert!(speed.raw() < 400_000); + assert!(speed.raw() > 360_000); + } + + #[test] + fn example_test_3() { + let clk_cfg = calculate_divisors(133.MHz(), I2cSpeed::Normal100kHz).unwrap(); + assert_eq!(clk_cfg.div_a(), 1); + assert_eq!(clk_cfg.div_b(), 33); + let speed = calculate_i2c_speed(133.MHz(), clk_cfg); + assert!(speed.raw() < 100_000); + assert!(speed.raw() > 85_000); + } + + #[test] + fn example_test_4() { + let clk_cfg = calculate_divisors(133.MHz(), I2cSpeed::HighSpeed400KHz).unwrap(); + assert_eq!(clk_cfg.div_a(), 0); + assert_eq!(clk_cfg.div_b(), 15); + let speed = calculate_i2c_speed(133.MHz(), clk_cfg); + assert!(speed.raw() < 400_000); + assert!(speed.raw() > 360_000); + } +} diff --git a/zynq7000-hal/src/lib.rs b/zynq7000-hal/src/lib.rs new file mode 100644 index 0000000..b241405 --- /dev/null +++ b/zynq7000-hal/src/lib.rs @@ -0,0 +1,203 @@ +//! # HAL for the AMD Zynq 7000 SoC family +//! +//! This repository contains the **H**ardware **A**bstraction **L**ayer (HAL), which is an additional +//! hardware abstraction on top of the [peripheral access API](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/zynq7000). +//! +//! It is the result of reading the datasheet for the device and encoding a type-safe layer over the +//! raw PAC. This crate also implements traits specified by the +//! [embedded-hal](https://github.com/rust-embedded/embedded-hal) project, making it compatible with +//! various drivers in the embedded rust ecosystem. +#![no_std] + +use slcr::Slcr; +use zynq7000::slcr::LevelShifterReg; + +pub mod clocks; +pub mod gic; +pub mod gpio; +pub mod gtc; +pub mod i2c; +pub mod log; +pub mod prelude; +pub mod slcr; +pub mod spi; +pub mod time; +pub mod ttc; +pub mod uart; + +/// This enumeration encodes the various boot sources. +#[derive(Debug, Copy, Clone)] +pub enum BootDevice { + JtagCascaded, + JtagIndependent, + Nor, + Nand, + Qspi, + SdCard, +} + +#[derive(Debug, Copy, Clone)] +pub enum BootPllConfig { + Enabled, + Bypassed, +} + +#[derive(Debug)] +pub struct BootMode { + boot_mode: Option, + pll_config: BootPllConfig, +} + +impl BootMode { + #[allow(clippy::new_without_default)] + /// Create a new boot mode information structure by reading the boot mode register from the + /// fixed SLCR block. + pub fn new() -> Self { + // Safety: Only read a read-only register here. + Self::new_with_raw_reg( + unsafe { zynq7000::slcr::Slcr::new_mmio_fixed() } + .read_boot_mode() + .raw_value(), + ) + } + + fn new_with_raw_reg(raw_register: u32) -> Self { + let msb_three_bits = (raw_register >> 1) & 0b111; + + let boot_mode = match msb_three_bits { + 0b000 => { + if raw_register & 0b1 == 0 { + Some(BootDevice::JtagCascaded) + } else { + Some(BootDevice::JtagIndependent) + } + } + 0b001 => Some(BootDevice::Nor), + 0b010 => Some(BootDevice::Nand), + 0b100 => Some(BootDevice::Qspi), + 0b110 => Some(BootDevice::SdCard), + _ => None, + }; + let pll_config = if (raw_register >> 4) & 0b1 == 0 { + BootPllConfig::Enabled + } else { + BootPllConfig::Bypassed + }; + Self { + boot_mode, + pll_config, + } + } + pub fn boot_device(&self) -> Option { + self.boot_mode + } + + pub const fn pll_enable(&self) -> BootPllConfig { + self.pll_config + } +} + +/// This configures the level shifters between the programmable logic (PL) and the processing +/// system (PS). +/// +/// The Zynq-7000 TRM p.32 specifies more information about this register and how to use it. +pub fn configure_level_shifter(config: zynq7000::slcr::LevelShifterConfig) { + // Safety: We only manipulate the level shift registers. + unsafe { + Slcr::with(|slcr_unlocked| { + slcr_unlocked.write_lvl_shftr_en(LevelShifterReg::new_with_raw_value(config as u32)); + }); + } +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum PeripheralSelect { + Smc = 24, + Lqspi = 23, + Gpio = 22, + Uart1 = 21, + Uart0 = 20, + I2c1 = 19, + I2c0 = 18, + Can1 = 17, + Can0 = 16, + Spi1 = 15, + Spi0 = 14, + Sdio1 = 11, + Sdio0 = 10, + Gem1 = 7, + Gem0 = 6, + Usb1 = 3, + Usb0 = 2, + Dma = 0, +} + +/// Enable the AMBA peripheral clock, which is required to read the registers of a peripheral +/// block. +#[inline] +pub fn enable_amba_peripheral_clock(select: PeripheralSelect) { + unsafe { + Slcr::with(|regs| { + regs.clk_ctrl().modify_aper_clk_ctrl(|mut val| { + match select { + PeripheralSelect::Smc => val.set_smc_1x_clk_act(true), + PeripheralSelect::Lqspi => val.set_lqspi_1x_clk_act(true), + PeripheralSelect::Gpio => val.set_gpio_1x_clk_act(true), + PeripheralSelect::Uart1 => val.set_uart_1_1x_clk_act(true), + PeripheralSelect::Uart0 => val.set_uart_0_1x_clk_act(true), + PeripheralSelect::I2c1 => val.set_i2c_1_1x_clk_act(true), + PeripheralSelect::I2c0 => val.set_i2c_0_1x_clk_act(true), + PeripheralSelect::Can1 => val.set_can_1_1x_clk_act(true), + PeripheralSelect::Can0 => val.set_can_0_1x_clk_act(true), + PeripheralSelect::Spi1 => val.set_spi_1_1x_clk_act(true), + PeripheralSelect::Spi0 => val.set_spi_1_1x_clk_act(true), + PeripheralSelect::Sdio1 => val.set_sdio_1_1x_clk_act(true), + PeripheralSelect::Sdio0 => val.set_sdio_0_1x_clk_act(true), + PeripheralSelect::Gem1 => val.set_gem_1_1x_clk_act(true), + PeripheralSelect::Gem0 => val.set_gem_0_1x_clk_act(true), + PeripheralSelect::Usb1 => val.set_usb_1_cpu_1x_clk_act(true), + PeripheralSelect::Usb0 => val.set_usb_0_cpu_1x_clk_act(true), + PeripheralSelect::Dma => val.set_dma_cpu_2x_clk_act(true), + } + val + }) + }); + } +} + +/// Disable the AMBA peripheral clock, which is required to read the registers of a peripheral +/// block. +#[inline] +pub fn disable_amba_peripheral_clock(select: PeripheralSelect) { + unsafe { + Slcr::with(|regs| { + regs.clk_ctrl().modify_aper_clk_ctrl(|mut val| { + match select { + PeripheralSelect::Smc => val.set_smc_1x_clk_act(false), + PeripheralSelect::Lqspi => val.set_lqspi_1x_clk_act(false), + PeripheralSelect::Gpio => val.set_gpio_1x_clk_act(false), + PeripheralSelect::Uart1 => val.set_uart_1_1x_clk_act(false), + PeripheralSelect::Uart0 => val.set_uart_0_1x_clk_act(false), + PeripheralSelect::I2c1 => val.set_i2c_1_1x_clk_act(false), + PeripheralSelect::I2c0 => val.set_i2c_0_1x_clk_act(false), + PeripheralSelect::Can1 => val.set_can_1_1x_clk_act(false), + PeripheralSelect::Can0 => val.set_can_0_1x_clk_act(false), + PeripheralSelect::Spi1 => val.set_spi_1_1x_clk_act(false), + PeripheralSelect::Spi0 => val.set_spi_1_1x_clk_act(false), + PeripheralSelect::Sdio1 => val.set_sdio_1_1x_clk_act(false), + PeripheralSelect::Sdio0 => val.set_sdio_0_1x_clk_act(false), + PeripheralSelect::Gem1 => val.set_gem_1_1x_clk_act(false), + PeripheralSelect::Gem0 => val.set_gem_0_1x_clk_act(false), + PeripheralSelect::Usb1 => val.set_usb_1_cpu_1x_clk_act(false), + PeripheralSelect::Usb0 => val.set_usb_0_cpu_1x_clk_act(false), + PeripheralSelect::Dma => val.set_dma_cpu_2x_clk_act(false), + } + val + }) + }); + } +} + +pub(crate) mod sealed { + pub trait Sealed {} +} diff --git a/zynq7000-hal/src/log.rs b/zynq7000-hal/src/log.rs new file mode 100644 index 0000000..06e698a --- /dev/null +++ b/zynq7000-hal/src/log.rs @@ -0,0 +1,230 @@ +//! # Simple logging providers. + +/// Blocking UART loggers. +pub mod uart_blocking { + use core::cell::{Cell, RefCell, UnsafeCell}; + use embedded_io::Write as _; + + use cortex_ar::register::Cpsr; + use critical_section::Mutex; + use log::{LevelFilter, set_logger, set_max_level}; + + use crate::uart::Uart; + + pub struct UartLoggerBlocking(Mutex>>); + + unsafe impl Send for UartLoggerBlocking {} + unsafe impl Sync for UartLoggerBlocking {} + + static UART_LOGGER_BLOCKING: UartLoggerBlocking = + UartLoggerBlocking(Mutex::new(RefCell::new(None))); + + /// Initialize the logger with a blocking UART instance. + /// + /// This is a blocking logger which performs a write inside a critical section. This logger is + /// thread-safe, but interrupts will be disabled while the logger is writing to the UART. + /// + /// For async applications, it is strongly recommended to use the asynchronous ring buffer + /// logger instead. + pub fn init_with_locks(uart: Uart, level: LevelFilter) { + // TODO: Impl debug for Uart + critical_section::with(|cs| { + let inner = UART_LOGGER_BLOCKING.0.borrow(cs); + inner.replace(Some(uart)); + }); + set_logger(&UART_LOGGER_BLOCKING).unwrap(); + // Adjust as needed + set_max_level(level); + } + + impl log::Log for UartLoggerBlocking { + fn enabled(&self, _metadata: &log::Metadata) -> bool { + true + } + + fn log(&self, record: &log::Record) { + critical_section::with(|cs| { + let mut opt_logger = self.0.borrow(cs).borrow_mut(); + if opt_logger.is_none() { + return; + } + let logger = opt_logger.as_mut().unwrap(); + writeln!(logger, "{} - {}\r", record.level(), record.args()).unwrap(); + }) + } + + fn flush(&self) {} + } + + pub struct UartLoggerUnsafeSingleThread { + skip_in_isr: Cell, + uart: UnsafeCell>, + } + + unsafe impl Send for UartLoggerUnsafeSingleThread {} + unsafe impl Sync for UartLoggerUnsafeSingleThread {} + + static UART_LOGGER_UNSAFE_SINGLE_THREAD: UartLoggerUnsafeSingleThread = + UartLoggerUnsafeSingleThread { + skip_in_isr: Cell::new(false), + uart: UnsafeCell::new(None), + }; + + /// Initialize the logger with a blocking UART instance. + /// + /// For async applications, it is strongly recommended to use the asynchronous ring buffer + /// logger instead. + /// + /// # Safety + /// + /// This is a blocking logger which performs a write WITHOUT a critical section. This logger is + /// NOT thread-safe. Users must ensure that this logger is not used inside a pre-emptive + /// multi-threading context and interrupt handlers. + pub unsafe fn create_unsafe_single_thread_logger(uart: Uart) -> UartLoggerUnsafeSingleThread { + UartLoggerUnsafeSingleThread { + skip_in_isr: Cell::new(false), + uart: UnsafeCell::new(Some(uart)), + } + } + + /// Initialize the logger with a blocking UART instance which does not use locks. + /// + /// # Safety + /// + /// This is a blocking logger which performs a write WITHOUT a critical section. This logger is + /// NOT thread-safe, which might lead to garbled output. Log output in ISRs can optionally be + /// surpressed. + pub unsafe fn init_unsafe_single_core(uart: Uart, level: LevelFilter, skip_in_isr: bool) { + let opt_uart = unsafe { &mut *UART_LOGGER_UNSAFE_SINGLE_THREAD.uart.get() }; + opt_uart.replace(uart); + UART_LOGGER_UNSAFE_SINGLE_THREAD + .skip_in_isr + .set(skip_in_isr); + + set_logger(&UART_LOGGER_UNSAFE_SINGLE_THREAD).unwrap(); + set_max_level(level); // Adjust as needed + } + + impl log::Log for UartLoggerUnsafeSingleThread { + fn enabled(&self, _metadata: &log::Metadata) -> bool { + true + } + + fn log(&self, record: &log::Record) { + if self.skip_in_isr.get() { + match Cpsr::read().mode().unwrap() { + cortex_ar::register::cpsr::ProcessorMode::Fiq + | cortex_ar::register::cpsr::ProcessorMode::Irq => { + return; + } + _ => {} + } + } + + let uart_mut = unsafe { &mut *self.uart.get() }.as_mut(); + if uart_mut.is_none() { + return; + } + writeln!( + uart_mut.unwrap(), + "{} - {}\r", + record.level(), + record.args() + ) + .unwrap(); + } + + fn flush(&self) {} + } +} + +/// Logger module which logs into a ring buffer to allow asynchronous logging handling. +pub mod rb { + use core::cell::RefCell; + use core::fmt::Write as _; + + use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; + use log::{LevelFilter, set_logger, set_max_level}; + use ringbuf::{ + StaticRb, + traits::{Consumer, Producer}, + }; + + /// Logger implementation which logs frames via a ring buffer and sends the frame sizes + /// as messages. + /// + /// The logger does not require allocation and reserved a generous amount of 4096 bytes for + /// both data buffer and ring buffer. This should be sufficient for most logging needs. + pub struct Logger { + frame_queue: embassy_sync::channel::Channel, + data_buf: critical_section::Mutex>>, + ring_buf: critical_section::Mutex>>>, + } + + unsafe impl Send for Logger {} + unsafe impl Sync for Logger {} + + static LOGGER_RB: Logger = Logger { + frame_queue: embassy_sync::channel::Channel::new(), + data_buf: critical_section::Mutex::new(RefCell::new(heapless::String::new())), + ring_buf: critical_section::Mutex::new(RefCell::new(None)), + }; + + impl log::Log for Logger { + fn enabled(&self, _metadata: &log::Metadata) -> bool { + true + } + + fn log(&self, record: &log::Record) { + critical_section::with(|cs| { + let ref_buf = self.data_buf.borrow(cs); + let mut buf = ref_buf.borrow_mut(); + buf.clear(); + let _ = writeln!(buf, "{} - {}\r", record.level(), record.args()); + let rb_ref = self.ring_buf.borrow(cs); + let mut rb_opt = rb_ref.borrow_mut(); + if rb_opt.is_none() { + panic!("log call on uninitialized logger"); + } + rb_opt.as_mut().unwrap().push_slice(buf.as_bytes()); + let _ = self.frame_queue.try_send(buf.len()); + }); + } + + fn flush(&self) { + while !self.frame_queue().is_empty() {} + } + } + + impl Logger { + pub fn frame_queue( + &self, + ) -> &embassy_sync::channel::Channel { + &self.frame_queue + } + } + + pub fn init(level: LevelFilter) { + critical_section::with(|cs| { + let rb = StaticRb::::default(); + let rb_ref = LOGGER_RB.ring_buf.borrow(cs); + rb_ref.borrow_mut().replace(rb); + }); + set_logger(&LOGGER_RB).unwrap(); + set_max_level(level); // Adjust as needed + } + + pub fn read_next_frame(frame_len: usize, buf: &mut [u8]) { + let read_len = core::cmp::min(frame_len, buf.len()); + critical_section::with(|cs| { + let rb_ref = LOGGER_RB.ring_buf.borrow(cs); + let mut rb = rb_ref.borrow_mut(); + rb.as_mut().unwrap().pop_slice(&mut buf[0..read_len]); + }) + } + + pub fn get_frame_queue() + -> &'static embassy_sync::channel::Channel { + LOGGER_RB.frame_queue() + } +} diff --git a/zynq7000-hal/src/prelude.rs b/zynq7000-hal/src/prelude.rs new file mode 100644 index 0000000..435a2f7 --- /dev/null +++ b/zynq7000-hal/src/prelude.rs @@ -0,0 +1,3 @@ +//! Prelude +pub use fugit::ExtU32 as _; +pub use fugit::RateExtU32 as _; diff --git a/zynq7000-hal/src/slcr.rs b/zynq7000-hal/src/slcr.rs new file mode 100644 index 0000000..778e1f4 --- /dev/null +++ b/zynq7000-hal/src/slcr.rs @@ -0,0 +1,67 @@ +//! # System Level Control Register (SLCR) module. +use zynq7000::slcr::MmioSlcr; + +pub const LOCK_KEY: u32 = 0x767B; +pub const UNLOCK_KEY: u32 = 0xDF0D; + +pub struct Slcr(zynq7000::slcr::MmioSlcr<'static>); + +impl Slcr { + /// Modify the SLCR register. + /// + /// # Safety + /// + /// This method unsafely steals the SLCR MMIO block and then calls a user provided function + /// with the [SLCR MMIO][MmioSlcr] block as an input argument. It is the user's responsibility + /// that the SLCR is not used concurrently in a way which leads to data races. + pub unsafe fn with(mut f: F) { + let mut slcr = unsafe { zynq7000::slcr::Slcr::new_mmio_fixed() }; + slcr.write_unlock(UNLOCK_KEY); + f(&mut slcr); + slcr.write_lock(LOCK_KEY); + } + + /// Create a new SLCR peripheral wrapper. + pub fn new(slcr: zynq7000::slcr::MmioSlcr<'static>) -> Self { + Self(slcr) + } + + /// Unsafely create a new SLCR peripheral wrapper. + /// + /// # Safety + /// + /// This allows to create an arbitrary number of SLCR peripheral wrappers. It is the user's + /// responsibility that these wrappers are not used concurrently in a way which leads to + /// data races. + pub unsafe fn steal() -> Self { + Self::new(unsafe { zynq7000::slcr::Slcr::new_mmio_fixed() }) + } + + /// Returns a mutable reference to the SLCR MMIO block. + /// + /// The MMIO block will not be unlocked. However, the registers can still be read. + pub fn regs(&mut self) -> &mut MmioSlcr<'static> { + &mut self.0 + } + + /// Modify the SLCR register. + /// + /// This method unlocks the SLCR registers and then calls a user provided function + /// with the [SLCR MMIO][MmioSlcr] block as an input argument. This allows the user + /// to safely modify the SLCR registers. The SLCR will be locked afte the operation. + pub fn modify(&mut self, mut f: F) { + self.0.write_unlock(UNLOCK_KEY); + f(&mut self.0); + self.0.write_lock(LOCK_KEY); + } + + /// Manually unlock the SLCR registers. + pub fn unlock(&mut self) { + self.0.write_unlock(UNLOCK_KEY); + } + + /// Manually lock the SLCR registers. + pub fn lock(&mut self) { + self.0.write_lock(LOCK_KEY); + } +} diff --git a/zynq7000-hal/src/spi/asynch.rs b/zynq7000-hal/src/spi/asynch.rs new file mode 100644 index 0000000..cd230f8 --- /dev/null +++ b/zynq7000-hal/src/spi/asynch.rs @@ -0,0 +1,584 @@ +//! Asynchronous PS SPI driver. +use core::{cell::RefCell, convert::Infallible, sync::atomic::AtomicBool}; + +use critical_section::Mutex; +use embassy_sync::waitqueue::AtomicWaker; +use embedded_hal_async::spi::SpiBus; +use raw_slice::{RawBufSlice, RawBufSliceMut}; +use zynq7000::spi::InterruptStatus; + +use super::{ChipSelect, FIFO_DEPTH, Spi, SpiId, SpiLowLevel}; + +static WAKERS: [AtomicWaker; 2] = [const { AtomicWaker::new() }; 2]; +static TRANSFER_CONTEXTS: [Mutex>; 2] = + [const { Mutex::new(RefCell::new(TransferContext::new())) }; 2]; +// Completion flag. Kept outside of the context structure as an atomic to avoid +// critical section. +static DONE: [AtomicBool; 2] = [const { AtomicBool::new(false) }; 2]; + +/// This is a generic interrupt handler to handle asynchronous SPI operations for a given +/// SPI peripheral. +/// +/// The user has to call this once in the interrupt handler responsible for the SPI interrupts on +/// the given SPI bank. +pub fn on_interrupt(peripheral: SpiId) { + let mut spi = unsafe { SpiLowLevel::steal(peripheral) }; + let idx = peripheral as usize; + let imr = spi.read_imr(); + // IRQ is not related. + if !imr.tx_trig() && !imr.tx_full() && !imr.tx_underflow() && !imr.rx_ovr() && !imr.rx_full() { + return; + } + // Prevent spurious interrupts from messing with out logic here. + spi.disable_interrupts(); + let isr = spi.read_isr(); + spi.clear_interrupts(); + let mut context = critical_section::with(|cs| { + let context_ref = TRANSFER_CONTEXTS[idx].borrow(cs); + *context_ref.borrow() + }); + // No transfer active. + if context.transfer_type.is_none() { + return; + } + let transfer_type = context.transfer_type.unwrap(); + match transfer_type { + TransferType::Read => on_interrupt_read(idx, &mut context, &mut spi, isr), + TransferType::Write => on_interrupt_write(idx, &mut context, &mut spi, isr), + TransferType::Transfer => on_interrupt_transfer(idx, &mut context, &mut spi, isr), + TransferType::TransferInPlace => { + on_interrupt_transfer_in_place(idx, &mut context, &mut spi, isr) + } + }; +} + +fn on_interrupt_read( + idx: usize, + context: &mut TransferContext, + spi: &mut SpiLowLevel, + mut isr: InterruptStatus, +) { + let read_slice = unsafe { context.rx_slice.get_mut().unwrap() }; + let transfer_len = read_slice.len(); + + // Read data from RX FIFO first. + let read_len = calculate_read_len(spi, isr, transfer_len, context.rx_progress); + (0..read_len).for_each(|_| { + read_slice[context.rx_progress] = spi.read_fifo_unchecked(); + context.rx_progress += 1; + }); + + // The FIFO still needs to be pumped. + while context.tx_progress < read_slice.len() && !isr.tx_full() { + spi.write_fifo_unchecked(0); + context.tx_progress += 1; + isr = spi.read_isr(); + } + + isr_finish_handler(idx, spi, context, transfer_len) +} + +fn on_interrupt_write( + idx: usize, + context: &mut TransferContext, + spi: &mut SpiLowLevel, + mut isr: InterruptStatus, +) { + let write_slice = unsafe { context.tx_slice.get().unwrap() }; + let transfer_len = write_slice.len(); + + // Read data from RX FIFO first. + let read_len = calculate_read_len(spi, isr, transfer_len, context.rx_progress); + (0..read_len).for_each(|_| { + spi.read_fifo_unchecked(); + context.rx_progress += 1; + }); + + // Data still needs to be sent + while context.tx_progress < transfer_len && !isr.tx_full() { + spi.write_fifo_unchecked(write_slice[context.tx_progress]); + context.tx_progress += 1; + isr = spi.read_isr(); + } + + isr_finish_handler(idx, spi, context, transfer_len) +} + +fn on_interrupt_transfer( + idx: usize, + context: &mut TransferContext, + spi: &mut SpiLowLevel, + mut isr: InterruptStatus, +) { + let read_slice = unsafe { context.rx_slice.get_mut().unwrap() }; + let read_len = read_slice.len(); + let write_slice = unsafe { context.tx_slice.get().unwrap() }; + let write_len = write_slice.len(); + let transfer_len = core::cmp::max(read_len, write_len); + + // Read data from RX FIFO first. + let read_len = calculate_read_len(spi, isr, transfer_len, context.rx_progress); + (0..read_len).for_each(|_| { + if context.rx_progress < read_len { + read_slice[context.rx_progress] = spi.read_fifo_unchecked(); + } else { + spi.read_fifo_unchecked(); + } + context.rx_progress += 1; + }); + + // Data still needs to be sent + while context.tx_progress < transfer_len && !isr.tx_full() { + if context.tx_progress < write_len { + spi.write_fifo_unchecked(write_slice[context.tx_progress]); + } else { + // Dummy write. + spi.write_fifo_unchecked(0); + } + context.tx_progress += 1; + isr = spi.read_isr(); + } + + isr_finish_handler(idx, spi, context, transfer_len) +} + +fn on_interrupt_transfer_in_place( + idx: usize, + context: &mut TransferContext, + spi: &mut SpiLowLevel, + mut isr: InterruptStatus, +) { + let transfer_slice = unsafe { context.rx_slice.get_mut().unwrap() }; + let transfer_len = transfer_slice.len(); + // Read data from RX FIFO first. + let read_len = calculate_read_len(spi, isr, transfer_len, context.rx_progress); + (0..read_len).for_each(|_| { + transfer_slice[context.rx_progress] = spi.read_fifo_unchecked(); + context.rx_progress += 1; + }); + + // Data still needs to be sent + while context.tx_progress < transfer_len && !isr.tx_full() { + spi.write_fifo_unchecked(transfer_slice[context.tx_progress]); + context.tx_progress += 1; + isr = spi.read_isr(); + } + + isr_finish_handler(idx, spi, context, transfer_len) +} + +fn calculate_read_len( + spi: &mut SpiLowLevel, + isr: InterruptStatus, + total_read_len: usize, + rx_progress: usize, +) -> usize { + if isr.rx_full() { + core::cmp::min(FIFO_DEPTH, total_read_len - rx_progress) + } else if isr.rx_not_empty() { + let trigger = spi.read_rx_not_empty_threshold(); + core::cmp::min(total_read_len - rx_progress, trigger as usize) + } else { + 0 + } +} + +/// Generic handler after RX FIFO and TX FIFO were handled. Checks and handles finished +/// and unfinished conditions. +fn isr_finish_handler( + idx: usize, + spi: &mut SpiLowLevel, + context: &mut TransferContext, + transfer_len: usize, +) { + // Transfer finish condition. + if context.rx_progress == context.tx_progress && context.rx_progress == transfer_len { + finish_transfer(idx, context, spi); + return; + } + + unfinished_transfer(spi, transfer_len, context.rx_progress); + + // If the transfer is done, the context structure was already written back. + // Write back updated context structure. + critical_section::with(|cs| { + let context_ref = TRANSFER_CONTEXTS[idx].borrow(cs); + *context_ref.borrow_mut() = *context; + }); +} + +fn finish_transfer(idx: usize, context: &mut TransferContext, spi: &mut SpiLowLevel) { + // Write back updated context structure. + critical_section::with(|cs| { + let context_ref = TRANSFER_CONTEXTS[idx].borrow(cs); + *context_ref.borrow_mut() = *context; + }); + spi.set_rx_fifo_trigger(1).unwrap(); + spi.set_tx_fifo_trigger(1).unwrap(); + // Interrupts were already disabled and cleared. + DONE[idx].store(true, core::sync::atomic::Ordering::Relaxed); + WAKERS[idx].wake(); +} + +fn unfinished_transfer(spi: &mut SpiLowLevel, transfer_len: usize, rx_progress: usize) { + let new_trig_level = core::cmp::min(FIFO_DEPTH, transfer_len - rx_progress); + spi.set_rx_fifo_trigger(new_trig_level as u32).unwrap(); + // Re-enable interrupts with the new RX FIFO trigger level. + spi.enable_interrupts(); +} + +#[derive(Debug, Clone, Copy)] +pub enum TransferType { + Read, + Write, + Transfer, + TransferInPlace, +} + +#[derive(Default, Debug, Copy, Clone)] +pub struct TransferContext { + transfer_type: Option, + tx_progress: usize, + rx_progress: usize, + tx_slice: RawBufSlice, + rx_slice: RawBufSliceMut, +} + +#[allow(clippy::new_without_default)] +impl TransferContext { + pub const fn new() -> Self { + Self { + transfer_type: None, + tx_progress: 0, + rx_progress: 0, + tx_slice: RawBufSlice::new_nulled(), + rx_slice: RawBufSliceMut::new_nulled(), + } + } +} + +pub struct SpiFuture { + id: super::SpiId, + spi: super::SpiLowLevel, + config: super::Config, + finished_regularly: core::cell::Cell, +} + +impl SpiFuture { + fn new_for_read(spi: &mut Spi, spi_id: SpiId, words: &mut [u8]) -> Self { + if words.is_empty() { + panic!("words length unexpectedly 0"); + } + let idx = spi_id as usize; + DONE[idx].store(false, core::sync::atomic::Ordering::Relaxed); + spi.inner.disable_interrupts(); + + let write_idx = core::cmp::min(super::FIFO_DEPTH, words.len()); + // Send dummy bytes. + (0..write_idx).for_each(|_| { + spi.inner.write_fifo_unchecked(0); + }); + + Self::set_triggers(spi, write_idx, words.len()); + // We assume that the slave select configuration was already performed, but we take + // care of issuing a start if necessary. + spi.issue_manual_start_for_manual_cfg(); + + critical_section::with(|cs| { + let context_ref = TRANSFER_CONTEXTS[idx].borrow(cs); + let mut context = context_ref.borrow_mut(); + context.transfer_type = Some(TransferType::Read); + unsafe { + context.rx_slice.set(words); + } + context.tx_slice.set_null(); + context.tx_progress = write_idx; + context.rx_progress = 0; + spi.inner.clear_interrupts(); + spi.inner.enable_interrupts(); + spi.inner.enable(); + }); + Self { + id: spi_id, + config: spi.config, + spi: unsafe { spi.inner.clone() }, + finished_regularly: core::cell::Cell::new(false), + } + } + + fn new_for_write(spi: &mut Spi, spi_id: SpiId, words: &[u8]) -> Self { + if words.is_empty() { + panic!("words length unexpectedly 0"); + } + let (idx, write_idx) = Self::generic_init_transfer(spi, spi_id, words); + critical_section::with(|cs| { + let context_ref = TRANSFER_CONTEXTS[idx].borrow(cs); + let mut context = context_ref.borrow_mut(); + context.transfer_type = Some(TransferType::Write); + unsafe { + context.tx_slice.set(words); + } + context.rx_slice.set_null(); + context.tx_progress = write_idx; + context.rx_progress = 0; + spi.inner.clear_interrupts(); + spi.inner.enable_interrupts(); + spi.inner.enable(); + }); + Self { + id: spi_id, + config: spi.config, + spi: unsafe { spi.inner.clone() }, + finished_regularly: core::cell::Cell::new(false), + } + } + + fn new_for_transfer(spi: &mut Spi, spi_id: SpiId, read: &mut [u8], write: &[u8]) -> Self { + if read.is_empty() || write.is_empty() { + panic!("read or write buffer unexpectedly empty"); + } + let (idx, write_idx) = Self::generic_init_transfer(spi, spi_id, write); + critical_section::with(|cs| { + let context_ref = TRANSFER_CONTEXTS[idx].borrow(cs); + let mut context = context_ref.borrow_mut(); + context.transfer_type = Some(TransferType::Transfer); + unsafe { + context.tx_slice.set(write); + context.rx_slice.set(read); + } + context.tx_progress = write_idx; + context.rx_progress = 0; + spi.inner.clear_interrupts(); + spi.inner.enable_interrupts(); + spi.inner.enable(); + }); + Self { + id: spi_id, + config: spi.config, + spi: unsafe { spi.inner.clone() }, + finished_regularly: core::cell::Cell::new(false), + } + } + + fn new_for_transfer_in_place(spi: &mut Spi, spi_id: SpiId, words: &mut [u8]) -> Self { + if words.is_empty() { + panic!("read and write buffer unexpectedly empty"); + } + let (idx, write_idx) = Self::generic_init_transfer(spi, spi_id, words); + critical_section::with(|cs| { + let context_ref = TRANSFER_CONTEXTS[idx].borrow(cs); + let mut context = context_ref.borrow_mut(); + context.transfer_type = Some(TransferType::TransferInPlace); + unsafe { + context.rx_slice.set(words); + } + context.tx_slice.set_null(); + context.tx_progress = write_idx; + context.rx_progress = 0; + spi.inner.clear_interrupts(); + spi.inner.enable_interrupts(); + spi.inner.enable(); + }); + Self { + id: spi_id, + config: spi.config, + spi: unsafe { spi.inner.clone() }, + finished_regularly: core::cell::Cell::new(false), + } + } + + fn generic_init_transfer(spi: &mut Spi, spi_id: SpiId, write: &[u8]) -> (usize, usize) { + let idx = spi_id as usize; + DONE[idx].store(false, core::sync::atomic::Ordering::Relaxed); + spi.inner.disable(); + spi.inner.disable_interrupts(); + + let write_idx = core::cmp::min(super::FIFO_DEPTH, write.len()); + (0..write_idx).for_each(|idx| { + spi.inner.write_fifo_unchecked(write[idx]); + }); + + Self::set_triggers(spi, write_idx, write.len()); + // We assume that the slave select configuration was already performed, but we take + // care of issuing a start if necessary. + spi.issue_manual_start_for_manual_cfg(); + (idx, write_idx) + } + + fn set_triggers(spi: &mut Spi, write_idx: usize, write_len: usize) { + // This should never fail because it is never larger than the FIFO depth. + spi.inner.set_rx_fifo_trigger(write_idx as u32).unwrap(); + // We want to re-fill the TX FIFO before it is completely empty if the full transfer size + // is larger than the FIFO depth. I am not sure whether the default value of 1 ensures + // this because the TMR says that this interrupt is triggered when the FIFO has less than + // threshold entries. + if write_len > super::FIFO_DEPTH { + spi.inner.set_tx_fifo_trigger(2).unwrap(); + } + } +} + +impl Future for SpiFuture { + type Output = (); + + fn poll( + self: core::pin::Pin<&mut Self>, + cx: &mut core::task::Context<'_>, + ) -> core::task::Poll { + WAKERS[self.id as usize].register(cx.waker()); + if DONE[self.id as usize].swap(false, core::sync::atomic::Ordering::Relaxed) { + critical_section::with(|cs| { + let mut ctx = TRANSFER_CONTEXTS[self.id as usize].borrow(cs).borrow_mut(); + *ctx = TransferContext::default(); + }); + self.finished_regularly.set(true); + return core::task::Poll::Ready(()); + } + core::task::Poll::Pending + } +} + +impl Drop for SpiFuture { + fn drop(&mut self) { + if !self.finished_regularly.get() { + // It might be sufficient to disable and enable the SPI.. But this definitely + // ensures the SPI is fully reset. + self.spi.reset_and_reconfigure(self.config); + } + } +} + +/// Asynchronous SPI driver. +/// +/// This is the primary data structure used to perform non-blocking SPI operations. +/// It implements the [embedded_hal_async::spi::SpiBus] as well. +pub struct SpiAsync(pub Spi); + +impl SpiAsync { + pub fn new(spi: Spi) -> Self { + Self(spi) + } + + async fn read(&mut self, words: &mut [u8]) { + if words.is_empty() { + return; + } + let id = self.0.inner.id; + let spi_fut = SpiFuture::new_for_read(&mut self.0, id, words); + spi_fut.await; + } + + async fn write(&mut self, words: &[u8]) { + if words.is_empty() { + return; + } + let id = self.0.inner.id; + let spi_fut = SpiFuture::new_for_write(&mut self.0, id, words); + spi_fut.await; + } + + async fn transfer(&mut self, read: &mut [u8], write: &[u8]) { + if read.is_empty() || write.is_empty() { + return; + } + let id = self.0.inner.id; + let spi_fut = SpiFuture::new_for_transfer(&mut self.0, id, read, write); + spi_fut.await; + } + + async fn transfer_in_place(&mut self, words: &mut [u8]) { + if words.is_empty() { + return; + } + let id = self.0.inner.id; + let spi_fut = SpiFuture::new_for_transfer_in_place(&mut self.0, id, words); + spi_fut.await; + } +} + +impl embedded_hal_async::spi::ErrorType for SpiAsync { + type Error = Infallible; +} + +impl embedded_hal_async::spi::SpiBus for SpiAsync { + async fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { + self.read(words).await; + Ok(()) + } + + async fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { + self.write(words).await; + Ok(()) + } + + async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> { + self.transfer(read, write).await; + Ok(()) + } + + async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { + self.transfer_in_place(words).await; + Ok(()) + } + + async fn flush(&mut self) -> Result<(), Self::Error> { + Ok(()) + } +} + +/// This structure is a wrapper for [SpiAsync] which implements the +/// [embedded_hal_async::spi::SpiDevice] trait as well. +pub struct SpiWithHwCsAsync { + pub spi: SpiAsync, + pub cs: ChipSelect, + pub delay: Delay, +} + +impl SpiWithHwCsAsync { + pub fn new(spi: SpiAsync, cs: ChipSelect, delay: Delay) -> Self { + Self { spi, cs, delay } + } + + pub fn release(self) -> SpiAsync { + self.spi + } +} + +impl embedded_hal_async::spi::ErrorType + for SpiWithHwCsAsync +{ + type Error = Infallible; +} + +impl embedded_hal_async::spi::SpiDevice + for SpiWithHwCsAsync +{ + async fn transaction( + &mut self, + operations: &mut [embedded_hal::spi::Operation<'_, u8>], + ) -> Result<(), Self::Error> { + self.spi.0.inner.select_hw_cs(self.cs); + for op in operations { + match op { + embedded_hal::spi::Operation::Read(items) => { + self.spi.read(items).await; + } + embedded_hal::spi::Operation::Write(items) => { + self.spi.write(items).await; + } + embedded_hal::spi::Operation::Transfer(read, write) => { + self.spi.transfer(read, write).await; + } + embedded_hal::spi::Operation::TransferInPlace(items) => { + self.spi.transfer_in_place(items).await; + } + embedded_hal::spi::Operation::DelayNs(delay) => { + self.delay.delay_ns(*delay).await; + } + } + } + self.spi.flush().await?; + self.spi.0.inner.no_hw_cs(); + Ok(()) + } +} diff --git a/zynq7000-hal/src/spi/mod.rs b/zynq7000-hal/src/spi/mod.rs new file mode 100644 index 0000000..8cda596 --- /dev/null +++ b/zynq7000-hal/src/spi/mod.rs @@ -0,0 +1,1222 @@ +//! PS SPI HAL driver. +use core::convert::Infallible; + +use crate::clocks::Clocks; +use crate::enable_amba_peripheral_clock; +use crate::gpio::{ + IoPeriph, IoPeriphPin, Mio10, Mio11, Mio12, Mio13, Mio14, Mio15, Mio28, Mio29, Mio30, Mio31, + Mio32, Mio33, Mio34, Mio35, Mio36, Mio37, Mio38, Mio39, MioPin, MuxConf, +}; +#[cfg(not(feature = "7z010-7z007s-clg225"))] +use crate::gpio::{ + Mio16, Mio17, Mio18, Mio19, Mio20, Mio21, Mio22, Mio23, Mio24, Mio25, Mio26, Mio27, Mio40, + Mio41, Mio42, Mio43, Mio44, Mio45, Mio46, Mio47, Mio48, Mio49, Mio50, Mio51, +}; + +use crate::{clocks::IoClocks, slcr::Slcr, time::Hertz}; +use arbitrary_int::{Number, u3, u4, u6}; +use embedded_hal::delay::DelayNs; +pub use embedded_hal::spi::Mode; +use embedded_hal::spi::{MODE_0, MODE_1, MODE_2, MODE_3, SpiBus as _}; +use zynq7000::slcr::reset::DualRefAndClockReset; +use zynq7000::spi::{ + BaudDivSelect, DelayControl, FifoWrite, InterruptControl, InterruptMask, InterruptStatus, + MmioSpi, SPI_0_BASE_ADDR, SPI_1_BASE_ADDR, +}; + +pub const FIFO_DEPTH: usize = 128; +pub const MODULE_ID: u32 = 0x90106; + +pub mod asynch; +pub use asynch::*; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum SpiId { + Spi0 = 0, + Spi1 = 1, +} + +pub trait PsSpi { + fn reg_block(&self) -> MmioSpi<'static>; + fn id(&self) -> Option; +} + +impl PsSpi for MmioSpi<'static> { + #[inline] + fn reg_block(&self) -> MmioSpi<'static> { + unsafe { self.clone() } + } + + #[inline] + fn id(&self) -> Option { + let base_addr = unsafe { self.ptr() } as usize; + if base_addr == SPI_0_BASE_ADDR { + return Some(SpiId::Spi0); + } else if base_addr == SPI_1_BASE_ADDR { + return Some(SpiId::Spi1); + } + None + } +} + +pub trait SckPin: IoPeriphPin { + const SPI: SpiId; + const GROUP: usize; +} + +pub trait MosiPin: IoPeriphPin { + const SPI: SpiId; + const GROUP: usize; +} + +pub trait MisoPin: IoPeriphPin { + const SPI: SpiId; + const GROUP: usize; +} + +pub trait SsPin: IoPeriphPin { + const IDX: usize; + const SPI: SpiId; + const GROUP: usize; +} + +pub const SPI_MUX_CONF: MuxConf = MuxConf::new_with_l3(u3::new(0b101)); + +macro_rules! impl_into_spi { + (($($Mio:ident),+)) => { + $( + impl MioPin<$Mio, M> { + /// Convert the pin into SPI pins by configuring the pin routing via the + /// MIO multiplexer bits. Also disables pull-ups for the pins. + pub fn into_spi(self) -> MioPin<$Mio, IoPeriph> { + self.into_io_periph(SPI_MUX_CONF, Some(false)) + } + } + )+ + }; +} + +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl_into_spi!(( + Mio16, Mio21, Mio17, Mio18, Mio19, Mio20, Mio40, Mio45, Mio41, Mio42, Mio43, Mio44, Mio24, + Mio22, Mio23, Mio25, Mio26, Mio27, Mio48, Mio46, Mio47, Mio49, Mio50, Mio51 +)); + +impl_into_spi!(( + Mio28, Mio33, Mio29, Mio30, Mio31, Mio32, Mio12, Mio10, Mio11, Mio13, Mio14, Mio15, Mio36, + Mio34, Mio35, Mio37, Mio38, Mio39 +)); + +// SPI0, choice 1 +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl SckPin for MioPin { + const SPI: SpiId = SpiId::Spi0; + const GROUP: usize = 0; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl MosiPin for MioPin { + const SPI: SpiId = SpiId::Spi0; + const GROUP: usize = 0; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl MisoPin for MioPin { + const SPI: SpiId = SpiId::Spi0; + const GROUP: usize = 0; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl SsPin for MioPin { + const SPI: SpiId = SpiId::Spi0; + const GROUP: usize = 0; + const IDX: usize = 0; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl SsPin for MioPin { + const SPI: SpiId = SpiId::Spi0; + const GROUP: usize = 0; + const IDX: usize = 1; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl SsPin for MioPin { + const SPI: SpiId = SpiId::Spi0; + const GROUP: usize = 0; + const IDX: usize = 2; +} + +// SPI0, choice 2 +impl SckPin for MioPin { + const SPI: SpiId = SpiId::Spi0; + const GROUP: usize = 1; +} +impl MosiPin for MioPin { + const SPI: SpiId = SpiId::Spi0; + const GROUP: usize = 1; +} +impl MisoPin for MioPin { + const SPI: SpiId = SpiId::Spi0; + const GROUP: usize = 1; +} +impl SsPin for MioPin { + const SPI: SpiId = SpiId::Spi0; + const GROUP: usize = 1; + const IDX: usize = 0; +} +impl SsPin for MioPin { + const SPI: SpiId = SpiId::Spi0; + const GROUP: usize = 1; + const IDX: usize = 1; +} +impl SsPin for MioPin { + const SPI: SpiId = SpiId::Spi0; + const GROUP: usize = 1; + const IDX: usize = 2; +} + +// SPI0, choice 3 +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl SckPin for MioPin { + const SPI: SpiId = SpiId::Spi0; + const GROUP: usize = 2; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl MosiPin for MioPin { + const SPI: SpiId = SpiId::Spi0; + const GROUP: usize = 2; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl MisoPin for MioPin { + const SPI: SpiId = SpiId::Spi0; + const GROUP: usize = 2; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl SsPin for MioPin { + const SPI: SpiId = SpiId::Spi0; + const GROUP: usize = 2; + const IDX: usize = 0; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl SsPin for MioPin { + const SPI: SpiId = SpiId::Spi0; + const GROUP: usize = 2; + const IDX: usize = 1; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl SsPin for MioPin { + const SPI: SpiId = SpiId::Spi0; + const GROUP: usize = 2; + const IDX: usize = 2; +} + +// SPI1, choice 1 +impl SckPin for MioPin { + const SPI: SpiId = SpiId::Spi1; + const GROUP: usize = 0; +} +impl MosiPin for MioPin { + const SPI: SpiId = SpiId::Spi1; + const GROUP: usize = 0; +} +impl MisoPin for MioPin { + const SPI: SpiId = SpiId::Spi1; + const GROUP: usize = 0; +} +impl SsPin for MioPin { + const SPI: SpiId = SpiId::Spi1; + const GROUP: usize = 0; + const IDX: usize = 0; +} +impl SsPin for MioPin { + const SPI: SpiId = SpiId::Spi1; + const GROUP: usize = 0; + const IDX: usize = 1; +} +impl SsPin for MioPin { + const SPI: SpiId = SpiId::Spi1; + const GROUP: usize = 0; + const IDX: usize = 2; +} + +// SPI1, choice 2 +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl SckPin for MioPin { + const SPI: SpiId = SpiId::Spi1; + const GROUP: usize = 1; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl MosiPin for MioPin { + const SPI: SpiId = SpiId::Spi1; + const GROUP: usize = 1; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl MisoPin for MioPin { + const SPI: SpiId = SpiId::Spi1; + const GROUP: usize = 1; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl SsPin for MioPin { + const SPI: SpiId = SpiId::Spi1; + const GROUP: usize = 1; + const IDX: usize = 0; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl SsPin for MioPin { + const SPI: SpiId = SpiId::Spi1; + const GROUP: usize = 1; + const IDX: usize = 1; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl SsPin for MioPin { + const SPI: SpiId = SpiId::Spi1; + const GROUP: usize = 1; + const IDX: usize = 2; +} + +// SPI1, choice 2 +impl SckPin for MioPin { + const SPI: SpiId = SpiId::Spi1; + const GROUP: usize = 2; +} +impl MosiPin for MioPin { + const SPI: SpiId = SpiId::Spi1; + const GROUP: usize = 2; +} +impl MisoPin for MioPin { + const SPI: SpiId = SpiId::Spi1; + const GROUP: usize = 2; +} +impl SsPin for MioPin { + const SPI: SpiId = SpiId::Spi1; + const GROUP: usize = 2; + const IDX: usize = 0; +} +impl SsPin for MioPin { + const SPI: SpiId = SpiId::Spi1; + const GROUP: usize = 2; + const IDX: usize = 1; +} +impl SsPin for MioPin { + const SPI: SpiId = SpiId::Spi1; + const GROUP: usize = 2; + const IDX: usize = 2; +} + +// SPI1, choice 3 +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl SckPin for MioPin { + const SPI: SpiId = SpiId::Spi1; + const GROUP: usize = 3; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl MosiPin for MioPin { + const SPI: SpiId = SpiId::Spi1; + const GROUP: usize = 3; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl MisoPin for MioPin { + const SPI: SpiId = SpiId::Spi1; + const GROUP: usize = 3; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl SsPin for MioPin { + const SPI: SpiId = SpiId::Spi1; + const GROUP: usize = 3; + const IDX: usize = 0; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl SsPin for MioPin { + const SPI: SpiId = SpiId::Spi1; + const GROUP: usize = 3; + const IDX: usize = 1; +} +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl SsPin for MioPin { + const SPI: SpiId = SpiId::Spi1; + const GROUP: usize = 3; + const IDX: usize = 2; +} + +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub enum ChipSelect { + Slave0, + Slave1, + Slave2, + Decoded { cs0: bool, cs1: bool, cs2: bool }, + None, +} + +impl ChipSelect { + pub const fn raw_reg(&self) -> u4 { + u4::new(match self { + ChipSelect::Slave0 => 0b0000, + ChipSelect::Slave1 => 0b0001, + ChipSelect::Slave2 => 0b0010, + ChipSelect::None => 0b1111, + ChipSelect::Decoded { cs0, cs1, cs2 } => { + (1 << 3) | (*cs0 as u8) | ((*cs1 as u8) << 1) | ((*cs2 as u8) << 2) + } + }) + } + + #[inline] + pub const fn cs_no_ext_decoding(&self, raw: u4) -> Option { + let val = raw.value(); + if val == 0b1111 { + return Some(ChipSelect::None); + } + if val & 0b1 == 0 { + return Some(ChipSelect::Slave0); + } else if val & 0b11 == 0b01 { + return Some(ChipSelect::Slave1); + } else if val & 0b111 == 0b010 { + return Some(ChipSelect::Slave2); + } + None + } +} + +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] +/// Slave select configuration. +pub enum SlaveSelectConfig { + /// User must take care of controlling slave select lines as well as issuing a start command. + ManualWithManualStart = 0b11, + ManualAutoStart = 0b10, + /// Hardware slave select, but start needs to be issued manually. + AutoWithManualStart = 0b01, + /// Hardware slave select, auto serialiation if there is data in the TX FIFO. + #[default] + AutoWithAutoStart = 0b00, +} + +#[derive(Debug, Copy, Clone)] +pub struct Config { + baud_div: BaudDivSelect, + init_mode: Mode, + ss_config: SlaveSelectConfig, + with_ext_decoding: bool, +} + +impl Config { + pub fn new(baud_div: BaudDivSelect, init_mode: Mode, ss_config: SlaveSelectConfig) -> Self { + Self { + baud_div, + init_mode, + ss_config, + with_ext_decoding: false, + } + } + + pub fn enable_external_decoding(&mut self) { + self.with_ext_decoding = true; + } +} + +/// Thin re-usable low-level helper to interface with the SPI. +pub struct SpiLowLevel { + id: SpiId, + regs: zynq7000::spi::MmioSpi<'static>, +} + +impl SpiLowLevel { + /// Steal the SPI low level helper. + /// + /// # Safety + /// + /// This API can be used to potentially create a driver to the same peripheral structure + /// from multiple threads. The user must ensure that concurrent accesses are safe and do not + /// interfere with each other. + pub unsafe fn steal(id: SpiId) -> Self { + let regs = unsafe { + match id { + SpiId::Spi0 => zynq7000::spi::Spi::new_mmio_fixed_0(), + SpiId::Spi1 => zynq7000::spi::Spi::new_mmio_fixed_1(), + } + }; + Self { id, regs } + } + + /// Clone the SPI low level helper. + /// + /// # Safety + /// + /// This API can be used to potentially create a driver to the same peripheral structure + /// from multiple threads. The user must ensure that concurrent accesses are safe and do not + /// interfere with each other. + pub unsafe fn clone(&self) -> Self { + Self { + id: self.id, + regs: unsafe { self.regs.clone() }, + } + } + + pub fn id(&self) -> SpiId { + self.id + } + + #[inline] + pub fn disable(&mut self) { + self.regs.write_enable(0); + } + + #[inline] + pub fn enable(&mut self) { + self.regs.write_enable(1); + } + + /// Select the peripheral chip select line. + /// + /// This needs to be done before starting a transfer to select the correct peripheral chip + /// select line. + /// + /// The decoder bits logic is is based + /// [on online documentation](https://www.realdigital.org/doc/3eb4f7a05e5003f2e0e6858a27a679bb?utm_source=chatgpt.com) + /// because the TRM does not specify how decoding really works. This also only works if + /// the external decoding was enabled via the [Config::enable_external_decoding] option. + #[inline] + pub fn select_hw_cs(&mut self, chip_select: ChipSelect) { + self.regs.modify_cr(|mut val| { + val.set_cs_raw(chip_select.raw_reg()); + val + }); + } + + /// Re-configures the mode register. + #[inline] + pub fn configure_mode(&mut self, mode: Mode) { + let (cpol, cpha) = match mode { + MODE_0 => (false, false), + MODE_1 => (false, true), + MODE_2 => (true, false), + MODE_3 => (true, true), + }; + self.regs.modify_cr(|mut val| { + val.set_cpha(cpha); + val.set_cpha(cpol); + val + }); + } + + /// Re-configures the delay control register. + #[inline] + pub fn configure_delays(&mut self, config: DelayControl) { + self.regs.write_delay_control(config) + } + + /// Re-configures the SPI peripheral with the initial configuration. + pub fn reconfigure(&mut self, config: Config) { + self.regs.write_enable(0); + let (man_ss, man_start) = match config.ss_config { + SlaveSelectConfig::ManualWithManualStart => (true, true), + SlaveSelectConfig::ManualAutoStart => (true, false), + SlaveSelectConfig::AutoWithManualStart => (false, true), + SlaveSelectConfig::AutoWithAutoStart => (false, false), + }; + let (cpol, cpha) = match config.init_mode { + MODE_0 => (false, false), + MODE_1 => (false, true), + MODE_2 => (true, false), + MODE_3 => (true, true), + }; + + self.regs.write_cr( + zynq7000::spi::Config::builder() + .with_modefail_gen_en(false) + .with_manual_start(false) + .with_manual_start_enable(man_start) + .with_manual_cs(man_ss) + .with_cs_raw(ChipSelect::None.raw_reg()) + .with_peri_sel(config.with_ext_decoding) + .with_baud_rate_div(config.baud_div) + .with_cpha(cpha) + .with_cpol(cpol) + .with_master_ern(true) + .build(), + ); + // Configures for polling mode by default: TX trigger by one will lead to the + // TX FIFO not full signal being set when the TX FIFO is emtpy. + self.regs.write_tx_trig(1); + // Same as TX. + self.regs.write_rx_trig(1); + + self.regs.write_enable(1); + } + + /// [Resets][reset] and [re-configures][Self::reconfigure] the SPI peripheral. + /// + /// This can also be used to reset the FIFOs and the state machine of the SPI. + pub fn reset_and_reconfigure(&mut self, config: Config) { + reset(self.id()); + self.reconfigure(config); + } + + /// No peripheral slave selection. + #[inline] + pub fn no_hw_cs(&mut self) { + self.select_hw_cs(ChipSelect::None); + } + + #[inline(always)] + pub fn write_fifo_unchecked(&mut self, data: u8) { + self.regs + .write_txd(FifoWrite::new(data)); + } + + #[inline(always)] + pub fn read_fifo_unchecked(&mut self) -> u8 { + self.regs.read_rxd().value() + } + + #[inline] + pub fn issue_manual_start(&mut self) { + self.regs.modify_cr(|mut val| { + val.set_manual_start(true); + val + }); + } + + #[inline] + pub fn read_isr(&self) -> InterruptStatus { + self.regs.read_isr() + } + + #[inline] + pub fn read_imr(&self) -> InterruptMask { + self.regs.read_imr() + } + + #[inline] + pub fn read_rx_not_empty_threshold(&self) -> u32 { + self.regs.read_rx_trig() + } + + #[inline] + pub fn set_rx_fifo_trigger(&mut self, trigger: u32) -> Result<(), InvalidTriggerError> { + if trigger > FIFO_DEPTH as u32 { + return Err(InvalidTriggerError(trigger as usize)); + } + self.regs.write_rx_trig(trigger.value()); + Ok(()) + } + + #[inline] + pub fn set_tx_fifo_trigger(&mut self, trigger: u32) -> Result<(), InvalidTriggerError> { + if trigger > FIFO_DEPTH as u32 { + return Err(InvalidTriggerError(trigger as usize)); + } + self.regs.write_tx_trig(trigger.value()); + Ok(()) + } + + /// This disables all interrupts relevant for non-blocking interrupt driven SPI operation + /// in SPI master mode. + #[inline] + pub fn disable_interrupts(&mut self) { + self.regs.write_idr( + InterruptControl::builder() + .with_tx_underflow(true) + .with_rx_full(true) + .with_rx_not_empty(true) + .with_tx_full(false) + .with_tx_trig(true) + .with_mode_fault(false) + .with_rx_ovr(true) + .build(), + ); + } + + /// This enables all interrupts relevant for non-blocking interrupt driven SPI operation + /// in SPI master mode. + #[inline] + pub fn enable_interrupts(&mut self) { + self.regs.write_ier( + InterruptControl::builder() + .with_tx_underflow(true) + .with_rx_full(true) + .with_rx_not_empty(true) + .with_tx_full(false) + .with_tx_trig(true) + .with_mode_fault(false) + .with_rx_ovr(true) + .build(), + ); + } + + /// This clears all interrupts relevant for non-blocking interrupt driven SPI operation + /// in SPI master mode. + #[inline] + pub fn clear_interrupts(&mut self) { + self.regs.write_isr( + InterruptStatus::builder() + .with_tx_underflow(true) + .with_rx_full(true) + .with_rx_not_empty(true) + .with_tx_full(false) + .with_tx_not_full(true) + .with_mode_fault(false) + .with_rx_ovr(true) + .build(), + ); + } +} + +/// Blocking Driver for the PS SPI peripheral in master mode. +pub struct Spi { + inner: SpiLowLevel, + sclk: Hertz, + config: Config, + outstanding_rx: bool, +} + +#[derive(Debug, thiserror::Error)] +#[error("invalid SPI ID")] +pub struct InvalidPsSpiError; + +#[derive(Debug, thiserror::Error)] +#[error("invalid trigger value {0}")] +pub struct InvalidTriggerError(pub usize); + +// TODO: Add and handle MUX config check. +#[derive(Debug, thiserror::Error)] +pub enum SpiConstructionError { + #[error("invalid SPI ID {0}")] + InvalidPsSpi(#[from] InvalidPsSpiError), + /// The specified pins are not compatible to the specified SPI peripheral. + #[error("pin invalid for SPI ID")] + PinInvalidForSpiId, + /// The specified pins are not from the same pin group. + #[error("pin group missmatch")] + GroupMissmatch, + #[error("invalid pin configuration for SPI")] + InvalidPinConf, +} + +impl Spi { + pub fn new_no_hw_ss( + spi: impl PsSpi, + clocks: &IoClocks, + config: Config, + spi_pins: (Sck, Mosi, Miso), + ) -> Result { + let spi_id = spi.id(); + if spi_id.is_none() { + return Err(InvalidPsSpiError.into()); + } + let spi_id = spi_id.unwrap(); + if Sck::GROUP != Mosi::GROUP || Sck::GROUP != Miso::GROUP { + return Err(SpiConstructionError::GroupMissmatch); + } + if Sck::SPI != spi_id || Mosi::SPI != spi_id || Miso::SPI != spi_id { + return Err(SpiConstructionError::PinInvalidForSpiId); + } + if spi_pins.0.mux_conf() != SPI_MUX_CONF + || spi_pins.0.mux_conf() != spi_pins.2.mux_conf() + || spi_pins.1.mux_conf() != spi_pins.2.mux_conf() + { + return Err(SpiConstructionError::InvalidPinConf); + } + Ok(Self::new_generic_unchecked( + spi_id, + spi.reg_block(), + clocks, + config, + )) + } + + pub fn new_one_hw_cs( + spi: impl PsSpi, + clocks: &IoClocks, + config: Config, + spi_pins: (Sck, Mosi, Miso), + ss_pin: Ss, + ) -> Result { + let spi_id = spi.id(); + if spi_id.is_none() { + return Err(InvalidPsSpiError.into()); + } + let spi_id = spi_id.unwrap(); + if Sck::GROUP != Mosi::GROUP || Sck::GROUP != Miso::GROUP || Sck::GROUP != Ss::GROUP { + return Err(SpiConstructionError::GroupMissmatch); + } + if Sck::SPI != spi_id || Mosi::SPI != spi_id || Miso::SPI != spi_id || Ss::SPI != spi_id { + return Err(SpiConstructionError::PinInvalidForSpiId); + } + if spi_pins.0.mux_conf() != SPI_MUX_CONF + || spi_pins.0.mux_conf() != spi_pins.2.mux_conf() + || spi_pins.1.mux_conf() != spi_pins.2.mux_conf() + || ss_pin.mux_conf() != spi_pins.0.mux_conf() + { + return Err(SpiConstructionError::InvalidPinConf); + } + Ok(Self::new_generic_unchecked( + spi_id, + spi.reg_block(), + clocks, + config, + )) + } + + pub fn new_with_two_hw_cs( + spi: impl PsSpi, + clocks: &IoClocks, + config: Config, + spi_pins: (Sck, Mosi, Miso), + ss_pins: (Ss0, Ss1), + ) -> Result { + let spi_id = spi.id(); + if spi_id.is_none() { + return Err(InvalidPsSpiError.into()); + } + let spi_id = spi_id.unwrap(); + if Sck::GROUP != Mosi::GROUP + || Sck::GROUP != Miso::GROUP + || Sck::GROUP != Ss0::GROUP + || Sck::GROUP != Ss1::GROUP + { + return Err(SpiConstructionError::GroupMissmatch); + } + if Sck::SPI != spi_id + || Mosi::SPI != spi_id + || Miso::SPI != spi_id + || Ss0::SPI != spi_id + || Ss1::SPI != spi_id + { + return Err(SpiConstructionError::PinInvalidForSpiId); + } + if spi_pins.0.mux_conf() != SPI_MUX_CONF + || spi_pins.0.mux_conf() != spi_pins.2.mux_conf() + || spi_pins.1.mux_conf() != spi_pins.2.mux_conf() + || ss_pins.0.mux_conf() != spi_pins.0.mux_conf() + || ss_pins.1.mux_conf() != spi_pins.0.mux_conf() + { + return Err(SpiConstructionError::InvalidPinConf); + } + Ok(Self::new_generic_unchecked( + spi_id, + spi.reg_block(), + clocks, + config, + )) + } + + pub fn new_with_three_hw_cs< + Sck: SckPin, + Mosi: MosiPin, + Miso: MisoPin, + Ss0: SsPin, + Ss1: SsPin, + Ss2: SsPin, + >( + spi: impl PsSpi, + clocks: &IoClocks, + config: Config, + spi_pins: (Sck, Mosi, Miso), + ss_pins: (Ss0, Ss1, Ss2), + ) -> Result { + let spi_id = spi.id(); + if spi_id.is_none() { + return Err(InvalidPsSpiError.into()); + } + let spi_id = spi_id.unwrap(); + if Sck::GROUP != Mosi::GROUP + || Sck::GROUP != Miso::GROUP + || Sck::GROUP != Ss0::GROUP + || Sck::GROUP != Ss1::GROUP + || Sck::GROUP != Ss2::GROUP + { + return Err(SpiConstructionError::GroupMissmatch); + } + if Sck::SPI != spi_id + || Mosi::SPI != spi_id + || Miso::SPI != spi_id + || Ss0::SPI != spi_id + || Ss1::SPI != spi_id + || Ss2::SPI != spi_id + { + return Err(SpiConstructionError::PinInvalidForSpiId); + } + if spi_pins.0.mux_conf() != SPI_MUX_CONF + || spi_pins.0.mux_conf() != spi_pins.2.mux_conf() + || spi_pins.1.mux_conf() != spi_pins.2.mux_conf() + || ss_pins.0.mux_conf() != spi_pins.0.mux_conf() + || ss_pins.1.mux_conf() != spi_pins.0.mux_conf() + || ss_pins.2.mux_conf() != spi_pins.2.mux_conf() + { + return Err(SpiConstructionError::InvalidPinConf); + } + Ok(Self::new_generic_unchecked( + spi_id, + spi.reg_block(), + clocks, + config, + )) + } + + pub fn new_generic_unchecked( + id: SpiId, + regs: MmioSpi<'static>, + clocks: &IoClocks, + config: Config, + ) -> Self { + let periph_sel = match id { + SpiId::Spi0 => crate::PeripheralSelect::Spi0, + SpiId::Spi1 => crate::PeripheralSelect::Spi1, + }; + enable_amba_peripheral_clock(periph_sel); + let sclk = clocks.spi_clk() / config.baud_div.div_value() as u32; + let mut spi = Self { + inner: SpiLowLevel { regs, id }, + sclk, + config, + outstanding_rx: false, + }; + spi.reset_and_reconfigure(); + spi + } + + /// Re-configures the SPI peripheral with the initial configuration. + pub fn reconfigure(&mut self) { + self.inner.reconfigure(self.config); + } + + /// [Resets][reset] and [re-configures][Self::reconfigure] the SPI peripheral. + /// + /// This can also be used to reset the FIFOs and the state machine of the SPI. + pub fn reset_and_reconfigure(&mut self) { + reset(self.inner.id()); + self.reconfigure(); + } + + #[inline] + pub fn issue_manual_start_for_manual_cfg(&mut self) { + if self.config.ss_config == SlaveSelectConfig::AutoWithManualStart + || self.config.ss_config == SlaveSelectConfig::ManualWithManualStart + { + self.inner.issue_manual_start(); + } + } + + /// Retrieve SCLK clock frequency currently configured for this SPI. + #[inline] + pub const fn sclk(&self) -> Hertz { + self.sclk + } + + /// Retrieve inner low-level helper. + #[inline] + pub const fn inner(&mut self) -> &mut SpiLowLevel { + &mut self.inner + } + + #[inline] + pub fn regs(&mut self) -> &mut MmioSpi<'static> { + &mut self.inner.regs + } + + fn initial_fifo_fill(&mut self, words: &[u8]) -> usize { + let write_len = core::cmp::min(FIFO_DEPTH, words.len()); + (0..write_len).for_each(|idx| { + self.inner.write_fifo_unchecked(words[idx]); + }); + write_len + } + + fn prepare_generic_blocking_transfer(&mut self, words: &[u8]) -> usize { + // We want to ensure the FIFO is empty for a new transfer. This is the simpler + // implementation for now. + self.flush().unwrap(); + // Write this to 1 in any case to allow polling, defensive programming. + self.inner.regs.write_rx_trig(1); + + // Fill the FIFO with initial data. + let written = self.initial_fifo_fill(words); + + // We assume that the slave select configuration was already performed, but we take + // care of issuing a start if necessary. + self.issue_manual_start_for_manual_cfg(); + written + } +} + +impl embedded_hal::spi::ErrorType for Spi { + type Error = Infallible; +} + +impl embedded_hal::spi::SpiBus for Spi { + fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { + if words.is_empty() { + return Ok(()); + } + // We want to ensure the FIFO is empty for a new transfer. This is the simpler + // implementation for now. + self.flush()?; + // Write this to 1 in any case to allow polling, defensive programming. + self.regs().write_rx_trig(1); + + let mut write_idx = core::cmp::min(FIFO_DEPTH, words.len()); + // Send dummy bytes. + (0..write_idx).for_each(|_| { + self.inner.write_fifo_unchecked(0); + }); + + // We assume that the slave select configuration was already performed, but we take + // care of issuing a start if necessary. + self.issue_manual_start_for_manual_cfg(); + + let mut read_idx = 0; + while read_idx < words.len() { + let status = self.regs().read_isr(); + if status.rx_not_empty() { + words[read_idx] = self.inner.read_fifo_unchecked(); + read_idx += 1; + } + // Continue pumping the FIFO if necesary and possible. + if write_idx < words.len() && !status.tx_full() { + self.inner.write_fifo_unchecked(0); + write_idx += 1; + } + } + + Ok(()) + } + + fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { + if words.is_empty() { + return Ok(()); + } + let mut written = self.prepare_generic_blocking_transfer(words); + let mut read_idx = 0; + + while written < words.len() { + let status = self.regs().read_isr(); + // We empty the FIFO to prevent it filling up completely, as long as we have to write + // bytes + if status.rx_not_empty() { + self.inner.read_fifo_unchecked(); + read_idx += 1; + } + if !status.tx_full() { + self.inner.write_fifo_unchecked(words[written]); + written += 1; + } + } + // We exit once all bytes have been written, so some bytes to read might be outstanding. + // We use the FIFO trigger mechanism to determine when we can read all the remaining bytes. + self.regs().write_rx_trig((words.len() - read_idx) as u32); + self.outstanding_rx = true; + Ok(()) + } + + fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> { + if read.is_empty() { + return Ok(()); + } + let mut write_idx = self.prepare_generic_blocking_transfer(write); + let mut read_idx = 0; + let max_idx = core::cmp::max(write.len(), read.len()); + + let mut writes_finished = write_idx == max_idx; + let mut reads_finished = false; + while !writes_finished || !reads_finished { + let status = self.regs().read_isr(); + if status.rx_not_empty() && !reads_finished { + if read_idx < read.len() { + read[read_idx] = self.inner.read_fifo_unchecked(); + } else { + // Discard the data. + self.inner.read_fifo_unchecked(); + } + read_idx += 1; + } + + if !status.tx_full() && !writes_finished { + if write_idx < write.len() { + self.inner.write_fifo_unchecked(write[write_idx]); + } else { + // Send dummy bytes. + self.inner.write_fifo_unchecked(0); + } + write_idx += 1; + } + writes_finished = write_idx == max_idx; + reads_finished = read_idx == max_idx; + } + + Ok(()) + } + + fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { + if words.is_empty() { + return Ok(()); + } + let mut write_idx = self.prepare_generic_blocking_transfer(words); + let mut read_idx = 0; + + let mut writes_finished = write_idx == words.len(); + let mut reads_finished = false; + while !writes_finished || !reads_finished { + let status = self.inner.read_isr(); + if status.rx_not_empty() && !reads_finished { + words[read_idx] = self.inner.read_fifo_unchecked(); + read_idx += 1; + } + + if !status.tx_full() && !writes_finished { + self.inner.write_fifo_unchecked(words[write_idx]); + write_idx += 1; + } + writes_finished = write_idx == words.len(); + reads_finished = read_idx == words.len(); + } + + Ok(()) + } + + /// Blocking flush implementation. + fn flush(&mut self) -> Result<(), Self::Error> { + if !self.outstanding_rx { + return Ok(()); + } + let rx_trig = self.inner.read_rx_not_empty_threshold(); + while !self.inner.read_isr().rx_not_empty() {} + (0..rx_trig).for_each(|_| { + self.inner.read_fifo_unchecked(); + }); + self.inner.set_rx_fifo_trigger(1).unwrap(); + self.outstanding_rx = false; + Ok(()) + } +} + +pub struct SpiWithHwCs { + pub spi: Spi, + pub cs: ChipSelect, + pub delay: Delay, +} + +impl SpiWithHwCs { + pub fn new(spi: Spi, cs: ChipSelect, delay: Delay) -> Self { + Self { spi, cs, delay } + } + + pub fn release(self) -> Spi { + self.spi + } +} + +impl embedded_hal::spi::ErrorType for SpiWithHwCs { + type Error = Infallible; +} + +impl embedded_hal::spi::SpiDevice for SpiWithHwCs { + fn transaction( + &mut self, + operations: &mut [embedded_hal::spi::Operation<'_, u8>], + ) -> Result<(), Self::Error> { + self.spi.inner.select_hw_cs(self.cs); + for op in operations { + match op { + embedded_hal::spi::Operation::Read(items) => { + self.spi.read(items)?; + } + embedded_hal::spi::Operation::Write(items) => { + self.spi.write(items)?; + } + embedded_hal::spi::Operation::Transfer(read, write) => { + self.spi.transfer(read, write)?; + } + embedded_hal::spi::Operation::TransferInPlace(items) => { + self.spi.transfer_in_place(items)?; + } + embedded_hal::spi::Operation::DelayNs(delay) => { + self.delay.delay_ns(*delay); + } + } + } + self.spi.flush()?; + self.spi.inner.no_hw_cs(); + Ok(()) + } +} + +/// Reset the SPI peripheral using the SLCR reset register for SPI. +/// +/// Please note that this function will interfere with an already configured +/// SPI instance. +#[inline] +pub fn reset(id: SpiId) { + let assert_reset = match id { + SpiId::Spi0 => DualRefAndClockReset::builder() + .with_periph1_ref_rst(false) + .with_periph0_ref_rst(true) + .with_periph1_cpu1x_rst(false) + .with_periph0_cpu1x_rst(true) + .build(), + SpiId::Spi1 => DualRefAndClockReset::builder() + .with_periph1_ref_rst(true) + .with_periph0_ref_rst(false) + .with_periph1_cpu1x_rst(true) + .with_periph0_cpu1x_rst(false) + .build(), + }; + unsafe { + Slcr::with(|regs| { + regs.reset_ctrl().write_spi(assert_reset); + // Keep it in reset for some cycles.. The TMR just mentions some small delay, + // no idea what is meant with that. + for _ in 0..3 { + cortex_ar::asm::nop(); + } + regs.reset_ctrl().write_spi(DualRefAndClockReset::DEFAULT); + }); + } +} + +/// Calculates the largest allowed SPI reference clock divisor. +/// +/// The Zynq7000 SPI peripheral has the following requirement for the SPI reference clock: +/// It must be larger than the CPU 1X clock. Therefore, the divisor used to calculate the reference +/// clock has a maximum value, which can be calculated with this function. +/// +/// [configure_spi_ref_clk] can be used to configure the SPI reference clock with the calculated +/// value. +pub fn calculate_largest_allowed_spi_ref_clk_divisor(clks: &Clocks) -> Option { + let mut slcr = unsafe { Slcr::steal() }; + let spi_clk_ctrl = slcr.regs().clk_ctrl().read_spi_clk_ctrl(); + let div = match spi_clk_ctrl.srcsel() { + zynq7000::slcr::clocks::SrcSelIo::IoPll | zynq7000::slcr::clocks::SrcSelIo::IoPllAlt => { + clks.io_clocks().ref_clk() / clks.arm_clocks().cpu_1x_clk() + } + zynq7000::slcr::clocks::SrcSelIo::ArmPll => { + clks.arm_clocks().ref_clk() / clks.arm_clocks().cpu_1x_clk() + } + zynq7000::slcr::clocks::SrcSelIo::DdrPll => { + clks.ddr_clocks().ref_clk() / clks.arm_clocks().cpu_1x_clk() + } + }; + if div > u6::MAX.value() as u32 { + return None; + } + + Some(u6::new(div as u8)) +} + +pub fn configure_spi_ref_clk(clks: &mut Clocks, divisor: u6) { + let mut slcr = unsafe { Slcr::steal() }; + let spi_clk_ctrl = slcr.regs().clk_ctrl().read_spi_clk_ctrl(); + slcr.modify(|regs| { + regs.clk_ctrl().modify_spi_clk_ctrl(|mut val| { + val.set_divisor(divisor); + val + }); + }); + let new_clk = match spi_clk_ctrl.srcsel() { + zynq7000::slcr::clocks::SrcSelIo::IoPll | zynq7000::slcr::clocks::SrcSelIo::IoPllAlt => { + clks.io_clocks().ref_clk() / divisor.value() as u32 + } + zynq7000::slcr::clocks::SrcSelIo::ArmPll => { + clks.arm_clocks().ref_clk() / divisor.value() as u32 + } + zynq7000::slcr::clocks::SrcSelIo::DdrPll => { + clks.ddr_clocks().ref_clk() / divisor.value() as u32 + } + }; + clks.io_clocks_mut().update_spi_clk(new_clk); +} diff --git a/zynq7000-hal/src/time.rs b/zynq7000-hal/src/time.rs new file mode 100644 index 0000000..9808028 --- /dev/null +++ b/zynq7000-hal/src/time.rs @@ -0,0 +1,26 @@ +//! Time units + +// Frequency based + +/// Hertz +pub type Hertz = fugit::HertzU32; + +/// KiloHertz +pub type KiloHertz = fugit::KilohertzU32; + +/// MegaHertz +pub type MegaHertz = fugit::MegahertzU32; + +// Period based + +/// Seconds +pub type Seconds = fugit::SecsDurationU32; + +/// Milliseconds +pub type Milliseconds = fugit::MillisDurationU32; + +/// Microseconds +pub type Microseconds = fugit::MicrosDurationU32; + +/// Nanoseconds +pub type Nanoseconds = fugit::NanosDurationU32; diff --git a/zynq7000-hal/src/ttc.rs b/zynq7000-hal/src/ttc.rs new file mode 100644 index 0000000..4037c7d --- /dev/null +++ b/zynq7000-hal/src/ttc.rs @@ -0,0 +1,341 @@ +//! Triple-timer counter (TTC) high-level driver. +//! +//! This module also contains support for PWM and output waveform generation. + +use core::convert::Infallible; + +use arbitrary_int::{Number, u3, u4}; +use zynq7000::ttc::{MmioTtc, TTC_0_BASE_ADDR, TTC_1_BASE_ADDR}; + +#[cfg(not(feature = "7z010-7z007s-clg225"))] +use crate::gpio::{Mio16, Mio17, Mio18, Mio19, Mio40, Mio41, Mio42, Mio43}; +use crate::{ + clocks::ArmClocks, + gpio::{IoPeriph, IoPeriphPin, Mio28, Mio29, Mio30, Mio31, MioPin, MuxConf, PinMode}, + time::Hertz, +}; + +/// Each TTC consists of three independent timers/counters. +#[derive(Debug, Copy, Clone)] +pub enum TtcId { + Ttc0 = 0, + Ttc1 = 1, +} + +#[derive(Debug, Copy, Clone)] +pub enum ChannelId { + Ch0 = 0, + Ch1 = 1, + Ch2 = 2, +} + +pub trait PsTtc { + fn reg_block(&self) -> MmioTtc<'static>; + fn id(&self) -> Option; +} + +impl PsTtc for MmioTtc<'static> { + #[inline] + fn reg_block(&self) -> MmioTtc<'static> { + unsafe { self.clone() } + } + + #[inline] + fn id(&self) -> Option { + let base_addr = unsafe { self.ptr() } as usize; + if base_addr == TTC_0_BASE_ADDR { + return Some(TtcId::Ttc0); + } else if base_addr == TTC_1_BASE_ADDR { + return Some(TtcId::Ttc1); + } + None + } +} + +pub const TTC_MUX_CONF: MuxConf = MuxConf::new_with_l3(u3::new(0b110)); + +pub trait ClockInPin: IoPeriphPin { + const ID: TtcId; +} + +pub trait WaveOutPin: IoPeriphPin { + const ID: TtcId; +} + +macro_rules! into_ttc { + ($($Mio:ident),+) => { + $( + impl MioPin<$Mio, M> { + /// Convert the pin into a TTC pin by configuring the pin routing via the + /// MIO multiplexer bits. + pub fn into_ttck(self) -> MioPin<$Mio, IoPeriph> { + self.into_io_periph(TTC_MUX_CONF, None) + } + } + )+ + }; +} + +#[cfg(not(feature = "7z010-7z007s-clg225"))] +into_ttc!(Mio16, Mio17, Mio18, Mio19, Mio40, Mio41, Mio42, Mio43); +into_ttc!(Mio28, Mio29, Mio30, Mio31); + +pub struct Ttc { + pub ch0: TtcChannel, + pub ch1: TtcChannel, + pub ch2: TtcChannel, +} + +impl Ttc { + /// Create a new TTC instance. The passed TTC peripheral instance MUST point to a valid + /// processing system TTC peripheral. + /// + /// Returns [None] if the passed peripheral block does not have a valid PS TTC address. + pub fn new(ps_ttc: impl PsTtc) -> Option { + ps_ttc.id()?; + let regs = ps_ttc.reg_block(); + let ch0 = TtcChannel { + regs: unsafe { regs.clone() }, + id: ChannelId::Ch0, + }; + let ch1 = TtcChannel { + regs: unsafe { regs.clone() }, + id: ChannelId::Ch1, + }; + let ch2 = TtcChannel { + regs, + id: ChannelId::Ch2, + }; + Some(Self { ch0, ch1, ch2 }) + } +} + +pub struct TtcChannel { + regs: MmioTtc<'static>, + id: ChannelId, +} + +impl TtcChannel { + pub fn regs_mut(&mut self) -> &mut MmioTtc<'static> { + &mut self.regs + } + + #[inline] + pub fn read_counter(&self) -> u16 { + self.regs + .read_current_counter(self.id as usize) + .unwrap() + .count() + } + + pub fn id(&self) -> ChannelId { + self.id + } +} + +#[derive(Debug, thiserror::Error)] +#[error("invalid TTC pin configuration")] +pub struct InvalidTtcPinConfigError(pub MuxConf); + +#[derive(Debug, thiserror::Error)] +#[error("frequency is zero")] +pub struct FrequencyIsZeroError; + +#[derive(Debug, thiserror::Error)] +pub enum TtcConstructionError { + #[error("invalid TTC pin configuration")] + InvalidTtcPinConfig(#[from] InvalidTtcPinConfigError), + #[error("frequency is zero")] + FrequencyIsZero(#[from] FrequencyIsZeroError), +} + +pub fn calculate_prescaler_reg_and_interval_ticks( + mut ref_clk: Hertz, + freq: Hertz, +) -> (Option, u16) { + // TODO: Can this be optimized? + let mut prescaler_reg: Option = None; + let mut tick_val = ref_clk / freq; + while tick_val > u16::MAX as u32 { + ref_clk /= 2; + if let Some(prescaler_reg) = prescaler_reg { + // TODO: Better error handling for this case? Can this even happen? + if prescaler_reg.value() == u4::MAX.value() { + break; + } else { + prescaler_reg.checked_add(u4::new(1)); + } + } else { + prescaler_reg = Some(u4::new(0)); + } + tick_val = ref_clk / freq; + } + (prescaler_reg, tick_val as u16) +} + +pub struct Pwm { + channel: TtcChannel, + ref_clk: Hertz, +} + +impl Pwm { + /// Create a new PWM instance which uses the CPU 1x clock as the clock source and also uses + /// a MIO output pin for the waveform output. + pub fn new_with_cpu_clk_and_mio_waveout( + channel: TtcChannel, + arm_clocks: &ArmClocks, + freq: Hertz, + wave_out: impl WaveOutPin, + ) -> Result { + if wave_out.mux_conf() != TTC_MUX_CONF { + return Err(InvalidTtcPinConfigError(wave_out.mux_conf()).into()); + } + Ok(Self::new_with_cpu_clk(channel, arm_clocks, freq)?) + } + + /// Create a new PWM instance which uses the CPU 1x clock as the clock source. + pub fn new_with_cpu_clk( + channel: TtcChannel, + arm_clocks: &ArmClocks, + freq: Hertz, + ) -> Result { + Self::new_generic(channel, arm_clocks.cpu_1x_clk(), freq) + } + + /// Create a new PWM instance based on a reference clock source. + pub fn new_generic( + channel: TtcChannel, + ref_clk: Hertz, + freq: Hertz, + ) -> Result { + if freq.raw() == 0 { + return Err(FrequencyIsZeroError); + } + let (prescaler_reg, tick_val) = calculate_prescaler_reg_and_interval_ticks(ref_clk, freq); + let id = channel.id() as usize; + let mut pwm = Self { channel, ref_clk }; + pwm.set_up_and_configure_pwm(id, prescaler_reg, tick_val); + Ok(pwm) + } + + /// Set a new frequency for the PWM cycle. + /// + /// This resets the duty cycle to 0%. + pub fn set_frequency(&mut self, freq: Hertz) -> Result<(), FrequencyIsZeroError> { + if freq.raw() == 0 { + return Err(FrequencyIsZeroError); + } + let id = self.channel.id() as usize; + let (prescaler_reg, tick_val) = + calculate_prescaler_reg_and_interval_ticks(self.ref_clk, freq); + self.set_up_and_configure_pwm(id, prescaler_reg, tick_val); + Ok(()) + } + + #[inline] + pub fn ttc_channel_mut(&mut self) -> &mut TtcChannel { + &mut self.channel + } + + #[inline] + pub fn max_duty_cycle(&self) -> u16 { + self.channel + .regs + .read_interval_value(self.channel.id() as usize) + .unwrap() + .value() + } + + #[inline] + pub fn set_duty_cycle(&mut self, duty: u16) { + let id = self.channel.id() as usize; + self.channel + .regs + .modify_cnt_ctrl(id, |mut val| { + val.set_disable(true); + val + }) + .unwrap(); + self.channel + .regs + .write_match_value_0( + self.channel.id() as usize, + zynq7000::ttc::RwValue::new_with_raw_value(duty as u32), + ) + .unwrap(); + self.channel + .regs + .modify_cnt_ctrl(id, |mut val| { + val.set_disable(false); + val.set_reset(true); + val + }) + .unwrap(); + } + + fn set_up_and_configure_pwm(&mut self, id: usize, prescaler_reg: Option, tick_val: u16) { + // Disable the counter first. + self.channel + .regs + .write_cnt_ctrl(id, zynq7000::ttc::CounterControl::new_with_raw_value(1)) + .unwrap(); + + // Clock configuration + self.channel + .regs + .write_clk_cntr( + id, + zynq7000::ttc::ClockControl::builder() + .with_ext_clk_edge(false) + .with_clk_src(zynq7000::ttc::ClockSource::Pclk) + .with_prescaler(prescaler_reg.unwrap_or(u4::new(0))) + .with_prescale_enable(prescaler_reg.is_some()) + .build(), + ) + .unwrap(); + self.channel + .regs + .write_interval_value( + id, + zynq7000::ttc::RwValue::new_with_raw_value(tick_val as u32), + ) + .unwrap(); + // Corresponds to duty cycle 0. + self.channel + .regs + .write_match_value_0(id, zynq7000::ttc::RwValue::new_with_raw_value(0)) + .unwrap(); + self.channel + .regs + .write_cnt_ctrl( + id, + zynq7000::ttc::CounterControl::builder() + .with_wave_polarity(zynq7000::ttc::WavePolarity::LowToHighOnMatch1) + .with_wave_enable_n(zynq7000::ttc::WaveEnable::Enable) + .with_reset(true) + .with_match_enable(true) + .with_decrementing(false) + .with_mode(zynq7000::ttc::Mode::Interval) + .with_disable(false) + .build(), + ) + .unwrap(); + } +} + +impl embedded_hal::pwm::ErrorType for Pwm { + type Error = Infallible; +} + +impl embedded_hal::pwm::SetDutyCycle for Pwm { + #[inline] + fn max_duty_cycle(&self) -> u16 { + self.max_duty_cycle() + } + + #[inline] + fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { + self.set_duty_cycle(duty); + Ok(()) + } +} diff --git a/zynq7000-hal/src/uart/mod.rs b/zynq7000-hal/src/uart/mod.rs new file mode 100644 index 0000000..273afe8 --- /dev/null +++ b/zynq7000-hal/src/uart/mod.rs @@ -0,0 +1,739 @@ +//! # UART module. +//! +//! Support for the processing system UARTs. +use core::convert::Infallible; + +use arbitrary_int::u3; +use libm::round; +use zynq7000::{ + slcr::reset::DualRefAndClockReset, + uart::{ + BaudRateDiv, Baudgen, ChMode, ClkSel, FifoTrigger, InterruptControl, MmioUart, Mode, + UART_0_BASE, UART_1_BASE, + }, +}; + +use crate::{ + enable_amba_peripheral_clock, + gpio::{ + IoPeriph, IoPeriphPin, Mio8, Mio9, Mio10, Mio11, Mio12, Mio13, Mio14, Mio15, Mio28, Mio29, + Mio30, Mio31, Mio32, Mio33, Mio34, Mio35, Mio36, Mio37, Mio38, Mio39, Mio48, Mio49, Mio52, + Mio53, MioPin, MuxConf, PinMode, + }, + slcr::Slcr, +}; + +#[cfg(not(feature = "7z010-7z007s-clg225"))] +use crate::gpio::{ + Mio16, Mio17, Mio18, Mio19, Mio20, Mio21, Mio22, Mio23, Mio24, Mio25, Mio26, Mio27, Mio40, + Mio41, Mio42, Mio43, Mio44, Mio45, Mio46, Mio47, Mio50, Mio51, +}; + +use super::{clocks::IoClocks, time::Hertz}; + +pub mod tx; +pub use tx::*; + +pub mod tx_async; +pub use tx_async::*; + +pub mod rx; +pub use rx::*; + +pub const FIFO_DEPTH: usize = 64; +pub const DEFAULT_RX_TRIGGER_LEVEL: u8 = 32; +pub const UART_MUX_CONF: MuxConf = MuxConf::new_with_l3(u3::new(0b111)); + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum UartId { + Uart0 = 0, + Uart1 = 1, +} + +pub trait PsUart { + fn reg_block(&self) -> MmioUart<'static>; + fn uart_id(&self) -> Option; +} + +impl PsUart for MmioUart<'static> { + #[inline] + fn reg_block(&self) -> MmioUart<'static> { + unsafe { self.clone() } + } + + fn uart_id(&self) -> Option { + let base_addr = unsafe { self.ptr() } as usize; + if base_addr == UART_0_BASE { + return Some(UartId::Uart0); + } else if base_addr == UART_1_BASE { + return Some(UartId::Uart1); + } + None + } +} + +impl UartId { + /// Unsafely steal a peripheral MMIO block for the given UART. + /// + /// # Safety + /// + /// Circumvents ownership and safety guarantees by the HAL. + pub const unsafe fn regs(&self) -> MmioUart<'static> { + match self { + UartId::Uart0 => unsafe { zynq7000::uart::Uart::new_mmio_fixed_0() }, + UartId::Uart1 => unsafe { zynq7000::uart::Uart::new_mmio_fixed_1() }, + } + } +} + +pub trait RxPin { + const UART_IDX: UartId; +} +pub trait TxPin { + const UART_IDX: UartId; +} + +pub trait UartPins {} + +#[derive(Debug, thiserror::Error)] +#[error("divisor is zero")] +pub struct DivisorZero; + +macro_rules! pin_pairs { + ($UartPeriph:path, ($( [$(#[$meta:meta], )? $TxMio:ident, $RxMio:ident] ),+ $(,)? )) => { + $( + $( #[$meta] )? + impl TxPin for MioPin<$TxMio, IoPeriph> { + const UART_IDX: UartId = $UartPeriph; + } + + + $( #[$meta] )? + impl RxPin for MioPin<$RxMio, IoPeriph> { + const UART_IDX: UartId = $UartPeriph; + } + + impl UartPins for (MioPin<$TxMio, IoPeriph>, MioPin<$RxMio, IoPeriph>) {} + )+ + }; +} + +macro_rules! impl_into_uart { + (($($Mio:ident),+)) => { + $( + impl MioPin<$Mio, M> { + pub fn into_uart(self) -> MioPin<$Mio, IoPeriph> { + self.into_io_periph(UART_MUX_CONF, None) + } + } + )+ + }; +} + +impl_into_uart!(( + Mio10, Mio11, Mio15, Mio14, Mio31, Mio30, Mio35, Mio34, Mio39, Mio38, Mio8, Mio9, Mio12, Mio13, + Mio28, Mio29, Mio32, Mio33, Mio36, Mio37, Mio48, Mio49, Mio52, Mio53 +)); + +#[cfg(not(feature = "7z010-7z007s-clg225"))] +impl_into_uart!(( + Mio19, Mio18, Mio23, Mio22, Mio43, Mio42, Mio47, Mio46, Mio51, Mio50, Mio16, Mio17, Mio20, + Mio21, Mio24, Mio25, Mio40, Mio41, Mio44, Mio45 +)); + +pin_pairs!( + UartId::Uart0, + ( + [Mio11, Mio10], + [Mio15, Mio14], + [#[cfg(not(feature ="7z010-7z007s-clg225"))], Mio19, Mio18], + [#[cfg(not(feature ="7z010-7z007s-clg225"))], Mio23, Mio22], + [#[cfg(not(feature ="7z010-7z007s-clg225"))], Mio27, Mio26], + [Mio31, Mio30], + [Mio35, Mio34], + [Mio39, Mio38], + [#[cfg(not(feature ="7z010-7z007s-clg225"))], Mio43, Mio42], + [#[cfg(not(feature ="7z010-7z007s-clg225"))], Mio47, Mio46], + [#[cfg(not(feature ="7z010-7z007s-clg225"))], Mio51, Mio50], + ) +); + +pin_pairs!( + UartId::Uart1, + ( + [Mio8, Mio9], + [Mio12, Mio13], + [#[cfg(not(feature ="7z010-7z007s-clg225"))], Mio16, Mio17], + [#[cfg(not(feature ="7z010-7z007s-clg225"))], Mio20, Mio21], + [#[cfg(not(feature ="7z010-7z007s-clg225"))], Mio24, Mio25], + [Mio28, Mio29], + [Mio32, Mio33], + [Mio36, Mio37], + [#[cfg(not(feature ="7z010-7z007s-clg225"))], Mio40, Mio41], + [#[cfg(not(feature ="7z010-7z007s-clg225"))], Mio44, Mio45], + [Mio48, Mio49], + [Mio52, Mio53], + ) +); + +/// Based on values provided by the vendor library. +pub const MAX_BAUD_RATE: u32 = 6240000; +/// Based on values provided by the vendor library. +pub const MIN_BAUD_RATE: u32 = 110; + +#[derive(Debug, Default, Clone, Copy)] +pub enum Parity { + Even, + Odd, + #[default] + None, +} + +#[derive(Debug, Default, Clone, Copy)] +pub enum Stopbits { + #[default] + One, + OnePointFive, + Two, +} + +#[derive(Debug, Default, Clone, Copy)] +pub enum CharLen { + SixBits, + SevenBits, + #[default] + EightBits, +} + +#[derive(Debug, Clone, Copy)] +pub struct ClkConfigRaw { + cd: u16, + bdiv: u8, +} + +#[cfg(feature = "alloc")] +pub fn calculate_viable_configs( + mut uart_clk: Hertz, + clk_sel: ClkSel, + target_baud: u32, +) -> alloc::vec::Vec<(ClkConfigRaw, f64)> { + let mut viable_cfgs = alloc::vec::Vec::new(); + if clk_sel == ClkSel::UartRefClkDiv8 { + uart_clk /= 8; + } + let mut current_clk_config = ClkConfigRaw::new(0, 0); + for bdiv in 4..u8::MAX { + let cd = + round(uart_clk.raw() as f64 / ((bdiv as u32 + 1) as f64 * target_baud as f64)) as u64; + if cd > u16::MAX as u64 { + continue; + } + current_clk_config.cd = cd as u16; + current_clk_config.bdiv = bdiv; + let baud = current_clk_config.actual_baud(uart_clk); + let error = ((baud - target_baud as f64).abs() / target_baud as f64) * 100.0; + if error < MAX_BAUDERROR_RATE as f64 { + viable_cfgs.push((current_clk_config, error)); + } + } + + viable_cfgs +} + +/// Calculate the clock configuration for the smallest error to reach the desired target +/// baud rate. +/// +/// You can also use [calculate_viable_configs] to get a list of all viable configurations. +pub fn calculate_raw_baud_cfg_smallest_error( + mut uart_clk: Hertz, + clk_sel: ClkSel, + target_baud: u32, +) -> Result<(ClkConfigRaw, f64), DivisorZero> { + if target_baud == 0 { + return Err(DivisorZero); + } + if clk_sel == ClkSel::UartRefClkDiv8 { + uart_clk /= 8; + } + let mut current_clk_config = ClkConfigRaw::default(); + let mut best_clk_config = ClkConfigRaw::default(); + let mut smallest_error: f64 = 100.0; + for bdiv in 4..u8::MAX { + let cd = + round(uart_clk.raw() as f64 / ((bdiv as u32 + 1) as f64 * target_baud as f64)) as u64; + if cd > u16::MAX as u64 { + continue; + } + current_clk_config.cd = cd as u16; + current_clk_config.bdiv = bdiv; + let baud = current_clk_config.actual_baud(uart_clk); + let error = ((baud - target_baud as f64).abs() / target_baud as f64) * 100.0; + if error < smallest_error { + best_clk_config = current_clk_config; + smallest_error = error; + } + } + + Ok((best_clk_config, smallest_error)) +} + +impl ClkConfigRaw { + #[inline] + pub const fn new(cd: u16, bdiv: u8) -> Result { + if cd == 0 { + return Err(DivisorZero); + } + Ok(ClkConfigRaw { cd, bdiv }) + } + + /// Auto-calculates the best clock configuration settings for the target baudrate. + /// + /// This function assumes [ClkSel::UartRefClk] as the clock source. It returns a tuple + /// where the first entry is the clock configuration while the second entry is the associated + /// baud error from 0.0 to 1.0. It is recommended to keep this error below 2-3 %. + pub fn new_autocalc_with_error( + io_clks: &IoClocks, + target_baud: u32, + ) -> Result<(Self, f64), DivisorZero> { + Self::new_autocalc_generic(io_clks, ClkSel::UartRefClk, target_baud) + } + + pub fn new_autocalc_generic( + io_clks: &IoClocks, + clk_sel: ClkSel, + target_baud: u32, + ) -> Result<(Self, f64), DivisorZero> { + Self::new_autocalc_with_raw_clk(io_clks.uart_clk(), clk_sel, target_baud) + } + + pub fn new_autocalc_with_raw_clk( + uart_clk: Hertz, + clk_sel: ClkSel, + target_baud: u32, + ) -> Result<(Self, f64), DivisorZero> { + calculate_raw_baud_cfg_smallest_error(uart_clk, clk_sel, target_baud) + } + + #[inline] + pub const fn cd(&self) -> u16 { + self.cd + } + + #[inline] + pub const fn bdiv(&self) -> u8 { + self.bdiv + } + + #[inline] + pub fn rounded_baud(&self, sel_clk: Hertz) -> u32 { + round(self.actual_baud(sel_clk)) as u32 + } + + #[inline] + pub fn actual_baud(&self, sel_clk: Hertz) -> f64 { + sel_clk.raw() as f64 / (self.cd as f64 * (self.bdiv + 1) as f64) + } +} + +impl Default for ClkConfigRaw { + #[inline] + fn default() -> Self { + ClkConfigRaw::new(1, 0).unwrap() + } +} + +#[derive(Debug)] +pub struct UartConfig { + clk_config: ClkConfigRaw, + chmode: ChMode, + parity: Parity, + stopbits: Stopbits, + chrl: CharLen, + clk_sel: ClkSel, +} + +impl UartConfig { + pub fn new_with_clk_config(clk_config: ClkConfigRaw) -> Self { + Self::new( + clk_config, + ChMode::default(), + Parity::default(), + Stopbits::default(), + CharLen::default(), + ClkSel::default(), + ) + } + + #[inline] + pub const fn new( + clk_config: ClkConfigRaw, + chmode: ChMode, + parity: Parity, + stopbits: Stopbits, + chrl: CharLen, + clk_sel: ClkSel, + ) -> Self { + UartConfig { + clk_config, + chmode, + parity, + stopbits, + chrl, + clk_sel, + } + } + + #[inline] + pub const fn raw_clk_config(&self) -> ClkConfigRaw { + self.clk_config + } + + #[inline] + pub const fn chmode(&self) -> ChMode { + self.chmode + } + + #[inline] + pub const fn parity(&self) -> Parity { + self.parity + } + + #[inline] + pub const fn stopbits(&self) -> Stopbits { + self.stopbits + } + + #[inline] + pub const fn chrl(&self) -> CharLen { + self.chrl + } + + #[inline] + pub const fn clksel(&self) -> ClkSel { + self.clk_sel + } +} + +// TODO: Impl Debug +pub struct Uart { + rx: Rx, + tx: Tx, + cfg: UartConfig, +} + +#[derive(Debug, thiserror::Error)] +#[error("invalid UART ID")] +pub struct InvalidPsUart; + +#[derive(Debug, thiserror::Error)] +pub enum UartConstructionError { + #[error("invalid UART ID")] + InvalidPsUart(#[from] InvalidPsUart), + #[error("missmatch between pins index and passed index")] + IdxMissmatch, + #[error("invalid pin mux conf for UART")] + InvalidMuxConf(MuxConf), +} + +impl Uart { + /// This is the constructor to use the PS UART with EMIO pins to route the UART into the PL + /// or expose them via the PL package pins. + /// + /// A valid PL design which routes the UART pins through into the PL must be used for this to + /// work. + pub fn new_with_emio(uart: impl PsUart, cfg: UartConfig) -> Result { + if uart.uart_id().is_none() { + return Err(InvalidPsUart); + } + Ok(Self::new_generic_unchecked( + uart.reg_block(), + uart.uart_id().unwrap(), + cfg, + )) + } + + /// This is the constructor to use the PS UART with MIO pins. + pub fn new_with_mio( + uart: impl PsUart, + cfg: UartConfig, + pins: (TxPinI, RxPinI), + ) -> Result + where + (TxPinI, RxPinI): UartPins, + { + let id = uart.uart_id(); + if id.is_none() { + return Err(InvalidPsUart.into()); + } + if id.unwrap() != TxPinI::UART_IDX || id.unwrap() != RxPinI::UART_IDX { + return Err(UartConstructionError::IdxMissmatch); + } + if pins.0.mux_conf() != UART_MUX_CONF { + return Err(UartConstructionError::InvalidMuxConf(pins.0.mux_conf())); + } + if pins.1.mux_conf() != UART_MUX_CONF { + return Err(UartConstructionError::InvalidMuxConf(pins.1.mux_conf())); + } + Ok(Self::new_generic_unchecked( + uart.reg_block(), + id.unwrap(), + cfg, + )) + } + + /// This is the generic constructor used by all other constructors. + /// + /// It does not do any pin checks and resource control. It is recommended to use the other + /// constructors instead. + pub fn new_generic_unchecked( + mut reg_block: MmioUart<'static>, + uart_id: UartId, + cfg: UartConfig, + ) -> Uart { + let periph_sel = match uart_id { + UartId::Uart0 => crate::PeripheralSelect::Uart0, + UartId::Uart1 => crate::PeripheralSelect::Uart1, + }; + enable_amba_peripheral_clock(periph_sel); + reset(uart_id); + reg_block.modify_cr(|mut v| { + v.set_tx_dis(true); + v.set_rx_dis(true); + v + }); + // Disable all interrupts. + reg_block.write_idr(InterruptControl::new_with_raw_value(0xFFFF_FFFF)); + let mode = Mode::builder() + .with_chmode(cfg.chmode) + .with_nbstop(match cfg.stopbits { + Stopbits::One => zynq7000::uart::Stopbits::One, + Stopbits::OnePointFive => zynq7000::uart::Stopbits::OnePointFive, + Stopbits::Two => zynq7000::uart::Stopbits::Two, + }) + .with_par(match cfg.parity { + Parity::Even => zynq7000::uart::Parity::Even, + Parity::Odd => zynq7000::uart::Parity::Odd, + Parity::None => zynq7000::uart::Parity::NoParity, + }) + .with_chrl(match cfg.chrl { + CharLen::SixBits => zynq7000::uart::Chrl::SixBits, + CharLen::SevenBits => zynq7000::uart::Chrl::SevenBits, + CharLen::EightBits => zynq7000::uart::Chrl::EightBits, + }) + .with_clksel(cfg.clk_sel) + .build(); + reg_block.write_mr(mode); + reg_block.write_baudgen( + Baudgen::builder() + .with_cd(cfg.raw_clk_config().cd()) + .build(), + ); + reg_block.write_baud_rate_div( + BaudRateDiv::builder() + .with_bdiv(cfg.raw_clk_config().bdiv()) + .build(), + ); + // Soft reset for both TX and RX. + reg_block.modify_cr(|mut v| { + v.set_tx_rst(true); + v.set_rx_rst(true); + v + }); + + // Write default value. + reg_block.write_rx_fifo_trigger(FifoTrigger::new_with_raw_value( + DEFAULT_RX_TRIGGER_LEVEL as u32, + )); + + // Enable TX and RX. + reg_block.modify_cr(|mut v| { + v.set_tx_dis(false); + v.set_rx_dis(false); + v.set_tx_en(true); + v.set_rx_en(true); + v + }); + + Uart { + rx: Rx { + regs: unsafe { reg_block.clone() }, + }, + tx: Tx { + regs: reg_block, + idx: uart_id, + }, + cfg, + } + } + + #[inline] + pub fn set_mode(&mut self, mode: ChMode) { + self.regs().modify_mr(|mut mr| { + mr.set_chmode(mode); + mr + }); + } + + #[inline] + pub const fn regs(&mut self) -> &mut MmioUart<'static> { + &mut self.rx.regs + } + + #[inline] + pub const fn cfg(&self) -> &UartConfig { + &self.cfg + } + + #[inline] + pub const fn split(self) -> (Tx, Rx) { + (self.tx, self.rx) + } +} + +impl embedded_hal_nb::serial::ErrorType for Uart { + type Error = Infallible; +} + +impl embedded_hal_nb::serial::Write for Uart { + #[inline] + fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { + self.tx.write(word) + } + + fn flush(&mut self) -> nb::Result<(), Self::Error> { + self.tx.flush() + } +} + +impl embedded_hal_nb::serial::Read for Uart { + /// Read one byte from the FIFO. + /// + /// This operation is infallible because pulling an available byte from the FIFO + /// always succeeds. If you want to be informed about RX errors, you should look at the + /// non-blocking API using interrupts, which also tracks the RX error bits. + #[inline] + fn read(&mut self) -> nb::Result { + self.rx.read() + } +} + +impl embedded_io::ErrorType for Uart { + type Error = Infallible; +} + +impl embedded_io::Write for Uart { + fn write(&mut self, buf: &[u8]) -> Result { + self.tx.write(buf) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + self.tx.flush() + } +} + +impl embedded_io::Read for Uart { + fn read(&mut self, buf: &mut [u8]) -> Result { + self.rx.read(buf) + } +} + +/// Reset the UART peripheral using the SLCR reset register for UART. +/// +/// Please note that this function will interfere with an already configured +/// UART instance. +#[inline] +pub fn reset(id: UartId) { + let assert_reset = match id { + UartId::Uart0 => DualRefAndClockReset::builder() + .with_periph1_ref_rst(false) + .with_periph0_ref_rst(true) + .with_periph1_cpu1x_rst(false) + .with_periph0_cpu1x_rst(true) + .build(), + UartId::Uart1 => DualRefAndClockReset::builder() + .with_periph1_ref_rst(true) + .with_periph0_ref_rst(false) + .with_periph1_cpu1x_rst(true) + .with_periph0_cpu1x_rst(false) + .build(), + }; + unsafe { + Slcr::with(|regs| { + regs.reset_ctrl().write_uart(assert_reset); + // Keep it in reset for one cycle.. not sure if this is necessary. + cortex_ar::asm::nop(); + regs.reset_ctrl().write_uart(DualRefAndClockReset::DEFAULT); + }); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use approx::abs_diff_eq; + use fugit::HertzU32; + use zynq7000::uart::ClkSel; + + const REF_UART_CLK: HertzU32 = HertzU32::from_raw(50_000_000); + const REF_UART_CLK_DIV_8: HertzU32 = HertzU32::from_raw(6_250_000); + + #[test] + fn test_error_calc_0() { + // Baud 600 + let cfg_0 = ClkConfigRaw::new(10417, 7).unwrap(); + let actual_baud_0 = cfg_0.actual_baud(REF_UART_CLK); + assert!(abs_diff_eq!(actual_baud_0, 599.980, epsilon = 0.01)); + } + + #[test] + fn test_error_calc_1() { + // Baud 9600 + let cfg = ClkConfigRaw::new(81, 7).unwrap(); + let actual_baud = cfg.actual_baud(REF_UART_CLK_DIV_8); + assert!(abs_diff_eq!(actual_baud, 9645.061, epsilon = 0.01)); + } + + #[test] + fn test_error_calc_2() { + // Baud 9600 + let cfg = ClkConfigRaw::new(651, 7).unwrap(); + let actual_baud = cfg.actual_baud(REF_UART_CLK); + assert!(abs_diff_eq!(actual_baud, 9600.614, epsilon = 0.01)); + } + + #[test] + fn test_error_calc_3() { + // Baud 28800 + let cfg = ClkConfigRaw::new(347, 4).unwrap(); + let actual_baud = cfg.actual_baud(REF_UART_CLK); + assert!(abs_diff_eq!(actual_baud, 28818.44, epsilon = 0.01)); + } + + #[test] + fn test_error_calc_4() { + // Baud 921600 + let cfg = ClkConfigRaw::new(9, 5).unwrap(); + let actual_baud = cfg.actual_baud(REF_UART_CLK); + assert!(abs_diff_eq!(actual_baud, 925925.92, epsilon = 0.01)); + } + + #[test] + fn test_best_calc_0() { + let result = ClkConfigRaw::new_autocalc_with_raw_clk(REF_UART_CLK, ClkSel::UartRefClk, 600); + assert!(result.is_ok()); + let (cfg, _error) = result.unwrap(); + assert_eq!(cfg.cd(), 499); + assert_eq!(cfg.bdiv(), 166); + } + + #[test] + #[cfg(feature = "alloc")] + fn test_viable_config_calculation() { + let cfgs = calculate_viable_configs(REF_UART_CLK, ClkSel::UartRefClk, 115200); + assert!( + cfgs.iter() + .find(|(cfg, _error)| { cfg.cd() == 62 && cfg.bdiv() == 6 }) + .is_some() + ); + } +} diff --git a/zynq7000-hal/src/uart/rx.rs b/zynq7000-hal/src/uart/rx.rs new file mode 100644 index 0000000..3702676 --- /dev/null +++ b/zynq7000-hal/src/uart/rx.rs @@ -0,0 +1,249 @@ +use core::convert::Infallible; + +use arbitrary_int::Number; +use zynq7000::uart::{InterruptControl, InterruptStatus, MmioUart}; + +use super::FIFO_DEPTH; + +pub struct Rx { + pub(crate) regs: MmioUart<'static>, +} +// TODO: Remove once this is impelemnted for MmioUart +unsafe impl Send for Rx {} + +#[derive(Debug, Default, Clone, Copy)] +pub struct RxErrors { + framing: bool, + overrun: bool, + parity: bool, +} + +impl RxErrors { + #[inline] + pub const fn framing(&self) -> bool { + self.framing + } + #[inline] + pub const fn overrun(&self) -> bool { + self.overrun + } + #[inline] + pub const fn parity(&self) -> bool { + self.parity + } +} + +#[derive(Debug, Default)] +pub struct RxInterruptResult { + read_bytes: usize, + errors: Option, +} + +impl RxInterruptResult { + pub fn read_bytes(&self) -> usize { + self.read_bytes + } + + pub fn errors(&self) -> Option { + self.errors + } +} + +impl Rx { + #[inline] + pub fn read_fifo(&mut self) -> nb::Result { + if self.regs.read_sr().rx_empty() { + return Err(nb::Error::WouldBlock); + } + Ok(self.regs.read_fifo().fifo()) + } + + #[inline(always)] + pub fn read_fifo_unchecked(&mut self) -> u8 { + self.regs.read_fifo().fifo() + } + + /// Write the receiver timeout value. + /// + /// A value of 0 will disable the receiver timeout. + /// Otherwise, the 10-bit counter used by the receiver timeout mechanism of the UART will + /// load this value for the upper 8 bits on a reload. The counter is clocked by the UART + /// bit clock, so this value times 4 is the number of UART clock ticks until a timeout occurs. + #[inline] + pub fn set_rx_timeout_value(&mut self, rto: u8) { + self.regs.write_rx_tout(rto as u32); + } + + #[inline] + pub fn soft_reset(&mut self) { + self.regs.modify_cr(|mut cr| { + cr.set_rx_rst(true); + cr + }); + while self.regs.read_cr().rx_rst() {} + } + + /// Helper function to start the interrupt driven reception of data. + /// + /// This function will perform a soft-reset, clear RX related interrupts and then enable + /// all relevant interrupts for the RX side of the UART. These steps are recommended to have + /// a glitch-free start of the interrupt driven reception. + /// + /// This should be called once at system start-up. After that, you only need to call + /// [Self::on_interrupt] in the interrupt handler for the UART peripheral. + pub fn start_interrupt_driven_reception(&mut self) { + self.soft_reset(); + self.clear_interrupts(); + self.enable_interrupts(); + } + + /// Enables all interrupts relevant for the RX side of the UART. + /// + /// It is recommended to also clear all interrupts immediately after enabling them. + #[inline] + pub fn enable_interrupts(&mut self) { + self.regs.write_ier( + InterruptControl::builder() + .with_tx_over(false) + .with_tx_near_full(false) + .with_tx_trig(false) + .with_rx_dms(false) + .with_rx_timeout(true) + .with_rx_parity(true) + .with_rx_framing(true) + .with_rx_over(true) + .with_tx_full(false) + .with_tx_empty(false) + .with_rx_full(true) + .with_rx_empty(false) + .with_rx_trg(true) + .build(), + ); + } + + pub fn on_interrupt( + &mut self, + buf: &mut [u8; FIFO_DEPTH], + reset_rx_timeout: bool, + ) -> RxInterruptResult { + let mut result = RxInterruptResult::default(); + let imr = self.regs.read_imr(); + if !imr.rx_full() + && !imr.rx_trg() + && !imr.rx_parity() + && !imr.rx_framing() + && !imr.rx_over() + && !imr.rx_timeout() + { + return result; + } + let isr = self.regs.read_isr(); + if isr.rx_full() { + // Read all bytes in the full RX fifo. + for byte in buf.iter_mut() { + *byte = self.read_fifo_unchecked(); + } + result.read_bytes = FIFO_DEPTH; + } else if isr.rx_trg() { + // It is guaranteed that we can read the FIFO level amount of data + let fifo_trigger = self.regs.read_rx_fifo_trigger().trig().as_usize(); + (0..fifo_trigger).for_each(|i| { + buf[i] = self.read_fifo_unchecked(); + }); + result.read_bytes = fifo_trigger; + } + // Read everything else that is available, as long as there is space left. + while result.read_bytes < buf.len() { + if let Ok(byte) = self.read_fifo() { + buf[result.read_bytes] = byte; + result.read_bytes += 1; + } else { + break; + } + } + // Handle error events. + if isr.rx_parity() || isr.rx_framing() || isr.rx_over() { + result.errors = Some(RxErrors { + framing: isr.rx_framing(), + overrun: isr.rx_over(), + parity: isr.rx_parity(), + }); + } + // Handle timeout event. + if isr.rx_timeout() && reset_rx_timeout { + self.regs.modify_cr(|mut cr| { + cr.set_rstto(true); + cr + }); + } + self.clear_interrupts(); + result + } + + // This clears all RX related interrupts. + #[inline] + pub fn clear_interrupts(&mut self) { + self.regs.write_isr( + InterruptStatus::builder() + .with_tx_over(false) + .with_tx_near_full(false) + .with_tx_trig(false) + .with_rx_dms(true) + .with_rx_timeout(true) + .with_rx_parity(true) + .with_rx_framing(true) + .with_rx_over(true) + .with_tx_full(false) + .with_tx_empty(false) + .with_rx_full(true) + .with_rx_empty(true) + .with_rx_trg(true) + .build(), + ); + } +} + +impl embedded_hal_nb::serial::ErrorType for Rx { + type Error = Infallible; +} + +impl embedded_hal_nb::serial::Read for Rx { + /// Read one byte from the FIFO. + /// + /// This operation is infallible because pulling an available byte from the FIFO + /// always succeeds. If you want to be informed about RX errors, you should look at the + /// non-blocking API using interrupts, which also tracks the RX error bits. + #[inline] + fn read(&mut self) -> nb::Result { + self.read_fifo() + } +} + +impl embedded_io::ErrorType for Rx { + type Error = Infallible; +} + +impl embedded_io::Read for Rx { + fn read(&mut self, buf: &mut [u8]) -> Result { + if buf.is_empty() { + return Ok(0); + } + let mut read = 0; + loop { + if !self.regs.read_sr().rx_empty() { + break; + } + } + for byte in buf.iter_mut() { + match >::read(self) { + Ok(w) => { + *byte = w; + read += 1; + } + Err(nb::Error::WouldBlock) => break, + } + } + + Ok(read) + } +} diff --git a/zynq7000-hal/src/uart/tx.rs b/zynq7000-hal/src/uart/tx.rs new file mode 100644 index 0000000..9433174 --- /dev/null +++ b/zynq7000-hal/src/uart/tx.rs @@ -0,0 +1,201 @@ +use core::convert::Infallible; + +use zynq7000::uart::{Fifo, InterruptControl, InterruptStatus, MmioUart}; + +use super::UartId; + +pub struct Tx { + pub(crate) regs: MmioUart<'static>, + pub(crate) idx: UartId, +} + +impl Tx { + /// Steal the TX side of the UART for a given UART index. + /// + /// # Safety + /// + /// Circumvents safety guarantees provided by the compiler. + #[inline] + pub const unsafe fn steal(idx: UartId) -> Self { + Tx { + regs: unsafe { idx.regs() }, + idx, + } + } + + #[inline] + pub const fn uart_idx(&self) -> UartId { + self.idx + } + + #[inline] + pub const fn regs(&mut self) -> &mut MmioUart<'static> { + &mut self.regs + } + + #[inline] + pub fn write_fifo(&mut self, word: u8) -> nb::Result<(), Infallible> { + if self.regs.read_sr().tx_full() { + return Err(nb::Error::WouldBlock); + } + self.write_fifo_unchecked(word); + Ok(()) + } + + /// Enables TX side of the UART. + #[inline] + pub fn enable(&mut self, with_reset: bool) { + if with_reset { + self.soft_reset(); + } + self.regs.modify_cr(|mut val| { + val.set_tx_en(true); + val.set_tx_dis(false); + val + }); + } + + /// Disables TX side of the UART. + #[inline] + pub fn disable(&mut self) { + self.regs.modify_cr(|mut val| { + val.set_tx_en(false); + val.set_tx_dis(true); + val + }); + } + + #[inline] + pub fn soft_reset(&mut self) { + self.regs.modify_cr(|mut val| { + val.set_tx_rst(true); + val + }); + loop { + if !self.regs.read_cr().tx_rst() { + break; + } + } + } + + #[inline] + pub fn write_fifo_unchecked(&mut self, word: u8) { + self.regs.write_fifo(Fifo::new_with_raw_value(word as u32)); + } + + /// Enables interrupts relevant for the TX side of the UART except the TX trigger interrupt. + #[inline] + pub fn enable_interrupts(&mut self) { + self.regs.write_ier( + InterruptControl::builder() + .with_tx_over(true) + .with_tx_near_full(true) + .with_tx_trig(false) + .with_rx_dms(false) + .with_rx_timeout(false) + .with_rx_parity(false) + .with_rx_framing(false) + .with_rx_over(false) + .with_tx_full(true) + .with_tx_empty(true) + .with_rx_full(false) + .with_rx_empty(false) + .with_rx_trg(false) + .build(), + ); + } + + /// Disable interrupts relevant for the TX side of the UART except the TX trigger interrupt. + #[inline] + pub fn disable_interrupts(&mut self) { + self.regs.write_idr( + InterruptControl::builder() + .with_tx_over(true) + .with_tx_near_full(true) + .with_tx_trig(false) + .with_rx_dms(false) + .with_rx_timeout(false) + .with_rx_parity(false) + .with_rx_framing(false) + .with_rx_over(false) + .with_tx_full(true) + .with_tx_empty(true) + .with_rx_full(false) + .with_rx_empty(false) + .with_rx_trg(false) + .build(), + ); + } + + /// Clears interrupts relevant for the TX side of the UART except the TX trigger interrupt. + #[inline] + pub fn clear_interrupts(&mut self) { + self.regs.write_isr( + InterruptStatus::builder() + .with_tx_over(true) + .with_tx_near_full(true) + .with_tx_trig(false) + .with_rx_dms(false) + .with_rx_timeout(false) + .with_rx_parity(false) + .with_rx_framing(false) + .with_rx_over(false) + .with_tx_full(true) + .with_tx_empty(true) + .with_rx_full(false) + .with_rx_empty(false) + .with_rx_trg(false) + .build(), + ); + } +} + +impl embedded_hal_nb::serial::ErrorType for Tx { + type Error = Infallible; +} + +impl embedded_hal_nb::serial::Write for Tx { + #[inline] + fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { + self.write_fifo(word) + } + + fn flush(&mut self) -> nb::Result<(), Self::Error> { + loop { + if self.regs.read_sr().tx_empty() { + return Ok(()); + } + } + } +} + +impl embedded_io::ErrorType for Tx { + type Error = Infallible; +} + +impl embedded_io::Write for Tx { + fn write(&mut self, buf: &[u8]) -> Result { + if buf.is_empty() { + return Ok(0); + } + let mut written = 0; + loop { + if !self.regs.read_sr().tx_full() { + break; + } + } + for byte in buf.iter() { + match self.write_fifo(*byte) { + Ok(_) => written += 1, + Err(nb::Error::WouldBlock) => return Ok(written), + } + } + + Ok(written) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + >::flush(self).ok(); + Ok(()) + } +} diff --git a/zynq7000-hal/src/uart/tx_async.rs b/zynq7000-hal/src/uart/tx_async.rs new file mode 100644 index 0000000..f349e71 --- /dev/null +++ b/zynq7000-hal/src/uart/tx_async.rs @@ -0,0 +1,205 @@ +use core::{cell::RefCell, convert::Infallible, sync::atomic::AtomicBool}; + +use critical_section::Mutex; +use embassy_sync::waitqueue::AtomicWaker; +use raw_slice::RawBufSlice; + +use crate::uart::{FIFO_DEPTH, Tx, UartId}; + +#[derive(Debug)] +pub enum TransferType { + Read, + Write, + Transfer, + TransferInPlace, +} + +static UART_TX_WAKERS: [AtomicWaker; 2] = [const { AtomicWaker::new() }; 2]; +static TX_CONTEXTS: [Mutex>; 2] = + [const { Mutex::new(RefCell::new(TxContext::new())) }; 2]; +// Completion flag. Kept outside of the context structure as an atomic to avoid +// critical section. +static TX_DONE: [AtomicBool; 2] = [const { AtomicBool::new(false) }; 2]; + +/// This is a generic interrupt handler to handle asynchronous UART TX operations for a given +/// UART peripheral. +/// +/// The user has to call this once in the interrupt handler responsible for the TX interrupts on +/// the given UART bank. +pub fn on_interrupt_tx(peripheral: UartId) { + let mut tx_with_irq = unsafe { Tx::steal(peripheral) }; + let idx = peripheral as usize; + let imr = tx_with_irq.regs().read_imr(); + // IRQ is not related to TX. + if !imr.tx_over() && !imr.tx_near_full() && !imr.tx_full() && !imr.tx_empty() && !imr.tx_full() + { + return; + } + + let isr = tx_with_irq.regs().read_isr(); + let unexpected_overrun = isr.tx_over(); + let mut context = critical_section::with(|cs| { + let context_ref = TX_CONTEXTS[idx].borrow(cs); + *context_ref.borrow() + }); + // No transfer active. + if context.slice.is_null() { + return; + } + let slice_len = context.slice.len().unwrap(); + context.tx_overrun = unexpected_overrun; + if (context.progress >= slice_len && isr.tx_empty()) || slice_len == 0 { + // Write back updated context structure. + critical_section::with(|cs| { + let context_ref = TX_CONTEXTS[idx].borrow(cs); + *context_ref.borrow_mut() = context; + }); + // Transfer is done. + TX_DONE[idx].store(true, core::sync::atomic::Ordering::Relaxed); + tx_with_irq.disable_interrupts(); + tx_with_irq.clear_interrupts(); + UART_TX_WAKERS[idx].wake(); + return; + } + // Safety: We documented that the user provided slice must outlive the future, so we convert + // the raw pointer back to the slice here. + let slice = unsafe { context.slice.get() }.expect("slice is invalid"); + while context.progress < slice_len { + if tx_with_irq.regs().read_sr().tx_full() { + break; + } + // Safety: TX structure is owned by the future which does not write into the the data + // register, so we can assume we are the only one writing to the data register. + tx_with_irq.write_fifo_unchecked(slice[context.progress]); + context.progress += 1; + } + + // Write back updated context structure. + critical_section::with(|cs| { + let context_ref = TX_CONTEXTS[idx].borrow(cs); + *context_ref.borrow_mut() = context; + }); + // Clear interrupts. + tx_with_irq.clear_interrupts(); +} + +#[derive(Debug, Copy, Clone)] +pub struct TxContext { + progress: usize, + tx_overrun: bool, + slice: RawBufSlice, +} + +#[allow(clippy::new_without_default)] +impl TxContext { + pub const fn new() -> Self { + Self { + progress: 0, + tx_overrun: false, + slice: RawBufSlice::new_nulled(), + } + } +} + +pub struct TxFuture { + id: UartId, +} + +impl TxFuture { + /// # Safety + /// + /// This function stores the raw pointer of the passed data slice. The user MUST ensure + /// that the slice outlives the data structure. + pub unsafe fn new(tx_with_irq: &mut Tx, data: &[u8]) -> Self { + let idx = tx_with_irq.uart_idx() as usize; + TX_DONE[idx].store(false, core::sync::atomic::Ordering::Relaxed); + tx_with_irq.disable_interrupts(); + tx_with_irq.disable(); + + let init_fill_count = core::cmp::min(data.len(), FIFO_DEPTH); + critical_section::with(|cs| { + let context_ref = TX_CONTEXTS[idx].borrow(cs); + let mut context = context_ref.borrow_mut(); + unsafe { + context.slice.set(data); + } + context.progress = init_fill_count; // We fill the FIFO. + }); + tx_with_irq.enable(true); + for data in data.iter().take(init_fill_count) { + tx_with_irq.write_fifo_unchecked(*data); + } + tx_with_irq.enable_interrupts(); + + Self { + id: tx_with_irq.uart_idx(), + } + } +} + +impl Future for TxFuture { + type Output = usize; + + fn poll( + self: core::pin::Pin<&mut Self>, + cx: &mut core::task::Context<'_>, + ) -> core::task::Poll { + UART_TX_WAKERS[self.id as usize].register(cx.waker()); + if TX_DONE[self.id as usize].swap(false, core::sync::atomic::Ordering::Relaxed) { + let progress = critical_section::with(|cs| { + let mut ctx = TX_CONTEXTS[self.id as usize].borrow(cs).borrow_mut(); + ctx.slice.set_null(); + ctx.progress + }); + return core::task::Poll::Ready(progress); + } + core::task::Poll::Pending + } +} + +impl Drop for TxFuture { + fn drop(&mut self) { + let mut tx = unsafe { Tx::steal(self.id) }; + tx.disable_interrupts(); + } +} + +pub struct TxAsync { + tx: Tx, +} + +impl TxAsync { + pub fn new(tx: Tx) -> Self { + Self { tx } + } + + /// Write a buffer asynchronously. + /// + /// This implementation is not side effect free, and a started future might have already + /// written part of the passed buffer. + pub async fn write(&mut self, buf: &[u8]) -> usize { + if buf.is_empty() { + return 0; + } + let fut = unsafe { TxFuture::new(&mut self.tx, buf) }; + fut.await + } + + pub fn release(self) -> Tx { + self.tx + } +} + +impl embedded_io::ErrorType for TxAsync { + type Error = Infallible; +} + +impl embedded_io_async::Write for TxAsync { + /// Write a buffer asynchronously. + /// + /// This implementation is not side effect free, and a started future might have already + /// written part of the passed buffer. + async fn write(&mut self, buf: &[u8]) -> Result { + Ok(self.write(buf).await) + } +} diff --git a/zynq7000-rt/Cargo.lock b/zynq7000-rt/Cargo.lock new file mode 100644 index 0000000..d536135 --- /dev/null +++ b/zynq7000-rt/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "zynq-rt" +version = "0.1.0" diff --git a/zynq7000-rt/Cargo.toml b/zynq7000-rt/Cargo.toml new file mode 100644 index 0000000..9a4cfe2 --- /dev/null +++ b/zynq7000-rt/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "zynq7000-rt" +version = "0.1.0" +authors = ["Robin Mueller "] +edition = "2024" +description = "Run-time support for the Zynq7000 family of SoCs for running bare-metal applications" +homepage = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs" +repository = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs" +license = "MIT OR Apache-2.0" +keywords = ["no-std", "arm", "cortex-a", "amd", "zynq7000"] +categories = ["embedded", "no-std", "hardware-support"] + +[dependencies] +cortex-a-rt = { path = "/home/rmueller/Rust/cortex-ar/cortex-a-rt", optional = true, features = ["vfp-dp"] } +cortex-ar = { path = "/home/rmueller/Rust/cortex-ar/cortex-ar" } + +[features] +default = ["rt"] +tools = [] +rt = ["dep:cortex-a-rt"] + +[[bin]] +name = "table-gen" +path = "src/bin/table-gen.rs" +# Prevents default build +required-features = ["tools"] diff --git a/zynq7000-rt/README.md b/zynq7000-rt/README.md new file mode 100644 index 0000000..77d189f --- /dev/null +++ b/zynq7000-rt/README.md @@ -0,0 +1,27 @@ +Zynq7000 Rust Run-Time Support +======== + +Startup code and minimal runtime for the AMD Zynq7000 SoC to write bare metal Rust code. +This run-time crate is strongly based on the +[startup code provided by AMD](https://github.com/Xilinx/embeddedsw/blob/master/lib/bsp/standalone/src/arm/cortexa9/gcc/boot.S). + +One major difference is that the MMU table is specified as Rust code. There are also modification +to the stack setup code, because a different linker script is used. + +This crate pulls in the [cortex-a-rt](https://github.com/us-irs/cortex-ar/tree/cortex-a-addition/cortex-a-rt) +crate to provide ARM vectors and the linker script. + +## Features + +- `rt` is a default feature which activates the run-time. + +## Re-Generating the MMU table + +The MMU table is a static flat map of 4096 entries for each 1 MB in the memory map. +It was generated using the `table-gen` binary tool. + +You can re-run the tool using + +```sh +cargo +stable --target run --bin table-gen --no-default-features --features tools +``` diff --git a/zynq7000-rt/regen-table.sh b/zynq7000-rt/regen-table.sh new file mode 100755 index 0000000..4efe896 --- /dev/null +++ b/zynq7000-rt/regen-table.sh @@ -0,0 +1,2 @@ +#!/bin/bash +cargo +stable run --target $(rustc -vV | grep host | cut -d ' ' -f2) --bin table-gen --no-default-features --features tools diff --git a/zynq7000-rt/src/bin/table-gen.rs b/zynq7000-rt/src/bin/table-gen.rs new file mode 100644 index 0000000..b8a440b --- /dev/null +++ b/zynq7000-rt/src/bin/table-gen.rs @@ -0,0 +1,285 @@ +use std::fs::File; +use std::io::Write; +use std::process::Command; +use zynq7000_rt::mmu::ONE_MB; +pub use zynq7000_rt::mmu::segments::*; + +fn main() { + let file_path = "src/mmu_table.rs"; + let file = File::create(file_path).expect("Failed to create file"); + + let mut offset = 0; + let attr_ddr = stringify!(section_attrs::DDR); + let attr_unassigned = stringify!(section_attrs::UNASSIGNED_RESERVED); + let attr_fpga_slaves = stringify!(section_attrs::FPGA_SLAVES); + let attr_shared_dev = stringify!(section_attrs::SHAREABLE_DEVICE); + let attr_sram = stringify!(section_attrs::SRAM); + let attr_qspi = stringify!(section_attrs::QSPI_XIP); + let attr_ocm_high = stringify!(section_attrs::OCM_MAPPED_HIGH); + + assert_eq!( + 1 + DDR_FULL_ACCESSIBLE + + FPGA_SLAVE + + FPGA_SLAVE + + UNASSIGNED_0 + + IO_PERIPHS + + UNASSIGNED_1 + + NAND + + NOR + + SRAM + + SEGMENTS_UNASSIGNED_2 + + AMBA_APB + + UNASSIGNED_3 + + QSPI_XIP + + UNASSIGNED_4 + + OCM_MAPPED_HIGH, + 4096 + ); + let mut buf_writer = std::io::BufWriter::new(file); + writeln!( + buf_writer, + "//! This file was auto-generated by table-gen.rs" + ) + .unwrap(); + writeln!(buf_writer, "use cortex_ar::mmu::L1Section;").unwrap(); + writeln!(buf_writer, "use crate::mmu::{{section_attrs, L1Table}};").unwrap(); + writeln!(buf_writer, "").unwrap(); + + writeln!(buf_writer, "/// MMU Level 1 Page table.").unwrap(); + writeln!(buf_writer, "///").unwrap(); + writeln!( + buf_writer, + "/// 4096 entries, each covering 1MB of the address space." + ) + .unwrap(); + writeln!( + buf_writer, + "pub const MMU_L1_PAGE_TABLE: L1Table = L1Table([" + ) + .unwrap(); + + writeln!( + buf_writer, + "// First DDR segment, OCM memory (0x0000_0000 - 0x0010_0000)" + ) + .unwrap(); + writeln!( + buf_writer, + "L1Section::new({}, {}).raw_value(),", + offset, attr_ddr + ) + .unwrap(); + + offset += ONE_MB; + writeln!(buf_writer, "// DDR memory (0x00100000 - 0x4000_0000)").unwrap(); + for _ in 0..DDR_FULL_ACCESSIBLE { + writeln!( + buf_writer, + "L1Section::new({}, {}).raw_value(),", + offset, attr_ddr + ) + .unwrap(); + offset += ONE_MB; + } + + writeln!(buf_writer, "// FPGA slave 0 (0x4000_0000 - 0x8000_0000)").unwrap(); + for _ in 0..FPGA_SLAVE { + writeln!( + buf_writer, + "L1Section::new({}, {}).raw_value(),", + offset, attr_fpga_slaves + ) + .unwrap(); + offset += ONE_MB; + } + + writeln!(buf_writer, "// FPGA slave 1 (0x8000_0000 - 0xC000_0000)").unwrap(); + for _ in 0..FPGA_SLAVE { + writeln!( + buf_writer, + "L1Section::new({}, {}).raw_value(),", + offset, attr_fpga_slaves + ) + .unwrap(); + offset += ONE_MB; + } + + writeln!( + buf_writer, + "// Unassigned/Reserved (0xC000_0000 - 0xE000_0000)" + ) + .unwrap(); + for _ in 0..UNASSIGNED_0 { + writeln!( + buf_writer, + "L1Section::new({}, {}).raw_value(),", + offset, attr_unassigned + ) + .unwrap(); + offset += ONE_MB; + } + + writeln!( + buf_writer, + "// Segments IO peripherals (0xE000_0000 - 0xE030_0000)" + ) + .unwrap(); + for _ in 0..IO_PERIPHS { + writeln!( + buf_writer, + "L1Section::new({}, {}).raw_value(),", + offset, attr_shared_dev + ) + .unwrap(); + offset += ONE_MB; + } + + writeln!( + buf_writer, + "// Unassigned/Reserved (0xE030_0000 - 0xE100_0000)" + ) + .unwrap(); + for _ in 0..UNASSIGNED_1 { + writeln!( + buf_writer, + "L1Section::new({}, {}).raw_value(),", + offset, attr_unassigned + ) + .unwrap(); + offset += ONE_MB; + } + + writeln!(buf_writer, "// NAND (0xE100_0000 - 0xE200_0000)").unwrap(); + for _ in 0..NAND { + writeln!( + buf_writer, + "L1Section::new({}, {}).raw_value(),", + offset, attr_shared_dev + ) + .unwrap(); + offset += ONE_MB; + } + + writeln!(buf_writer, "// NOR (0xE200_0000 - 0xE400_0000)").unwrap(); + for _ in 0..NOR { + writeln!( + buf_writer, + "L1Section::new({}, {}).raw_value(),", + offset, attr_shared_dev + ) + .unwrap(); + offset += ONE_MB; + } + + writeln!(buf_writer, "// SRAM (0xE400_0000 - 0xE600_0000)").unwrap(); + for _ in 0..SRAM { + writeln!( + buf_writer, + "L1Section::new({}, {}).raw_value(),", + offset, attr_sram + ) + .unwrap(); + offset += ONE_MB; + } + + writeln!( + buf_writer, + "// Unassigned/Reserved (0xE600_0000 - 0xF800_0000)" + ) + .unwrap(); + for _ in 0..SEGMENTS_UNASSIGNED_2 { + writeln!( + buf_writer, + "L1Section::new({}, {}).raw_value(),", + offset, attr_unassigned + ) + .unwrap(); + offset += ONE_MB; + } + + writeln!( + buf_writer, + "// AMBA APB peripherals (0xF800_0000 - 0xF900_0000)" + ) + .unwrap(); + for _ in 0..AMBA_APB { + writeln!( + buf_writer, + "L1Section::new({}, {}).raw_value(),", + offset, attr_shared_dev + ) + .unwrap(); + offset += ONE_MB; + } + + writeln!( + buf_writer, + "// Unassigned/Reserved (0xF900_0000 - 0xFC00_0000)" + ) + .unwrap(); + for _ in 0..UNASSIGNED_3 { + writeln!( + buf_writer, + "L1Section::new({}, {}).raw_value(),", + offset, attr_unassigned + ) + .unwrap(); + offset += ONE_MB; + } + + writeln!(buf_writer, "// QSPI XIP (0xFC00_0000 - 0xFE00_0000)").unwrap(); + for _ in 0..QSPI_XIP { + writeln!( + buf_writer, + "L1Section::new({}, {}).raw_value(),", + offset, attr_qspi + ) + .unwrap(); + offset += ONE_MB; + } + + writeln!( + buf_writer, + "// Unassiged/Reserved (0xFE00_0000 - 0xFFF0_0000)" + ) + .unwrap(); + for _ in 0..UNASSIGNED_4 { + writeln!( + buf_writer, + "L1Section::new({}, {}).raw_value(),", + offset, attr_unassigned + ) + .unwrap(); + offset += ONE_MB; + } + + writeln!(buf_writer, "// OCM High (0xFFF0_0000 - 0xFFFF_FFFF)").unwrap(); + let mut offset_u64 = offset as u64; + for _ in 0..OCM_MAPPED_HIGH { + writeln!( + buf_writer, + "L1Section::new({}, {}).raw_value(),", + offset, attr_ocm_high + ) + .unwrap(); + + offset_u64 += ONE_MB as u64; + } + // Check that the full 4 GB were covered (not too much, or less) + assert_eq!(offset_u64, 0x1_0000_0000 as u64); + + writeln!(buf_writer, "]);").unwrap(); + // Finish the file. + drop(buf_writer); + println!("Generated mmu_table.rs"); + + // Run rustfmt on the generated file + let output = Command::new("rustfmt") + .arg(file_path) + .output() + .expect("Failed to run rustfmt"); + + if !output.status.success() { + eprintln!("rustfmt failed: {:?}", output); + } +} diff --git a/zynq7000-rt/src/lib.rs b/zynq7000-rt/src/lib.rs new file mode 100644 index 0000000..9975309 --- /dev/null +++ b/zynq7000-rt/src/lib.rs @@ -0,0 +1,11 @@ +//! Rust bare metal run-time support for the AMD Zynq 7000 SoCs +//! +//! This includes basic low-level startup code similar to the bare-metal boot routines +//! [provided by Xilinx](https://github.com/Xilinx/embeddedsw/tree/master/lib/bsp/standalone/src/arm/cortexa9/gcc). +#![no_std] + +pub mod mmu; +#[cfg(feature = "rt")] +mod mmu_table; +#[cfg(feature = "rt")] +pub mod rt; diff --git a/zynq7000-rt/src/mmu.rs b/zynq7000-rt/src/mmu.rs new file mode 100644 index 0000000..fc1925a --- /dev/null +++ b/zynq7000-rt/src/mmu.rs @@ -0,0 +1,191 @@ +//! The overview of translation table memory attributes is described below. +//! +//!| | Memory Range | Definition in Translation Table | +//!|-----------------------|-------------------------|-----------------------------------| +//!| DDR | 0x00000000 - 0x3FFFFFFF | Normal write-back Cacheable | +//!| PL | 0x40000000 - 0xBFFFFFFF | Strongly Ordered | +//!| Reserved | 0xC0000000 - 0xDFFFFFFF | Unassigned | +//!| Memory mapped devices | 0xE0000000 - 0xE02FFFFF | Device Memory | +//!| Reserved | 0xE0300000 - 0xE0FFFFFF | Unassigned | +//!| NAND, NOR | 0xE1000000 - 0xE3FFFFFF | Device memory | +//!| SRAM | 0xE4000000 - 0xE5FFFFFF | Normal write-back Cacheable | +//!| Reserved | 0xE6000000 - 0xF7FFFFFF | Unassigned | +//!| AMBA APB Peripherals | 0xF8000000 - 0xF8FFFFFF | Device Memory | +//!| Reserved | 0xF9000000 - 0xFBFFFFFF | Unassigned | +//!| Linear QSPI - XIP | 0xFC000000 - 0xFDFFFFFF | Normal write-through cacheable | +//!| Reserved | 0xFE000000 - 0xFFEFFFFF | Unassigned | +//!| OCM | 0xFFF00000 - 0xFFFFFFFF | Normal inner write-back cacheable | +//! +//! For region 0x00000000 - 0x3FFFFFFF, a system where DDR is less than 1 GB, +//! region after DDR and before PL is marked as undefined/reserved in translation +//! table. In 0xF8000000 - 0xF8FFFFFF, 0xF8000C00 - 0xF8000FFF, 0xF8010000 - +//! 0xF88FFFFF and 0xF8F03000 to 0xF8FFFFFF are reserved but due to granual size +//! of 1 MB, it is not possible to define separate regions for them. For region +//! 0xFFF00000 - 0xFFFFFFFF, 0xFFF00000 to 0xFFFB0000 is reserved but due to 1MB +//! granual size, it is not possible to define separate region for it. +pub const MAX_DDR_SIZE: usize = 0x4000_0000; +pub const ONE_MB: usize = 0x10_0000; + +pub mod offsets { + pub const OFFSET_DDR: usize = 0; + pub const OFFSET_DDR_ALL_ACCESSIBLE: usize = 0x10_0000; + + pub const OFFSET_FPGA_SLAVE_0: usize = 0x4000_0000; + pub const OFFSET_FPGA_SLAVE_1_START: usize = 0x8000_0000; + pub const OFFSET_FPGA_SLAVE_1_END: usize = 0xC000_0000; + + pub const OFFSET_IO_PERIPHERALS_START: usize = 0xE000_0000; + pub const OFFSET_IO_PERIPHERALS_END: usize = 0xE030_0000; + + pub const OFFSET_NAND_MEMORY: usize = 0xE100_0000; + pub const OFFSET_NOR_MEMORY: usize = 0xE200_0000; + pub const OFFSET_SRAM_MEMORY: usize = 0xE400_0000; + pub const OFFSET_SMC_MEMORIES_END: usize = 0xE600_0000; + + /// 0xf8000c00 to 0xf8000fff, 0xf8010000 to 0xf88fffff and + /// 0xf8f03000 to 0xf8ffffff are reserved but due to granual size of + /// 1MB, it is not possible to define separate regions for them. + pub const OFFSET_AMBA_APB_START: usize = 0xF800_0000; + pub const OFFSET_AMBA_APB_END: usize = 0xF900_0000; + + pub const OFFSET_QSPI_XIP_START: usize = 0xFC00_0000; + pub const OFFSET_QSPI_XIP_END: usize = 0xFE00_0000; + + /// 0xfff00000 to 0xfffb0000 is reserved but due to granual size of + /// 1MB, it is not possible to define separate region for it + pub const OFFSET_OCM_MAPPED_HIGH_START: usize = 0xFFF0_0000; + pub const OFFSET_OCM_MAPPED_HIGH_END: u64 = 0x1_0000_0000; +} +pub mod segments { + pub use super::offsets::*; + use super::{MAX_DDR_SIZE, ONE_MB}; + + /// First 1 MB of DDR has special treatment, access is dependant on SCU/OCM state. + /// Refer to Zynq TRM UG585 p.106 for more details. + pub const DDR_FULL_ACCESSIBLE: usize = (MAX_DDR_SIZE - ONE_MB) / ONE_MB; + pub const FPGA_SLAVE: usize = (OFFSET_FPGA_SLAVE_1_START - OFFSET_FPGA_SLAVE_0) / ONE_MB; + pub const UNASSIGNED_0: usize = + (OFFSET_IO_PERIPHERALS_START - OFFSET_FPGA_SLAVE_1_END) / ONE_MB; + pub const IO_PERIPHS: usize = + (OFFSET_IO_PERIPHERALS_END - OFFSET_IO_PERIPHERALS_START) / ONE_MB; + pub const UNASSIGNED_1: usize = (OFFSET_NAND_MEMORY - OFFSET_IO_PERIPHERALS_END) / ONE_MB; + pub const NAND: usize = (OFFSET_NOR_MEMORY - OFFSET_NAND_MEMORY) / ONE_MB; + pub const NOR: usize = (OFFSET_SRAM_MEMORY - OFFSET_NOR_MEMORY) / ONE_MB; + pub const SRAM: usize = (OFFSET_SMC_MEMORIES_END - OFFSET_SRAM_MEMORY) / ONE_MB; + pub const SEGMENTS_UNASSIGNED_2: usize = + (OFFSET_AMBA_APB_START - OFFSET_SMC_MEMORIES_END) / ONE_MB; + pub const AMBA_APB: usize = (OFFSET_AMBA_APB_END - OFFSET_AMBA_APB_START) / ONE_MB; + pub const UNASSIGNED_3: usize = (OFFSET_QSPI_XIP_START - OFFSET_AMBA_APB_END) / ONE_MB; + pub const QSPI_XIP: usize = (OFFSET_QSPI_XIP_END - OFFSET_QSPI_XIP_START) / ONE_MB; + pub const UNASSIGNED_4: usize = (OFFSET_OCM_MAPPED_HIGH_START - OFFSET_QSPI_XIP_END) / ONE_MB; + pub const OCM_MAPPED_HIGH: usize = ((OFFSET_OCM_MAPPED_HIGH_END + - OFFSET_OCM_MAPPED_HIGH_START as u64) + / ONE_MB as u64) as usize; +} + +pub mod section_attrs { + use cortex_ar::mmu::{ + AccessPermissions, CacheableMemoryAttribute, MemoryRegionAttributes, SectionAttributes, + }; + + pub const DDR: SectionAttributes = SectionAttributes { + non_global: false, + p_bit: false, + shareable: true, + access: AccessPermissions::FullAccess, + // Manager domain + domain: 0b1111, + execute_never: false, + memory_attrs: MemoryRegionAttributes::CacheableMemory { + inner: CacheableMemoryAttribute::WriteBackWriteAlloc, + outer: CacheableMemoryAttribute::WriteBackWriteAlloc, + } + .as_raw(), + }; + pub const FPGA_SLAVES: SectionAttributes = SectionAttributes { + non_global: false, + p_bit: false, + shareable: false, + access: AccessPermissions::FullAccess, + domain: 0b0000, + execute_never: false, + memory_attrs: MemoryRegionAttributes::StronglyOrdered.as_raw(), + }; + pub const SHAREABLE_DEVICE: SectionAttributes = SectionAttributes { + non_global: false, + p_bit: false, + shareable: false, + access: AccessPermissions::FullAccess, + domain: 0b0000, + execute_never: false, + memory_attrs: MemoryRegionAttributes::ShareableDevice.as_raw(), + }; + pub const SRAM: SectionAttributes = SectionAttributes { + non_global: false, + p_bit: false, + shareable: false, + access: AccessPermissions::FullAccess, + domain: 0b0000, + execute_never: false, + memory_attrs: MemoryRegionAttributes::OuterAndInnerWriteBackNoWriteAlloc.as_raw(), + }; + pub const QSPI_XIP: SectionAttributes = SectionAttributes { + non_global: false, + p_bit: false, + shareable: false, + access: AccessPermissions::FullAccess, + domain: 0b0000, + execute_never: false, + memory_attrs: MemoryRegionAttributes::OuterAndInnerWriteThroughNoWriteAlloc.as_raw(), + }; + pub const OCM_MAPPED_HIGH: SectionAttributes = SectionAttributes { + non_global: false, + p_bit: false, + shareable: false, + access: AccessPermissions::FullAccess, + domain: 0b0000, + execute_never: false, + memory_attrs: MemoryRegionAttributes::CacheableMemory { + inner: CacheableMemoryAttribute::WriteThroughNoWriteAlloc, + outer: CacheableMemoryAttribute::NonCacheable, + } + .as_raw(), + }; + pub const UNASSIGNED_RESERVED: SectionAttributes = SectionAttributes { + non_global: false, + p_bit: false, + shareable: false, + access: AccessPermissions::PermissionFault, + domain: 0b0000, + execute_never: false, + memory_attrs: MemoryRegionAttributes::StronglyOrdered.as_raw(), + }; +} + +pub const NUM_L1_PAGE_TABLE_ENTRIES: usize = 4096; + +#[repr(C, align(16384))] +#[cfg(feature = "rt")] +pub struct L1Table(pub(crate) [u32; NUM_L1_PAGE_TABLE_ENTRIES]); + +/// Load the MMU translation table base address into the MMU. +/// +/// # Safety +/// +/// This function is unsafe because it directly writes to the MMU related registers. It has to be +/// called once in the boot code before enabling the MMU, and it should be called while the MMU is +/// disabled. +#[unsafe(no_mangle)] +#[cfg(feature = "rt")] +unsafe extern "C" fn load_mmu_table() { + let table_base = &crate::mmu_table::MMU_L1_PAGE_TABLE.0 as *const _ as u32; + + unsafe { + core::arch::asm!( + "orr {0}, {0}, #0x5B", // Outer-cacheable, WB + "mcr p15, 0, {0}, c2, c0, 0", // Load table pointer + inout(reg) table_base => _, + options(nostack, preserves_flags) + ); + } +} diff --git a/zynq7000-rt/src/mmu_table.rs b/zynq7000-rt/src/mmu_table.rs new file mode 100644 index 0000000..cf791d6 --- /dev/null +++ b/zynq7000-rt/src/mmu_table.rs @@ -0,0 +1,4121 @@ +//! This file was auto-generated by table-gen.rs +use crate::mmu::{L1Table, section_attrs}; +use cortex_ar::mmu::L1Section; + +/// MMU Level 1 Page table. +/// +/// 4096 entries, each covering 1MB of the address space. +pub const MMU_L1_PAGE_TABLE: L1Table = L1Table([ + // First DDR segment, OCM memory (0x0000_0000 - 0x0010_0000) + L1Section::new(0, section_attrs::DDR).raw_value(), + // DDR memory (0x00100000 - 0x4000_0000) + L1Section::new(1048576, section_attrs::DDR).raw_value(), + L1Section::new(2097152, section_attrs::DDR).raw_value(), + L1Section::new(3145728, section_attrs::DDR).raw_value(), + L1Section::new(4194304, section_attrs::DDR).raw_value(), + L1Section::new(5242880, section_attrs::DDR).raw_value(), + L1Section::new(6291456, section_attrs::DDR).raw_value(), + L1Section::new(7340032, section_attrs::DDR).raw_value(), + L1Section::new(8388608, section_attrs::DDR).raw_value(), + L1Section::new(9437184, section_attrs::DDR).raw_value(), + L1Section::new(10485760, section_attrs::DDR).raw_value(), + L1Section::new(11534336, section_attrs::DDR).raw_value(), + L1Section::new(12582912, section_attrs::DDR).raw_value(), + L1Section::new(13631488, section_attrs::DDR).raw_value(), + L1Section::new(14680064, section_attrs::DDR).raw_value(), + L1Section::new(15728640, section_attrs::DDR).raw_value(), + L1Section::new(16777216, section_attrs::DDR).raw_value(), + L1Section::new(17825792, section_attrs::DDR).raw_value(), + L1Section::new(18874368, section_attrs::DDR).raw_value(), + L1Section::new(19922944, section_attrs::DDR).raw_value(), + L1Section::new(20971520, section_attrs::DDR).raw_value(), + L1Section::new(22020096, section_attrs::DDR).raw_value(), + L1Section::new(23068672, section_attrs::DDR).raw_value(), + L1Section::new(24117248, section_attrs::DDR).raw_value(), + L1Section::new(25165824, section_attrs::DDR).raw_value(), + L1Section::new(26214400, section_attrs::DDR).raw_value(), + L1Section::new(27262976, section_attrs::DDR).raw_value(), + L1Section::new(28311552, section_attrs::DDR).raw_value(), + L1Section::new(29360128, section_attrs::DDR).raw_value(), + L1Section::new(30408704, section_attrs::DDR).raw_value(), + L1Section::new(31457280, section_attrs::DDR).raw_value(), + L1Section::new(32505856, section_attrs::DDR).raw_value(), + L1Section::new(33554432, section_attrs::DDR).raw_value(), + L1Section::new(34603008, section_attrs::DDR).raw_value(), + L1Section::new(35651584, section_attrs::DDR).raw_value(), + L1Section::new(36700160, section_attrs::DDR).raw_value(), + L1Section::new(37748736, section_attrs::DDR).raw_value(), + L1Section::new(38797312, section_attrs::DDR).raw_value(), + L1Section::new(39845888, section_attrs::DDR).raw_value(), + L1Section::new(40894464, section_attrs::DDR).raw_value(), + L1Section::new(41943040, section_attrs::DDR).raw_value(), + L1Section::new(42991616, section_attrs::DDR).raw_value(), + L1Section::new(44040192, section_attrs::DDR).raw_value(), + L1Section::new(45088768, section_attrs::DDR).raw_value(), + L1Section::new(46137344, section_attrs::DDR).raw_value(), + L1Section::new(47185920, section_attrs::DDR).raw_value(), + L1Section::new(48234496, section_attrs::DDR).raw_value(), + L1Section::new(49283072, section_attrs::DDR).raw_value(), + L1Section::new(50331648, section_attrs::DDR).raw_value(), + L1Section::new(51380224, section_attrs::DDR).raw_value(), + L1Section::new(52428800, section_attrs::DDR).raw_value(), + L1Section::new(53477376, section_attrs::DDR).raw_value(), + L1Section::new(54525952, section_attrs::DDR).raw_value(), + L1Section::new(55574528, section_attrs::DDR).raw_value(), + L1Section::new(56623104, section_attrs::DDR).raw_value(), + L1Section::new(57671680, section_attrs::DDR).raw_value(), + L1Section::new(58720256, section_attrs::DDR).raw_value(), + L1Section::new(59768832, section_attrs::DDR).raw_value(), + L1Section::new(60817408, section_attrs::DDR).raw_value(), + L1Section::new(61865984, section_attrs::DDR).raw_value(), + L1Section::new(62914560, section_attrs::DDR).raw_value(), + L1Section::new(63963136, section_attrs::DDR).raw_value(), + L1Section::new(65011712, section_attrs::DDR).raw_value(), + L1Section::new(66060288, section_attrs::DDR).raw_value(), + L1Section::new(67108864, section_attrs::DDR).raw_value(), + L1Section::new(68157440, section_attrs::DDR).raw_value(), + L1Section::new(69206016, section_attrs::DDR).raw_value(), + L1Section::new(70254592, section_attrs::DDR).raw_value(), + L1Section::new(71303168, section_attrs::DDR).raw_value(), + L1Section::new(72351744, section_attrs::DDR).raw_value(), + L1Section::new(73400320, section_attrs::DDR).raw_value(), + L1Section::new(74448896, section_attrs::DDR).raw_value(), + L1Section::new(75497472, section_attrs::DDR).raw_value(), + L1Section::new(76546048, section_attrs::DDR).raw_value(), + L1Section::new(77594624, section_attrs::DDR).raw_value(), + L1Section::new(78643200, section_attrs::DDR).raw_value(), + L1Section::new(79691776, section_attrs::DDR).raw_value(), + L1Section::new(80740352, section_attrs::DDR).raw_value(), + L1Section::new(81788928, section_attrs::DDR).raw_value(), + L1Section::new(82837504, section_attrs::DDR).raw_value(), + L1Section::new(83886080, section_attrs::DDR).raw_value(), + L1Section::new(84934656, section_attrs::DDR).raw_value(), + L1Section::new(85983232, section_attrs::DDR).raw_value(), + L1Section::new(87031808, section_attrs::DDR).raw_value(), + L1Section::new(88080384, section_attrs::DDR).raw_value(), + L1Section::new(89128960, section_attrs::DDR).raw_value(), + L1Section::new(90177536, section_attrs::DDR).raw_value(), + L1Section::new(91226112, section_attrs::DDR).raw_value(), + L1Section::new(92274688, section_attrs::DDR).raw_value(), + L1Section::new(93323264, section_attrs::DDR).raw_value(), + L1Section::new(94371840, section_attrs::DDR).raw_value(), + L1Section::new(95420416, section_attrs::DDR).raw_value(), + L1Section::new(96468992, section_attrs::DDR).raw_value(), + L1Section::new(97517568, section_attrs::DDR).raw_value(), + L1Section::new(98566144, section_attrs::DDR).raw_value(), + L1Section::new(99614720, section_attrs::DDR).raw_value(), + L1Section::new(100663296, section_attrs::DDR).raw_value(), + L1Section::new(101711872, section_attrs::DDR).raw_value(), + L1Section::new(102760448, section_attrs::DDR).raw_value(), + L1Section::new(103809024, section_attrs::DDR).raw_value(), + L1Section::new(104857600, section_attrs::DDR).raw_value(), + L1Section::new(105906176, section_attrs::DDR).raw_value(), + L1Section::new(106954752, section_attrs::DDR).raw_value(), + L1Section::new(108003328, section_attrs::DDR).raw_value(), + L1Section::new(109051904, section_attrs::DDR).raw_value(), + L1Section::new(110100480, section_attrs::DDR).raw_value(), + L1Section::new(111149056, section_attrs::DDR).raw_value(), + L1Section::new(112197632, section_attrs::DDR).raw_value(), + L1Section::new(113246208, section_attrs::DDR).raw_value(), + L1Section::new(114294784, section_attrs::DDR).raw_value(), + L1Section::new(115343360, section_attrs::DDR).raw_value(), + L1Section::new(116391936, section_attrs::DDR).raw_value(), + L1Section::new(117440512, section_attrs::DDR).raw_value(), + L1Section::new(118489088, section_attrs::DDR).raw_value(), + L1Section::new(119537664, section_attrs::DDR).raw_value(), + L1Section::new(120586240, section_attrs::DDR).raw_value(), + L1Section::new(121634816, section_attrs::DDR).raw_value(), + L1Section::new(122683392, section_attrs::DDR).raw_value(), + L1Section::new(123731968, section_attrs::DDR).raw_value(), + L1Section::new(124780544, section_attrs::DDR).raw_value(), + L1Section::new(125829120, section_attrs::DDR).raw_value(), + L1Section::new(126877696, section_attrs::DDR).raw_value(), + L1Section::new(127926272, section_attrs::DDR).raw_value(), + L1Section::new(128974848, section_attrs::DDR).raw_value(), + L1Section::new(130023424, section_attrs::DDR).raw_value(), + L1Section::new(131072000, section_attrs::DDR).raw_value(), + L1Section::new(132120576, section_attrs::DDR).raw_value(), + L1Section::new(133169152, section_attrs::DDR).raw_value(), + L1Section::new(134217728, section_attrs::DDR).raw_value(), + L1Section::new(135266304, section_attrs::DDR).raw_value(), + L1Section::new(136314880, section_attrs::DDR).raw_value(), + L1Section::new(137363456, section_attrs::DDR).raw_value(), + L1Section::new(138412032, section_attrs::DDR).raw_value(), + L1Section::new(139460608, section_attrs::DDR).raw_value(), + L1Section::new(140509184, section_attrs::DDR).raw_value(), + L1Section::new(141557760, section_attrs::DDR).raw_value(), + L1Section::new(142606336, section_attrs::DDR).raw_value(), + L1Section::new(143654912, section_attrs::DDR).raw_value(), + L1Section::new(144703488, section_attrs::DDR).raw_value(), + L1Section::new(145752064, section_attrs::DDR).raw_value(), + L1Section::new(146800640, section_attrs::DDR).raw_value(), + L1Section::new(147849216, section_attrs::DDR).raw_value(), + L1Section::new(148897792, section_attrs::DDR).raw_value(), + L1Section::new(149946368, section_attrs::DDR).raw_value(), + L1Section::new(150994944, section_attrs::DDR).raw_value(), + L1Section::new(152043520, section_attrs::DDR).raw_value(), + L1Section::new(153092096, section_attrs::DDR).raw_value(), + L1Section::new(154140672, section_attrs::DDR).raw_value(), + L1Section::new(155189248, section_attrs::DDR).raw_value(), + L1Section::new(156237824, section_attrs::DDR).raw_value(), + L1Section::new(157286400, section_attrs::DDR).raw_value(), + L1Section::new(158334976, section_attrs::DDR).raw_value(), + L1Section::new(159383552, section_attrs::DDR).raw_value(), + L1Section::new(160432128, section_attrs::DDR).raw_value(), + L1Section::new(161480704, section_attrs::DDR).raw_value(), + L1Section::new(162529280, section_attrs::DDR).raw_value(), + L1Section::new(163577856, section_attrs::DDR).raw_value(), + L1Section::new(164626432, section_attrs::DDR).raw_value(), + L1Section::new(165675008, section_attrs::DDR).raw_value(), + L1Section::new(166723584, section_attrs::DDR).raw_value(), + L1Section::new(167772160, section_attrs::DDR).raw_value(), + L1Section::new(168820736, section_attrs::DDR).raw_value(), + L1Section::new(169869312, section_attrs::DDR).raw_value(), + L1Section::new(170917888, section_attrs::DDR).raw_value(), + L1Section::new(171966464, section_attrs::DDR).raw_value(), + L1Section::new(173015040, section_attrs::DDR).raw_value(), + L1Section::new(174063616, section_attrs::DDR).raw_value(), + L1Section::new(175112192, section_attrs::DDR).raw_value(), + L1Section::new(176160768, section_attrs::DDR).raw_value(), + L1Section::new(177209344, section_attrs::DDR).raw_value(), + L1Section::new(178257920, section_attrs::DDR).raw_value(), + L1Section::new(179306496, section_attrs::DDR).raw_value(), + L1Section::new(180355072, section_attrs::DDR).raw_value(), + L1Section::new(181403648, section_attrs::DDR).raw_value(), + L1Section::new(182452224, section_attrs::DDR).raw_value(), + L1Section::new(183500800, section_attrs::DDR).raw_value(), + L1Section::new(184549376, section_attrs::DDR).raw_value(), + L1Section::new(185597952, section_attrs::DDR).raw_value(), + L1Section::new(186646528, section_attrs::DDR).raw_value(), + L1Section::new(187695104, section_attrs::DDR).raw_value(), + L1Section::new(188743680, section_attrs::DDR).raw_value(), + L1Section::new(189792256, section_attrs::DDR).raw_value(), + L1Section::new(190840832, section_attrs::DDR).raw_value(), + L1Section::new(191889408, section_attrs::DDR).raw_value(), + L1Section::new(192937984, section_attrs::DDR).raw_value(), + L1Section::new(193986560, section_attrs::DDR).raw_value(), + L1Section::new(195035136, section_attrs::DDR).raw_value(), + L1Section::new(196083712, section_attrs::DDR).raw_value(), + L1Section::new(197132288, section_attrs::DDR).raw_value(), + L1Section::new(198180864, section_attrs::DDR).raw_value(), + L1Section::new(199229440, section_attrs::DDR).raw_value(), + L1Section::new(200278016, section_attrs::DDR).raw_value(), + L1Section::new(201326592, section_attrs::DDR).raw_value(), + L1Section::new(202375168, section_attrs::DDR).raw_value(), + L1Section::new(203423744, section_attrs::DDR).raw_value(), + L1Section::new(204472320, section_attrs::DDR).raw_value(), + L1Section::new(205520896, section_attrs::DDR).raw_value(), + L1Section::new(206569472, section_attrs::DDR).raw_value(), + L1Section::new(207618048, section_attrs::DDR).raw_value(), + L1Section::new(208666624, section_attrs::DDR).raw_value(), + L1Section::new(209715200, section_attrs::DDR).raw_value(), + L1Section::new(210763776, section_attrs::DDR).raw_value(), + L1Section::new(211812352, section_attrs::DDR).raw_value(), + L1Section::new(212860928, section_attrs::DDR).raw_value(), + L1Section::new(213909504, section_attrs::DDR).raw_value(), + L1Section::new(214958080, section_attrs::DDR).raw_value(), + L1Section::new(216006656, section_attrs::DDR).raw_value(), + L1Section::new(217055232, section_attrs::DDR).raw_value(), + L1Section::new(218103808, section_attrs::DDR).raw_value(), + L1Section::new(219152384, section_attrs::DDR).raw_value(), + L1Section::new(220200960, section_attrs::DDR).raw_value(), + L1Section::new(221249536, section_attrs::DDR).raw_value(), + L1Section::new(222298112, section_attrs::DDR).raw_value(), + L1Section::new(223346688, section_attrs::DDR).raw_value(), + L1Section::new(224395264, section_attrs::DDR).raw_value(), + L1Section::new(225443840, section_attrs::DDR).raw_value(), + L1Section::new(226492416, section_attrs::DDR).raw_value(), + L1Section::new(227540992, section_attrs::DDR).raw_value(), + L1Section::new(228589568, section_attrs::DDR).raw_value(), + L1Section::new(229638144, section_attrs::DDR).raw_value(), + L1Section::new(230686720, section_attrs::DDR).raw_value(), + L1Section::new(231735296, section_attrs::DDR).raw_value(), + L1Section::new(232783872, section_attrs::DDR).raw_value(), + L1Section::new(233832448, section_attrs::DDR).raw_value(), + L1Section::new(234881024, section_attrs::DDR).raw_value(), + L1Section::new(235929600, section_attrs::DDR).raw_value(), + L1Section::new(236978176, section_attrs::DDR).raw_value(), + L1Section::new(238026752, section_attrs::DDR).raw_value(), + L1Section::new(239075328, section_attrs::DDR).raw_value(), + L1Section::new(240123904, section_attrs::DDR).raw_value(), + L1Section::new(241172480, section_attrs::DDR).raw_value(), + L1Section::new(242221056, section_attrs::DDR).raw_value(), + L1Section::new(243269632, section_attrs::DDR).raw_value(), + L1Section::new(244318208, section_attrs::DDR).raw_value(), + L1Section::new(245366784, section_attrs::DDR).raw_value(), + L1Section::new(246415360, section_attrs::DDR).raw_value(), + L1Section::new(247463936, section_attrs::DDR).raw_value(), + L1Section::new(248512512, section_attrs::DDR).raw_value(), + L1Section::new(249561088, section_attrs::DDR).raw_value(), + L1Section::new(250609664, section_attrs::DDR).raw_value(), + L1Section::new(251658240, section_attrs::DDR).raw_value(), + L1Section::new(252706816, section_attrs::DDR).raw_value(), + L1Section::new(253755392, section_attrs::DDR).raw_value(), + L1Section::new(254803968, section_attrs::DDR).raw_value(), + L1Section::new(255852544, section_attrs::DDR).raw_value(), + L1Section::new(256901120, section_attrs::DDR).raw_value(), + L1Section::new(257949696, section_attrs::DDR).raw_value(), + L1Section::new(258998272, section_attrs::DDR).raw_value(), + L1Section::new(260046848, section_attrs::DDR).raw_value(), + L1Section::new(261095424, section_attrs::DDR).raw_value(), + L1Section::new(262144000, section_attrs::DDR).raw_value(), + L1Section::new(263192576, section_attrs::DDR).raw_value(), + L1Section::new(264241152, section_attrs::DDR).raw_value(), + L1Section::new(265289728, section_attrs::DDR).raw_value(), + L1Section::new(266338304, section_attrs::DDR).raw_value(), + L1Section::new(267386880, section_attrs::DDR).raw_value(), + L1Section::new(268435456, section_attrs::DDR).raw_value(), + L1Section::new(269484032, section_attrs::DDR).raw_value(), + L1Section::new(270532608, section_attrs::DDR).raw_value(), + L1Section::new(271581184, section_attrs::DDR).raw_value(), + L1Section::new(272629760, section_attrs::DDR).raw_value(), + L1Section::new(273678336, section_attrs::DDR).raw_value(), + L1Section::new(274726912, section_attrs::DDR).raw_value(), + L1Section::new(275775488, section_attrs::DDR).raw_value(), + L1Section::new(276824064, section_attrs::DDR).raw_value(), + L1Section::new(277872640, section_attrs::DDR).raw_value(), + L1Section::new(278921216, section_attrs::DDR).raw_value(), + L1Section::new(279969792, section_attrs::DDR).raw_value(), + L1Section::new(281018368, section_attrs::DDR).raw_value(), + L1Section::new(282066944, section_attrs::DDR).raw_value(), + L1Section::new(283115520, section_attrs::DDR).raw_value(), + L1Section::new(284164096, section_attrs::DDR).raw_value(), + L1Section::new(285212672, section_attrs::DDR).raw_value(), + L1Section::new(286261248, section_attrs::DDR).raw_value(), + L1Section::new(287309824, section_attrs::DDR).raw_value(), + L1Section::new(288358400, section_attrs::DDR).raw_value(), + L1Section::new(289406976, section_attrs::DDR).raw_value(), + L1Section::new(290455552, section_attrs::DDR).raw_value(), + L1Section::new(291504128, section_attrs::DDR).raw_value(), + L1Section::new(292552704, section_attrs::DDR).raw_value(), + L1Section::new(293601280, section_attrs::DDR).raw_value(), + L1Section::new(294649856, section_attrs::DDR).raw_value(), + L1Section::new(295698432, section_attrs::DDR).raw_value(), + L1Section::new(296747008, section_attrs::DDR).raw_value(), + L1Section::new(297795584, section_attrs::DDR).raw_value(), + L1Section::new(298844160, section_attrs::DDR).raw_value(), + L1Section::new(299892736, section_attrs::DDR).raw_value(), + L1Section::new(300941312, section_attrs::DDR).raw_value(), + L1Section::new(301989888, section_attrs::DDR).raw_value(), + L1Section::new(303038464, section_attrs::DDR).raw_value(), + L1Section::new(304087040, section_attrs::DDR).raw_value(), + L1Section::new(305135616, section_attrs::DDR).raw_value(), + L1Section::new(306184192, section_attrs::DDR).raw_value(), + L1Section::new(307232768, section_attrs::DDR).raw_value(), + L1Section::new(308281344, section_attrs::DDR).raw_value(), + L1Section::new(309329920, section_attrs::DDR).raw_value(), + L1Section::new(310378496, section_attrs::DDR).raw_value(), + L1Section::new(311427072, section_attrs::DDR).raw_value(), + L1Section::new(312475648, section_attrs::DDR).raw_value(), + L1Section::new(313524224, section_attrs::DDR).raw_value(), + L1Section::new(314572800, section_attrs::DDR).raw_value(), + L1Section::new(315621376, section_attrs::DDR).raw_value(), + L1Section::new(316669952, section_attrs::DDR).raw_value(), + L1Section::new(317718528, section_attrs::DDR).raw_value(), + L1Section::new(318767104, section_attrs::DDR).raw_value(), + L1Section::new(319815680, section_attrs::DDR).raw_value(), + L1Section::new(320864256, section_attrs::DDR).raw_value(), + L1Section::new(321912832, section_attrs::DDR).raw_value(), + L1Section::new(322961408, section_attrs::DDR).raw_value(), + L1Section::new(324009984, section_attrs::DDR).raw_value(), + L1Section::new(325058560, section_attrs::DDR).raw_value(), + L1Section::new(326107136, section_attrs::DDR).raw_value(), + L1Section::new(327155712, section_attrs::DDR).raw_value(), + L1Section::new(328204288, section_attrs::DDR).raw_value(), + L1Section::new(329252864, section_attrs::DDR).raw_value(), + L1Section::new(330301440, section_attrs::DDR).raw_value(), + L1Section::new(331350016, section_attrs::DDR).raw_value(), + L1Section::new(332398592, section_attrs::DDR).raw_value(), + L1Section::new(333447168, section_attrs::DDR).raw_value(), + L1Section::new(334495744, section_attrs::DDR).raw_value(), + L1Section::new(335544320, section_attrs::DDR).raw_value(), + L1Section::new(336592896, section_attrs::DDR).raw_value(), + L1Section::new(337641472, section_attrs::DDR).raw_value(), + L1Section::new(338690048, section_attrs::DDR).raw_value(), + L1Section::new(339738624, section_attrs::DDR).raw_value(), + L1Section::new(340787200, section_attrs::DDR).raw_value(), + L1Section::new(341835776, section_attrs::DDR).raw_value(), + L1Section::new(342884352, section_attrs::DDR).raw_value(), + L1Section::new(343932928, section_attrs::DDR).raw_value(), + L1Section::new(344981504, section_attrs::DDR).raw_value(), + L1Section::new(346030080, section_attrs::DDR).raw_value(), + L1Section::new(347078656, section_attrs::DDR).raw_value(), + L1Section::new(348127232, section_attrs::DDR).raw_value(), + L1Section::new(349175808, section_attrs::DDR).raw_value(), + L1Section::new(350224384, section_attrs::DDR).raw_value(), + L1Section::new(351272960, section_attrs::DDR).raw_value(), + L1Section::new(352321536, section_attrs::DDR).raw_value(), + L1Section::new(353370112, section_attrs::DDR).raw_value(), + L1Section::new(354418688, section_attrs::DDR).raw_value(), + L1Section::new(355467264, section_attrs::DDR).raw_value(), + L1Section::new(356515840, section_attrs::DDR).raw_value(), + L1Section::new(357564416, section_attrs::DDR).raw_value(), + L1Section::new(358612992, section_attrs::DDR).raw_value(), + L1Section::new(359661568, section_attrs::DDR).raw_value(), + L1Section::new(360710144, section_attrs::DDR).raw_value(), + L1Section::new(361758720, section_attrs::DDR).raw_value(), + L1Section::new(362807296, section_attrs::DDR).raw_value(), + L1Section::new(363855872, section_attrs::DDR).raw_value(), + L1Section::new(364904448, section_attrs::DDR).raw_value(), + L1Section::new(365953024, section_attrs::DDR).raw_value(), + L1Section::new(367001600, section_attrs::DDR).raw_value(), + L1Section::new(368050176, section_attrs::DDR).raw_value(), + L1Section::new(369098752, section_attrs::DDR).raw_value(), + L1Section::new(370147328, section_attrs::DDR).raw_value(), + L1Section::new(371195904, section_attrs::DDR).raw_value(), + L1Section::new(372244480, section_attrs::DDR).raw_value(), + L1Section::new(373293056, section_attrs::DDR).raw_value(), + L1Section::new(374341632, section_attrs::DDR).raw_value(), + L1Section::new(375390208, section_attrs::DDR).raw_value(), + L1Section::new(376438784, section_attrs::DDR).raw_value(), + L1Section::new(377487360, section_attrs::DDR).raw_value(), + L1Section::new(378535936, section_attrs::DDR).raw_value(), + L1Section::new(379584512, section_attrs::DDR).raw_value(), + L1Section::new(380633088, section_attrs::DDR).raw_value(), + L1Section::new(381681664, section_attrs::DDR).raw_value(), + L1Section::new(382730240, section_attrs::DDR).raw_value(), + L1Section::new(383778816, section_attrs::DDR).raw_value(), + L1Section::new(384827392, section_attrs::DDR).raw_value(), + L1Section::new(385875968, section_attrs::DDR).raw_value(), + L1Section::new(386924544, section_attrs::DDR).raw_value(), + L1Section::new(387973120, section_attrs::DDR).raw_value(), + L1Section::new(389021696, section_attrs::DDR).raw_value(), + L1Section::new(390070272, section_attrs::DDR).raw_value(), + L1Section::new(391118848, section_attrs::DDR).raw_value(), + L1Section::new(392167424, section_attrs::DDR).raw_value(), + L1Section::new(393216000, section_attrs::DDR).raw_value(), + L1Section::new(394264576, section_attrs::DDR).raw_value(), + L1Section::new(395313152, section_attrs::DDR).raw_value(), + L1Section::new(396361728, section_attrs::DDR).raw_value(), + L1Section::new(397410304, section_attrs::DDR).raw_value(), + L1Section::new(398458880, section_attrs::DDR).raw_value(), + L1Section::new(399507456, section_attrs::DDR).raw_value(), + L1Section::new(400556032, section_attrs::DDR).raw_value(), + L1Section::new(401604608, section_attrs::DDR).raw_value(), + L1Section::new(402653184, section_attrs::DDR).raw_value(), + L1Section::new(403701760, section_attrs::DDR).raw_value(), + L1Section::new(404750336, section_attrs::DDR).raw_value(), + L1Section::new(405798912, section_attrs::DDR).raw_value(), + L1Section::new(406847488, section_attrs::DDR).raw_value(), + L1Section::new(407896064, section_attrs::DDR).raw_value(), + L1Section::new(408944640, section_attrs::DDR).raw_value(), + L1Section::new(409993216, section_attrs::DDR).raw_value(), + L1Section::new(411041792, section_attrs::DDR).raw_value(), + L1Section::new(412090368, section_attrs::DDR).raw_value(), + L1Section::new(413138944, section_attrs::DDR).raw_value(), + L1Section::new(414187520, section_attrs::DDR).raw_value(), + L1Section::new(415236096, section_attrs::DDR).raw_value(), + L1Section::new(416284672, section_attrs::DDR).raw_value(), + L1Section::new(417333248, section_attrs::DDR).raw_value(), + L1Section::new(418381824, section_attrs::DDR).raw_value(), + L1Section::new(419430400, section_attrs::DDR).raw_value(), + L1Section::new(420478976, section_attrs::DDR).raw_value(), + L1Section::new(421527552, section_attrs::DDR).raw_value(), + L1Section::new(422576128, section_attrs::DDR).raw_value(), + L1Section::new(423624704, section_attrs::DDR).raw_value(), + L1Section::new(424673280, section_attrs::DDR).raw_value(), + L1Section::new(425721856, section_attrs::DDR).raw_value(), + L1Section::new(426770432, section_attrs::DDR).raw_value(), + L1Section::new(427819008, section_attrs::DDR).raw_value(), + L1Section::new(428867584, section_attrs::DDR).raw_value(), + L1Section::new(429916160, section_attrs::DDR).raw_value(), + L1Section::new(430964736, section_attrs::DDR).raw_value(), + L1Section::new(432013312, section_attrs::DDR).raw_value(), + L1Section::new(433061888, section_attrs::DDR).raw_value(), + L1Section::new(434110464, section_attrs::DDR).raw_value(), + L1Section::new(435159040, section_attrs::DDR).raw_value(), + L1Section::new(436207616, section_attrs::DDR).raw_value(), + L1Section::new(437256192, section_attrs::DDR).raw_value(), + L1Section::new(438304768, section_attrs::DDR).raw_value(), + L1Section::new(439353344, section_attrs::DDR).raw_value(), + L1Section::new(440401920, section_attrs::DDR).raw_value(), + L1Section::new(441450496, section_attrs::DDR).raw_value(), + L1Section::new(442499072, section_attrs::DDR).raw_value(), + L1Section::new(443547648, section_attrs::DDR).raw_value(), + L1Section::new(444596224, section_attrs::DDR).raw_value(), + L1Section::new(445644800, section_attrs::DDR).raw_value(), + L1Section::new(446693376, section_attrs::DDR).raw_value(), + L1Section::new(447741952, section_attrs::DDR).raw_value(), + L1Section::new(448790528, section_attrs::DDR).raw_value(), + L1Section::new(449839104, section_attrs::DDR).raw_value(), + L1Section::new(450887680, section_attrs::DDR).raw_value(), + L1Section::new(451936256, section_attrs::DDR).raw_value(), + L1Section::new(452984832, section_attrs::DDR).raw_value(), + L1Section::new(454033408, section_attrs::DDR).raw_value(), + L1Section::new(455081984, section_attrs::DDR).raw_value(), + L1Section::new(456130560, section_attrs::DDR).raw_value(), + L1Section::new(457179136, section_attrs::DDR).raw_value(), + L1Section::new(458227712, section_attrs::DDR).raw_value(), + L1Section::new(459276288, section_attrs::DDR).raw_value(), + L1Section::new(460324864, section_attrs::DDR).raw_value(), + L1Section::new(461373440, section_attrs::DDR).raw_value(), + L1Section::new(462422016, section_attrs::DDR).raw_value(), + L1Section::new(463470592, section_attrs::DDR).raw_value(), + L1Section::new(464519168, section_attrs::DDR).raw_value(), + L1Section::new(465567744, section_attrs::DDR).raw_value(), + L1Section::new(466616320, section_attrs::DDR).raw_value(), + L1Section::new(467664896, section_attrs::DDR).raw_value(), + L1Section::new(468713472, section_attrs::DDR).raw_value(), + L1Section::new(469762048, section_attrs::DDR).raw_value(), + L1Section::new(470810624, section_attrs::DDR).raw_value(), + L1Section::new(471859200, section_attrs::DDR).raw_value(), + L1Section::new(472907776, section_attrs::DDR).raw_value(), + L1Section::new(473956352, section_attrs::DDR).raw_value(), + L1Section::new(475004928, section_attrs::DDR).raw_value(), + L1Section::new(476053504, section_attrs::DDR).raw_value(), + L1Section::new(477102080, section_attrs::DDR).raw_value(), + L1Section::new(478150656, section_attrs::DDR).raw_value(), + L1Section::new(479199232, section_attrs::DDR).raw_value(), + L1Section::new(480247808, section_attrs::DDR).raw_value(), + L1Section::new(481296384, section_attrs::DDR).raw_value(), + L1Section::new(482344960, section_attrs::DDR).raw_value(), + L1Section::new(483393536, section_attrs::DDR).raw_value(), + L1Section::new(484442112, section_attrs::DDR).raw_value(), + L1Section::new(485490688, section_attrs::DDR).raw_value(), + L1Section::new(486539264, section_attrs::DDR).raw_value(), + L1Section::new(487587840, section_attrs::DDR).raw_value(), + L1Section::new(488636416, section_attrs::DDR).raw_value(), + L1Section::new(489684992, section_attrs::DDR).raw_value(), + L1Section::new(490733568, section_attrs::DDR).raw_value(), + L1Section::new(491782144, section_attrs::DDR).raw_value(), + L1Section::new(492830720, section_attrs::DDR).raw_value(), + L1Section::new(493879296, section_attrs::DDR).raw_value(), + L1Section::new(494927872, section_attrs::DDR).raw_value(), + L1Section::new(495976448, section_attrs::DDR).raw_value(), + L1Section::new(497025024, section_attrs::DDR).raw_value(), + L1Section::new(498073600, section_attrs::DDR).raw_value(), + L1Section::new(499122176, section_attrs::DDR).raw_value(), + L1Section::new(500170752, section_attrs::DDR).raw_value(), + L1Section::new(501219328, section_attrs::DDR).raw_value(), + L1Section::new(502267904, section_attrs::DDR).raw_value(), + L1Section::new(503316480, section_attrs::DDR).raw_value(), + L1Section::new(504365056, section_attrs::DDR).raw_value(), + L1Section::new(505413632, section_attrs::DDR).raw_value(), + L1Section::new(506462208, section_attrs::DDR).raw_value(), + L1Section::new(507510784, section_attrs::DDR).raw_value(), + L1Section::new(508559360, section_attrs::DDR).raw_value(), + L1Section::new(509607936, section_attrs::DDR).raw_value(), + L1Section::new(510656512, section_attrs::DDR).raw_value(), + L1Section::new(511705088, section_attrs::DDR).raw_value(), + L1Section::new(512753664, section_attrs::DDR).raw_value(), + L1Section::new(513802240, section_attrs::DDR).raw_value(), + L1Section::new(514850816, section_attrs::DDR).raw_value(), + L1Section::new(515899392, section_attrs::DDR).raw_value(), + L1Section::new(516947968, section_attrs::DDR).raw_value(), + L1Section::new(517996544, section_attrs::DDR).raw_value(), + L1Section::new(519045120, section_attrs::DDR).raw_value(), + L1Section::new(520093696, section_attrs::DDR).raw_value(), + L1Section::new(521142272, section_attrs::DDR).raw_value(), + L1Section::new(522190848, section_attrs::DDR).raw_value(), + L1Section::new(523239424, section_attrs::DDR).raw_value(), + L1Section::new(524288000, section_attrs::DDR).raw_value(), + L1Section::new(525336576, section_attrs::DDR).raw_value(), + L1Section::new(526385152, section_attrs::DDR).raw_value(), + L1Section::new(527433728, section_attrs::DDR).raw_value(), + L1Section::new(528482304, section_attrs::DDR).raw_value(), + L1Section::new(529530880, section_attrs::DDR).raw_value(), + L1Section::new(530579456, section_attrs::DDR).raw_value(), + L1Section::new(531628032, section_attrs::DDR).raw_value(), + L1Section::new(532676608, section_attrs::DDR).raw_value(), + L1Section::new(533725184, section_attrs::DDR).raw_value(), + L1Section::new(534773760, section_attrs::DDR).raw_value(), + L1Section::new(535822336, section_attrs::DDR).raw_value(), + L1Section::new(536870912, section_attrs::DDR).raw_value(), + L1Section::new(537919488, section_attrs::DDR).raw_value(), + L1Section::new(538968064, section_attrs::DDR).raw_value(), + L1Section::new(540016640, section_attrs::DDR).raw_value(), + L1Section::new(541065216, section_attrs::DDR).raw_value(), + L1Section::new(542113792, section_attrs::DDR).raw_value(), + L1Section::new(543162368, section_attrs::DDR).raw_value(), + L1Section::new(544210944, section_attrs::DDR).raw_value(), + L1Section::new(545259520, section_attrs::DDR).raw_value(), + L1Section::new(546308096, section_attrs::DDR).raw_value(), + L1Section::new(547356672, section_attrs::DDR).raw_value(), + L1Section::new(548405248, section_attrs::DDR).raw_value(), + L1Section::new(549453824, section_attrs::DDR).raw_value(), + L1Section::new(550502400, section_attrs::DDR).raw_value(), + L1Section::new(551550976, section_attrs::DDR).raw_value(), + L1Section::new(552599552, section_attrs::DDR).raw_value(), + L1Section::new(553648128, section_attrs::DDR).raw_value(), + L1Section::new(554696704, section_attrs::DDR).raw_value(), + L1Section::new(555745280, section_attrs::DDR).raw_value(), + L1Section::new(556793856, section_attrs::DDR).raw_value(), + L1Section::new(557842432, section_attrs::DDR).raw_value(), + L1Section::new(558891008, section_attrs::DDR).raw_value(), + L1Section::new(559939584, section_attrs::DDR).raw_value(), + L1Section::new(560988160, section_attrs::DDR).raw_value(), + L1Section::new(562036736, section_attrs::DDR).raw_value(), + L1Section::new(563085312, section_attrs::DDR).raw_value(), + L1Section::new(564133888, section_attrs::DDR).raw_value(), + L1Section::new(565182464, section_attrs::DDR).raw_value(), + L1Section::new(566231040, section_attrs::DDR).raw_value(), + L1Section::new(567279616, section_attrs::DDR).raw_value(), + L1Section::new(568328192, section_attrs::DDR).raw_value(), + L1Section::new(569376768, section_attrs::DDR).raw_value(), + L1Section::new(570425344, section_attrs::DDR).raw_value(), + L1Section::new(571473920, section_attrs::DDR).raw_value(), + L1Section::new(572522496, section_attrs::DDR).raw_value(), + L1Section::new(573571072, section_attrs::DDR).raw_value(), + L1Section::new(574619648, section_attrs::DDR).raw_value(), + L1Section::new(575668224, section_attrs::DDR).raw_value(), + L1Section::new(576716800, section_attrs::DDR).raw_value(), + L1Section::new(577765376, section_attrs::DDR).raw_value(), + L1Section::new(578813952, section_attrs::DDR).raw_value(), + L1Section::new(579862528, section_attrs::DDR).raw_value(), + L1Section::new(580911104, section_attrs::DDR).raw_value(), + L1Section::new(581959680, section_attrs::DDR).raw_value(), + L1Section::new(583008256, section_attrs::DDR).raw_value(), + L1Section::new(584056832, section_attrs::DDR).raw_value(), + L1Section::new(585105408, section_attrs::DDR).raw_value(), + L1Section::new(586153984, section_attrs::DDR).raw_value(), + L1Section::new(587202560, section_attrs::DDR).raw_value(), + L1Section::new(588251136, section_attrs::DDR).raw_value(), + L1Section::new(589299712, section_attrs::DDR).raw_value(), + L1Section::new(590348288, section_attrs::DDR).raw_value(), + L1Section::new(591396864, section_attrs::DDR).raw_value(), + L1Section::new(592445440, section_attrs::DDR).raw_value(), + L1Section::new(593494016, section_attrs::DDR).raw_value(), + L1Section::new(594542592, section_attrs::DDR).raw_value(), + L1Section::new(595591168, section_attrs::DDR).raw_value(), + L1Section::new(596639744, section_attrs::DDR).raw_value(), + L1Section::new(597688320, section_attrs::DDR).raw_value(), + L1Section::new(598736896, section_attrs::DDR).raw_value(), + L1Section::new(599785472, section_attrs::DDR).raw_value(), + L1Section::new(600834048, section_attrs::DDR).raw_value(), + L1Section::new(601882624, section_attrs::DDR).raw_value(), + L1Section::new(602931200, section_attrs::DDR).raw_value(), + L1Section::new(603979776, section_attrs::DDR).raw_value(), + L1Section::new(605028352, section_attrs::DDR).raw_value(), + L1Section::new(606076928, section_attrs::DDR).raw_value(), + L1Section::new(607125504, section_attrs::DDR).raw_value(), + L1Section::new(608174080, section_attrs::DDR).raw_value(), + L1Section::new(609222656, section_attrs::DDR).raw_value(), + L1Section::new(610271232, section_attrs::DDR).raw_value(), + L1Section::new(611319808, section_attrs::DDR).raw_value(), + L1Section::new(612368384, section_attrs::DDR).raw_value(), + L1Section::new(613416960, section_attrs::DDR).raw_value(), + L1Section::new(614465536, section_attrs::DDR).raw_value(), + L1Section::new(615514112, section_attrs::DDR).raw_value(), + L1Section::new(616562688, section_attrs::DDR).raw_value(), + L1Section::new(617611264, section_attrs::DDR).raw_value(), + L1Section::new(618659840, section_attrs::DDR).raw_value(), + L1Section::new(619708416, section_attrs::DDR).raw_value(), + L1Section::new(620756992, section_attrs::DDR).raw_value(), + L1Section::new(621805568, section_attrs::DDR).raw_value(), + L1Section::new(622854144, section_attrs::DDR).raw_value(), + L1Section::new(623902720, section_attrs::DDR).raw_value(), + L1Section::new(624951296, section_attrs::DDR).raw_value(), + L1Section::new(625999872, section_attrs::DDR).raw_value(), + L1Section::new(627048448, section_attrs::DDR).raw_value(), + L1Section::new(628097024, section_attrs::DDR).raw_value(), + L1Section::new(629145600, section_attrs::DDR).raw_value(), + L1Section::new(630194176, section_attrs::DDR).raw_value(), + L1Section::new(631242752, section_attrs::DDR).raw_value(), + L1Section::new(632291328, section_attrs::DDR).raw_value(), + L1Section::new(633339904, section_attrs::DDR).raw_value(), + L1Section::new(634388480, section_attrs::DDR).raw_value(), + L1Section::new(635437056, section_attrs::DDR).raw_value(), + L1Section::new(636485632, section_attrs::DDR).raw_value(), + L1Section::new(637534208, section_attrs::DDR).raw_value(), + L1Section::new(638582784, section_attrs::DDR).raw_value(), + L1Section::new(639631360, section_attrs::DDR).raw_value(), + L1Section::new(640679936, section_attrs::DDR).raw_value(), + L1Section::new(641728512, section_attrs::DDR).raw_value(), + L1Section::new(642777088, section_attrs::DDR).raw_value(), + L1Section::new(643825664, section_attrs::DDR).raw_value(), + L1Section::new(644874240, section_attrs::DDR).raw_value(), + L1Section::new(645922816, section_attrs::DDR).raw_value(), + L1Section::new(646971392, section_attrs::DDR).raw_value(), + L1Section::new(648019968, section_attrs::DDR).raw_value(), + L1Section::new(649068544, section_attrs::DDR).raw_value(), + L1Section::new(650117120, section_attrs::DDR).raw_value(), + L1Section::new(651165696, section_attrs::DDR).raw_value(), + L1Section::new(652214272, section_attrs::DDR).raw_value(), + L1Section::new(653262848, section_attrs::DDR).raw_value(), + L1Section::new(654311424, section_attrs::DDR).raw_value(), + L1Section::new(655360000, section_attrs::DDR).raw_value(), + L1Section::new(656408576, section_attrs::DDR).raw_value(), + L1Section::new(657457152, section_attrs::DDR).raw_value(), + L1Section::new(658505728, section_attrs::DDR).raw_value(), + L1Section::new(659554304, section_attrs::DDR).raw_value(), + L1Section::new(660602880, section_attrs::DDR).raw_value(), + L1Section::new(661651456, section_attrs::DDR).raw_value(), + L1Section::new(662700032, section_attrs::DDR).raw_value(), + L1Section::new(663748608, section_attrs::DDR).raw_value(), + L1Section::new(664797184, section_attrs::DDR).raw_value(), + L1Section::new(665845760, section_attrs::DDR).raw_value(), + L1Section::new(666894336, section_attrs::DDR).raw_value(), + L1Section::new(667942912, section_attrs::DDR).raw_value(), + L1Section::new(668991488, section_attrs::DDR).raw_value(), + L1Section::new(670040064, section_attrs::DDR).raw_value(), + L1Section::new(671088640, section_attrs::DDR).raw_value(), + L1Section::new(672137216, section_attrs::DDR).raw_value(), + L1Section::new(673185792, section_attrs::DDR).raw_value(), + L1Section::new(674234368, section_attrs::DDR).raw_value(), + L1Section::new(675282944, section_attrs::DDR).raw_value(), + L1Section::new(676331520, section_attrs::DDR).raw_value(), + L1Section::new(677380096, section_attrs::DDR).raw_value(), + L1Section::new(678428672, section_attrs::DDR).raw_value(), + L1Section::new(679477248, section_attrs::DDR).raw_value(), + L1Section::new(680525824, section_attrs::DDR).raw_value(), + L1Section::new(681574400, section_attrs::DDR).raw_value(), + L1Section::new(682622976, section_attrs::DDR).raw_value(), + L1Section::new(683671552, section_attrs::DDR).raw_value(), + L1Section::new(684720128, section_attrs::DDR).raw_value(), + L1Section::new(685768704, section_attrs::DDR).raw_value(), + L1Section::new(686817280, section_attrs::DDR).raw_value(), + L1Section::new(687865856, section_attrs::DDR).raw_value(), + L1Section::new(688914432, section_attrs::DDR).raw_value(), + L1Section::new(689963008, section_attrs::DDR).raw_value(), + L1Section::new(691011584, section_attrs::DDR).raw_value(), + L1Section::new(692060160, section_attrs::DDR).raw_value(), + L1Section::new(693108736, section_attrs::DDR).raw_value(), + L1Section::new(694157312, section_attrs::DDR).raw_value(), + L1Section::new(695205888, section_attrs::DDR).raw_value(), + L1Section::new(696254464, section_attrs::DDR).raw_value(), + L1Section::new(697303040, section_attrs::DDR).raw_value(), + L1Section::new(698351616, section_attrs::DDR).raw_value(), + L1Section::new(699400192, section_attrs::DDR).raw_value(), + L1Section::new(700448768, section_attrs::DDR).raw_value(), + L1Section::new(701497344, section_attrs::DDR).raw_value(), + L1Section::new(702545920, section_attrs::DDR).raw_value(), + L1Section::new(703594496, section_attrs::DDR).raw_value(), + L1Section::new(704643072, section_attrs::DDR).raw_value(), + L1Section::new(705691648, section_attrs::DDR).raw_value(), + L1Section::new(706740224, section_attrs::DDR).raw_value(), + L1Section::new(707788800, section_attrs::DDR).raw_value(), + L1Section::new(708837376, section_attrs::DDR).raw_value(), + L1Section::new(709885952, section_attrs::DDR).raw_value(), + L1Section::new(710934528, section_attrs::DDR).raw_value(), + L1Section::new(711983104, section_attrs::DDR).raw_value(), + L1Section::new(713031680, section_attrs::DDR).raw_value(), + L1Section::new(714080256, section_attrs::DDR).raw_value(), + L1Section::new(715128832, section_attrs::DDR).raw_value(), + L1Section::new(716177408, section_attrs::DDR).raw_value(), + L1Section::new(717225984, section_attrs::DDR).raw_value(), + L1Section::new(718274560, section_attrs::DDR).raw_value(), + L1Section::new(719323136, section_attrs::DDR).raw_value(), + L1Section::new(720371712, section_attrs::DDR).raw_value(), + L1Section::new(721420288, section_attrs::DDR).raw_value(), + L1Section::new(722468864, section_attrs::DDR).raw_value(), + L1Section::new(723517440, section_attrs::DDR).raw_value(), + L1Section::new(724566016, section_attrs::DDR).raw_value(), + L1Section::new(725614592, section_attrs::DDR).raw_value(), + L1Section::new(726663168, section_attrs::DDR).raw_value(), + L1Section::new(727711744, section_attrs::DDR).raw_value(), + L1Section::new(728760320, section_attrs::DDR).raw_value(), + L1Section::new(729808896, section_attrs::DDR).raw_value(), + L1Section::new(730857472, section_attrs::DDR).raw_value(), + L1Section::new(731906048, section_attrs::DDR).raw_value(), + L1Section::new(732954624, section_attrs::DDR).raw_value(), + L1Section::new(734003200, section_attrs::DDR).raw_value(), + L1Section::new(735051776, section_attrs::DDR).raw_value(), + L1Section::new(736100352, section_attrs::DDR).raw_value(), + L1Section::new(737148928, section_attrs::DDR).raw_value(), + L1Section::new(738197504, section_attrs::DDR).raw_value(), + L1Section::new(739246080, section_attrs::DDR).raw_value(), + L1Section::new(740294656, section_attrs::DDR).raw_value(), + L1Section::new(741343232, section_attrs::DDR).raw_value(), + L1Section::new(742391808, section_attrs::DDR).raw_value(), + L1Section::new(743440384, section_attrs::DDR).raw_value(), + L1Section::new(744488960, section_attrs::DDR).raw_value(), + L1Section::new(745537536, section_attrs::DDR).raw_value(), + L1Section::new(746586112, section_attrs::DDR).raw_value(), + L1Section::new(747634688, section_attrs::DDR).raw_value(), + L1Section::new(748683264, section_attrs::DDR).raw_value(), + L1Section::new(749731840, section_attrs::DDR).raw_value(), + L1Section::new(750780416, section_attrs::DDR).raw_value(), + L1Section::new(751828992, section_attrs::DDR).raw_value(), + L1Section::new(752877568, section_attrs::DDR).raw_value(), + L1Section::new(753926144, section_attrs::DDR).raw_value(), + L1Section::new(754974720, section_attrs::DDR).raw_value(), + L1Section::new(756023296, section_attrs::DDR).raw_value(), + L1Section::new(757071872, section_attrs::DDR).raw_value(), + L1Section::new(758120448, section_attrs::DDR).raw_value(), + L1Section::new(759169024, section_attrs::DDR).raw_value(), + L1Section::new(760217600, section_attrs::DDR).raw_value(), + L1Section::new(761266176, section_attrs::DDR).raw_value(), + L1Section::new(762314752, section_attrs::DDR).raw_value(), + L1Section::new(763363328, section_attrs::DDR).raw_value(), + L1Section::new(764411904, section_attrs::DDR).raw_value(), + L1Section::new(765460480, section_attrs::DDR).raw_value(), + L1Section::new(766509056, section_attrs::DDR).raw_value(), + L1Section::new(767557632, section_attrs::DDR).raw_value(), + L1Section::new(768606208, section_attrs::DDR).raw_value(), + L1Section::new(769654784, section_attrs::DDR).raw_value(), + L1Section::new(770703360, section_attrs::DDR).raw_value(), + L1Section::new(771751936, section_attrs::DDR).raw_value(), + L1Section::new(772800512, section_attrs::DDR).raw_value(), + L1Section::new(773849088, section_attrs::DDR).raw_value(), + L1Section::new(774897664, section_attrs::DDR).raw_value(), + L1Section::new(775946240, section_attrs::DDR).raw_value(), + L1Section::new(776994816, section_attrs::DDR).raw_value(), + L1Section::new(778043392, section_attrs::DDR).raw_value(), + L1Section::new(779091968, section_attrs::DDR).raw_value(), + L1Section::new(780140544, section_attrs::DDR).raw_value(), + L1Section::new(781189120, section_attrs::DDR).raw_value(), + L1Section::new(782237696, section_attrs::DDR).raw_value(), + L1Section::new(783286272, section_attrs::DDR).raw_value(), + L1Section::new(784334848, section_attrs::DDR).raw_value(), + L1Section::new(785383424, section_attrs::DDR).raw_value(), + L1Section::new(786432000, section_attrs::DDR).raw_value(), + L1Section::new(787480576, section_attrs::DDR).raw_value(), + L1Section::new(788529152, section_attrs::DDR).raw_value(), + L1Section::new(789577728, section_attrs::DDR).raw_value(), + L1Section::new(790626304, section_attrs::DDR).raw_value(), + L1Section::new(791674880, section_attrs::DDR).raw_value(), + L1Section::new(792723456, section_attrs::DDR).raw_value(), + L1Section::new(793772032, section_attrs::DDR).raw_value(), + L1Section::new(794820608, section_attrs::DDR).raw_value(), + L1Section::new(795869184, section_attrs::DDR).raw_value(), + L1Section::new(796917760, section_attrs::DDR).raw_value(), + L1Section::new(797966336, section_attrs::DDR).raw_value(), + L1Section::new(799014912, section_attrs::DDR).raw_value(), + L1Section::new(800063488, section_attrs::DDR).raw_value(), + L1Section::new(801112064, section_attrs::DDR).raw_value(), + L1Section::new(802160640, section_attrs::DDR).raw_value(), + L1Section::new(803209216, section_attrs::DDR).raw_value(), + L1Section::new(804257792, section_attrs::DDR).raw_value(), + L1Section::new(805306368, section_attrs::DDR).raw_value(), + L1Section::new(806354944, section_attrs::DDR).raw_value(), + L1Section::new(807403520, section_attrs::DDR).raw_value(), + L1Section::new(808452096, section_attrs::DDR).raw_value(), + L1Section::new(809500672, section_attrs::DDR).raw_value(), + L1Section::new(810549248, section_attrs::DDR).raw_value(), + L1Section::new(811597824, section_attrs::DDR).raw_value(), + L1Section::new(812646400, section_attrs::DDR).raw_value(), + L1Section::new(813694976, section_attrs::DDR).raw_value(), + L1Section::new(814743552, section_attrs::DDR).raw_value(), + L1Section::new(815792128, section_attrs::DDR).raw_value(), + L1Section::new(816840704, section_attrs::DDR).raw_value(), + L1Section::new(817889280, section_attrs::DDR).raw_value(), + L1Section::new(818937856, section_attrs::DDR).raw_value(), + L1Section::new(819986432, section_attrs::DDR).raw_value(), + L1Section::new(821035008, section_attrs::DDR).raw_value(), + L1Section::new(822083584, section_attrs::DDR).raw_value(), + L1Section::new(823132160, section_attrs::DDR).raw_value(), + L1Section::new(824180736, section_attrs::DDR).raw_value(), + L1Section::new(825229312, section_attrs::DDR).raw_value(), + L1Section::new(826277888, section_attrs::DDR).raw_value(), + L1Section::new(827326464, section_attrs::DDR).raw_value(), + L1Section::new(828375040, section_attrs::DDR).raw_value(), + L1Section::new(829423616, section_attrs::DDR).raw_value(), + L1Section::new(830472192, section_attrs::DDR).raw_value(), + L1Section::new(831520768, section_attrs::DDR).raw_value(), + L1Section::new(832569344, section_attrs::DDR).raw_value(), + L1Section::new(833617920, section_attrs::DDR).raw_value(), + L1Section::new(834666496, section_attrs::DDR).raw_value(), + L1Section::new(835715072, section_attrs::DDR).raw_value(), + L1Section::new(836763648, section_attrs::DDR).raw_value(), + L1Section::new(837812224, section_attrs::DDR).raw_value(), + L1Section::new(838860800, section_attrs::DDR).raw_value(), + L1Section::new(839909376, section_attrs::DDR).raw_value(), + L1Section::new(840957952, section_attrs::DDR).raw_value(), + L1Section::new(842006528, section_attrs::DDR).raw_value(), + L1Section::new(843055104, section_attrs::DDR).raw_value(), + L1Section::new(844103680, section_attrs::DDR).raw_value(), + L1Section::new(845152256, section_attrs::DDR).raw_value(), + L1Section::new(846200832, section_attrs::DDR).raw_value(), + L1Section::new(847249408, section_attrs::DDR).raw_value(), + L1Section::new(848297984, section_attrs::DDR).raw_value(), + L1Section::new(849346560, section_attrs::DDR).raw_value(), + L1Section::new(850395136, section_attrs::DDR).raw_value(), + L1Section::new(851443712, section_attrs::DDR).raw_value(), + L1Section::new(852492288, section_attrs::DDR).raw_value(), + L1Section::new(853540864, section_attrs::DDR).raw_value(), + L1Section::new(854589440, section_attrs::DDR).raw_value(), + L1Section::new(855638016, section_attrs::DDR).raw_value(), + L1Section::new(856686592, section_attrs::DDR).raw_value(), + L1Section::new(857735168, section_attrs::DDR).raw_value(), + L1Section::new(858783744, section_attrs::DDR).raw_value(), + L1Section::new(859832320, section_attrs::DDR).raw_value(), + L1Section::new(860880896, section_attrs::DDR).raw_value(), + L1Section::new(861929472, section_attrs::DDR).raw_value(), + L1Section::new(862978048, section_attrs::DDR).raw_value(), + L1Section::new(864026624, section_attrs::DDR).raw_value(), + L1Section::new(865075200, section_attrs::DDR).raw_value(), + L1Section::new(866123776, section_attrs::DDR).raw_value(), + L1Section::new(867172352, section_attrs::DDR).raw_value(), + L1Section::new(868220928, section_attrs::DDR).raw_value(), + L1Section::new(869269504, section_attrs::DDR).raw_value(), + L1Section::new(870318080, section_attrs::DDR).raw_value(), + L1Section::new(871366656, section_attrs::DDR).raw_value(), + L1Section::new(872415232, section_attrs::DDR).raw_value(), + L1Section::new(873463808, section_attrs::DDR).raw_value(), + L1Section::new(874512384, section_attrs::DDR).raw_value(), + L1Section::new(875560960, section_attrs::DDR).raw_value(), + L1Section::new(876609536, section_attrs::DDR).raw_value(), + L1Section::new(877658112, section_attrs::DDR).raw_value(), + L1Section::new(878706688, section_attrs::DDR).raw_value(), + L1Section::new(879755264, section_attrs::DDR).raw_value(), + L1Section::new(880803840, section_attrs::DDR).raw_value(), + L1Section::new(881852416, section_attrs::DDR).raw_value(), + L1Section::new(882900992, section_attrs::DDR).raw_value(), + L1Section::new(883949568, section_attrs::DDR).raw_value(), + L1Section::new(884998144, section_attrs::DDR).raw_value(), + L1Section::new(886046720, section_attrs::DDR).raw_value(), + L1Section::new(887095296, section_attrs::DDR).raw_value(), + L1Section::new(888143872, section_attrs::DDR).raw_value(), + L1Section::new(889192448, section_attrs::DDR).raw_value(), + L1Section::new(890241024, section_attrs::DDR).raw_value(), + L1Section::new(891289600, section_attrs::DDR).raw_value(), + L1Section::new(892338176, section_attrs::DDR).raw_value(), + L1Section::new(893386752, section_attrs::DDR).raw_value(), + L1Section::new(894435328, section_attrs::DDR).raw_value(), + L1Section::new(895483904, section_attrs::DDR).raw_value(), + L1Section::new(896532480, section_attrs::DDR).raw_value(), + L1Section::new(897581056, section_attrs::DDR).raw_value(), + L1Section::new(898629632, section_attrs::DDR).raw_value(), + L1Section::new(899678208, section_attrs::DDR).raw_value(), + L1Section::new(900726784, section_attrs::DDR).raw_value(), + L1Section::new(901775360, section_attrs::DDR).raw_value(), + L1Section::new(902823936, section_attrs::DDR).raw_value(), + L1Section::new(903872512, section_attrs::DDR).raw_value(), + L1Section::new(904921088, section_attrs::DDR).raw_value(), + L1Section::new(905969664, section_attrs::DDR).raw_value(), + L1Section::new(907018240, section_attrs::DDR).raw_value(), + L1Section::new(908066816, section_attrs::DDR).raw_value(), + L1Section::new(909115392, section_attrs::DDR).raw_value(), + L1Section::new(910163968, section_attrs::DDR).raw_value(), + L1Section::new(911212544, section_attrs::DDR).raw_value(), + L1Section::new(912261120, section_attrs::DDR).raw_value(), + L1Section::new(913309696, section_attrs::DDR).raw_value(), + L1Section::new(914358272, section_attrs::DDR).raw_value(), + L1Section::new(915406848, section_attrs::DDR).raw_value(), + L1Section::new(916455424, section_attrs::DDR).raw_value(), + L1Section::new(917504000, section_attrs::DDR).raw_value(), + L1Section::new(918552576, section_attrs::DDR).raw_value(), + L1Section::new(919601152, section_attrs::DDR).raw_value(), + L1Section::new(920649728, section_attrs::DDR).raw_value(), + L1Section::new(921698304, section_attrs::DDR).raw_value(), + L1Section::new(922746880, section_attrs::DDR).raw_value(), + L1Section::new(923795456, section_attrs::DDR).raw_value(), + L1Section::new(924844032, section_attrs::DDR).raw_value(), + L1Section::new(925892608, section_attrs::DDR).raw_value(), + L1Section::new(926941184, section_attrs::DDR).raw_value(), + L1Section::new(927989760, section_attrs::DDR).raw_value(), + L1Section::new(929038336, section_attrs::DDR).raw_value(), + L1Section::new(930086912, section_attrs::DDR).raw_value(), + L1Section::new(931135488, section_attrs::DDR).raw_value(), + L1Section::new(932184064, section_attrs::DDR).raw_value(), + L1Section::new(933232640, section_attrs::DDR).raw_value(), + L1Section::new(934281216, section_attrs::DDR).raw_value(), + L1Section::new(935329792, section_attrs::DDR).raw_value(), + L1Section::new(936378368, section_attrs::DDR).raw_value(), + L1Section::new(937426944, section_attrs::DDR).raw_value(), + L1Section::new(938475520, section_attrs::DDR).raw_value(), + L1Section::new(939524096, section_attrs::DDR).raw_value(), + L1Section::new(940572672, section_attrs::DDR).raw_value(), + L1Section::new(941621248, section_attrs::DDR).raw_value(), + L1Section::new(942669824, section_attrs::DDR).raw_value(), + L1Section::new(943718400, section_attrs::DDR).raw_value(), + L1Section::new(944766976, section_attrs::DDR).raw_value(), + L1Section::new(945815552, section_attrs::DDR).raw_value(), + L1Section::new(946864128, section_attrs::DDR).raw_value(), + L1Section::new(947912704, section_attrs::DDR).raw_value(), + L1Section::new(948961280, section_attrs::DDR).raw_value(), + L1Section::new(950009856, section_attrs::DDR).raw_value(), + L1Section::new(951058432, section_attrs::DDR).raw_value(), + L1Section::new(952107008, section_attrs::DDR).raw_value(), + L1Section::new(953155584, section_attrs::DDR).raw_value(), + L1Section::new(954204160, section_attrs::DDR).raw_value(), + L1Section::new(955252736, section_attrs::DDR).raw_value(), + L1Section::new(956301312, section_attrs::DDR).raw_value(), + L1Section::new(957349888, section_attrs::DDR).raw_value(), + L1Section::new(958398464, section_attrs::DDR).raw_value(), + L1Section::new(959447040, section_attrs::DDR).raw_value(), + L1Section::new(960495616, section_attrs::DDR).raw_value(), + L1Section::new(961544192, section_attrs::DDR).raw_value(), + L1Section::new(962592768, section_attrs::DDR).raw_value(), + L1Section::new(963641344, section_attrs::DDR).raw_value(), + L1Section::new(964689920, section_attrs::DDR).raw_value(), + L1Section::new(965738496, section_attrs::DDR).raw_value(), + L1Section::new(966787072, section_attrs::DDR).raw_value(), + L1Section::new(967835648, section_attrs::DDR).raw_value(), + L1Section::new(968884224, section_attrs::DDR).raw_value(), + L1Section::new(969932800, section_attrs::DDR).raw_value(), + L1Section::new(970981376, section_attrs::DDR).raw_value(), + L1Section::new(972029952, section_attrs::DDR).raw_value(), + L1Section::new(973078528, section_attrs::DDR).raw_value(), + L1Section::new(974127104, section_attrs::DDR).raw_value(), + L1Section::new(975175680, section_attrs::DDR).raw_value(), + L1Section::new(976224256, section_attrs::DDR).raw_value(), + L1Section::new(977272832, section_attrs::DDR).raw_value(), + L1Section::new(978321408, section_attrs::DDR).raw_value(), + L1Section::new(979369984, section_attrs::DDR).raw_value(), + L1Section::new(980418560, section_attrs::DDR).raw_value(), + L1Section::new(981467136, section_attrs::DDR).raw_value(), + L1Section::new(982515712, section_attrs::DDR).raw_value(), + L1Section::new(983564288, section_attrs::DDR).raw_value(), + L1Section::new(984612864, section_attrs::DDR).raw_value(), + L1Section::new(985661440, section_attrs::DDR).raw_value(), + L1Section::new(986710016, section_attrs::DDR).raw_value(), + L1Section::new(987758592, section_attrs::DDR).raw_value(), + L1Section::new(988807168, section_attrs::DDR).raw_value(), + L1Section::new(989855744, section_attrs::DDR).raw_value(), + L1Section::new(990904320, section_attrs::DDR).raw_value(), + L1Section::new(991952896, section_attrs::DDR).raw_value(), + L1Section::new(993001472, section_attrs::DDR).raw_value(), + L1Section::new(994050048, section_attrs::DDR).raw_value(), + L1Section::new(995098624, section_attrs::DDR).raw_value(), + L1Section::new(996147200, section_attrs::DDR).raw_value(), + L1Section::new(997195776, section_attrs::DDR).raw_value(), + L1Section::new(998244352, section_attrs::DDR).raw_value(), + L1Section::new(999292928, section_attrs::DDR).raw_value(), + L1Section::new(1000341504, section_attrs::DDR).raw_value(), + L1Section::new(1001390080, section_attrs::DDR).raw_value(), + L1Section::new(1002438656, section_attrs::DDR).raw_value(), + L1Section::new(1003487232, section_attrs::DDR).raw_value(), + L1Section::new(1004535808, section_attrs::DDR).raw_value(), + L1Section::new(1005584384, section_attrs::DDR).raw_value(), + L1Section::new(1006632960, section_attrs::DDR).raw_value(), + L1Section::new(1007681536, section_attrs::DDR).raw_value(), + L1Section::new(1008730112, section_attrs::DDR).raw_value(), + L1Section::new(1009778688, section_attrs::DDR).raw_value(), + L1Section::new(1010827264, section_attrs::DDR).raw_value(), + L1Section::new(1011875840, section_attrs::DDR).raw_value(), + L1Section::new(1012924416, section_attrs::DDR).raw_value(), + L1Section::new(1013972992, section_attrs::DDR).raw_value(), + L1Section::new(1015021568, section_attrs::DDR).raw_value(), + L1Section::new(1016070144, section_attrs::DDR).raw_value(), + L1Section::new(1017118720, section_attrs::DDR).raw_value(), + L1Section::new(1018167296, section_attrs::DDR).raw_value(), + L1Section::new(1019215872, section_attrs::DDR).raw_value(), + L1Section::new(1020264448, section_attrs::DDR).raw_value(), + L1Section::new(1021313024, section_attrs::DDR).raw_value(), + L1Section::new(1022361600, section_attrs::DDR).raw_value(), + L1Section::new(1023410176, section_attrs::DDR).raw_value(), + L1Section::new(1024458752, section_attrs::DDR).raw_value(), + L1Section::new(1025507328, section_attrs::DDR).raw_value(), + L1Section::new(1026555904, section_attrs::DDR).raw_value(), + L1Section::new(1027604480, section_attrs::DDR).raw_value(), + L1Section::new(1028653056, section_attrs::DDR).raw_value(), + L1Section::new(1029701632, section_attrs::DDR).raw_value(), + L1Section::new(1030750208, section_attrs::DDR).raw_value(), + L1Section::new(1031798784, section_attrs::DDR).raw_value(), + L1Section::new(1032847360, section_attrs::DDR).raw_value(), + L1Section::new(1033895936, section_attrs::DDR).raw_value(), + L1Section::new(1034944512, section_attrs::DDR).raw_value(), + L1Section::new(1035993088, section_attrs::DDR).raw_value(), + L1Section::new(1037041664, section_attrs::DDR).raw_value(), + L1Section::new(1038090240, section_attrs::DDR).raw_value(), + L1Section::new(1039138816, section_attrs::DDR).raw_value(), + L1Section::new(1040187392, section_attrs::DDR).raw_value(), + L1Section::new(1041235968, section_attrs::DDR).raw_value(), + L1Section::new(1042284544, section_attrs::DDR).raw_value(), + L1Section::new(1043333120, section_attrs::DDR).raw_value(), + L1Section::new(1044381696, section_attrs::DDR).raw_value(), + L1Section::new(1045430272, section_attrs::DDR).raw_value(), + L1Section::new(1046478848, section_attrs::DDR).raw_value(), + L1Section::new(1047527424, section_attrs::DDR).raw_value(), + L1Section::new(1048576000, section_attrs::DDR).raw_value(), + L1Section::new(1049624576, section_attrs::DDR).raw_value(), + L1Section::new(1050673152, section_attrs::DDR).raw_value(), + L1Section::new(1051721728, section_attrs::DDR).raw_value(), + L1Section::new(1052770304, section_attrs::DDR).raw_value(), + L1Section::new(1053818880, section_attrs::DDR).raw_value(), + L1Section::new(1054867456, section_attrs::DDR).raw_value(), + L1Section::new(1055916032, section_attrs::DDR).raw_value(), + L1Section::new(1056964608, section_attrs::DDR).raw_value(), + L1Section::new(1058013184, section_attrs::DDR).raw_value(), + L1Section::new(1059061760, section_attrs::DDR).raw_value(), + L1Section::new(1060110336, section_attrs::DDR).raw_value(), + L1Section::new(1061158912, section_attrs::DDR).raw_value(), + L1Section::new(1062207488, section_attrs::DDR).raw_value(), + L1Section::new(1063256064, section_attrs::DDR).raw_value(), + L1Section::new(1064304640, section_attrs::DDR).raw_value(), + L1Section::new(1065353216, section_attrs::DDR).raw_value(), + L1Section::new(1066401792, section_attrs::DDR).raw_value(), + L1Section::new(1067450368, section_attrs::DDR).raw_value(), + L1Section::new(1068498944, section_attrs::DDR).raw_value(), + L1Section::new(1069547520, section_attrs::DDR).raw_value(), + L1Section::new(1070596096, section_attrs::DDR).raw_value(), + L1Section::new(1071644672, section_attrs::DDR).raw_value(), + L1Section::new(1072693248, section_attrs::DDR).raw_value(), + // FPGA slave 0 (0x4000_0000 - 0x8000_0000) + L1Section::new(1073741824, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1074790400, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1075838976, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1076887552, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1077936128, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1078984704, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1080033280, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1081081856, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1082130432, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1083179008, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1084227584, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1085276160, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1086324736, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1087373312, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1088421888, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1089470464, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1090519040, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1091567616, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1092616192, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1093664768, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1094713344, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1095761920, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1096810496, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1097859072, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1098907648, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1099956224, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1101004800, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1102053376, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1103101952, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1104150528, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1105199104, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1106247680, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1107296256, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1108344832, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1109393408, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1110441984, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1111490560, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1112539136, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1113587712, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1114636288, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1115684864, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1116733440, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1117782016, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1118830592, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1119879168, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1120927744, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1121976320, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1123024896, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1124073472, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1125122048, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1126170624, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1127219200, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1128267776, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1129316352, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1130364928, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1131413504, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1132462080, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1133510656, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1134559232, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1135607808, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1136656384, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1137704960, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1138753536, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1139802112, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1140850688, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1141899264, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1142947840, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1143996416, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1145044992, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1146093568, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1147142144, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1148190720, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1149239296, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1150287872, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1151336448, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1152385024, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1153433600, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1154482176, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1155530752, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1156579328, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1157627904, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1158676480, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1159725056, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1160773632, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1161822208, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1162870784, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1163919360, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1164967936, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1166016512, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1167065088, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1168113664, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1169162240, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1170210816, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1171259392, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1172307968, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1173356544, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1174405120, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1175453696, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1176502272, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1177550848, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1178599424, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1179648000, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1180696576, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1181745152, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1182793728, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1183842304, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1184890880, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1185939456, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1186988032, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1188036608, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1189085184, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1190133760, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1191182336, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1192230912, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1193279488, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1194328064, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1195376640, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1196425216, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1197473792, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1198522368, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1199570944, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1200619520, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1201668096, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1202716672, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1203765248, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1204813824, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1205862400, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1206910976, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1207959552, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1209008128, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1210056704, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1211105280, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1212153856, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1213202432, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1214251008, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1215299584, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1216348160, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1217396736, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1218445312, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1219493888, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1220542464, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1221591040, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1222639616, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1223688192, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1224736768, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1225785344, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1226833920, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1227882496, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1228931072, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1229979648, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1231028224, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1232076800, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1233125376, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1234173952, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1235222528, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1236271104, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1237319680, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1238368256, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1239416832, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1240465408, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1241513984, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1242562560, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1243611136, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1244659712, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1245708288, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1246756864, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1247805440, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1248854016, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1249902592, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1250951168, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1251999744, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1253048320, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1254096896, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1255145472, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1256194048, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1257242624, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1258291200, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1259339776, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1260388352, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1261436928, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1262485504, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1263534080, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1264582656, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1265631232, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1266679808, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1267728384, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1268776960, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1269825536, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1270874112, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1271922688, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1272971264, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1274019840, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1275068416, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1276116992, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1277165568, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1278214144, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1279262720, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1280311296, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1281359872, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1282408448, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1283457024, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1284505600, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1285554176, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1286602752, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1287651328, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1288699904, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1289748480, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1290797056, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1291845632, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1292894208, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1293942784, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1294991360, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1296039936, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1297088512, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1298137088, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1299185664, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1300234240, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1301282816, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1302331392, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1303379968, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1304428544, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1305477120, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1306525696, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1307574272, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1308622848, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1309671424, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1310720000, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1311768576, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1312817152, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1313865728, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1314914304, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1315962880, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1317011456, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1318060032, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1319108608, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1320157184, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1321205760, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1322254336, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1323302912, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1324351488, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1325400064, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1326448640, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1327497216, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1328545792, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1329594368, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1330642944, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1331691520, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1332740096, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1333788672, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1334837248, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1335885824, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1336934400, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1337982976, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1339031552, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1340080128, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1341128704, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1342177280, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1343225856, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1344274432, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1345323008, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1346371584, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1347420160, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1348468736, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1349517312, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1350565888, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1351614464, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1352663040, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1353711616, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1354760192, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1355808768, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1356857344, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1357905920, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1358954496, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1360003072, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1361051648, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1362100224, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1363148800, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1364197376, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1365245952, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1366294528, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1367343104, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1368391680, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1369440256, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1370488832, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1371537408, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1372585984, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1373634560, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1374683136, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1375731712, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1376780288, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1377828864, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1378877440, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1379926016, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1380974592, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1382023168, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1383071744, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1384120320, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1385168896, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1386217472, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1387266048, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1388314624, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1389363200, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1390411776, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1391460352, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1392508928, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1393557504, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1394606080, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1395654656, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1396703232, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1397751808, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1398800384, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1399848960, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1400897536, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1401946112, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1402994688, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1404043264, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1405091840, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1406140416, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1407188992, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1408237568, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1409286144, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1410334720, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1411383296, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1412431872, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1413480448, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1414529024, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1415577600, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1416626176, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1417674752, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1418723328, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1419771904, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1420820480, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1421869056, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1422917632, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1423966208, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1425014784, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1426063360, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1427111936, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1428160512, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1429209088, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1430257664, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1431306240, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1432354816, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1433403392, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1434451968, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1435500544, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1436549120, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1437597696, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1438646272, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1439694848, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1440743424, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1441792000, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1442840576, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1443889152, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1444937728, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1445986304, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1447034880, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1448083456, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1449132032, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1450180608, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1451229184, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1452277760, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1453326336, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1454374912, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1455423488, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1456472064, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1457520640, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1458569216, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1459617792, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1460666368, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1461714944, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1462763520, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1463812096, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1464860672, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1465909248, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1466957824, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1468006400, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1469054976, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1470103552, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1471152128, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1472200704, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1473249280, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1474297856, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1475346432, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1476395008, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1477443584, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1478492160, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1479540736, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1480589312, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1481637888, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1482686464, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1483735040, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1484783616, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1485832192, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1486880768, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1487929344, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1488977920, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1490026496, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1491075072, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1492123648, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1493172224, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1494220800, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1495269376, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1496317952, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1497366528, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1498415104, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1499463680, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1500512256, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1501560832, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1502609408, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1503657984, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1504706560, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1505755136, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1506803712, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1507852288, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1508900864, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1509949440, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1510998016, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1512046592, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1513095168, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1514143744, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1515192320, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1516240896, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1517289472, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1518338048, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1519386624, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1520435200, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1521483776, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1522532352, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1523580928, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1524629504, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1525678080, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1526726656, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1527775232, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1528823808, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1529872384, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1530920960, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1531969536, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1533018112, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1534066688, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1535115264, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1536163840, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1537212416, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1538260992, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1539309568, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1540358144, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1541406720, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1542455296, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1543503872, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1544552448, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1545601024, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1546649600, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1547698176, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1548746752, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1549795328, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1550843904, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1551892480, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1552941056, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1553989632, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1555038208, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1556086784, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1557135360, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1558183936, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1559232512, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1560281088, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1561329664, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1562378240, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1563426816, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1564475392, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1565523968, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1566572544, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1567621120, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1568669696, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1569718272, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1570766848, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1571815424, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1572864000, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1573912576, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1574961152, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1576009728, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1577058304, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1578106880, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1579155456, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1580204032, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1581252608, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1582301184, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1583349760, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1584398336, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1585446912, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1586495488, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1587544064, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1588592640, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1589641216, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1590689792, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1591738368, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1592786944, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1593835520, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1594884096, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1595932672, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1596981248, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1598029824, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1599078400, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1600126976, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1601175552, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1602224128, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1603272704, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1604321280, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1605369856, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1606418432, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1607467008, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1608515584, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1609564160, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1610612736, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1611661312, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1612709888, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1613758464, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1614807040, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1615855616, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1616904192, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1617952768, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1619001344, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1620049920, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1621098496, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1622147072, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1623195648, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1624244224, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1625292800, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1626341376, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1627389952, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1628438528, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1629487104, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1630535680, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1631584256, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1632632832, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1633681408, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1634729984, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1635778560, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1636827136, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1637875712, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1638924288, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1639972864, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1641021440, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1642070016, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1643118592, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1644167168, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1645215744, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1646264320, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1647312896, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1648361472, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1649410048, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1650458624, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1651507200, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1652555776, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1653604352, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1654652928, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1655701504, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1656750080, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1657798656, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1658847232, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1659895808, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1660944384, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1661992960, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1663041536, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1664090112, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1665138688, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1666187264, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1667235840, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1668284416, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1669332992, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1670381568, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1671430144, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1672478720, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1673527296, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1674575872, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1675624448, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1676673024, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1677721600, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1678770176, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1679818752, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1680867328, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1681915904, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1682964480, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1684013056, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1685061632, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1686110208, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1687158784, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1688207360, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1689255936, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1690304512, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1691353088, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1692401664, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1693450240, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1694498816, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1695547392, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1696595968, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1697644544, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1698693120, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1699741696, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1700790272, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1701838848, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1702887424, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1703936000, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1704984576, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1706033152, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1707081728, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1708130304, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1709178880, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1710227456, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1711276032, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1712324608, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1713373184, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1714421760, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1715470336, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1716518912, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1717567488, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1718616064, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1719664640, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1720713216, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1721761792, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1722810368, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1723858944, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1724907520, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1725956096, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1727004672, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1728053248, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1729101824, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1730150400, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1731198976, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1732247552, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1733296128, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1734344704, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1735393280, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1736441856, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1737490432, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1738539008, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1739587584, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1740636160, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1741684736, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1742733312, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1743781888, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1744830464, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1745879040, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1746927616, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1747976192, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1749024768, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1750073344, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1751121920, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1752170496, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1753219072, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1754267648, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1755316224, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1756364800, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1757413376, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1758461952, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1759510528, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1760559104, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1761607680, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1762656256, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1763704832, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1764753408, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1765801984, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1766850560, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1767899136, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1768947712, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1769996288, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1771044864, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1772093440, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1773142016, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1774190592, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1775239168, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1776287744, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1777336320, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1778384896, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1779433472, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1780482048, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1781530624, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1782579200, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1783627776, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1784676352, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1785724928, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1786773504, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1787822080, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1788870656, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1789919232, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1790967808, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1792016384, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1793064960, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1794113536, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1795162112, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1796210688, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1797259264, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1798307840, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1799356416, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1800404992, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1801453568, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1802502144, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1803550720, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1804599296, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1805647872, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1806696448, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1807745024, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1808793600, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1809842176, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1810890752, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1811939328, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1812987904, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1814036480, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1815085056, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1816133632, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1817182208, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1818230784, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1819279360, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1820327936, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1821376512, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1822425088, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1823473664, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1824522240, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1825570816, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1826619392, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1827667968, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1828716544, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1829765120, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1830813696, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1831862272, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1832910848, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1833959424, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1835008000, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1836056576, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1837105152, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1838153728, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1839202304, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1840250880, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1841299456, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1842348032, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1843396608, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1844445184, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1845493760, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1846542336, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1847590912, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1848639488, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1849688064, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1850736640, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1851785216, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1852833792, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1853882368, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1854930944, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1855979520, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1857028096, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1858076672, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1859125248, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1860173824, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1861222400, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1862270976, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1863319552, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1864368128, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1865416704, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1866465280, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1867513856, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1868562432, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1869611008, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1870659584, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1871708160, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1872756736, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1873805312, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1874853888, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1875902464, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1876951040, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1877999616, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1879048192, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1880096768, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1881145344, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1882193920, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1883242496, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1884291072, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1885339648, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1886388224, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1887436800, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1888485376, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1889533952, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1890582528, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1891631104, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1892679680, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1893728256, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1894776832, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1895825408, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1896873984, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1897922560, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1898971136, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1900019712, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1901068288, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1902116864, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1903165440, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1904214016, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1905262592, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1906311168, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1907359744, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1908408320, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1909456896, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1910505472, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1911554048, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1912602624, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1913651200, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1914699776, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1915748352, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1916796928, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1917845504, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1918894080, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1919942656, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1920991232, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1922039808, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1923088384, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1924136960, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1925185536, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1926234112, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1927282688, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1928331264, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1929379840, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1930428416, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1931476992, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1932525568, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1933574144, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1934622720, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1935671296, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1936719872, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1937768448, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1938817024, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1939865600, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1940914176, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1941962752, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1943011328, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1944059904, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1945108480, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1946157056, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1947205632, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1948254208, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1949302784, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1950351360, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1951399936, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1952448512, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1953497088, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1954545664, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1955594240, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1956642816, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1957691392, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1958739968, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1959788544, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1960837120, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1961885696, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1962934272, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1963982848, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1965031424, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1966080000, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1967128576, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1968177152, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1969225728, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1970274304, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1971322880, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1972371456, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1973420032, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1974468608, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1975517184, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1976565760, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1977614336, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1978662912, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1979711488, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1980760064, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1981808640, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1982857216, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1983905792, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1984954368, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1986002944, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1987051520, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1988100096, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1989148672, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1990197248, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1991245824, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1992294400, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1993342976, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1994391552, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1995440128, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1996488704, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1997537280, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1998585856, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(1999634432, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2000683008, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2001731584, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2002780160, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2003828736, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2004877312, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2005925888, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2006974464, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2008023040, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2009071616, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2010120192, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2011168768, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2012217344, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2013265920, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2014314496, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2015363072, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2016411648, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2017460224, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2018508800, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2019557376, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2020605952, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2021654528, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2022703104, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2023751680, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2024800256, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2025848832, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2026897408, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2027945984, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2028994560, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2030043136, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2031091712, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2032140288, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2033188864, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2034237440, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2035286016, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2036334592, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2037383168, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2038431744, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2039480320, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2040528896, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2041577472, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2042626048, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2043674624, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2044723200, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2045771776, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2046820352, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2047868928, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2048917504, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2049966080, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2051014656, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2052063232, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2053111808, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2054160384, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2055208960, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2056257536, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2057306112, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2058354688, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2059403264, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2060451840, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2061500416, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2062548992, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2063597568, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2064646144, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2065694720, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2066743296, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2067791872, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2068840448, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2069889024, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2070937600, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2071986176, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2073034752, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2074083328, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2075131904, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2076180480, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2077229056, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2078277632, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2079326208, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2080374784, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2081423360, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2082471936, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2083520512, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2084569088, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2085617664, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2086666240, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2087714816, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2088763392, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2089811968, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2090860544, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2091909120, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2092957696, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2094006272, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2095054848, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2096103424, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2097152000, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2098200576, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2099249152, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2100297728, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2101346304, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2102394880, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2103443456, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2104492032, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2105540608, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2106589184, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2107637760, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2108686336, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2109734912, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2110783488, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2111832064, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2112880640, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2113929216, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2114977792, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2116026368, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2117074944, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2118123520, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2119172096, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2120220672, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2121269248, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2122317824, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2123366400, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2124414976, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2125463552, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2126512128, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2127560704, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2128609280, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2129657856, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2130706432, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2131755008, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2132803584, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2133852160, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2134900736, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2135949312, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2136997888, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2138046464, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2139095040, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2140143616, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2141192192, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2142240768, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2143289344, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2144337920, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2145386496, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2146435072, section_attrs::FPGA_SLAVES).raw_value(), + // FPGA slave 1 (0x8000_0000 - 0xC000_0000) + L1Section::new(2147483648, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2148532224, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2149580800, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2150629376, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2151677952, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2152726528, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2153775104, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2154823680, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2155872256, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2156920832, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2157969408, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2159017984, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2160066560, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2161115136, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2162163712, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2163212288, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2164260864, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2165309440, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2166358016, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2167406592, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2168455168, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2169503744, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2170552320, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2171600896, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2172649472, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2173698048, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2174746624, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2175795200, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2176843776, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2177892352, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2178940928, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2179989504, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2181038080, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2182086656, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2183135232, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2184183808, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2185232384, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2186280960, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2187329536, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2188378112, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2189426688, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2190475264, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2191523840, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2192572416, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2193620992, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2194669568, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2195718144, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2196766720, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2197815296, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2198863872, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2199912448, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2200961024, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2202009600, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2203058176, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2204106752, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2205155328, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2206203904, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2207252480, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2208301056, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2209349632, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2210398208, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2211446784, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2212495360, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2213543936, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2214592512, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2215641088, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2216689664, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2217738240, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2218786816, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2219835392, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2220883968, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2221932544, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2222981120, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2224029696, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2225078272, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2226126848, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2227175424, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2228224000, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2229272576, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2230321152, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2231369728, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2232418304, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2233466880, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2234515456, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2235564032, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2236612608, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2237661184, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2238709760, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2239758336, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2240806912, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2241855488, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2242904064, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2243952640, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2245001216, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2246049792, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2247098368, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2248146944, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2249195520, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2250244096, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2251292672, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2252341248, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2253389824, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2254438400, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2255486976, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2256535552, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2257584128, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2258632704, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2259681280, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2260729856, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2261778432, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2262827008, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2263875584, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2264924160, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2265972736, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2267021312, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2268069888, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2269118464, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2270167040, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2271215616, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2272264192, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2273312768, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2274361344, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2275409920, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2276458496, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2277507072, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2278555648, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2279604224, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2280652800, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2281701376, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2282749952, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2283798528, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2284847104, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2285895680, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2286944256, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2287992832, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2289041408, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2290089984, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2291138560, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2292187136, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2293235712, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2294284288, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2295332864, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2296381440, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2297430016, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2298478592, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2299527168, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2300575744, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2301624320, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2302672896, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2303721472, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2304770048, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2305818624, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2306867200, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2307915776, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2308964352, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2310012928, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2311061504, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2312110080, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2313158656, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2314207232, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2315255808, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2316304384, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2317352960, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2318401536, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2319450112, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2320498688, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2321547264, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2322595840, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2323644416, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2324692992, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2325741568, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2326790144, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2327838720, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2328887296, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2329935872, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2330984448, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2332033024, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2333081600, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2334130176, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2335178752, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2336227328, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2337275904, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2338324480, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2339373056, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2340421632, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2341470208, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2342518784, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2343567360, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2344615936, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2345664512, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2346713088, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2347761664, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2348810240, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2349858816, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2350907392, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2351955968, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2353004544, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2354053120, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2355101696, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2356150272, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2357198848, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2358247424, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2359296000, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2360344576, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2361393152, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2362441728, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2363490304, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2364538880, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2365587456, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2366636032, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2367684608, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2368733184, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2369781760, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2370830336, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2371878912, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2372927488, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2373976064, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2375024640, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2376073216, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2377121792, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2378170368, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2379218944, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2380267520, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2381316096, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2382364672, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2383413248, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2384461824, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2385510400, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2386558976, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2387607552, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2388656128, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2389704704, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2390753280, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2391801856, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2392850432, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2393899008, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2394947584, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2395996160, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2397044736, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2398093312, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2399141888, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2400190464, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2401239040, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2402287616, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2403336192, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2404384768, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2405433344, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2406481920, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2407530496, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2408579072, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2409627648, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2410676224, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2411724800, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2412773376, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2413821952, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2414870528, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2415919104, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2416967680, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2418016256, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2419064832, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2420113408, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2421161984, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2422210560, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2423259136, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2424307712, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2425356288, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2426404864, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2427453440, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2428502016, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2429550592, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2430599168, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2431647744, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2432696320, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2433744896, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2434793472, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2435842048, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2436890624, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2437939200, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2438987776, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2440036352, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2441084928, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2442133504, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2443182080, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2444230656, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2445279232, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2446327808, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2447376384, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2448424960, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2449473536, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2450522112, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2451570688, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2452619264, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2453667840, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2454716416, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2455764992, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2456813568, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2457862144, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2458910720, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2459959296, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2461007872, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2462056448, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2463105024, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2464153600, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2465202176, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2466250752, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2467299328, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2468347904, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2469396480, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2470445056, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2471493632, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2472542208, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2473590784, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2474639360, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2475687936, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2476736512, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2477785088, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2478833664, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2479882240, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2480930816, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2481979392, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2483027968, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2484076544, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2485125120, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2486173696, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2487222272, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2488270848, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2489319424, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2490368000, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2491416576, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2492465152, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2493513728, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2494562304, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2495610880, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2496659456, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2497708032, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2498756608, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2499805184, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2500853760, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2501902336, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2502950912, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2503999488, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2505048064, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2506096640, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2507145216, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2508193792, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2509242368, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2510290944, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2511339520, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2512388096, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2513436672, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2514485248, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2515533824, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2516582400, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2517630976, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2518679552, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2519728128, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2520776704, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2521825280, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2522873856, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2523922432, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2524971008, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2526019584, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2527068160, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2528116736, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2529165312, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2530213888, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2531262464, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2532311040, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2533359616, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2534408192, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2535456768, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2536505344, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2537553920, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2538602496, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2539651072, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2540699648, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2541748224, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2542796800, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2543845376, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2544893952, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2545942528, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2546991104, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2548039680, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2549088256, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2550136832, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2551185408, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2552233984, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2553282560, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2554331136, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2555379712, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2556428288, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2557476864, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2558525440, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2559574016, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2560622592, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2561671168, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2562719744, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2563768320, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2564816896, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2565865472, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2566914048, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2567962624, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2569011200, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2570059776, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2571108352, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2572156928, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2573205504, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2574254080, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2575302656, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2576351232, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2577399808, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2578448384, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2579496960, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2580545536, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2581594112, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2582642688, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2583691264, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2584739840, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2585788416, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2586836992, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2587885568, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2588934144, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2589982720, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2591031296, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2592079872, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2593128448, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2594177024, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2595225600, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2596274176, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2597322752, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2598371328, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2599419904, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2600468480, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2601517056, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2602565632, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2603614208, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2604662784, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2605711360, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2606759936, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2607808512, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2608857088, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2609905664, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2610954240, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2612002816, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2613051392, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2614099968, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2615148544, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2616197120, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2617245696, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2618294272, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2619342848, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2620391424, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2621440000, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2622488576, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2623537152, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2624585728, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2625634304, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2626682880, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2627731456, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2628780032, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2629828608, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2630877184, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2631925760, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2632974336, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2634022912, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2635071488, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2636120064, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2637168640, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2638217216, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2639265792, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2640314368, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2641362944, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2642411520, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2643460096, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2644508672, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2645557248, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2646605824, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2647654400, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2648702976, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2649751552, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2650800128, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2651848704, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2652897280, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2653945856, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2654994432, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2656043008, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2657091584, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2658140160, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2659188736, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2660237312, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2661285888, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2662334464, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2663383040, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2664431616, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2665480192, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2666528768, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2667577344, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2668625920, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2669674496, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2670723072, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2671771648, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2672820224, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2673868800, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2674917376, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2675965952, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2677014528, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2678063104, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2679111680, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2680160256, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2681208832, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2682257408, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2683305984, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2684354560, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2685403136, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2686451712, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2687500288, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2688548864, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2689597440, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2690646016, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2691694592, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2692743168, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2693791744, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2694840320, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2695888896, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2696937472, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2697986048, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2699034624, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2700083200, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2701131776, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2702180352, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2703228928, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2704277504, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2705326080, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2706374656, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2707423232, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2708471808, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2709520384, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2710568960, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2711617536, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2712666112, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2713714688, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2714763264, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2715811840, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2716860416, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2717908992, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2718957568, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2720006144, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2721054720, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2722103296, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2723151872, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2724200448, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2725249024, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2726297600, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2727346176, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2728394752, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2729443328, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2730491904, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2731540480, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2732589056, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2733637632, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2734686208, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2735734784, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2736783360, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2737831936, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2738880512, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2739929088, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2740977664, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2742026240, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2743074816, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2744123392, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2745171968, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2746220544, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2747269120, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2748317696, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2749366272, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2750414848, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2751463424, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2752512000, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2753560576, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2754609152, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2755657728, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2756706304, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2757754880, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2758803456, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2759852032, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2760900608, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2761949184, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2762997760, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2764046336, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2765094912, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2766143488, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2767192064, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2768240640, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2769289216, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2770337792, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2771386368, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2772434944, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2773483520, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2774532096, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2775580672, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2776629248, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2777677824, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2778726400, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2779774976, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2780823552, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2781872128, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2782920704, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2783969280, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2785017856, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2786066432, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2787115008, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2788163584, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2789212160, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2790260736, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2791309312, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2792357888, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2793406464, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2794455040, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2795503616, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2796552192, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2797600768, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2798649344, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2799697920, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2800746496, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2801795072, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2802843648, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2803892224, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2804940800, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2805989376, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2807037952, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2808086528, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2809135104, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2810183680, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2811232256, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2812280832, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2813329408, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2814377984, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2815426560, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2816475136, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2817523712, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2818572288, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2819620864, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2820669440, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2821718016, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2822766592, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2823815168, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2824863744, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2825912320, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2826960896, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2828009472, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2829058048, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2830106624, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2831155200, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2832203776, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2833252352, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2834300928, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2835349504, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2836398080, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2837446656, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2838495232, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2839543808, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2840592384, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2841640960, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2842689536, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2843738112, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2844786688, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2845835264, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2846883840, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2847932416, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2848980992, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2850029568, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2851078144, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2852126720, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2853175296, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2854223872, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2855272448, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2856321024, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2857369600, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2858418176, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2859466752, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2860515328, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2861563904, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2862612480, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2863661056, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2864709632, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2865758208, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2866806784, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2867855360, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2868903936, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2869952512, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2871001088, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2872049664, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2873098240, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2874146816, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2875195392, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2876243968, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2877292544, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2878341120, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2879389696, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2880438272, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2881486848, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2882535424, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2883584000, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2884632576, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2885681152, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2886729728, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2887778304, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2888826880, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2889875456, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2890924032, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2891972608, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2893021184, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2894069760, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2895118336, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2896166912, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2897215488, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2898264064, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2899312640, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2900361216, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2901409792, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2902458368, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2903506944, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2904555520, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2905604096, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2906652672, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2907701248, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2908749824, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2909798400, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2910846976, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2911895552, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2912944128, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2913992704, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2915041280, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2916089856, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2917138432, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2918187008, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2919235584, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2920284160, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2921332736, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2922381312, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2923429888, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2924478464, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2925527040, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2926575616, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2927624192, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2928672768, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2929721344, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2930769920, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2931818496, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2932867072, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2933915648, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2934964224, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2936012800, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2937061376, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2938109952, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2939158528, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2940207104, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2941255680, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2942304256, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2943352832, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2944401408, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2945449984, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2946498560, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2947547136, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2948595712, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2949644288, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2950692864, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2951741440, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2952790016, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2953838592, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2954887168, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2955935744, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2956984320, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2958032896, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2959081472, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2960130048, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2961178624, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2962227200, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2963275776, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2964324352, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2965372928, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2966421504, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2967470080, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2968518656, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2969567232, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2970615808, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2971664384, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2972712960, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2973761536, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2974810112, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2975858688, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2976907264, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2977955840, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2979004416, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2980052992, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2981101568, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2982150144, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2983198720, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2984247296, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2985295872, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2986344448, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2987393024, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2988441600, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2989490176, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2990538752, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2991587328, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2992635904, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2993684480, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2994733056, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2995781632, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2996830208, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2997878784, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2998927360, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(2999975936, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3001024512, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3002073088, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3003121664, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3004170240, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3005218816, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3006267392, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3007315968, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3008364544, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3009413120, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3010461696, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3011510272, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3012558848, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3013607424, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3014656000, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3015704576, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3016753152, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3017801728, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3018850304, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3019898880, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3020947456, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3021996032, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3023044608, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3024093184, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3025141760, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3026190336, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3027238912, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3028287488, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3029336064, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3030384640, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3031433216, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3032481792, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3033530368, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3034578944, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3035627520, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3036676096, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3037724672, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3038773248, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3039821824, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3040870400, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3041918976, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3042967552, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3044016128, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3045064704, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3046113280, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3047161856, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3048210432, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3049259008, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3050307584, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3051356160, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3052404736, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3053453312, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3054501888, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3055550464, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3056599040, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3057647616, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3058696192, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3059744768, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3060793344, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3061841920, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3062890496, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3063939072, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3064987648, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3066036224, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3067084800, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3068133376, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3069181952, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3070230528, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3071279104, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3072327680, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3073376256, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3074424832, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3075473408, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3076521984, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3077570560, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3078619136, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3079667712, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3080716288, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3081764864, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3082813440, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3083862016, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3084910592, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3085959168, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3087007744, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3088056320, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3089104896, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3090153472, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3091202048, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3092250624, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3093299200, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3094347776, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3095396352, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3096444928, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3097493504, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3098542080, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3099590656, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3100639232, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3101687808, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3102736384, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3103784960, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3104833536, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3105882112, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3106930688, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3107979264, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3109027840, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3110076416, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3111124992, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3112173568, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3113222144, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3114270720, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3115319296, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3116367872, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3117416448, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3118465024, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3119513600, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3120562176, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3121610752, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3122659328, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3123707904, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3124756480, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3125805056, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3126853632, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3127902208, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3128950784, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3129999360, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3131047936, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3132096512, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3133145088, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3134193664, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3135242240, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3136290816, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3137339392, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3138387968, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3139436544, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3140485120, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3141533696, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3142582272, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3143630848, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3144679424, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3145728000, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3146776576, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3147825152, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3148873728, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3149922304, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3150970880, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3152019456, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3153068032, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3154116608, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3155165184, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3156213760, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3157262336, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3158310912, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3159359488, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3160408064, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3161456640, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3162505216, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3163553792, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3164602368, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3165650944, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3166699520, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3167748096, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3168796672, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3169845248, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3170893824, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3171942400, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3172990976, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3174039552, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3175088128, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3176136704, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3177185280, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3178233856, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3179282432, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3180331008, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3181379584, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3182428160, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3183476736, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3184525312, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3185573888, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3186622464, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3187671040, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3188719616, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3189768192, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3190816768, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3191865344, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3192913920, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3193962496, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3195011072, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3196059648, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3197108224, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3198156800, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3199205376, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3200253952, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3201302528, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3202351104, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3203399680, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3204448256, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3205496832, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3206545408, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3207593984, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3208642560, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3209691136, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3210739712, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3211788288, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3212836864, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3213885440, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3214934016, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3215982592, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3217031168, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3218079744, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3219128320, section_attrs::FPGA_SLAVES).raw_value(), + L1Section::new(3220176896, section_attrs::FPGA_SLAVES).raw_value(), + // Unassigned/Reserved (0xC000_0000 - 0xE000_0000) + L1Section::new(3221225472, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3222274048, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3223322624, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3224371200, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3225419776, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3226468352, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3227516928, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3228565504, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3229614080, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3230662656, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3231711232, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3232759808, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3233808384, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3234856960, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3235905536, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3236954112, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3238002688, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3239051264, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3240099840, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3241148416, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3242196992, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3243245568, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3244294144, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3245342720, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3246391296, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3247439872, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3248488448, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3249537024, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3250585600, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3251634176, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3252682752, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3253731328, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3254779904, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3255828480, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3256877056, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3257925632, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3258974208, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3260022784, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3261071360, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3262119936, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3263168512, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3264217088, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3265265664, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3266314240, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3267362816, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3268411392, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3269459968, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3270508544, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3271557120, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3272605696, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3273654272, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3274702848, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3275751424, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3276800000, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3277848576, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3278897152, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3279945728, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3280994304, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3282042880, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3283091456, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3284140032, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3285188608, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3286237184, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3287285760, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3288334336, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3289382912, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3290431488, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3291480064, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3292528640, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3293577216, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3294625792, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3295674368, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3296722944, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3297771520, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3298820096, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3299868672, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3300917248, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3301965824, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3303014400, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3304062976, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3305111552, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3306160128, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3307208704, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3308257280, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3309305856, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3310354432, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3311403008, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3312451584, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3313500160, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3314548736, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3315597312, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3316645888, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3317694464, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3318743040, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3319791616, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3320840192, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3321888768, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3322937344, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3323985920, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3325034496, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3326083072, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3327131648, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3328180224, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3329228800, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3330277376, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3331325952, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3332374528, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3333423104, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3334471680, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3335520256, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3336568832, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3337617408, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3338665984, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3339714560, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3340763136, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3341811712, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3342860288, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3343908864, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3344957440, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3346006016, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3347054592, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3348103168, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3349151744, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3350200320, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3351248896, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3352297472, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3353346048, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3354394624, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3355443200, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3356491776, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3357540352, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3358588928, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3359637504, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3360686080, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3361734656, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3362783232, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3363831808, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3364880384, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3365928960, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3366977536, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3368026112, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3369074688, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3370123264, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3371171840, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3372220416, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3373268992, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3374317568, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3375366144, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3376414720, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3377463296, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3378511872, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3379560448, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3380609024, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3381657600, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3382706176, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3383754752, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3384803328, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3385851904, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3386900480, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3387949056, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3388997632, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3390046208, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3391094784, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3392143360, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3393191936, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3394240512, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3395289088, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3396337664, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3397386240, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3398434816, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3399483392, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3400531968, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3401580544, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3402629120, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3403677696, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3404726272, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3405774848, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3406823424, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3407872000, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3408920576, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3409969152, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3411017728, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3412066304, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3413114880, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3414163456, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3415212032, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3416260608, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3417309184, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3418357760, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3419406336, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3420454912, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3421503488, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3422552064, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3423600640, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3424649216, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3425697792, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3426746368, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3427794944, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3428843520, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3429892096, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3430940672, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3431989248, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3433037824, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3434086400, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3435134976, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3436183552, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3437232128, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3438280704, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3439329280, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3440377856, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3441426432, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3442475008, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3443523584, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3444572160, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3445620736, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3446669312, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3447717888, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3448766464, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3449815040, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3450863616, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3451912192, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3452960768, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3454009344, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3455057920, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3456106496, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3457155072, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3458203648, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3459252224, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3460300800, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3461349376, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3462397952, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3463446528, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3464495104, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3465543680, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3466592256, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3467640832, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3468689408, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3469737984, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3470786560, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3471835136, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3472883712, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3473932288, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3474980864, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3476029440, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3477078016, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3478126592, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3479175168, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3480223744, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3481272320, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3482320896, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3483369472, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3484418048, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3485466624, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3486515200, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3487563776, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3488612352, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3489660928, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3490709504, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3491758080, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3492806656, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3493855232, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3494903808, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3495952384, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3497000960, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3498049536, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3499098112, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3500146688, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3501195264, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3502243840, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3503292416, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3504340992, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3505389568, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3506438144, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3507486720, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3508535296, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3509583872, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3510632448, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3511681024, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3512729600, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3513778176, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3514826752, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3515875328, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3516923904, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3517972480, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3519021056, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3520069632, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3521118208, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3522166784, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3523215360, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3524263936, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3525312512, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3526361088, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3527409664, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3528458240, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3529506816, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3530555392, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3531603968, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3532652544, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3533701120, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3534749696, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3535798272, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3536846848, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3537895424, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3538944000, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3539992576, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3541041152, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3542089728, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3543138304, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3544186880, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3545235456, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3546284032, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3547332608, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3548381184, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3549429760, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3550478336, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3551526912, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3552575488, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3553624064, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3554672640, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3555721216, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3556769792, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3557818368, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3558866944, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3559915520, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3560964096, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3562012672, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3563061248, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3564109824, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3565158400, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3566206976, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3567255552, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3568304128, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3569352704, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3570401280, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3571449856, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3572498432, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3573547008, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3574595584, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3575644160, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3576692736, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3577741312, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3578789888, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3579838464, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3580887040, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3581935616, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3582984192, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3584032768, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3585081344, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3586129920, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3587178496, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3588227072, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3589275648, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3590324224, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3591372800, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3592421376, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3593469952, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3594518528, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3595567104, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3596615680, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3597664256, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3598712832, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3599761408, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3600809984, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3601858560, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3602907136, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3603955712, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3605004288, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3606052864, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3607101440, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3608150016, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3609198592, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3610247168, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3611295744, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3612344320, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3613392896, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3614441472, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3615490048, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3616538624, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3617587200, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3618635776, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3619684352, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3620732928, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3621781504, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3622830080, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3623878656, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3624927232, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3625975808, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3627024384, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3628072960, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3629121536, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3630170112, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3631218688, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3632267264, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3633315840, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3634364416, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3635412992, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3636461568, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3637510144, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3638558720, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3639607296, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3640655872, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3641704448, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3642753024, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3643801600, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3644850176, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3645898752, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3646947328, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3647995904, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3649044480, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3650093056, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3651141632, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3652190208, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3653238784, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3654287360, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3655335936, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3656384512, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3657433088, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3658481664, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3659530240, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3660578816, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3661627392, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3662675968, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3663724544, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3664773120, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3665821696, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3666870272, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3667918848, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3668967424, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3670016000, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3671064576, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3672113152, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3673161728, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3674210304, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3675258880, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3676307456, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3677356032, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3678404608, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3679453184, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3680501760, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3681550336, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3682598912, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3683647488, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3684696064, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3685744640, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3686793216, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3687841792, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3688890368, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3689938944, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3690987520, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3692036096, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3693084672, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3694133248, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3695181824, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3696230400, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3697278976, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3698327552, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3699376128, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3700424704, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3701473280, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3702521856, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3703570432, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3704619008, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3705667584, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3706716160, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3707764736, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3708813312, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3709861888, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3710910464, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3711959040, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3713007616, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3714056192, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3715104768, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3716153344, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3717201920, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3718250496, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3719299072, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3720347648, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3721396224, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3722444800, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3723493376, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3724541952, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3725590528, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3726639104, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3727687680, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3728736256, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3729784832, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3730833408, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3731881984, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3732930560, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3733979136, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3735027712, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3736076288, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3737124864, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3738173440, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3739222016, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3740270592, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3741319168, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3742367744, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3743416320, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3744464896, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3745513472, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3746562048, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3747610624, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3748659200, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3749707776, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3750756352, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3751804928, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3752853504, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3753902080, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3754950656, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3755999232, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3757047808, section_attrs::UNASSIGNED_RESERVED).raw_value(), + // Segments IO peripherals (0xE000_0000 - 0xE030_0000) + L1Section::new(3758096384, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3759144960, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3760193536, section_attrs::SHAREABLE_DEVICE).raw_value(), + // Unassigned/Reserved (0xE030_0000 - 0xE100_0000) + L1Section::new(3761242112, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3762290688, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3763339264, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3764387840, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3765436416, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3766484992, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3767533568, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3768582144, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3769630720, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3770679296, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3771727872, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3772776448, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3773825024, section_attrs::UNASSIGNED_RESERVED).raw_value(), + // NAND (0xE100_0000 - 0xE200_0000) + L1Section::new(3774873600, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3775922176, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3776970752, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3778019328, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3779067904, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3780116480, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3781165056, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3782213632, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3783262208, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3784310784, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3785359360, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3786407936, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3787456512, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3788505088, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3789553664, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3790602240, section_attrs::SHAREABLE_DEVICE).raw_value(), + // NOR (0xE200_0000 - 0xE400_0000) + L1Section::new(3791650816, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3792699392, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3793747968, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3794796544, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3795845120, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3796893696, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3797942272, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3798990848, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3800039424, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3801088000, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3802136576, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3803185152, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3804233728, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3805282304, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3806330880, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3807379456, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3808428032, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3809476608, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3810525184, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3811573760, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3812622336, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3813670912, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3814719488, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3815768064, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3816816640, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3817865216, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3818913792, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3819962368, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3821010944, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3822059520, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3823108096, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(3824156672, section_attrs::SHAREABLE_DEVICE).raw_value(), + // SRAM (0xE400_0000 - 0xE600_0000) + L1Section::new(3825205248, section_attrs::SRAM).raw_value(), + L1Section::new(3826253824, section_attrs::SRAM).raw_value(), + L1Section::new(3827302400, section_attrs::SRAM).raw_value(), + L1Section::new(3828350976, section_attrs::SRAM).raw_value(), + L1Section::new(3829399552, section_attrs::SRAM).raw_value(), + L1Section::new(3830448128, section_attrs::SRAM).raw_value(), + L1Section::new(3831496704, section_attrs::SRAM).raw_value(), + L1Section::new(3832545280, section_attrs::SRAM).raw_value(), + L1Section::new(3833593856, section_attrs::SRAM).raw_value(), + L1Section::new(3834642432, section_attrs::SRAM).raw_value(), + L1Section::new(3835691008, section_attrs::SRAM).raw_value(), + L1Section::new(3836739584, section_attrs::SRAM).raw_value(), + L1Section::new(3837788160, section_attrs::SRAM).raw_value(), + L1Section::new(3838836736, section_attrs::SRAM).raw_value(), + L1Section::new(3839885312, section_attrs::SRAM).raw_value(), + L1Section::new(3840933888, section_attrs::SRAM).raw_value(), + L1Section::new(3841982464, section_attrs::SRAM).raw_value(), + L1Section::new(3843031040, section_attrs::SRAM).raw_value(), + L1Section::new(3844079616, section_attrs::SRAM).raw_value(), + L1Section::new(3845128192, section_attrs::SRAM).raw_value(), + L1Section::new(3846176768, section_attrs::SRAM).raw_value(), + L1Section::new(3847225344, section_attrs::SRAM).raw_value(), + L1Section::new(3848273920, section_attrs::SRAM).raw_value(), + L1Section::new(3849322496, section_attrs::SRAM).raw_value(), + L1Section::new(3850371072, section_attrs::SRAM).raw_value(), + L1Section::new(3851419648, section_attrs::SRAM).raw_value(), + L1Section::new(3852468224, section_attrs::SRAM).raw_value(), + L1Section::new(3853516800, section_attrs::SRAM).raw_value(), + L1Section::new(3854565376, section_attrs::SRAM).raw_value(), + L1Section::new(3855613952, section_attrs::SRAM).raw_value(), + L1Section::new(3856662528, section_attrs::SRAM).raw_value(), + L1Section::new(3857711104, section_attrs::SRAM).raw_value(), + // Unassigned/Reserved (0xE600_0000 - 0xF800_0000) + L1Section::new(3858759680, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3859808256, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3860856832, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3861905408, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3862953984, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3864002560, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3865051136, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3866099712, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3867148288, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3868196864, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3869245440, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3870294016, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3871342592, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3872391168, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3873439744, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3874488320, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3875536896, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3876585472, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3877634048, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3878682624, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3879731200, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3880779776, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3881828352, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3882876928, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3883925504, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3884974080, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3886022656, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3887071232, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3888119808, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3889168384, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3890216960, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3891265536, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3892314112, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3893362688, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3894411264, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3895459840, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3896508416, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3897556992, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3898605568, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3899654144, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3900702720, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3901751296, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3902799872, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3903848448, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3904897024, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3905945600, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3906994176, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3908042752, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3909091328, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3910139904, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3911188480, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3912237056, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3913285632, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3914334208, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3915382784, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3916431360, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3917479936, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3918528512, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3919577088, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3920625664, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3921674240, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3922722816, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3923771392, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3924819968, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3925868544, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3926917120, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3927965696, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3929014272, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3930062848, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3931111424, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3932160000, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3933208576, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3934257152, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3935305728, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3936354304, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3937402880, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3938451456, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3939500032, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3940548608, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3941597184, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3942645760, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3943694336, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3944742912, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3945791488, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3946840064, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3947888640, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3948937216, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3949985792, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3951034368, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3952082944, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3953131520, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3954180096, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3955228672, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3956277248, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3957325824, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3958374400, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3959422976, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3960471552, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3961520128, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3962568704, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3963617280, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3964665856, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3965714432, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3966763008, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3967811584, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3968860160, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3969908736, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3970957312, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3972005888, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3973054464, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3974103040, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3975151616, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3976200192, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3977248768, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3978297344, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3979345920, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3980394496, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3981443072, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3982491648, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3983540224, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3984588800, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3985637376, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3986685952, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3987734528, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3988783104, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3989831680, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3990880256, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3991928832, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3992977408, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3994025984, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3995074560, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3996123136, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3997171712, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3998220288, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(3999268864, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4000317440, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4001366016, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4002414592, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4003463168, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4004511744, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4005560320, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4006608896, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4007657472, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4008706048, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4009754624, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4010803200, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4011851776, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4012900352, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4013948928, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4014997504, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4016046080, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4017094656, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4018143232, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4019191808, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4020240384, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4021288960, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4022337536, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4023386112, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4024434688, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4025483264, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4026531840, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4027580416, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4028628992, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4029677568, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4030726144, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4031774720, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4032823296, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4033871872, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4034920448, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4035969024, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4037017600, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4038066176, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4039114752, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4040163328, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4041211904, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4042260480, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4043309056, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4044357632, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4045406208, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4046454784, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4047503360, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4048551936, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4049600512, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4050649088, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4051697664, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4052746240, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4053794816, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4054843392, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4055891968, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4056940544, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4057989120, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4059037696, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4060086272, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4061134848, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4062183424, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4063232000, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4064280576, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4065329152, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4066377728, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4067426304, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4068474880, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4069523456, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4070572032, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4071620608, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4072669184, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4073717760, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4074766336, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4075814912, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4076863488, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4077912064, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4078960640, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4080009216, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4081057792, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4082106368, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4083154944, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4084203520, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4085252096, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4086300672, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4087349248, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4088397824, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4089446400, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4090494976, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4091543552, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4092592128, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4093640704, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4094689280, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4095737856, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4096786432, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4097835008, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4098883584, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4099932160, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4100980736, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4102029312, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4103077888, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4104126464, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4105175040, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4106223616, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4107272192, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4108320768, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4109369344, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4110417920, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4111466496, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4112515072, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4113563648, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4114612224, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4115660800, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4116709376, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4117757952, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4118806528, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4119855104, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4120903680, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4121952256, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4123000832, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4124049408, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4125097984, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4126146560, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4127195136, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4128243712, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4129292288, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4130340864, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4131389440, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4132438016, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4133486592, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4134535168, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4135583744, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4136632320, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4137680896, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4138729472, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4139778048, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4140826624, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4141875200, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4142923776, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4143972352, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4145020928, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4146069504, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4147118080, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4148166656, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4149215232, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4150263808, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4151312384, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4152360960, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4153409536, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4154458112, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4155506688, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4156555264, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4157603840, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4158652416, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4159700992, section_attrs::UNASSIGNED_RESERVED).raw_value(), + // AMBA APB peripherals (0xF800_0000 - 0xF900_0000) + L1Section::new(4160749568, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(4161798144, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(4162846720, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(4163895296, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(4164943872, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(4165992448, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(4167041024, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(4168089600, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(4169138176, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(4170186752, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(4171235328, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(4172283904, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(4173332480, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(4174381056, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(4175429632, section_attrs::SHAREABLE_DEVICE).raw_value(), + L1Section::new(4176478208, section_attrs::SHAREABLE_DEVICE).raw_value(), + // Unassigned/Reserved (0xF900_0000 - 0xFC00_0000) + L1Section::new(4177526784, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4178575360, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4179623936, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4180672512, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4181721088, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4182769664, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4183818240, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4184866816, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4185915392, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4186963968, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4188012544, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4189061120, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4190109696, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4191158272, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4192206848, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4193255424, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4194304000, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4195352576, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4196401152, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4197449728, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4198498304, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4199546880, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4200595456, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4201644032, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4202692608, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4203741184, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4204789760, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4205838336, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4206886912, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4207935488, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4208984064, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4210032640, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4211081216, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4212129792, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4213178368, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4214226944, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4215275520, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4216324096, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4217372672, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4218421248, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4219469824, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4220518400, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4221566976, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4222615552, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4223664128, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4224712704, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4225761280, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4226809856, section_attrs::UNASSIGNED_RESERVED).raw_value(), + // QSPI XIP (0xFC00_0000 - 0xFE00_0000) + L1Section::new(4227858432, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4228907008, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4229955584, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4231004160, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4232052736, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4233101312, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4234149888, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4235198464, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4236247040, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4237295616, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4238344192, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4239392768, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4240441344, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4241489920, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4242538496, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4243587072, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4244635648, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4245684224, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4246732800, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4247781376, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4248829952, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4249878528, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4250927104, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4251975680, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4253024256, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4254072832, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4255121408, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4256169984, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4257218560, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4258267136, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4259315712, section_attrs::QSPI_XIP).raw_value(), + L1Section::new(4260364288, section_attrs::QSPI_XIP).raw_value(), + // Unassiged/Reserved (0xFE00_0000 - 0xFFF0_0000) + L1Section::new(4261412864, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4262461440, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4263510016, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4264558592, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4265607168, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4266655744, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4267704320, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4268752896, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4269801472, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4270850048, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4271898624, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4272947200, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4273995776, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4275044352, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4276092928, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4277141504, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4278190080, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4279238656, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4280287232, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4281335808, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4282384384, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4283432960, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4284481536, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4285530112, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4286578688, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4287627264, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4288675840, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4289724416, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4290772992, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4291821568, section_attrs::UNASSIGNED_RESERVED).raw_value(), + L1Section::new(4292870144, section_attrs::UNASSIGNED_RESERVED).raw_value(), + // OCM High (0xFFF0_0000 - 0xFFFF_FFFF) + L1Section::new(4293918720, section_attrs::OCM_MAPPED_HIGH).raw_value(), +]); diff --git a/zynq7000-rt/src/rt.rs b/zynq7000-rt/src/rt.rs new file mode 100644 index 0000000..a674f23 --- /dev/null +++ b/zynq7000-rt/src/rt.rs @@ -0,0 +1,396 @@ +//! Start-up code for Zynq 7000 +//! +//! The bootup routine was kepts as similar to the one +//! [provided by Xilinx](https://github.com/Xilinx/embeddedsw/blob/master/lib/bsp/standalone/src/arm/cortexa9/gcc/boot.S) +//! as possible. The boot routine includes stack, MMU, cache and .bss/.data section initialization. +use cortex_a_rt as _; +use cortex_ar::register::{Cpsr, cpsr::ProcessorMode}; + +// Start-up code for Armv7-A +// +// We set up our stacks and `kmain` in system mode. +core::arch::global_asm!( + r#" +.set PSS_L2CC_BASE_ADDR, 0xF8F02000 +.set PSS_SLCR_BASE_ADDR, 0xF8000000 + +.set RESERVED, 0x0fffff00 +.set LRemap, 0xFE00000F /* set the base address of the peripheral block as not shared */ +.set L2CCWay, (PSS_L2CC_BASE_ADDR + 0x077C) /*(PSS_L2CC_BASE_ADDR + PSS_L2CC_CACHE_INVLD_WAY_OFFSET)*/ +.set L2CCSync, (PSS_L2CC_BASE_ADDR + 0x0730) /*(PSS_L2CC_BASE_ADDR + PSS_L2CC_CACHE_SYNC_OFFSET)*/ +.set L2CCCrtl, (PSS_L2CC_BASE_ADDR + 0x0100) /*(PSS_L2CC_BASE_ADDR + PSS_L2CC_CNTRL_OFFSET)*/ +.set L2CCAuxCrtl, (PSS_L2CC_BASE_ADDR + 0x0104) /*(PSS_L2CC_BASE_ADDR + XPSS_L2CC_AUX_CNTRL_OFFSET)*/ +.set L2CCTAGLatReg, (PSS_L2CC_BASE_ADDR + 0x0108) /*(PSS_L2CC_BASE_ADDR + XPSS_L2CC_TAG_RAM_CNTRL_OFFSET)*/ +.set L2CCDataLatReg, (PSS_L2CC_BASE_ADDR + 0x010C) /*(PSS_L2CC_BASE_ADDR + XPSS_L2CC_DATA_RAM_CNTRL_OFFSET)*/ +.set L2CCIntClear, (PSS_L2CC_BASE_ADDR + 0x0220) /*(PSS_L2CC_BASE_ADDR + XPSS_L2CC_IAR_OFFSET)*/ +.set L2CCIntRaw, (PSS_L2CC_BASE_ADDR + 0x021C) /*(PSS_L2CC_BASE_ADDR + XPSS_L2CC_ISR_OFFSET)*/ + +.set SLCRlockReg, (PSS_SLCR_BASE_ADDR + 0x04) /*(PSS_SLCR_BASE_ADDR + XPSS_SLCR_LOCK_OFFSET)*/ +.set SLCRUnlockReg, (PSS_SLCR_BASE_ADDR + 0x08) /*(PSS_SLCR_BASE_ADDR + XPSS_SLCR_UNLOCK_OFFSET)*/ +.set SLCRL2cRamReg, (PSS_SLCR_BASE_ADDR + 0xA1C) /*(PSS_SLCR_BASE_ADDR + XPSS_SLCR_L2C_RAM_OFFSET)*/ +.set SLCRCPURSTReg, (0xF8000000 + 0x244) /*(XPS_SYS_CTRL_BASEADDR + A9_CPU_RST_CTRL_OFFSET)*/ +.set EFUSEStatus, (0xF800D000 + 0x10) /*(XPS_EFUSE_BASEADDR + EFUSE_STATUS_OFFSET)*/ + +.set CRValMmuCac, 0b01000000000101 /* Enable IDC, and MMU */ +.set CRValHiVectorAddr, 0b10000000000000 /* Set the Vector address to high, 0xFFFF0000 */ + +.set L2CCAuxControl, 0x72360000 /* Enable all prefetching, Cache replacement policy, Parity enable, + Event monitor bus enable and Way Size (64 KB) */ +.set L2CCControl, 0x01 /* Enable L2CC */ +.set L2CCTAGLatency, 0x0111 /* latency for TAG RAM */ +.set L2CCDataLatency, 0x0121 /* latency for DATA RAM */ + +.set SLCRlockKey, 0x767B /* SLCR lock key */ +.set SLCRUnlockKey, 0xDF0D /* SLCR unlock key */ +.set SLCRL2cRamConfig, 0x00020202 /* SLCR L2C ram configuration */ + +.set FPEXC_EN, 0x40000000 /* FPU enable bit, (1 << 30) */ + +.section .text.startup +.align 0 + +.global _start +.type _start, %function +_start: + // only allow cpu0 through + // Read MPIDR + mrc p15,0,r1,c0,c0,5 + // Extract CPU ID bits. For single-core systems, this should always be 0 + and r1, r1, #0x3 + cmp r1, #0 + beq check_efuse + b initialize + +// Zynq specific code. It is recommended to reset CPU1 according to page 160 of the datasheet +check_efuse: + ldr r0,=EFUSEStatus + ldr r1,[r0] /* Read eFuse setting */ + ands r1,r1,#0x80 /* Check whether device is having single core */ + beq initialize + + /* single core device, reset cpu1 */ + ldr r0,=SLCRUnlockReg /* Load SLCR base address base + unlock register */ + ldr r1,=SLCRUnlockKey /* set unlock key */ + str r1, [r0] /* Unlock SLCR */ + + ldr r0,=SLCRCPURSTReg + ldr r1,[r0] /* Read CPU Software Reset Control register */ + orr r1,r1,#0x22 + str r1,[r0] /* Reset CPU1 */ + + ldr r0,=SLCRlockReg /* Load SLCR base address base + lock register */ + ldr r1,=SLCRlockKey /* set lock key */ + str r1, [r0] /* lock SLCR */ +initialize: + mrc p15, 0, r0, c0, c0, 0 /* Get the revision */ + and r5, r0, #0x00f00000 + and r6, r0, #0x0000000f + orr r6, r6, r5, lsr #20-4 + + /* set VBAR to the _vector_table address in linker script */ + ldr r0, =_vector_table + mcr p15, 0, r0, c12, c0, 0 + + /* Invalidate scu */ + ldr r7, =0xf8f0000c + ldr r6, =0xffff + str r6, [r7] + + /* Invalidate caches and TLBs */ + mov r0,#0 /* r0 = 0 */ + mcr p15, 0, r0, c8, c7, 0 /* invalidate TLBs */ + mcr p15, 0, r0, c7, c5, 0 /* invalidate icache */ + mcr p15, 0, r0, c7, c5, 6 /* Invalidate branch predictor array */ + bl invalidate_dcache /* invalidate dcache */ + + /* Disable MMU, if enabled */ + mrc p15, 0, r0, c1, c0, 0 /* read CP15 register 1 */ + bic r0, r0, #0x1 /* clear bit 0 */ + mcr p15, 0, r0, c1, c0, 0 /* write value back */ + + // Set up stacks first. + ldr r3, =_stack_top + + // get the current PSR + mrs r0, cpsr + // mask for mode bits + mvn r1, #0x1f + and r2, r1, r0 + // IRQ mode + orr r2, r2, {irq_mode} + msr cpsr, r2 + // IRQ stack pointer + mov sp, r3 + ldr r1, =_irq_stack_size + sub r3, r3, r1 + + mrs r0, cpsr + and r2, r1, r0 + // Supervisor mode + orr r2, r2, {svc_mode} + msr cpsr, r2 + // Supervisor stack pointer + mov sp, r3 + ldr r1, =_svc_stack_size + sub r3, r3, r1 + + mrs r0, cpsr + and r2, r1, r0 + // Abort mode + orr r2, r2, {abt_mode} + msr cpsr, r2 + // Abort stack pointer + mov sp, r3 + ldr r1, =_abt_stack_size + sub r3, r3, r1 + + mrs r0, cpsr + and r2, r1, r0 + // FIQ mode + orr r2, r2, {fiq_mode} + msr cpsr, r2 + // FIQ stack pointer + mov sp, r3 + ldr r1, =_fiq_stack_size + sub r3, r3, r1 + + mrs r0, cpsr + and r2, r1, r0 + // Undefined mode + orr r2, r2, {und_mode} + msr cpsr, r2 + // Undefined stack pointer + mov sp, r3 + ldr r1, =_und_stack_size + sub r3, r3, r1 + + mrs r0, cpsr + and r2, r1, r0 + // System mode + orr r2, r2, {sys_mode} + msr cpsr, r2 + // System stack pointer (main stack) + mov sp, r3 + + // set scu enable bit in scu + ldr r7, =0xf8f00000 + ldr r0, [r7] + orr r0, r0, #0x1 + str r0, [r7] + + /* enable MMU and cache */ + bl load_mmu_table + + mvn r0,#0 /* Load MMU domains -- all ones=manager */ + mcr p15,0,r0,c3,c0,0 + + /* Enable mmu, icahce and dcache */ + ldr r0,=CRValMmuCac + mcr p15,0,r0,c1,c0,0 /* Enable cache and MMU */ + dsb /* dsb allow the MMU to start up */ + isb /* isb flush prefetch buffer */ + + /* Write to ACTLR */ + mrc p15, 0, r0, c1, c0, 1 /* Read ACTLR*/ + orr r0, r0, #(0x01 << 6) /* set SMP bit */ + orr r0, r0, #(0x01 ) /* Cache/TLB maintenance broadcast */ + mcr p15, 0, r0, c1, c0, 1 /* Write ACTLR*/ + + /* Invalidate L2 Cache and enable L2 Cache*/ + /* For AMP, assume running on CPU1. Don't initialize L2 Cache (up to Linux) */ + ldr r0,=L2CCCrtl /* Load L2CC base address base + control register */ + mov r1, #0 /* force the disable bit */ + str r1, [r0] /* disable the L2 Caches */ + + ldr r0,=L2CCAuxCrtl /* Load L2CC base address base + Aux control register */ + ldr r1,[r0] /* read the register */ + ldr r2,=L2CCAuxControl /* set the default bits */ + orr r1,r1,r2 + str r1, [r0] /* store the Aux Control Register */ + + ldr r0,=L2CCTAGLatReg /* Load L2CC base address base + TAG Latency address */ + ldr r1,=L2CCTAGLatency /* set the latencies for the TAG*/ + str r1, [r0] /* store the TAG Latency register Register */ + + ldr r0,=L2CCDataLatReg /* Load L2CC base address base + Data Latency address */ + ldr r1,=L2CCDataLatency /* set the latencies for the Data*/ + str r1, [r0] /* store the Data Latency register Register */ + + ldr r0,=L2CCWay /* Load L2CC base address base + way register*/ + ldr r2, =0xFFFF + str r2, [r0] /* force invalidate */ + + ldr r0,=L2CCSync /* need to poll 0x730, PSS_L2CC_CACHE_SYNC_OFFSET */ + /* Load L2CC base address base + sync register*/ + /* poll for completion */ +Sync: + ldr r1, [r0] + cmp r1, #0 + bne Sync + + ldr r0,=L2CCIntRaw /* clear pending interrupts */ + ldr r1,[r0] + ldr r0,=L2CCIntClear + str r1,[r0] + + ldr r0,=SLCRUnlockReg /* Load SLCR base address base + unlock register */ + ldr r1,=SLCRUnlockKey /* set unlock key */ + str r1, [r0] /* Unlock SLCR */ + + ldr r0,=SLCRL2cRamReg /* Load SLCR base address base + l2c Ram Control register */ + ldr r1,=SLCRL2cRamConfig /* set the configuration value */ + str r1, [r0] /* store the L2c Ram Control Register */ + + ldr r0,=SLCRlockReg /* Load SLCR base address base + lock register */ + ldr r1,=SLCRlockKey /* set lock key */ + str r1, [r0] /* lock SLCR */ + + ldr r0,=L2CCCrtl /* Load L2CC base address base + control register */ + ldr r1,[r0] /* read the register */ + mov r2, #L2CCControl /* set the enable bit */ + orr r1,r1,r2 + str r1, [r0] /* enable the L2 Caches */ + + mov r0, r0 + mrc p15, 0, r1, c1, c0, 2 /* read cp access control register (CACR) into r1 */ + orr r1, r1, #(0xf << 20) /* enable full access for p10 & p11 */ + mcr p15, 0, r1, c1, c0, 2 /* write back into CACR */ + + /* enable vfp */ + fmrx r1, FPEXC /* read the exception register */ + orr r1,r1, #FPEXC_EN /* set VFP enable bit, leave the others in orig state */ + fmxr FPEXC, r1 /* write back the exception register */ + + mrc p15,0,r0,c1,c0,0 /* flow prediction enable */ + orr r0, r0, #(0x01 << 11) /* #0x8000 */ + mcr p15,0,r0,c1,c0,0 + + mrc p15,0,r0,c1,c0,1 /* read Auxiliary Control Register */ + orr r0, r0, #(0x1 << 2) /* enable Dside prefetch */ + orr r0, r0, #(0x1 << 1) /* enable L2 Prefetch hint */ + mcr p15,0,r0,c1,c0,1 /* write Auxiliary Control Register */ + + mrs r0, cpsr /* get the current PSR */ + bic r0, r0, #0x100 /* enable asynchronous abort exception */ + msr cpsr_xsf, r0 + + /* Zero BSS and initialize data before calling any function which might require them. */ + + // Initialise .bss + ldr r0, =__sbss + ldr r1, =__ebss + mov r2, 0 +0: + cmp r1, r0 + beq 1f + stm r0!, {{r2}} + b 0b +1: + // Initialise .data + ldr r0, =__sdata + ldr r1, =__edata + ldr r2, =__sidata +0: + cmp r1, r0 + beq 1f + ldm r2!, {{r3}} + stm r0!, {{r3}} + b 0b +1: + // Jump to application + // Load CPU ID 0, which will be used as a function argument to the boot_core function. + mov r0, #0x0 + bl boot_core + // In case the application returns, loop forever + b . +.size _start, . - _start + +.type _invalidate_dcache, %function +invalidate_dcache: + mrc p15, 1, r0, c0, c0, 1 /* read CLIDR */ + ands r3, r0, #0x7000000 + mov r3, r3, lsr #23 /* cache level value (naturally aligned) */ + beq finished + mov r10, #0 /* start with level 0 */ +loop1: + add r2, r10, r10, lsr #1 /* work out 3xcachelevel */ + mov r1, r0, lsr r2 /* bottom 3 bits are the Cache type for this level */ + and r1, r1, #7 /* get those 3 bits alone */ + cmp r1, #2 + blt skip /* no cache or only instruction cache at this level */ + mcr p15, 2, r10, c0, c0, 0 /* write the Cache Size selection register */ + isb /* isb to sync the change to the CacheSizeID reg */ + mrc p15, 1, r1, c0, c0, 0 /* reads current Cache Size ID register */ + and r2, r1, #7 /* extract the line length field */ + add r2, r2, #4 /* add 4 for the line length offset (log2 16 bytes) */ + ldr r4, =0x3ff + ands r4, r4, r1, lsr #3 /* r4 is the max number on the way size (right aligned) */ + clz r5, r4 /* r5 is the bit position of the way size increment */ + ldr r7, =0x7fff + ands r7, r7, r1, lsr #13 /* r7 is the max number of the index size (right aligned) */ +loop2: + mov r9, r4 /* r9 working copy of the max way size (right aligned) */ +loop3: + orr r11, r10, r9, lsl r5 /* factor in the way number and cache number into r11 */ + orr r11, r11, r7, lsl r2 /* factor in the index number */ + mcr p15, 0, r11, c7, c6, 2 /* invalidate by set/way */ + subs r9, r9, #1 /* decrement the way number */ + bge loop3 + subs r7, r7, #1 /* decrement the index */ + bge loop2 +skip: + add r10, r10, #2 /* increment the cache number */ + cmp r3, r10 + bgt loop1 + +finished: + mov r10, #0 /* switch back to cache level 0 */ + mcr p15, 2, r10, c0, c0, 0 /* select current cache level in cssr */ + dsb + isb + bx lr +.size invalidate_dcache, . - invalidate_dcache + "#, + fiq_mode = const { + Cpsr::new_with_raw_value(0) + .with_mode(ProcessorMode::Fiq) + .with_i(true) + .with_f(true) + .raw_value() + }, + irq_mode = const { + Cpsr::new_with_raw_value(0) + .with_mode(ProcessorMode::Irq) + .with_i(true) + .with_f(true) + .raw_value() + }, + svc_mode = const { + Cpsr::new_with_raw_value(0) + .with_mode(ProcessorMode::Svc) + .with_i(true) + .with_f(true) + .raw_value() + }, + und_mode = const { + Cpsr::new_with_raw_value(0) + .with_mode(ProcessorMode::Und) + .with_i(true) + .with_f(true) + .raw_value() + }, + abt_mode = const { + Cpsr::new_with_raw_value(0) + .with_mode(ProcessorMode::Abt) + .with_i(true) + .with_f(true) + .raw_value() + }, + sys_mode = const { + Cpsr::new_with_raw_value(0) + .with_mode(ProcessorMode::Sys) + .with_i(true) + .with_f(true) + .raw_value() + }, +); diff --git a/zynq7000/Cargo.toml b/zynq7000/Cargo.toml new file mode 100644 index 0000000..bb0700e --- /dev/null +++ b/zynq7000/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "zynq7000" +version = "0.1.0" +authors = ["Robin Mueller "] +edition = "2024" +description = "PAC for the Zynq7000 family of SoCs" +homepage = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs" +repository = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs" +license = "MIT OR Apache-2.0" +keywords = ["no-std", "arm", "cortex-a", "amd", "zynq7000"] +categories = ["embedded", "no-std", "hardware-support"] + +[dependencies] +static_assertions = "1.1" +derive-mmio = { path = "../../derive-mmio", default-features = false } +bitbybit = "1.3" +arbitrary-int = "1.3" +rustversion = "1" +thiserror = { version = "2", default-features = false } +once_cell = { version = "1", default-features = false, features = ["critical-section"] } + +[dev-dependencies] +approx = "0.5" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--generate-link-to-definition"] diff --git a/zynq7000/LICENSE-APACHE b/zynq7000/LICENSE-APACHE new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/zynq7000/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/zynq7000/LICENSE-MIT b/zynq7000/LICENSE-MIT new file mode 100644 index 0000000..8311204 --- /dev/null +++ b/zynq7000/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Robin A. Mueller + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/zynq7000/README.md b/zynq7000/README.md new file mode 100644 index 0000000..cddaee7 --- /dev/null +++ b/zynq7000/README.md @@ -0,0 +1,8 @@ +# PAC for the AMD Zynq 7000 SoC family + +This repository contains the Peripheral Access Crate (PAC) for the AMD Zynq7000 SoC family. + +If you are interested in higher-level abstractions, it is recommended you visit +the `zynq7000-hal` HAL crate which build on top of this PAC. + +Check out the documentation for more details. diff --git a/zynq7000/build.rs b/zynq7000/build.rs new file mode 100644 index 0000000..c2bce4f --- /dev/null +++ b/zynq7000/build.rs @@ -0,0 +1,3 @@ +fn main() { + println!("cargo:rerun-if-changed=build.rs"); +} diff --git a/zynq7000/src/gic.rs b/zynq7000/src/gic.rs new file mode 100644 index 0000000..2d85c88 --- /dev/null +++ b/zynq7000/src/gic.rs @@ -0,0 +1,202 @@ +//! # GIC (Generic Interrupt Controller) register module. +pub use crate::mpcore::{GICC_BASE_ADDR, GICD_BASE_ADDR}; +use arbitrary_int::{u3, u5, u10}; +use static_assertions::const_assert_eq; + +/// Distributor Control Register +#[bitbybit::bitfield(u32, default = 0x0)] +pub struct Dcr { + #[bit(1, rw)] + enable_non_secure: bool, + #[bit(0, rw)] + enable_secure: bool, +} + +/// Read only bit. This register only returns fixed constants. +#[bitbybit::bitfield(u32)] +pub struct TypeRegister { + #[bits(11..=15, r)] + lspi: u5, + #[bit(10, r)] + security_extension: bool, + #[bits(5..=7, r)] + cpu_number: u3, + #[bits(0..=4, r)] + it_lines_number: u5, +} + +impl TypeRegister { + pub const SECURITY_EXTNS_BIT: bool = true; + /// 31 LSPIs. + pub const NUM_LSPI: usize = 0x1f; + /// Encoding: 0b001 means that the Cortex-A9 MPCore has 2 processors. + pub const CPU_NUMBER_BITS: u8 = 0b001; + /// The distributor provides 96 interrupts. + pub const IT_LINES_NUMBER: u8 = 0x2; + + pub const NUM_OF_CPUS: usize = 2; + pub const NUM_OF_INTERRUPTS: usize = 96; +} + +pub type Typer = TypeRegister; + +/// GIC Distributor registers. +#[derive(derive_mmio::Mmio)] +#[repr(C, align(8))] +pub struct Gicd { + /// Distributor Control Register + pub dcr: Dcr, + /// Interrupt Controller Type Register + #[mmio(PureRead)] + pub ictr: Typer, + /// Distributor Implementer Identification Register + #[mmio(PureRead)] + pub iidr: u32, + _reserved_0: [u32; 0x1D], + /// Interrupt security registers + pub isr: [u32; 3], + _reserved_1: [u32; 0x1D], + /// Interrupt Set-Enable Registers + pub iser: [u32; 0x3], + _reserved_3: [u32; 0x1D], + /// Interrupt Clear-Enable Registers + pub icer: [u32; 0x3], + _reserved_4: [u32; 0x1D], + /// Interrupt Set-Pending Registers + pub ispr: [u32; 0x3], + _reserved_5: [u32; 0x1D], + /// Interrupt Clear-Pending Registers + pub icpr: [u32; 0x3], + _reserved_6: [u32; 0x1D], + /// Active Bit Registers + pub abr: [u32; 0x3], + _reserved_10: [u32; 0x3D], + /// Interrupt Priority Registers + pub ipr: [u32; 0x18], + _reserved_11: [u32; 0xE8], + /// Interrupt Processor Targes Registers + pub iptr_sgi: [u32; 0x4], + // TODO: Mark those read-only as soon as that works for arrays. + pub iptr_ppi: [u32; 0x4], + pub iptr_spi: [u32; 0x10], + // Those are split in the ARM documentation for some reason.. + _reserved_12: [u32; 0xE8], + /// Interrupt Configuration Registers + /// Interupt sensitivity register for software generated interrupts (SGI) + pub icfr_0_sgi: u32, + /// Interupt sensitivity register for private peripheral interrupts (PPI) + pub icfr_1_ppi: u32, + pub icfr_2_spi: u32, + pub icfr_3_spi: u32, + pub icfr_4_spi: u32, + pub icfr_5_spi: u32, + _reserved_13: [u32; 0x3A], + pub ppi_status: u32, + pub spi_status_0: u32, + pub spi_status_1: u32, + _reserved_14: [u32; 0x7D], + /// Software Generated Interrupt Register. + pub sgir: u32, + _reserved_15: [u32; 0x33], + pub pidr_4: u32, + pub pidr_5: u32, + pub pidr_6: u32, + pub pidr_7: u32, + pub pidr_0: u32, + pub pidr_1: u32, + pub pidr_2: u32, + pub pidr_3: u32, + pub cidr: [u32; 4], +} + +const_assert_eq!(core::mem::size_of::(), 0x1000); + +impl Gicd { + /// Create a new Global Interrupt Controller Distributor MMIO instance at the fixed address of + /// the processing system. + /// + /// # Safety + /// + /// This API can be used to potentially create a driver to the same peripheral structure + /// from multiple threads. The user must ensure that concurrent accesses are safe and do not + /// interfere with each other. + #[inline] + pub const unsafe fn new_mmio_fixed() -> MmioGicd<'static> { + unsafe { Self::new_mmio_at(GICD_BASE_ADDR) } + } +} + +/// CPU interface control register. +#[bitbybit::bitfield(u32, default = 0x0)] +pub struct Icr { + #[bit(4, rw)] + sbpr: bool, + #[bit(3, rw)] + fiq_en: bool, + #[bit(2, rw)] + ack_ctrl: bool, + #[bit(1, rw)] + enable_non_secure: bool, + #[bit(0, rw)] + enable_secure: bool, +} + +/// Priority Mask Register +#[bitbybit::bitfield(u32)] +pub struct PriorityRegister { + #[bits(0..=7, rw)] + priority: u8, +} + +/// Interrupt acknowledge register. +#[bitbybit::bitfield(u32)] +#[derive(Debug)] +pub struct InterruptSignalRegister { + #[bits(10..=12, rw)] + cpu_id: u3, + #[bits(0..=9, rw)] + ack_int_id: u10, +} + +/// GIC CPU interface registers. +#[derive(derive_mmio::Mmio)] +#[repr(C, align(8))] +pub struct Gicc { + /// CPU Interface Control Register. + pub icr: Icr, + /// Interrupt Priority Mask Register. + pub pmr: PriorityRegister, + /// Binary Point Register. + pub bpr: u32, + /// Interrupt Acknowledge Register. + pub iar: InterruptSignalRegister, + /// End of Interrupt Register. + pub eoir: InterruptSignalRegister, + /// Running Priority Register. + pub rpr: PriorityRegister, + /// Highest Pending Interrupt Register. + pub hpir: InterruptSignalRegister, + /// Aliased Binary Point Register + pub abpr: u32, + _reserved_0: [u32; 0x37], + /// CPU Interface Identification Register. + #[mmio(PureRead)] + pub iidr: u32, +} + +const_assert_eq!(core::mem::size_of::(), 0x100); + +impl Gicc { + /// Create a new Global Interrupt Controller CPU MMIO instance at the fixed address of the + /// processing system. + /// + /// # Safety + /// + /// This API can be used to potentially create a driver to the same peripheral structure + /// from multiple threads. The user must ensure that concurrent accesses are safe and do not + /// interfere with each other. + #[inline] + pub const unsafe fn new_mmio_fixed() -> MmioGicc<'static> { + unsafe { Self::new_mmio_at(GICC_BASE_ADDR) } + } +} diff --git a/zynq7000/src/gpio.rs b/zynq7000/src/gpio.rs new file mode 100644 index 0000000..2d3aab2 --- /dev/null +++ b/zynq7000/src/gpio.rs @@ -0,0 +1,121 @@ +//! # GPIO register module. +#[bitbybit::bitfield(u32, default = 0x0)] +#[derive(Debug)] +pub struct MaskedOutput { + #[bits(16..=31, w)] + pub mask: u16, + #[bits(0..=15, rw)] + pub output: u16, +} + +#[derive(derive_mmio::Mmio)] +#[repr(C)] +pub struct BankCtrl { + /// Direction mode + dirm: u32, + /// Output enable + out_en: u32, + /// Interrupt mask status + #[mmio(PureRead)] + int_mask: u32, + /// Interrupt enable/unmask + #[mmio(Write)] + int_en: u32, + /// Interrupt disable/mask + #[mmio(Write)] + int_dis: u32, + /// Interrupt status + #[mmio(PureRead, Write)] + int_sts: u32, + /// Interrupt type + int_type: u32, + /// Interrupt polarity + int_pol: u32, + /// Interrupt any edge sensitivity + int_any: u32, +} + +#[derive(derive_mmio::Mmio)] +#[repr(C)] +pub struct Gpio { + /// Maskable output data (GPIO bank 0, MIO, lower 16 bits) + masked_out_0_lsw: MaskedOutput, + /// Maskable output data (GPIO bank 0, MIO, upper 16 bits) + masked_out_0_msw: MaskedOutput, + /// Maskable output data (GPIO bank 1, MIO, lower 16 bits) + masked_out_1_lsw: MaskedOutput, + /// Maskable output data (GPIO bank 1, MIO, upper 16 bits) + masked_out_1_msw: MaskedOutput, + /// Maskable output data (GPIO bank 2, EMIO, lower 16 bits) + masked_out_2_lsw: MaskedOutput, + /// Maskable output data (GPIO bank 2, EMIO, upper 16 bits) + masked_out_2_msw: MaskedOutput, + /// Maskable output data (GPIO bank 3, EMIO, lower 16 bits) + masked_out_3_lsw: MaskedOutput, + /// Maskable output data (GPIO bank 3, EMIO, upper 16 bits) + masked_out_3_msw: MaskedOutput, + + _reserved_0: [u32; 8], + + /// Output data (GPIO bank 0, MIO) + out_0: u32, + /// Output data (GPIO bank 1, MIO) + out_1: u32, + /// Output data (GPIO bank 2, EMIO) + out_2: u32, + /// Output data (GPIO bank 3, EMIO) + out_3: u32, + + _reserved_1: [u32; 4], + + /// Input data (GPIO bank 0, MIO) + #[mmio(PureRead)] + in_0: u32, + /// Input data (GPIO bank 1, MIO) + #[mmio(PureRead)] + in_1: u32, + /// Input data (GPIO bank 2, EMIO) + #[mmio(PureRead)] + in_2: u32, + /// Input data (GPIO bank 3, EMIO) + #[mmio(PureRead)] + in_3: u32, + + _reserved_2: [u32; 101], + + #[mmio(inner)] + bank_0: BankCtrl, + + _reserved_3: [u32; 7], + + #[mmio(inner)] + bank_1: BankCtrl, + + _reserved_4: [u32; 7], + + #[mmio(inner)] + bank_2: BankCtrl, + + _reserved_5: [u32; 7], + + #[mmio(inner)] + bank_3: BankCtrl, +} + +static_assertions::const_assert_eq!(core::mem::size_of::(), 0x2E8); + +impl Gpio { + /// Create a new XGPIOPS GPIO MMIO instance. + /// + /// # Safety + /// + /// This API can be used to potentially create a driver to the same peripheral structure + /// from multiple threads. The user must ensure that concurrent accesses are safe and do not + /// interfere with each other. + pub const unsafe fn new_mmio_fixed() -> MmioGpio<'static> { + MmioGpio { + ptr: 0xE000A000 as *mut Gpio, + phantom: core::marker::PhantomData, + } + } +} diff --git a/zynq7000/src/gtc.rs b/zynq7000/src/gtc.rs new file mode 100644 index 0000000..845c80e --- /dev/null +++ b/zynq7000/src/gtc.rs @@ -0,0 +1,60 @@ +//! # Global timer counter module. + +pub const GTC_BASE_ADDR: usize = super::mpcore::MPCORE_BASE_ADDR + 0x0000_0200; + +#[bitbybit::bitfield(u32)] +pub struct GtcCtrl { + #[bits(8..=15, rw)] + prescaler: u8, + #[bit(3, rw)] + auto_increment: bool, + #[bit(2, rw)] + irq_enable: bool, + #[bit(1, rw)] + comparator_enable: bool, + #[bit(0, rw)] + enable: bool, +} + +#[bitbybit::bitfield(u32)] +pub struct InterruptStatus { + #[bit(0, rw)] + event_flag: bool, +} + +/// Global timer counter. +#[derive(derive_mmio::Mmio)] +#[repr(C)] +pub struct Gtc { + /// Count register 0, lower 32 bits + count_lower: u32, + /// Count register 1, upper 32 bits + count_upper: u32, + /// Control register + ctrl: GtcCtrl, + /// Interrupt status register + #[mmio(PureRead, Write)] + isr: InterruptStatus, + /// Comparator 0, lower 32 bits + comparator_lower: u32, + /// Comparator 1, upper 32 bits + comparator_upper: u32, + /// Auto-increment register + auto_increment: u32, +} + +static_assertions::const_assert_eq!(core::mem::size_of::(), 0x1C); + +impl Gtc { + /// Create a new GTC MMIO instance at the fixed base address. + /// + /// # Safety + /// + /// This API can be used to potentially create a driver to the same peripheral structure + /// from multiple threads. The user must ensure that concurrent accesses are safe and do not + /// interfere with each other. + #[inline] + pub const unsafe fn new_mmio_fixed() -> MmioGtc<'static> { + unsafe { Gtc::new_mmio_at(GTC_BASE_ADDR) } + } +} diff --git a/zynq7000/src/i2c.rs b/zynq7000/src/i2c.rs new file mode 100644 index 0000000..b06d2f8 --- /dev/null +++ b/zynq7000/src/i2c.rs @@ -0,0 +1,203 @@ +//! SPI register module. +use arbitrary_int::{u2, u6, u10}; + +pub const I2C_0_BASE_ADDR: usize = 0xE000_4000; +pub const I2C_1_BASE_ADDR: usize = 0xE000_5000; + +#[bitbybit::bitenum(u1, exhaustive = true)] +#[derive(Debug)] +pub enum Direction { + Receiver = 0b1, + Transmitter = 0b0, +} + +#[bitbybit::bitenum(u1, exhaustive = true)] +#[derive(Debug)] +pub enum Mode { + Slave = 0b0, + Master = 0b1, +} + +#[bitbybit::bitfield(u32, default = 0x0)] +pub struct Control { + /// Divides the input PCLK frequency by this value + 1 + #[bits(14..=15, rw)] + div_a: u2, + /// Divides the output from divisor A by this value + 1 + #[bits(8..=13, rw)] + div_b: u6, + #[bit(6, rw)] + clear_fifo: bool, + #[bit(5, rw)] + slv_mon: bool, + /// 0: Allow transfer to terminate as soon as all data has been transmitted or received. + /// 1: When no more data is avilable for transmit or no more data can be received, hold + /// the SCK line low until services by the host. + #[bit(4, rw)] + hold_bus: bool, + /// Should be set to 1. 0: Disabled, NACK transmitted. 1: Enabled, ACK transmitted. + #[bit(3, rw)] + acken: bool, + /// Only used in master mode. 0: Reserved. 1: Normal 7-bit address. + #[bit(2, rw)] + addressing: bool, + #[bit(1, rw)] + mode: Mode, + #[bit(0, rw)] + dir: Direction, +} + +#[bitbybit::bitfield(u32)] +pub struct Status { + #[bit(8, r)] + bus_active: bool, + /// FIFO is full and new byte was received. The new byte is not acknowledged and the contents + /// of the FIFO remain unchanged. + #[bit(6, r)] + rx_overflow: bool, + /// 1: There is still a byte of data to be transmitted by the interface. + #[bit(6, r)] + tx_busy: bool, + /// Receiver data valid, ca be read from the interface. + #[bit(5, r)] + rx_valid: bool, + #[bit(3, r)] + rx_rw: bool, +} + +#[bitbybit::bitfield(u32)] +pub struct Addr { + #[bits(0..=9, rw)] + addr: u10, +} + +#[bitbybit::bitfield(u32)] +pub struct Fifo { + #[bits(0..=7, rw)] + data: u8, +} + +#[bitbybit::bitfield(u32)] +pub struct InterruptStatus { + #[bit(9, rw)] + arbitration_lost: bool, + #[bit(7, rw)] + rx_underflow: bool, + #[bit(6, rw)] + tx_overflow: bool, + #[bit(5, rw)] + rx_overflow: bool, + #[bit(4, rw)] + slave_ready: bool, + #[bit(3, rw)] + timeout: bool, + #[bit(2, rw)] + nack: bool, + #[bit(1, rw)] + data: bool, + #[bit(0, rw)] + complete: bool, +} + +#[bitbybit::bitfield(u32)] +pub struct InterruptMask { + #[bit(9, r)] + arbitration_lost: bool, + #[bit(7, r)] + rx_underflow: bool, + #[bit(6, r)] + tx_overflow: bool, + #[bit(5, r)] + rx_overflow: bool, + #[bit(4, r)] + slave_ready: bool, + #[bit(3, r)] + timeout: bool, + #[bit(2, r)] + nack: bool, + #[bit(1, r)] + data: bool, + #[bit(0, r)] + complete: bool, +} + +#[bitbybit::bitfield(u32)] +pub struct InterruptControl { + #[bit(9, w)] + arbitration_lost: bool, + #[bit(7, w)] + rx_underflow: bool, + #[bit(6, w)] + tx_overflow: bool, + #[bit(5, w)] + rx_overflow: bool, + #[bit(4, w)] + slave_ready: bool, + #[bit(3, w)] + timeout: bool, + #[bit(2, w)] + nack: bool, + #[bit(1, w)] + data: bool, + #[bit(0, w)] + complete: bool, +} + +#[bitbybit::bitfield(u32)] +pub struct Timeout { + /// Reset value: 0x1F. + #[bits(0..=7, rw)] + timeout: u8, +} + +#[bitbybit::bitfield(u32, default = 0x0)] +pub struct TransferSize { + #[bits(0..=7, rw)] + size: u8, +} + +#[derive(derive_mmio::Mmio)] +#[repr(C)] +pub struct I2c { + cr: Control, + #[mmio(PureRead)] + sr: Status, + addr: Addr, + #[mmio(Read, Write)] + data: Fifo, + #[mmio(PureRead, Write, Modify)] + isr: InterruptStatus, + transfer_size: TransferSize, + slave_pause: u32, + timeout: Timeout, + #[mmio(PureRead)] + imr: InterruptMask, + #[mmio(Write)] + ier: InterruptControl, + #[mmio(Write)] + idr: InterruptControl, +} + +impl I2c { + /// Create a new I2C MMIO instance for I2C0 at address [I2C_0_BASE_ADDR]. + /// + /// # Safety + /// + /// This API can be used to potentially create a driver to the same peripheral structure + /// from multiple threads. The user must ensure that concurrent accesses are safe and do not + /// interfere with each other. + pub const unsafe fn new_mmio_fixed_0() -> MmioI2c<'static> { + unsafe { Self::new_mmio_at(I2C_0_BASE_ADDR) } + } + + /// Create a new I2C MMIO instance for I2C1 at address [I2C_1_BASE_ADDR]. + /// + /// # Safety + /// + /// This API can be used to potentially create a driver to the same peripheral structure + /// from multiple threads. The user must ensure that concurrent accesses are safe and do not + /// interfere with each other. + pub const unsafe fn new_mmio_fixed_1() -> MmioI2c<'static> { + unsafe { Self::new_mmio_at(I2C_1_BASE_ADDR) } + } +} diff --git a/zynq7000/src/lib.rs b/zynq7000/src/lib.rs new file mode 100644 index 0000000..5ad2a15 --- /dev/null +++ b/zynq7000/src/lib.rs @@ -0,0 +1,85 @@ +//! # Rust peripheral acess crate to the AMD Zynq 7000 SoCs +//! +//! This crate provides a low-level register access API building on the +//! [`derive-mmio` crate](https://crates.io/crates/derive-mmio). However, its structure +//! is similar to the crates auto-generated by [`svd2rust`](https://docs.rs/svd2rust/latest/svd2rust/#peripheral-api). +//! +//! This crate is purposely kept low-level to allow building higher level abstractions like HALs +//! on top of it. +#![no_std] + +use core::sync::atomic::{AtomicBool, Ordering}; + +#[cfg(test)] +extern crate std; + +pub const MPCORE_BASE_ADDR: usize = 0xF8F0_0000; + +pub mod gic; +pub mod gpio; +pub mod gtc; +pub mod i2c; +pub mod mpcore; +pub mod slcr; +pub mod spi; +pub mod ttc; +pub mod uart; + +static PERIPHERALS_TAKEN: AtomicBool = AtomicBool::new(false); + +/// This is a collection of all the processing peripherals. +/// +/// It is a singleton which exposes all peripherals supported by this crate. +/// The [`svd2rust` documentation](https://docs.rs/svd2rust/latest/svd2rust/#peripheral-api) +/// provides some more information about this. +pub struct PsPeripherals { + pub gicc: gic::MmioGicc<'static>, + pub gicd: gic::MmioGicd<'static>, + pub uart_0: uart::MmioUart<'static>, + pub uart_1: uart::MmioUart<'static>, + pub spi_0: spi::MmioSpi<'static>, + pub spi_1: spi::MmioSpi<'static>, + pub i2c_0: i2c::MmioI2c<'static>, + pub i2c_1: i2c::MmioI2c<'static>, + pub gtc: gtc::MmioGtc<'static>, + pub gpio: gpio::MmioGpio<'static>, + pub slcr: slcr::MmioSlcr<'static>, + pub ttc_0: ttc::MmioTtc<'static>, + pub ttc_1: ttc::MmioTtc<'static>, +} + +impl PsPeripherals { + /// Returns all supported processing system peripherals *once*. + pub fn take() -> Option { + let taken = PERIPHERALS_TAKEN.swap(true, Ordering::Relaxed); + if taken { + return None; + } + Some(unsafe { Self::steal() }) + } + + /// Unchecked version of [Self::take]. + /// + /// # Safety + /// + /// Each of the returned peripherals must be used at most once. + pub unsafe fn steal() -> Self { + unsafe { + Self { + gicc: gic::Gicc::new_mmio_fixed(), + gicd: gic::Gicd::new_mmio_fixed(), + uart_0: uart::Uart::new_mmio_fixed_0(), + uart_1: uart::Uart::new_mmio_fixed_1(), + gtc: gtc::Gtc::new_mmio_fixed(), + gpio: gpio::Gpio::new_mmio_fixed(), + slcr: slcr::Slcr::new_mmio_fixed(), + spi_0: spi::Spi::new_mmio_fixed_0(), + spi_1: spi::Spi::new_mmio_fixed_1(), + i2c_0: i2c::I2c::new_mmio_fixed_0(), + i2c_1: i2c::I2c::new_mmio_fixed_1(), + ttc_0: ttc::Ttc::new_mmio_fixed_0(), + ttc_1: ttc::Ttc::new_mmio_fixed_1(), + } + } + } +} diff --git a/zynq7000/src/mpcore.rs b/zynq7000/src/mpcore.rs new file mode 100644 index 0000000..cbb4b89 --- /dev/null +++ b/zynq7000/src/mpcore.rs @@ -0,0 +1,97 @@ +//! Application Processing Unit Registers (mpcore) +//! +//! Based on p.1483 of the Zynq-7000 TRM. +use static_assertions::const_assert_eq; + +use crate::{ + gic::{Gicc, Gicd, MmioGicc, MmioGicd}, + gtc::{Gtc, MmioGtc}, +}; + +pub const MPCORE_BASE_ADDR: usize = 0xF8F0_0000; +pub const SCU_BASE_ADDR: usize = MPCORE_BASE_ADDR; +pub const GICC_BASE_ADDR: usize = MPCORE_BASE_ADDR + 0x100; +pub const GICD_BASE_ADDR: usize = MPCORE_BASE_ADDR + 0x1000; + +#[derive(derive_mmio::Mmio)] +#[repr(C)] +pub struct Scu { + ctrl: u32, + config: u32, + cpu_power_status: u32, + invalidate_all_regs_in_secure_state: u32, + _reserved_0: [u32; 0xC], + filtering_start_addr: u32, + filtering_end_addr: u32, + _reserved_1: [u32; 0x2], + access_ctrl: u32, + non_secure_access_ctrl: u32, +} + +impl Scu { + /// Create a new Snoop Control Unit interface at the fixed base address. + /// + /// # Safety + /// + /// This API can be used to potentially create a driver to the same peripheral structure + /// from multiple threads. The user must ensure that concurrent accesses are safe and do not + /// interfere with each other. + #[inline] + pub const unsafe fn new_mmio_fixed() -> MmioScu<'static> { + unsafe { Self::new_mmio_at(SCU_BASE_ADDR) } + } +} + +const_assert_eq!(core::mem::size_of::(), 0x58); + +#[derive(derive_mmio::Mmio)] +#[repr(C)] +pub struct Mpcore { + #[mmio(inner)] + scu: Scu, + + _reserved_0: [u32; 0x2A], + + #[mmio(inner)] + gicc: Gicc, + + #[mmio(inner)] + gt: Gtc, + + _reserved_1: [u32; 0xF9], + + private_timer_load: u32, + private_timer_counter: u32, + private_timer_ctrl: u32, + private_interrupt_status: u32, + + _reserved_2: [u32; 0x4], + + watchdog_load: u32, + watchdog_counter: u32, + watchdog_ctrl: u32, + watchdog_interrupt_status: u32, + watchdog_reset_status: u32, + watchdog_disable: u32, + + _reserved_3: [u32; 0x272], + + #[mmio(inner)] + gicd: Gicd, +} + +const_assert_eq!(core::mem::size_of::(), 0x2000); + +impl Mpcore { + /// Create a MP core peripheral interface at the fixed base address. + /// + /// # Safety + /// + /// This API can be used to potentially create a driver to the same peripheral structure + /// from multiple threads. The user must ensure that concurrent accesses are safe and do not + /// interfere with each other. + #[inline] + pub const unsafe fn new_mmio_fixed() -> MmioMpcore<'static> { + unsafe { Self::new_mmio_at(MPCORE_BASE_ADDR) } + } +} diff --git a/zynq7000/src/slcr/clocks.rs b/zynq7000/src/slcr/clocks.rs new file mode 100644 index 0000000..822c154 --- /dev/null +++ b/zynq7000/src/slcr/clocks.rs @@ -0,0 +1,364 @@ +//! SLCR clock control registers. +//! +//! Writing any of these registers required unlocking the SLCR first. +use super::{CLOCK_CONTROL_OFFSET, SLCR_BASE_ADDR}; +use arbitrary_int::{u4, u6, u7, u10}; + +#[bitbybit::bitenum(u1, exhaustive = true)] +#[derive(Debug)] +pub enum BypassForce { + EnabledOrSetByBootMode = 0b0, + Bypassed = 0b1, +} + +#[bitbybit::bitenum(u1, exhaustive = true)] +#[derive(Debug)] +pub enum BypassQual { + BypassForceBit = 0b0, + BootModeFourthBit = 0b1, +} + +#[bitbybit::bitfield(u32)] +#[derive(Debug)] +pub struct PllCtrl { + /// Feedback divisor for the PLL. + /// + /// NOTE: Before changing this value, the PLL must first be bypassed and then put into + /// reset mode. + #[bits(12..=18, rw)] + fdiv: u7, + /// Select source for the ARM PLL bypass control + #[bit(4, rw)] + bypass_force: BypassForce, + /// Select source for the ARM PLL bypass control + #[bit(3, rw)] + bypass_qual: BypassQual, + // Power-down control + #[bit(1, rw)] + pwrdwn: bool, + /// Reset control + #[bit(0, rw)] + reset: bool, +} + +#[bitbybit::bitfield(u32)] +#[derive(Debug)] +pub struct PllCfg { + #[bits(12..=21, rw)] + lock_count: u10, + /// Charge Pump control + #[bits(8..=11, rw)] + pll_cp: u4, + /// Loop resistor control + #[bits(4..=7, rw)] + pll_res: u4, +} + +#[bitbybit::bitfield(u32)] +#[derive(Debug)] +pub struct PllStatus { + #[bit(5)] + io_pll_stable: bool, + #[bit(4)] + ddr_pll_stable: bool, + #[bit(3)] + arm_pll_stable: bool, + #[bit(2)] + io_pll_lock: bool, + #[bit(1)] + drr_pll_lock: bool, + #[bit(0)] + arm_pll_lock: bool, +} + +#[bitbybit::bitfield(u32)] +#[derive(Debug)] +pub struct FpgaClkControl { + // Reset value 0x1 + #[bits(20..=25, rw)] + divisor_1: u6, + // Reset value 0x18 + #[bits(8..=13, rw)] + divisor_0: u6, + #[bits(4..=5, rw)] + srcsel: SrcSelIo, +} + +#[derive(derive_mmio::Mmio)] +#[repr(C)] +pub struct FpgaClkBlock { + clk_ctrl: FpgaClkControl, + thr_ctrl: u32, + thr_cnt: u32, + thr_status: u32, +} + +static_assertions::const_assert_eq!(core::mem::size_of::(), 0x10); + +#[bitbybit::bitenum(u2, exhaustive = true)] +#[derive(Debug)] +pub enum SrcSelArm { + ArmPll = 0b00, + ArmPllAlt = 0b01, + DdrPll = 0b10, + IoPll = 0b11, +} + +#[bitbybit::bitfield(u32)] +pub struct ArmClkCtrl { + #[bit(28, rw)] + cpu_peri_clk_act: bool, + #[bit(27, rw)] + cpu_1x_clk_act: bool, + #[bit(26, rw)] + cpu_2x_clk_act: bool, + #[bit(25, rw)] + cpu_3or2x_clk_act: bool, + #[bit(24, rw)] + cpu_6or4x_clk_act: bool, + /// Reset value: 0x4. There is a requirement for the quality of the high speed clock that + /// it has to be divided by an even number. This field must be equal to or greater than 2. + #[bits(8..=13, rw)] + divisor: u6, + /// Reset value: 0x0 + #[bits(4..=5, rw)] + srcsel: SrcSelArm, +} + +#[bitbybit::bitfield(u32)] +pub struct DdrClkCtrl { + /// Divisor for DDR 2x clock. Reset value: 0x6 + #[bits(26..=31, rw)] + div_2x_clk: u6, + /// Divisor for DDR 3x clock. Only even divisors are allowed! Reset value: 0x4 + #[bits(20..=25, rw)] + div_3x_clk: u6, + /// Reset value: 0x1 + #[bit(1, rw)] + ddr_2x_clk_act: bool, + /// Reset value: 0x1 + #[bit(0, rw)] + ddr_3x_clk_act: bool, +} + +#[bitbybit::bitfield(u32)] +pub struct DciClkCtrl { + /// Second cascade divider. Reset value: 0x1E + #[bits(20..=25, rw)] + divisor_1: u6, + /// Reset value: 0x32 + #[bits(8..=13, rw)] + divisor_0: u6, + /// Reset value: 0x1 + #[bit(0, rw)] + clk_act: bool, +} + +#[bitbybit::bitfield(u32)] +#[derive(Debug)] +pub struct ClockRatioSelectReg { + /// Reset value: 0x1 (6:2:1 clock) + #[bit(0, rw)] + sel: ClockRatioSelect, +} + +#[bitbybit::bitenum(u1, exhaustive = true)] +#[derive(Debug)] +pub enum ClockRatioSelect { + /// 4:2:1 clock ratio, which is an abbreviation for 4:2:2:1. + FourToTwoToOne = 0b0, + /// 6:2:1 clock ratio, which is an abbreviation for 6:3:2:1. + SixToTwoToOne = 0b1, +} + +#[bitbybit::bitenum(u2, exhaustive = true)] +#[derive(Debug)] +pub enum SrcSelIo { + IoPll = 0b00, + IoPllAlt = 0b01, + ArmPll = 0b10, + DdrPll = 0b11, +} + +#[bitbybit::bitfield(u32)] +#[derive(Debug)] +pub struct GigEthClkCtrl { + #[bits(20..=25, rw)] + divisor_1: u6, + #[bits(8..=13, rw)] + divisor_0: u6, + #[bit(6, rw)] + use_emio_tx_clk: bool, + #[bits(4..=5, rw)] + srcsel: SrcSelIo, + #[bit(0, rw)] + clk_act: bool, +} + +#[bitbybit::bitfield(u32)] +#[derive(Debug)] +pub struct CanClkCtrl { + #[bits(20..=25, rw)] + divisor_1: u6, + #[bits(8..=13, rw)] + divisor_0: u6, + #[bits(4..=5, rw)] + srcsel: SrcSelIo, + #[bit(1, rw)] + clk_1_act: bool, + #[bit(0, rw)] + clk_0_act: bool, +} + +#[bitbybit::bitfield(u32)] +pub struct SingleCommonPeriphIoClkCtrl { + #[bits(8..=13, rw)] + divisor: u6, + #[bits(4..=5, rw)] + srcsel: SrcSelIo, + #[bit(0, rw)] + clk_act: bool, +} + +#[bitbybit::bitfield(u32)] +#[derive(Debug)] +pub struct DualCommonPeriphIoClkCtrl { + #[bits(8..=13, rw)] + divisor: u6, + #[bits(4..=5, rw)] + srcsel: SrcSelIo, + #[bit(1, rw)] + clk_1_act: bool, + #[bit(0, rw)] + clk_0_act: bool, +} + +#[bitbybit::bitenum(u3, exhaustive = true)] +#[derive(Debug)] +pub enum SrcSelTpiu { + IoPll = 0b000, + IoPllAlt = 0b001, + ArmPll = 0b010, + DdrPll = 0b011, + EmioTraceClk = 0b100, + EmioTraceClkAlt0 = 0b101, + EmioTraceClkAlt1 = 0b110, + EmioTraceClkAlt2 = 0b111, +} + +#[bitbybit::bitfield(u32)] +pub struct TracePortClkCtrl { + #[bits(8..=13, rw)] + divisor: u6, + #[bits(4..=6, rw)] + srcsel: SrcSelTpiu, + #[bit(1, rw)] + clk_1x_clk_act: bool, + #[bit(0, rw)] + clk_act: bool, +} + +/// AMBA peripheral clock control. +/// +/// These clocks must be enabled if you want to read from the peripheral register space. +#[bitbybit::bitfield(u32)] +#[derive(Debug)] +pub struct AperClkCtrl { + #[bit(24, rw)] + smc_1x_clk_act: bool, + #[bit(23, rw)] + lqspi_1x_clk_act: bool, + #[bit(22, rw)] + gpio_1x_clk_act: bool, + #[bit(21, rw)] + uart_1_1x_clk_act: bool, + #[bit(20, rw)] + uart_0_1x_clk_act: bool, + #[bit(19, rw)] + i2c_1_1x_clk_act: bool, + #[bit(18, rw)] + i2c_0_1x_clk_act: bool, + #[bit(17, rw)] + can_1_1x_clk_act: bool, + #[bit(16, rw)] + can_0_1x_clk_act: bool, + #[bit(15, rw)] + spi_1_1x_clk_act: bool, + #[bit(14, rw)] + spi_0_1x_clk_act: bool, + #[bit(11, rw)] + sdio_1_1x_clk_act: bool, + #[bit(10, rw)] + sdio_0_1x_clk_act: bool, + #[bit(7, rw)] + gem_1_1x_clk_act: bool, + #[bit(6, rw)] + gem_0_1x_clk_act: bool, + #[bit(3, rw)] + usb_1_cpu_1x_clk_act: bool, + #[bit(2, rw)] + usb_0_cpu_1x_clk_act: bool, + #[bit(0, rw)] + dma_cpu_2x_clk_act: bool, +} + +#[derive(derive_mmio::Mmio)] +#[repr(C)] +pub struct ClockControl { + arm_pll: PllCtrl, + ddr_pll: PllCtrl, + io_pll: PllCtrl, + pll_status: PllStatus, + arm_pll_cfg: PllCfg, + ddr_pll_cfg: PllCfg, + io_pll_cfg: PllCfg, + _gap0: u32, + arm_clk_ctrl: ArmClkCtrl, + ddr_clk_ctrl: DdrClkCtrl, + dci_clk_ctrl: DciClkCtrl, + /// AMBA peripheral clock control + aper_clk_ctrl: AperClkCtrl, + usb_0_clk_ctrl: u32, + usb_1_clk_ctrl: u32, + gem_0_rclk_ctrl: u32, + gem_1_rclk_ctrl: u32, + gem_0_clk_ctrl: GigEthClkCtrl, + gem_1_clk_ctrl: GigEthClkCtrl, + smc_clk_ctrl: SingleCommonPeriphIoClkCtrl, + lqspi_clk_ctrl: SingleCommonPeriphIoClkCtrl, + sdio_clk_ctrl: DualCommonPeriphIoClkCtrl, + uart_clk_ctrl: DualCommonPeriphIoClkCtrl, + spi_clk_ctrl: DualCommonPeriphIoClkCtrl, + can_clk_ctrl: CanClkCtrl, + can_mioclk_ctrl: u32, + /// Debug or Trace Port clock control. + dbg_clk_ctrl: TracePortClkCtrl, + pcap_clk_ctrl: SingleCommonPeriphIoClkCtrl, + topsw_clk_ctrl: u32, + #[mmio(inner)] + fpga_0_clk_ctrl: FpgaClkBlock, + #[mmio(inner)] + fpga_1_clk_ctrl: FpgaClkBlock, + #[mmio(inner)] + fpga_2_clk_ctrl: FpgaClkBlock, + #[mmio(inner)] + fpga_3_clk_ctrl: FpgaClkBlock, + _gap1: [u32; 5], + clk_621_true: ClockRatioSelectReg, +} + +impl ClockControl { + /// Create a new handle to this peripheral. + /// + /// Writing to this register requires unlocking the SLCR registers first. + /// + /// # Safety + /// + /// If you create multiple instances of this handle at the same time, you are responsible for + /// ensuring that there are no read-modify-write races on any of the registers. + pub unsafe fn new_mmio_fixed() -> MmioClockControl<'static> { + unsafe { Self::new_mmio_at(SLCR_BASE_ADDR + CLOCK_CONTROL_OFFSET) } + } +} + +static_assertions::const_assert_eq!(core::mem::size_of::(), 0xC8); diff --git a/zynq7000/src/slcr/mio.rs b/zynq7000/src/slcr/mio.rs new file mode 100644 index 0000000..7236019 --- /dev/null +++ b/zynq7000/src/slcr/mio.rs @@ -0,0 +1,41 @@ +//! # SLCR MIO (Multiplexed I/O) configuration registers +//! +//! Writing any of these registers required unlocking the SLCR first. +use arbitrary_int::{u2, u3}; + +#[bitbybit::bitenum(u1, exhaustive = true)] +pub enum Speed { + SlowCmosEdge = 0b0, + FastCmosEdge = 0b1, +} + +#[bitbybit::bitenum(u3)] +pub enum IoType { + LvCmos18 = 0b001, + LvCmos25 = 0b010, + LvCmos33 = 0b011, + Hstl = 0b100, +} + +#[bitbybit::bitfield(u32)] +#[derive(Debug)] +pub struct Config { + #[bit(13, rw)] + disable_hstl_rcvr: bool, + #[bit(12, rw)] + pullup: bool, + #[bits(9..=11, rw)] + io_type: Option, + #[bit(8, rw)] + speed: Speed, + #[bits(5..=7, rw)] + l3_sel: u3, + #[bits(3..=4, rw)] + l2_sel: u2, + #[bit(2, rw)] + l1_sel: bool, + #[bit(1, rw)] + l0_sel: bool, + #[bit(0, rw)] + tri_enable: bool, +} diff --git a/zynq7000/src/slcr/mod.rs b/zynq7000/src/slcr/mod.rs new file mode 100644 index 0000000..c6b648e --- /dev/null +++ b/zynq7000/src/slcr/mod.rs @@ -0,0 +1,206 @@ +//! System Level Control Registers (slcr) +//! +//! Writing any of these registers required unlocking the SLCR first. +use arbitrary_int::u4; +pub use clocks::{ClockControl, MmioClockControl}; +pub use reset::{MmioResetControl, ResetControl}; + +const SLCR_BASE_ADDR: usize = 0xF8000000; +const CLOCK_CONTROL_OFFSET: usize = 0x100; +const RESET_BLOCK_OFFSET: usize = 0x200; +const GPIOB_OFFSET: usize = 0xB00; +const DDRIOB_OFFSET: usize = 0xB40; + +pub mod clocks; +pub mod mio; +pub mod reset; + +#[derive(derive_mmio::Mmio)] +#[repr(C)] +pub struct DdrIoB { + ddriob_addr0: u32, + ddriob_addr1: u32, + ddriob_data0: u32, + ddriob_data1: u32, + ddriob_diff0: u32, + ddriob_diff1: u32, + ddriob_clock: u32, + ddriob_drive_slew_addr: u32, + ddriob_drive_slew_data: u32, + ddriob_drive_slew_diff: u32, + ddriob_drive_slew_clock: u32, + ddriob_ddr_ctrl: u32, + ddriob_dci_ctrl: u32, + ddriob_dci_status: u32, +} + +impl DdrIoB { + /// Create a new handle to this peripheral. + /// + /// Writing to this register requires unlocking the SLCR registers first. + /// + /// # Safety + /// + /// If you create multiple instances of this handle at the same time, you are responsible for + /// ensuring that there are no read-modify-write races on any of the registers. + pub unsafe fn new_mmio_fixed() -> MmioDdrIoB<'static> { + unsafe { Self::new_mmio_at(SLCR_BASE_ADDR + DDRIOB_OFFSET) } + } +} + +static_assertions::const_assert_eq!(core::mem::size_of::(), 0x38); + +#[derive(derive_mmio::Mmio)] +#[repr(C)] +pub struct GpiobCtrl { + ctrl: u32, + cfg_cmos18: u32, + cfg_cmos25: u32, + cfg_cmos33: u32, + _gap17: u32, + cfg_hstl: u32, + drvr_bias_ctrl: u32, +} + +impl GpiobCtrl { + /// Create a new handle to this peripheral. + /// + /// Writing to this register requires unlocking the SLCR registers first. + /// + /// # Safety + /// + /// If you create multiple instances of this handle at the same time, you are responsible for + /// ensuring that there are no read-modify-write races on any of the registers. + pub unsafe fn new_mmio_fixed() -> MmioGpiobCtrl<'static> { + unsafe { Self::new_mmio_at(SLCR_BASE_ADDR + GPIOB_OFFSET) } + } +} + +#[bitbybit::bitfield(u32)] +pub struct BootModeRegister { + #[bit(4, r)] + pll_bypass: bool, + #[bits(0..=3, r)] + boot_mode: u4, +} + +#[bitbybit::bitenum(u4)] +#[derive(Debug, PartialEq, Eq)] +pub enum LevelShifterConfig { + DisableAll = 0x00, + EnablePsToPl = 0xA, + EnableAll = 0xF, +} + +#[bitbybit::bitfield(u32)] +pub struct LevelShifterReg { + #[bits(0..=3, rw)] + user_lvl_shftr_en: Option, +} + +/// System Level Control Registers +#[derive(derive_mmio::Mmio)] +#[repr(C)] +pub struct Slcr { + /// Secure configuration lock. + scl: u32, + /// SLCR write protection lock + lock: u32, + /// SLCR write protection unlock + unlock: u32, + /// SLCR write protection status + lock_status: u32, + + _gap0: [u32; 0x3C], + + #[mmio(inner)] + clk_ctrl: ClockControl, + + _gap1: [u32; 0x0E], + + #[mmio(inner)] + reset_ctrl: ResetControl, + + _gap2: [u32; 0x02], + + reboot_status: u32, + boot_mode: BootModeRegister, + + _gap3: [u32; 0x28], + + apu_ctrl: u32, + wdt_clk_set: u32, + + _gap4: [u32; 0x4E], + + tz_dma_ns: u32, + tz_dma_irq_ns: u32, + tz_dma_periph_ns: u32, + + _gap5: [u32; 0x39], + + pss_idcode: u32, + + _gap6: [u32; 0x33], + + ddr_urgent: u32, + _gap7: [u32; 0x02], + ddr_cal_start: u32, + _gap8: u32, + ddr_ref_start: u32, + ddr_cmd_status: u32, + ddr_urgent_sel: u32, + ddr_dfi_status: u32, + + _gap9: [u32; 0x37], + + mio_pins: [mio::Config; 0x36], + + _gap10: [u32; 0x0B], + + mio_loopback: u32, + _gap11: u32, + mio_mst_tri_0: u32, + mio_mst_tri_1: u32, + _gap12: [u32; 7], + sd_0_wp_cd_sel: u32, + sd_1_wp_cd_sel: u32, + + _gap13: [u32; 0x32], + + lvl_shftr_en: LevelShifterReg, + + _gap14: [u32; 0x03], + + ocm_cfg: u32, + + _gap15: [u32; 0x42], + + reserved: u32, + + _gap16: [u32; 0x38], + + _gap18: [u32; 0x09], + + #[mmio(inner)] + gpiob: GpiobCtrl, + + #[mmio(inner)] + ddriob: DdrIoB, +} + +static_assertions::const_assert_eq!(core::mem::size_of::(), 0xB78); + +impl Slcr { + /// Create a new handle to this peripheral. + /// + /// Writing to this register requires unlocking the SLCR registers first. + /// + /// # Safety + /// + /// If you create multiple instances of this handle at the same time, you are responsible for + /// ensuring that there are no read-modify-write races on any of the registers. + pub unsafe fn new_mmio_fixed() -> MmioSlcr<'static> { + unsafe { Self::new_mmio_at(SLCR_BASE_ADDR) } + } +} diff --git a/zynq7000/src/slcr/reset.rs b/zynq7000/src/slcr/reset.rs new file mode 100644 index 0000000..d427994 --- /dev/null +++ b/zynq7000/src/slcr/reset.rs @@ -0,0 +1,79 @@ +use super::{RESET_BLOCK_OFFSET, SLCR_BASE_ADDR}; + +#[bitbybit::bitfield(u32, default = 0x0)] +#[derive(Debug)] +pub struct DualClockReset { + /// Peripheral 1 AMBA software reset. + #[bit(1, rw)] + periph1_cpu1x_rst: bool, + /// Peripheral 0 AMBA software reset. + #[bit(0, rw)] + periph0_cpu1x_rst: bool, +} + +#[bitbybit::bitfield(u32, default = 0x0)] +#[derive(Debug)] +pub struct DualRefAndClockReset { + /// Periperal 1 Reference software reset. + #[bit(3, rw)] + periph1_ref_rst: bool, + /// Peripheral 0 Reference software reset. + #[bit(2, rw)] + periph0_ref_rst: bool, + /// Peripheral 1 AMBA software reset. + #[bit(1, rw)] + periph1_cpu1x_rst: bool, + /// Peripheral 0 AMBA software reset. + #[bit(0, rw)] + periph0_cpu1x_rst: bool, +} + +#[bitbybit::bitfield(u32, default = 0x0)] +#[derive(Debug)] +pub struct GpioClockReset { + #[bit(0, rw)] + gpio_cpu1x_rst: bool, +} + +#[derive(derive_mmio::Mmio)] +#[repr(C)] +pub struct ResetControl { + /// PS Software reset control + pss: u32, + ddr: u32, + /// Central interconnect reset control + topsw: u32, + dmac: u32, + usb: u32, + gem: u32, + sdio: DualRefAndClockReset, + spi: DualRefAndClockReset, + can: DualClockReset, + i2c: DualClockReset, + uart: DualRefAndClockReset, + gpio: GpioClockReset, + lqspi: u32, + smc: u32, + ocm: u32, + _gap0: u32, + fpga: u32, + a9_cpu: u32, + _gap1: u32, + rs_awdt: u32, +} + +impl ResetControl { + /// Create a new handle to this peripheral. + /// + /// Writing to this register requires unlocking the SLCR registers first. + /// + /// # Safety + /// + /// If you create multiple instances of this handle at the same time, you are responsible for + /// ensuring that there are no read-modify-write races on any of the registers. + pub unsafe fn new_mmio_fixed() -> MmioResetControl<'static> { + unsafe { Self::new_mmio_at(SLCR_BASE_ADDR + RESET_BLOCK_OFFSET) } + } +} + +static_assertions::const_assert_eq!(core::mem::size_of::(), 0x50); diff --git a/zynq7000/src/spi.rs b/zynq7000/src/spi.rs new file mode 100644 index 0000000..6645440 --- /dev/null +++ b/zynq7000/src/spi.rs @@ -0,0 +1,236 @@ +//! SPI register module. +use arbitrary_int::{u4, Number}; + +pub const SPI_0_BASE_ADDR: usize = 0xE000_6000; +pub const SPI_1_BASE_ADDR: usize = 0xE000_7000; + +/// The SPI reference block will be divided by a divisor value. +#[bitbybit::bitenum(u3)] +#[derive(Debug, PartialEq, Eq)] +pub enum BaudDivSelect { + By4 = 0b001, + By8 = 0b010, + By16 = 0b011, + By32 = 0b100, + By64 = 0b101, + By128 = 0b110, + By256 = 0b111, +} + +impl BaudDivSelect { + pub const fn div_value(&self) -> usize { + match self { + BaudDivSelect::By4 => 4, + BaudDivSelect::By8 => 8, + BaudDivSelect::By16 => 16, + BaudDivSelect::By32 => 32, + BaudDivSelect::By64 => 64, + BaudDivSelect::By128 => 128, + BaudDivSelect::By256 => 256, + } + } +} + +#[bitbybit::bitfield(u32, default = 0x0)] +#[derive(Debug)] +pub struct Config { + #[bit(17, rw)] + modefail_gen_en: bool, + #[bit(16, w)] + manual_start: bool, + #[bit(15, rw)] + manual_start_enable: bool, + #[bit(14, rw)] + manual_cs: bool, + #[bits(10..=13, rw)] + cs_raw: u4, + /// Peripheral select decode, 1: Allow external 3-to-8 decode. + /// I am not sure how exactly this work, but I suspect the last three bits of the chip + /// select bits will be output directly to the 3 chip select output lines. + #[bit(9, rw)] + peri_sel: bool, + /// Uses SPI reference clock, value 1 is not supported. + #[bit(8, r)] + ref_clk: bool, + #[bits(3..=5, rw)] + baud_rate_div: Option, + /// Clock phase. 1: The SPI clock is inactive outside the word. + #[bit(2, rw)] + cpha: bool, + /// Clock phase. 1: The SPI clock is quiescent high. + #[bit(1, rw)] + cpol: bool, + /// Master mode enable. 1 is master mode. + #[bit(0, rw)] + master_ern: bool, +} + +#[bitbybit::bitfield(u32, default = 0x0)] +#[derive(Debug)] +pub struct InterruptStatus { + #[bit(6, rw)] + tx_underflow: bool, + #[bit(5, rw)] + rx_full: bool, + #[bit(4, rw)] + rx_not_empty: bool, + #[bit(3, rw)] + tx_full: bool, + #[bit(2, rw)] + tx_not_full: bool, + #[bit(1, rw)] + mode_fault: bool, + /// Receiver overflow interrupt. + #[bit(0, rw)] + rx_ovr: bool, +} + +#[bitbybit::bitfield(u32, default = 0x0)] +#[derive(Debug)] +pub struct InterruptControl { + #[bit(6, w)] + tx_underflow: bool, + #[bit(5, w)] + rx_full: bool, + #[bit(4, w)] + rx_not_empty: bool, + #[bit(3, w)] + tx_full: bool, + #[bit(2, w)] + tx_trig: bool, + #[bit(1, w)] + mode_fault: bool, + /// Receiver overflow interrupt. + #[bit(0, w)] + rx_ovr: bool, +} + +#[bitbybit::bitfield(u32)] +#[derive(Debug)] +pub struct InterruptMask { + #[bit(6, r)] + tx_underflow: bool, + #[bit(5, r)] + rx_full: bool, + #[bit(4, r)] + rx_not_empty: bool, + #[bit(3, r)] + tx_full: bool, + #[bit(2, r)] + tx_trig: bool, + #[bit(1, r)] + mode_fault: bool, + /// Receiver overflow interrupt. + #[bit(0, r)] + rx_ovr: bool, +} + +#[derive(Debug)] +pub struct FifoWrite(arbitrary_int::UInt); + +impl FifoWrite { + #[inline] + pub fn new(data: u8) -> Self { + Self(data.into()) + } + + #[inline] + pub fn value(&self) -> u8 { + self.0.as_u8() + } + + #[inline] + pub fn write(&mut self, value:u8) { + self.0 = value.into(); + } +} + +#[derive(Debug)] +pub struct FifoRead(arbitrary_int::UInt); + +impl FifoRead { + #[inline] + pub fn new(data: u8) -> Self { + Self(data.into()) + } + + #[inline] + pub fn value(&self) -> u8 { + self.0.as_u8() + } +} + +/// The numbers specified in the register fields are always specified in number of +#[bitbybit::bitfield(u32, default = 0x0)] +#[derive(Debug)] +pub struct DelayControl { + /// Number of cycles the chip select is de-asserted between words when CPHA = 0 + #[bits(24..=31, rw)] + inter_word_cs_deassert: u8, + /// Delay between one chip select being de-activated, and activation of another. + #[bits(16..=23, rw)] + between_cs_assertion: u8, + /// Delay between words. + #[bits(8..=15, rw)] + inter_word: u8, + /// Added delay between assertion of slave select and first bit transfer. + #[bits(0..=7, rw)] + cs_to_first_bit: u8, +} + +/// Register block specification for both PS SPIs. +#[derive(derive_mmio::Mmio)] +#[repr(C)] +pub struct Spi { + cr: Config, + #[mmio(PureRead, Write)] + isr: InterruptStatus, + /// Interrupt Enable Register. + #[mmio(Write)] + ier: InterruptControl, + /// Interrupt Disable Register. + #[mmio(Write)] + idr: InterruptControl, + /// Interrupt Mask Register. + #[mmio(PureRead)] + imr: InterruptMask, + enable: u32, + delay_control: DelayControl, + #[mmio(Write)] + txd: FifoWrite, + #[mmio(Read)] + rxd: FifoRead, + sicr: u32, + tx_trig: u32, + rx_trig: u32, + _reserved: [u32; 0x33], + // Reset value: 0x90106 + #[mmio(PureRead)] + mod_id: u32, +} + +static_assertions::const_assert_eq!(core::mem::size_of::(), 0x100); + +impl Spi { + /// Create a new SPI MMIO instance for SPI0 at address [SPI_0_BASE_ADDR]. + /// + /// # Safety + /// + /// This API can be used to potentially create a driver to the same peripheral structure + /// from multiple threads. The user must ensure that concurrent accesses are safe and do not + /// interfere with each other. + pub const unsafe fn new_mmio_fixed_0() -> MmioSpi<'static> { + unsafe { Self::new_mmio_at(SPI_0_BASE_ADDR) } + } + + /// Create a new SPI MMIO instance for SPI1 at address [SPI_1_BASE_ADDR]. + /// + /// # Safety + /// + /// This API can be used to potentially create a driver to the same peripheral structure + /// from multiple threads. The user must ensure that concurrent accesses are safe and do not + /// interfere with each other. + pub const unsafe fn new_mmio_fixed_1() -> MmioSpi<'static> { + unsafe { Self::new_mmio_at(SPI_1_BASE_ADDR) } + } +} diff --git a/zynq7000/src/ttc.rs b/zynq7000/src/ttc.rs new file mode 100644 index 0000000..76fe4d8 --- /dev/null +++ b/zynq7000/src/ttc.rs @@ -0,0 +1,189 @@ +//! Triple-timer counter (TTC) register module. +use arbitrary_int::u4; + +pub const TTC_0_BASE_ADDR: usize = 0xF800_1000; +pub const TTC_1_BASE_ADDR: usize = 0xF800_2000; + +#[derive(Debug, Default)] +#[bitbybit::bitenum(u1, exhaustive = true)] +pub enum ClockSource { + /// PS internal bus clock. + #[default] + Pclk = 0b0, + External = 0b1, +} + +#[bitbybit::bitfield(u32, default = 0x0)] +pub struct ClockControl { + /// When this bit is set and the external clock is selected, the counter clocks on the + /// negative edge of the external clock input. + #[bit(6, rw)] + ext_clk_edge: bool, + #[bit(5, rw)] + clk_src: ClockSource, + #[bits(1..=4, rw)] + prescaler: u4, + #[bit(0, rw)] + prescale_enable: bool, +} + +#[derive(Debug)] +#[bitbybit::bitenum(u1, exhaustive = true)] +pub enum Mode { + Overflow = 0b0, + Interval = 0b1, +} + +#[derive(Debug, Default)] +#[bitbybit::bitenum(u1, exhaustive = true)] +pub enum WavePolarity { + /// The waveform output goes from high to low on a match 0 interrupt and returns high on + /// overflow or interval interrupt. + #[default] + HighToLowOnMatch1 = 0b0, + /// The waveform output goes from low to high on a match 0 interrupt and returns low on + /// overflow or interval interrupt. + LowToHighOnMatch1 = 0b1, +} + +#[derive(Debug)] +#[bitbybit::bitenum(u1, exhaustive = true)] +pub enum WaveEnable { + Enable = 0b0, + Disable = 0b1, +} + +#[bitbybit::bitfield(u32, default = 0x0)] +pub struct CounterControl { + #[bit(6, rw)] + wave_polarity: WavePolarity, + /// Output waveform enable, active low. Reset value 1. + #[bit(5, rw)] + wave_enable_n: WaveEnable, + /// Resets the counter and restarts counting. Automatically cleared on restart. + #[bit(4, rw)] + reset: bool, + /// When this bit is set, an interrupt is generated when the count value matches one of the + /// three match registers and the corresponding bit is set in the IER register. + #[bit(3, rw)] + match_enable: bool, + /// When this bit is high, the timer counts down. + #[bit(2, rw)] + decrementing: bool, + #[bit(1, rw)] + mode: Mode, + #[bit(0, rw)] + disable: bool, +} + +#[bitbybit::bitfield(u32)] +pub struct Counter { + #[bits(0..=15, r)] + count: u16, +} + +#[bitbybit::bitfield(u32)] +pub struct RwValue { + #[bits(0..=15, rw)] + value: u16, +} + +#[bitbybit::bitfield(u32)] +pub struct InterruptStatus { + /// Even timer overflow interrupt. + #[bit(5, r)] + event: bool, + #[bit(4, r)] + counter_overflow: bool, + #[bit(3, r)] + match_2: bool, + #[bit(2, r)] + match_1: bool, + #[bit(1, r)] + match_0: bool, + #[bit(0, r)] + interval: bool, +} + +#[bitbybit::bitfield(u32)] +pub struct InterruptControl { + /// Even timer overflow interrupt. + #[bit(5, rw)] + event: bool, + #[bit(4, rw)] + counter_overflow: bool, + #[bit(3, rw)] + match_2: bool, + #[bit(2, rw)] + match_1: bool, + #[bit(1, rw)] + match_0: bool, + #[bit(0, rw)] + interval: bool, +} + +#[bitbybit::bitfield(u32)] +pub struct EventControl { + /// E_Ov bit. When set to 0, the event timer is disabled and set to 0 when an event timer + /// register overflow occurs. Otherwise, continue counting on overflow. + #[bit(2, rw)] + continuous_mode: bool, + /// E_Lo bit. When set to 1, counts PCLK cycles during low level duration of the external + /// clock. Otherwise, counts it during high level duration. + #[bit(1, rw)] + count_low_level_of_ext_clk: bool, + #[bit(0, rw)] + enable: bool, +} + +#[bitbybit::bitfield(u32)] +pub struct EventCount { + #[bits(0..=15, r)] + count: u16, +} + +/// Triple-timer counter +#[derive(derive_mmio::Mmio)] +#[repr(C)] +pub struct Ttc { + clk_cntr: [ClockControl; 3], + cnt_ctrl: [CounterControl; 3], + #[mmio(PureRead)] + current_counter: [Counter; 3], + interval_value: [RwValue; 3], + match_value_0: [RwValue; 3], + match_value_1: [RwValue; 3], + match_value_2: [RwValue; 3], + #[mmio(Read)] + isr: [InterruptStatus; 3], + ier: [InterruptControl; 3], + event_cntrl: [EventControl; 3], + #[mmio(PureRead)] + event_reg: [EventCount; 3], +} + +static_assertions::const_assert_eq!(core::mem::size_of::(), 0x84); + +impl Ttc { + /// Create a new TTC MMIO instance for TTC0 at address [TTC_0_BASE_ADDR]. + /// + /// # Safety + /// + /// This API can be used to potentially create a driver to the same peripheral structure + /// from multiple threads. The user must ensure that concurrent accesses are safe and do not + /// interfere with each other. + pub const unsafe fn new_mmio_fixed_0() -> MmioTtc<'static> { + unsafe { Self::new_mmio_at(TTC_0_BASE_ADDR) } + } + + /// Create a new TTC MMIO instance for TTC1 at address [TTC_1_BASE_ADDR]. + /// + /// # Safety + /// + /// This API can be used to potentially create a driver to the same peripheral structure + /// from multiple threads. The user must ensure that concurrent accesses are safe and do not + /// interfere with each other. + pub const unsafe fn new_mmio_fixed_1() -> MmioTtc<'static> { + unsafe { Self::new_mmio_at(TTC_1_BASE_ADDR) } + } +} diff --git a/zynq7000/src/uart.rs b/zynq7000/src/uart.rs new file mode 100644 index 0000000..d04b42b --- /dev/null +++ b/zynq7000/src/uart.rs @@ -0,0 +1,356 @@ +//! PS UART register module. +use arbitrary_int::u6; + +pub const UART_0_BASE: usize = 0xE000_0000; +pub const UART_1_BASE: usize = 0xE000_1000; + +#[bitbybit::bitenum(u3, exhaustive = true)] +pub enum Parity { + Even = 0b000, + Odd = 0b001, + /// Forced to 0 (Space) + ForcedTo0 = 0b010, + /// Forced to 1 (Mark) + ForcedTo1 = 0b011, + NoParity = 0b100, + NoParityAlt0 = 0b101, + NoParityAlt1 = 0b110, + NoParityAlt2 = 0b111, +} + +#[bitbybit::bitenum(u2, exhaustive = true)] +#[derive(Default, Debug, PartialEq, Eq)] +pub enum Chrl { + SixBits = 0b11, + SevenBits = 0b10, + #[default] + EightBits = 0b00, + EightBitsAlt = 0b01, +} + +#[bitbybit::bitenum(u1, exhaustive = true)] +#[derive(Default, Debug, PartialEq, Eq)] +pub enum ClkSel { + #[default] + UartRefClk = 0b0, + UartRefClkDiv8 = 0b1, +} + +#[bitbybit::bitenum(u2)] +#[derive(Default, Debug, PartialEq, Eq)] +pub enum Stopbits { + #[default] + One = 0b00, + OnePointFive = 0b01, + Two = 0b10, +} + +#[bitbybit::bitenum(u2, exhaustive = true)] +#[derive(Debug, Default)] +pub enum ChMode { + #[default] + Normal = 0b00, + AutoEcho = 0b01, + LocalLoopback = 0b10, + RemoteLoopback = 0b11, +} + +#[bitbybit::bitfield(u32)] +#[derive(Debug)] +pub struct Ctrl { + /// Stop transmitter break. + #[bit(8, rw)] + stopbrk: bool, + /// Start transmitter break. + #[bit(7, rw)] + startbrk: bool, + /// Restart receiver timeout counter. + #[bit(6, rw)] + rstto: bool, + /// TX disable. If this is 1, TX is disabled, regardless of TXEN. + #[bit(5, rw)] + tx_dis: bool, + /// TX enable. TX will be enabled if this bit is 1 and the TXDIS is 0. + #[bit(4, rw)] + tx_en: bool, + /// RX disable. If this is 1, RX is disabled, regardless of RXEN. + #[bit(3, rw)] + rx_dis: bool, + /// RX enable. RX will be enabled if this bit is 1 and the RXDIS is 0. + #[bit(2, rw)] + rx_en: bool, + /// TX soft reset. + #[bit(1, rw)] + tx_rst: bool, + /// RX soft reset. + #[bit(0, rw)] + rx_rst: bool, +} + +#[bitbybit::bitfield(u32, default = 0x0)] +#[derive(Debug)] +pub struct Mode { + #[bits(8..=9, rw)] + chmode: ChMode, + #[bits(6..=7, rw)] + nbstop: Option, + #[bits(3..=5, rw)] + par: Parity, + /// Char length. + #[bits(1..=2, rw)] + chrl: Chrl, + #[bit(0, rw)] + clksel: ClkSel, +} + +#[bitbybit::bitfield(u32, default = 0x0)] +#[derive(Debug)] +pub struct Baudgen { + #[bits(0..=15, rw)] + cd: u16, +} + +#[bitbybit::bitfield(u32, default = 0x0)] +#[derive(Debug)] +pub struct BaudRateDiv { + #[bits(0..=7, rw)] + bdiv: u8, +} + +#[bitbybit::bitfield(u32)] +#[derive(Debug)] +pub struct Fifo { + #[bits(0..=7, rw)] + fifo: u8, +} + +#[bitbybit::bitenum(u1, exhaustive = true)] +pub enum Ttrig { + LessThanTTrig = 0b0, + GreaterEqualTTrig = 0b1, +} + +#[bitbybit::bitfield(u32)] +#[derive(Debug)] +pub struct Status { + #[bit(14, r)] + tx_near_full: bool, + #[bit(13, r)] + tx_trig: Ttrig, + #[bit(12, r)] + flowdel: bool, + /// Transmitter state machine active. + #[bit(11, r)] + tx_active: bool, + /// Receiver state machine active. + #[bit(10, r)] + rx_active: bool, + #[bit(4, r)] + tx_full: bool, + #[bit(3, r)] + tx_empty: bool, + #[bit(2, r)] + rx_full: bool, + #[bit(1, r)] + rx_empty: bool, + /// RX FIFO trigger level was reached. + #[bit(0, r)] + rx_trg: bool, +} + +#[bitbybit::bitfield(u32, default = 0x0)] +#[derive(Debug)] +pub struct InterruptControl { + #[bit(12, w)] + tx_over: bool, + #[bit(11, w)] + tx_near_full: bool, + #[bit(10, w)] + tx_trig: bool, + #[bit(9, w)] + rx_dms: bool, + /// Receiver timeout error interrupt. + #[bit(8, w)] + rx_timeout: bool, + #[bit(7, w)] + rx_parity: bool, + #[bit(6, w)] + rx_framing: bool, + #[bit(5, w)] + rx_over: bool, + #[bit(4, w)] + tx_full: bool, + #[bit(3, w)] + tx_empty: bool, + #[bit(2, w)] + rx_full: bool, + #[bit(1, w)] + rx_empty: bool, + #[bit(0, w)] + rx_trg: bool, +} + +#[bitbybit::bitfield(u32)] +#[derive(Debug)] +pub struct FifoTrigger { + #[bits(0..=5, rw)] + trig: u6, +} + +#[bitbybit::bitfield(u32)] +#[derive(Debug)] +pub struct InterruptMask { + #[bit(12, r)] + tx_over: bool, + #[bit(11, r)] + tx_near_full: bool, + #[bit(10, r)] + tx_trig: bool, + #[bit(9, r)] + rx_dms: bool, + /// Receiver timeout error interrupt. + #[bit(8, r)] + rx_timeout: bool, + #[bit(7, r)] + rx_parity: bool, + #[bit(6, r)] + rx_framing: bool, + #[bit(5, r)] + rx_over: bool, + #[bit(4, r)] + tx_full: bool, + #[bit(3, r)] + tx_empty: bool, + #[bit(2, r)] + rx_full: bool, + #[bit(1, r)] + rx_empty: bool, + /// RX FIFO trigger level reached. + #[bit(0, r)] + rx_trg: bool, +} + +#[bitbybit::bitfield(u32, default = 0x0)] +#[derive(Debug)] +pub struct InterruptStatus { + #[bit(12, rw)] + tx_over: bool, + #[bit(11, rw)] + tx_near_full: bool, + #[bit(10, rw)] + tx_trig: bool, + #[bit(9, rw)] + rx_dms: bool, + /// Receiver timeout error interrupt. + #[bit(8, rw)] + rx_timeout: bool, + #[bit(7, rw)] + rx_parity: bool, + #[bit(6, rw)] + rx_framing: bool, + #[bit(5, rw)] + rx_over: bool, + #[bit(4, rw)] + tx_full: bool, + #[bit(3, rw)] + tx_empty: bool, + #[bit(2, rw)] + rx_full: bool, + #[bit(1, rw)] + rx_empty: bool, + /// RX FIFO trigger level reached. + #[bit(0, rw)] + rx_trg: bool, +} + +impl InterruptStatus { + pub fn new_for_clearing_rx_errors() -> Self { + Self::builder() + .with_tx_over(false) + .with_tx_near_full(false) + .with_tx_trig(false) + .with_rx_dms(false) + .with_rx_timeout(false) + .with_rx_parity(true) + .with_rx_framing(true) + .with_rx_over(true) + .with_tx_full(false) + .with_tx_empty(false) + .with_rx_full(false) + .with_rx_empty(false) + .with_rx_trg(false) + .build() + } +} + +#[derive(derive_mmio::Mmio)] +#[repr(C)] +pub struct Uart { + /// Control Register + cr: Ctrl, + /// Mode register + mr: Mode, + /// Interrupt enable register + #[mmio(Write)] + ier: InterruptControl, + /// Interrupt disable register + #[mmio(Write)] + idr: InterruptControl, + /// Interrupt mask register, showing enabled interrupts. + #[mmio(PureRead)] + imr: InterruptMask, + /// Interrupt status register + #[mmio(PureRead, Write)] + isr: InterruptStatus, + /// Baudgen register + baudgen: Baudgen, + /// RX timeout register + rx_tout: u32, + /// RX FIFO trigger level register + rx_fifo_trigger: FifoTrigger, + /// Modem control register + modem_cr: u32, + /// Modem status register + modem_sr: u32, + /// Channel status register + #[mmio(PureRead)] + sr: Status, + /// FIFO register + #[mmio(Read, Write)] + fifo: Fifo, + /// Baud rate divider register + baud_rate_div: BaudRateDiv, + /// Flow control delay register + flow_delay: u32, + + _reserved: [u32; 2], + + /// TX fifo trigger level + tx_fifo_trigger: FifoTrigger, +} + +static_assertions::const_assert_eq!(core::mem::size_of::(), 0x48); + +impl Uart { + /// Create a new UART MMIO instance for uart0 at address 0xE000_0000. + /// + /// # Safety + /// + /// This API can be used to potentially create a driver to the same peripheral structure + /// from multiple threads. The user must ensure that concurrent accesses are safe and do not + /// interfere with each other. + pub const unsafe fn new_mmio_fixed_0() -> MmioUart<'static> { + unsafe { Self::new_mmio_at(UART_0_BASE) } + } + + /// Create a new UART MMIO instance for uart1 at address 0xE000_1000. + /// + /// # Safety + /// + /// This API can be used to potentially create a driver to the same peripheral structure + /// from multiple threads. The user must ensure that concurrent accesses are safe and do not + /// interfere with each other. + pub const unsafe fn new_mmio_fixed_1() -> MmioUart<'static> { + unsafe { Self::new_mmio_at(UART_1_BASE) } + } +}