Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a58d398d82 | |||
| fd178e1d3b | |||
| e8a6c88e2b | |||
| 8606bcbd63 | |||
| 2b6e27875f | |||
| fa6f7d836e | |||
| b7093706f5 | |||
| 56131100e7 | |||
| 9357464db0 | |||
| 79161ffe58 | |||
| 7c3051db46 | |||
| 89ee6d7451 | |||
| 3b23e9be05 | |||
| d34143ceef | |||
| 1abbe7b9c9 | |||
| 802ba665c7 | |||
| 3ba6c63554 | |||
| e3a05cc650 | |||
| 0583c9231d | |||
| 4ec2f2bae3 | |||
| 0d6713f248 |
@@ -10,3 +10,4 @@
|
||||
# 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"
|
||||
# HW_SERVER_IP = "localhost"
|
||||
|
||||
@@ -9,7 +9,7 @@ repository = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
aarch32-cpu = { version = "0.1" }
|
||||
aarch32-cpu = { version = "0.2" }
|
||||
zynq7000-rt = { path = "../../zynq7000-rt" }
|
||||
zynq7000 = { path = "../../zynq7000" }
|
||||
zynq7000-hal = { path = "../../zynq7000-hal", features = ["defmt"] }
|
||||
|
||||
@@ -4,12 +4,17 @@ MEMORY
|
||||
Leave 1 MB of memory which will be configured as uncached device memory by the MMU. This is
|
||||
recommended for something like DMA descriptors. */
|
||||
/*CODE(rx) : ORIGIN = 0x00100000, LENGTH = 63M*/
|
||||
/* CODE(rx) : ORIGIN = 0x00100000, LENGTH = 62M */
|
||||
CODE(rx) : ORIGIN = 0x00000000, LENGTH = 192K
|
||||
/* STACK: ORIGIN = 0x3F00000, LENGTH = 1M */
|
||||
UNCACHED(rx): ORIGIN = 0x4000000, LENGTH = 1M
|
||||
OCM_UPPER(rx): ORIGIN = 0xFFFF0000, LENGTH = 64K
|
||||
}
|
||||
|
||||
REGION_ALIAS("VECTORS", CODE);
|
||||
REGION_ALIAS("DATA", CODE);
|
||||
/* Use the upper OCM as the stack */
|
||||
REGION_ALIAS("STACKS", OCM_UPPER);
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@ keywords = ["no-std", "arm", "cortex-a", "amd", "zynq7000"]
|
||||
categories = ["embedded", "no-std", "hardware-support"]
|
||||
|
||||
[dependencies]
|
||||
aarch32-cpu = { version = "0.1", features = ["critical-section-single-core"] }
|
||||
aarch32-cpu = { version = "0.2", features = ["critical-section-single-core"] }
|
||||
zynq7000-rt = { path = "../../zynq7000-rt" }
|
||||
zynq7000 = { path = "../../zynq7000" }
|
||||
zynq7000-hal = { path = "../../zynq7000-hal" }
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
MEMORY
|
||||
{
|
||||
/* Zedboard: 512 MB DDR3. Only use 63 MB for now, should be plenty for a bare-metal app.
|
||||
Leave 1 MB of memory which will be configured as uncached device memory by the MMU. This is
|
||||
recommended for something like DMA descriptors. */
|
||||
CODE(rx) : ORIGIN = 0x00100000, LENGTH = 63M
|
||||
/* Zedboard: 512 MB DDR3. Only use 62 MB for now, should be plenty for a bare-metal app.
|
||||
1 MB stack memory and 1 MB of memory which will be configured as uncached device memory by the
|
||||
MMU. This is recommended for something like DMA descriptors. */
|
||||
CODE(rx) : ORIGIN = 0x00100000, LENGTH = 62M
|
||||
STACKS : ORIGIN = 0x3F00000, LENGTH = 1M
|
||||
UNCACHED(rx): ORIGIN = 0x4000000, LENGTH = 1M
|
||||
OCM_UPPER(rx): ORIGIN = 0xFFFF0000, LENGTH = 64K
|
||||
}
|
||||
|
||||
REGION_ALIAS("VECTORS", CODE);
|
||||
|
||||
@@ -9,7 +9,7 @@ repository = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
aarch32-cpu = { version = "0.1" }
|
||||
aarch32-cpu = { version = "0.2" }
|
||||
zynq7000-rt = { path = "../../zynq7000-rt" }
|
||||
zynq7000 = { path = "../../zynq7000" }
|
||||
zynq7000-hal = { path = "../../zynq7000-hal" }
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
MEMORY
|
||||
{
|
||||
/* Zedboard: 512 MB DDR3. Only use 63 MB for now, should be plenty for a bare-metal app.
|
||||
Leave 1 MB of memory which will be configured as uncached device memory by the MMU. This is
|
||||
recommended for something like DMA descriptors. */
|
||||
CODE(rx) : ORIGIN = 0x00100000, LENGTH = 63M
|
||||
/* Zedboard: 512 MB DDR3. Only use 62 MB for now, should be plenty for a bare-metal app.
|
||||
1 MB stack memory and 1 MB of memory which will be configured as uncached device memory by the
|
||||
MMU. This is recommended for something like DMA descriptors. */
|
||||
CODE(rx) : ORIGIN = 0x00100000, LENGTH = 62M
|
||||
STACKS : ORIGIN = 0x3F00000, LENGTH = 1M
|
||||
UNCACHED(rx): ORIGIN = 0x4000000, LENGTH = 1M
|
||||
OCM_UPPER(rx): ORIGIN = 0xFFFF0000, LENGTH = 64K
|
||||
}
|
||||
|
||||
REGION_ALIAS("VECTORS", CODE);
|
||||
|
||||
@@ -11,7 +11,7 @@ keywords = ["no-std", "arm", "cortex-a", "amd", "zynq7000"]
|
||||
categories = ["embedded", "no-std", "hardware-support"]
|
||||
|
||||
[dependencies]
|
||||
aarch32-cpu = { version = "0.1" }
|
||||
aarch32-cpu = { version = "0.2" }
|
||||
zynq7000-rt = { path = "../../zynq7000-rt" }
|
||||
zynq7000 = { path = "../../zynq7000" }
|
||||
zynq7000-hal = { path = "../../zynq7000-hal" }
|
||||
@@ -22,23 +22,23 @@ l3gd20 = { git = "https://github.com/us-irs/l3gd20.git", branch = "add-async-if"
|
||||
embedded-io = "0.7"
|
||||
bitbybit = "1.4"
|
||||
arbitrary-int = "2"
|
||||
embedded-io-async = "0.6"
|
||||
embedded-io-async = "0.7"
|
||||
critical-section = "1"
|
||||
static_cell = "2"
|
||||
embedded-alloc = "0.6"
|
||||
embedded-alloc = "0.7"
|
||||
embedded-hal = "1"
|
||||
embedded-hal-async = "1"
|
||||
fugit = "0.3"
|
||||
log = "0.4"
|
||||
rand = { version = "0.9", default-features = false, features = ["small_rng"] }
|
||||
|
||||
embassy-executor = { git = "https://github.com/us-irs/embassy.git", branch = "cortex-ar-update", features = [
|
||||
embassy-executor = { git = "https://github.com/us-irs/embassy.git", rev = "fd40f3e2f2efb67434a9e7d90eb35a30e30d1736", features = [
|
||||
"arch-cortex-ar",
|
||||
"executor-thread",
|
||||
]}
|
||||
# TODO: Remove generic-queue-16 feature as soon as upstream executor is used again.
|
||||
embassy-time = { version = "0.5", features = ["tick-hz-1_000_000", "generic-queue-16"] }
|
||||
embassy-net = { version = "0.7", features = ["dhcpv4", "packet-trace", "medium-ethernet", "icmp", "tcp", "udp"] }
|
||||
embassy-net = { version = "0.8", features = ["dhcpv4", "packet-trace", "medium-ethernet", "icmp", "tcp", "udp"] }
|
||||
embassy-sync = { version = "0.7" }
|
||||
# TODO: Bump as soon as new compatible smoltcp/embassy-net version is released.
|
||||
heapless = "0.8"
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
MEMORY
|
||||
{
|
||||
/* Zedboard: 512 MB DDR3. Only use 63 MB for now, should be plenty for a bare-metal app.
|
||||
Leave 1 MB of memory which will be configured as uncached device memory by the MMU. This is
|
||||
recommended for something like DMA descriptors. */
|
||||
CODE(rx) : ORIGIN = 0x00100000, LENGTH = 63M
|
||||
/* Zedboard: 512 MB DDR3. Only use 62 MB for now, should be plenty for a bare-metal app.
|
||||
1 MB stack memory and 1 MB of memory which will be configured as uncached device memory by the
|
||||
MMU. This is recommended for something like DMA descriptors. */
|
||||
CODE(rx) : ORIGIN = 0x00100000, LENGTH = 62M
|
||||
STACKS : ORIGIN = 0x3F00000, LENGTH = 1M
|
||||
UNCACHED(rx): ORIGIN = 0x4000000, LENGTH = 1M
|
||||
OCM_UPPER(rx): ORIGIN = 0xFFFF0000, LENGTH = 64K
|
||||
}
|
||||
|
||||
REGION_ALIAS("VECTORS", CODE);
|
||||
|
||||
@@ -373,9 +373,9 @@ async fn main(spawner: Spawner) -> ! {
|
||||
let tcp_socket = TcpSocket::new(stack, RX_TCP_BUFS.take(), TX_TCP_BUFS.take());
|
||||
|
||||
// Spawn all embassy tasks.
|
||||
spawner.spawn(embassy_net_task(runner)).unwrap();
|
||||
spawner.spawn(udp_task(udp_socket)).unwrap();
|
||||
spawner.spawn(tcp_task(tcp_socket)).unwrap();
|
||||
spawner.spawn(embassy_net_task(runner).unwrap());
|
||||
spawner.spawn(udp_task(udp_socket).unwrap());
|
||||
spawner.spawn(tcp_task(tcp_socket).unwrap());
|
||||
|
||||
let mut mio_led = Output::new_for_mio(gpio_pins.mio.mio7, PinState::Low);
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ async fn main(spawner: Spawner) -> ! {
|
||||
}
|
||||
}
|
||||
|
||||
spawner.spawn(logger_task(uart)).unwrap();
|
||||
spawner.spawn(logger_task(uart).unwrap());
|
||||
if BLOCKING {
|
||||
blocking_application(mio_led, emio_leds, spi).await;
|
||||
} else {
|
||||
|
||||
@@ -284,20 +284,20 @@ async fn main(spawner: Spawner) -> ! {
|
||||
.replace(uart16550_prod);
|
||||
RX_UART_0.borrow(cs).borrow_mut().replace(uart_0_rx);
|
||||
});
|
||||
spawner.spawn(led_task(mio_led, emio_leds)).unwrap();
|
||||
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();
|
||||
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();
|
||||
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();
|
||||
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];
|
||||
|
||||
@@ -12,7 +12,7 @@ categories = ["embedded", "no-std", "hardware-support"]
|
||||
[dependencies]
|
||||
zynq7000 = { path = "../zynq7000", version = "0.1" }
|
||||
zynq7000-hal = { path = "../zynq7000-hal", version = "0.1" }
|
||||
bitbybit = "1.4"
|
||||
bitbybit = "2"
|
||||
arbitrary-int = "2"
|
||||
num_enum = { version = "0.7", default-features = false }
|
||||
thiserror = { version = "2", default-features = false }
|
||||
|
||||
@@ -9,7 +9,7 @@ repository = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
aarch32-cpu = { version = "0.1", features = ["critical-section-single-core"] }
|
||||
aarch32-cpu = { version = "0.2", features = ["critical-section-single-core"] }
|
||||
zynq7000-rt = { path = "../zynq7000-rt" }
|
||||
zynq7000 = { path = "../zynq7000" }
|
||||
zynq7000-hal = { path = "../zynq7000-hal" }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
MEMORY
|
||||
{
|
||||
/* The Zynq7000 has 192 kB of OCM memory which can be used for the FSBL */
|
||||
CODE(rx) : ORIGIN = 0x00000000, LENGTH = 192K
|
||||
/* The Zynq7000 has 256 kB of OCM memory of which 196 kB can be used for the FSBL */
|
||||
CODE(rx) : ORIGIN = 0x00000000, LENGTH = 196K
|
||||
OCM_UPPER(rx): ORIGIN = 0xFFFF0000, LENGTH = 64K
|
||||
/* Leave 1 MB of memory which will be configured as uncached device memory by the MMU. This can
|
||||
be used for something like DMA descriptors, but the DDR needs to be set up first in addition
|
||||
@@ -11,6 +11,8 @@ MEMORY
|
||||
|
||||
REGION_ALIAS("VECTORS", CODE);
|
||||
REGION_ALIAS("DATA", CODE);
|
||||
/* Use the upper OCM as the stack */
|
||||
REGION_ALIAS("STACKS", OCM_UPPER);
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
aarch32-cpu = { version = "0.1", features = ["critical-section-single-core"] }
|
||||
aarch32-cpu = { version = "0.2", features = ["critical-section-single-core"] }
|
||||
zynq7000-rt = { path = "../zynq7000-rt" }
|
||||
zynq7000 = { path = "../zynq7000" }
|
||||
zynq7000-hal = { path = "../zynq7000-hal" }
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
MEMORY
|
||||
{
|
||||
/* Zedboard: 512 MB DDR3. Only use 63 MB for now, should be plenty for a bare-metal app.
|
||||
Leave 1 MB of memory which will be configured as uncached device memory by the MMU. This is
|
||||
recommended for something like DMA descriptors. */
|
||||
CODE(rx) : ORIGIN = 0x00100000, LENGTH = 63M
|
||||
/* Zedboard: 512 MB DDR3. Only use 62 MB for now, should be plenty for a bare-metal app.
|
||||
1 MB stack memory and 1 MB of memory which will be configured as uncached device memory by the
|
||||
MMU. This is recommended for something like DMA descriptors. */
|
||||
CODE(rx) : ORIGIN = 0x00100000, LENGTH = 62M
|
||||
OCM_UPPER(rx): ORIGIN = 0xFFFF0000, LENGTH = 64K
|
||||
STACKS : ORIGIN = 0x3F00000, LENGTH = 1M
|
||||
UNCACHED(rx): ORIGIN = 0x4000000, LENGTH = 1M
|
||||
}
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
# [unreleased]
|
||||
|
||||
# [v0.1.0] 2025-10-09
|
||||
# [v0.1.0] 2026-02-14
|
||||
|
||||
Initial release
|
||||
|
||||
[unreleased]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/v0.1.0...HEAD
|
||||
[unreleased]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-embassy-v0.1.0...HEAD
|
||||
[v0.1.0]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/tag/zynq7000-embassy-v0.1.0
|
||||
|
||||
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## Changed
|
||||
|
||||
- Added division by zero check in gtc frequency_to_ticks to avoid runtime panic
|
||||
- Increased UART type safety by providing dedicated MIO constructors for UART 0 and UART 1
|
||||
respectively.
|
||||
- Several bugfixes and improvements for GIC module. Some of the registers previously were
|
||||
|
||||
@@ -11,12 +11,12 @@ keywords = ["no-std", "hal", "amd", "zynq7000", "bare-metal"]
|
||||
categories = ["embedded", "no-std", "hardware-support"]
|
||||
|
||||
[dependencies]
|
||||
aarch32-cpu = { version = "0.1" }
|
||||
aarch32-cpu = { version = "0.2" }
|
||||
zynq7000 = { path = "../zynq7000", version = "0.1" }
|
||||
zynq7000-mmu = { path = "../zynq7000-mmu", version = "0.1" }
|
||||
|
||||
static_assertions = "1.1"
|
||||
bitbybit = "1.4"
|
||||
bitbybit = "2"
|
||||
arbitrary-int = "2"
|
||||
thiserror = { version = "2", default-features = false }
|
||||
num_enum = { version = "0.7", default-features = false }
|
||||
|
||||
@@ -209,7 +209,7 @@ pub fn configure_io_pll(boot_mode: BootMode, pll_config: PllConfig) {
|
||||
return;
|
||||
}
|
||||
// Safety: This will only run at most once because of the atomic boolean check.
|
||||
unsafe { configure_arm_pll_unchecked(boot_mode, pll_config) };
|
||||
unsafe { configure_io_pll_unchecked(boot_mode, pll_config) };
|
||||
}
|
||||
|
||||
/// This function configures the DDR PLL based on the provided [PllConfig].
|
||||
@@ -218,7 +218,7 @@ pub fn configure_ddr_pll(boot_mode: BootMode, pll_config: PllConfig) {
|
||||
return;
|
||||
}
|
||||
// Safety: This will only run at most once because of the atomic boolean check.
|
||||
unsafe { configure_arm_pll_unchecked(boot_mode, pll_config) };
|
||||
unsafe { configure_ddr_pll_unchecked(boot_mode, pll_config) };
|
||||
}
|
||||
|
||||
/// This function configures the ARM PLL based on the provided [PllConfig].
|
||||
|
||||
@@ -129,7 +129,7 @@ pub mod memtest {
|
||||
/// This tests writes and reads on a memory block starting at the base address
|
||||
/// with the size `words` times 4.
|
||||
pub unsafe fn walking_one_test(base_addr: usize, words: usize) -> Result<(), MemTestError> {
|
||||
unsafe { walking_value_test(true, base_addr, words) }
|
||||
unsafe { walking_value_test(false, base_addr, words) }
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
|
||||
@@ -53,10 +53,14 @@ pub fn configure_bitstream_non_secure(
|
||||
val.set_pcap_rate_enable(false);
|
||||
val
|
||||
});
|
||||
devcfg.write_dma_source_addr(bitstream.as_ptr() as u32);
|
||||
|
||||
// As specified in the TMR,
|
||||
// Setting the two LSBs of the source and destination address to 2'b01 indicates to the DevC
|
||||
// DMA module the last DMA command of an overall transfer
|
||||
devcfg.write_dma_source_addr(bitstream.as_ptr() as u32 | 0b01);
|
||||
devcfg.write_dma_dest_addr(0xFFFF_FFFF);
|
||||
devcfg.write_dma_source_len(bitstream.len() as u32);
|
||||
devcfg.write_dma_dest_len(bitstream.len() as u32);
|
||||
devcfg.write_dma_source_len(bitstream.len() as u32 / 4);
|
||||
devcfg.write_dma_dest_len(bitstream.len() as u32 / 4);
|
||||
|
||||
while !devcfg.read_interrupt_status().dma_done() {}
|
||||
// TODO: Check for errors.
|
||||
|
||||
@@ -18,7 +18,11 @@ unsafe impl Send for GlobalTimerCounter {}
|
||||
|
||||
/// Convert a frequency to GTC ticks given a clock frequency.
|
||||
pub const fn frequency_to_ticks(clock: Hertz, frequency: Hertz) -> u32 {
|
||||
clock.raw().div_ceil(frequency.raw())
|
||||
if frequency.raw() != 0 {
|
||||
clock.raw().div_ceil(frequency.raw())
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
impl GlobalTimerCounter {
|
||||
|
||||
@@ -18,7 +18,6 @@ use crate::{clocks::IoClocks, slcr::Slcr, time::Hertz};
|
||||
use arbitrary_int::{prelude::*, u3, u4, u6};
|
||||
use embedded_hal::delay::DelayNs;
|
||||
pub use embedded_hal::spi::Mode;
|
||||
use embedded_hal::spi::SpiBus as _;
|
||||
use zynq7000::slcr::reset::DualRefAndClockReset;
|
||||
use zynq7000::spi::{
|
||||
BaudDivSel, DelayControl, FifoWrite, InterruptControl, InterruptMask, InterruptStatus,
|
||||
@@ -874,7 +873,7 @@ impl Spi {
|
||||
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();
|
||||
self.flush();
|
||||
// Write this to 1 in any case to allow polling, defensive programming.
|
||||
self.inner.regs.write_rx_trig(1);
|
||||
|
||||
@@ -886,20 +885,14 @@ impl Spi {
|
||||
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> {
|
||||
fn read(&mut self, words: &mut [u8]) {
|
||||
if words.is_empty() {
|
||||
return Ok(());
|
||||
return;
|
||||
}
|
||||
// We want to ensure the FIFO is empty for a new transfer. This is the simpler
|
||||
// implementation for now.
|
||||
self.flush()?;
|
||||
self.flush();
|
||||
// Write this to 1 in any case to allow polling, defensive programming.
|
||||
self.regs().write_rx_trig(1);
|
||||
|
||||
@@ -926,13 +919,11 @@ impl embedded_hal::spi::SpiBus for Spi {
|
||||
write_idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
|
||||
fn write(&mut self, words: &[u8]) {
|
||||
if words.is_empty() {
|
||||
return Ok(());
|
||||
return;
|
||||
}
|
||||
let mut written = self.prepare_generic_blocking_transfer(words);
|
||||
let mut read_idx = 0;
|
||||
@@ -954,12 +945,11 @@ impl embedded_hal::spi::SpiBus for Spi {
|
||||
// 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> {
|
||||
fn transfer(&mut self, read: &mut [u8], write: &[u8]) {
|
||||
if read.is_empty() {
|
||||
return Ok(());
|
||||
return;
|
||||
}
|
||||
let mut write_idx = self.prepare_generic_blocking_transfer(write);
|
||||
let mut read_idx = 0;
|
||||
@@ -991,13 +981,11 @@ impl embedded_hal::spi::SpiBus for Spi {
|
||||
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> {
|
||||
fn transfer_in_place(&mut self, words: &mut [u8]) {
|
||||
if words.is_empty() {
|
||||
return Ok(());
|
||||
return;
|
||||
}
|
||||
let mut write_idx = self.prepare_generic_blocking_transfer(words);
|
||||
let mut read_idx = 0;
|
||||
@@ -1018,14 +1006,12 @@ impl embedded_hal::spi::SpiBus for Spi {
|
||||
writes_finished = write_idx == words.len();
|
||||
reads_finished = read_idx == words.len();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Blocking flush implementation.
|
||||
fn flush(&mut self) -> Result<(), Self::Error> {
|
||||
fn flush(&mut self) {
|
||||
if !self.outstanding_rx {
|
||||
return Ok(());
|
||||
return;
|
||||
}
|
||||
let rx_trig = self.inner.read_rx_not_empty_threshold();
|
||||
while !self.inner.read_isr().rx_not_empty() {}
|
||||
@@ -1034,6 +1020,37 @@ impl embedded_hal::spi::SpiBus for Spi {
|
||||
});
|
||||
self.inner.set_rx_fifo_trigger(1).unwrap();
|
||||
self.outstanding_rx = false;
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
Self::read(self, words);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
|
||||
Self::write(self, words);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
|
||||
Self::transfer(self, read, write);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
|
||||
Self::transfer_in_place(self, words);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Blocking flush implementation.
|
||||
fn flush(&mut self) -> Result<(), Self::Error> {
|
||||
Self::flush(self);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1067,23 +1084,23 @@ impl<Delay: DelayNs> embedded_hal::spi::SpiDevice for SpiWithHwCs<Delay> {
|
||||
for op in operations {
|
||||
match op {
|
||||
embedded_hal::spi::Operation::Read(items) => {
|
||||
self.spi.read(items)?;
|
||||
self.spi.read(items);
|
||||
}
|
||||
embedded_hal::spi::Operation::Write(items) => {
|
||||
self.spi.write(items)?;
|
||||
self.spi.write(items);
|
||||
}
|
||||
embedded_hal::spi::Operation::Transfer(read, write) => {
|
||||
self.spi.transfer(read, write)?;
|
||||
self.spi.transfer(read, write);
|
||||
}
|
||||
embedded_hal::spi::Operation::TransferInPlace(items) => {
|
||||
self.spi.transfer_in_place(items)?;
|
||||
self.spi.transfer_in_place(items);
|
||||
}
|
||||
embedded_hal::spi::Operation::DelayNs(delay) => {
|
||||
self.delay.delay_ns(*delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.spi.flush()?;
|
||||
self.spi.flush();
|
||||
self.spi.inner.no_hw_cs();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
# [unreleased]
|
||||
|
||||
# [v0.1.2] 2026-02-14
|
||||
|
||||
Bumped `aarch32-cpu` to v0.2
|
||||
|
||||
# [v0.1.1] 2025-10-10
|
||||
|
||||
Documentation fixes.
|
||||
@@ -16,6 +20,7 @@ Documentation fixes.
|
||||
|
||||
Initial release
|
||||
|
||||
[unreleased]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-mmu-v0.1.0...HEAD
|
||||
[unreleased]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-mmu-v0.1.2...HEAD
|
||||
[v0.1.2]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-mmu-v0.1.1...zynq7000-mmu-v0.1.2
|
||||
[v0.1.1]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-mmu-v0.1.0...zynq7000-mmu-v0.1.1
|
||||
[v0.1.0]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/tag/zynq7000-mmu-v0.1.0
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "zynq7000-mmu"
|
||||
description = "Zynq7000 MMU structures"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
edition = "2024"
|
||||
license = "MIT OR Apache-2.0"
|
||||
homepage = "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs"
|
||||
@@ -11,7 +11,7 @@ categories = ["embedded", "no-std", "hardware-support"]
|
||||
|
||||
[dependencies]
|
||||
thiserror = { version = "2", default-features = false }
|
||||
aarch32-cpu = { version = "0.1" }
|
||||
aarch32-cpu = { version = "0.2" }
|
||||
|
||||
[build-dependencies]
|
||||
arm-targets = { version = "0.4" }
|
||||
|
||||
@@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
# [unreleased]
|
||||
|
||||
# [v0.2.0] 2026-02-14
|
||||
|
||||
Bugfixes in startup assembler code.
|
||||
|
||||
## Changed
|
||||
@@ -17,6 +19,7 @@ Bugfixes in startup assembler code.
|
||||
- Runtime now calls a `kmain` method similar to the re-export `aarch32-rt` crate.
|
||||
Former `boot_core` method must be renamed to `kmain`, but it is recommended to use
|
||||
the `zynq7000-rt::entry` proc macro to annotate the main method.
|
||||
- Bumped `aarch32-rt` to v0.2 which now requires the `memory.x` file to place the `STACKS` segment
|
||||
|
||||
## Fixed
|
||||
|
||||
@@ -32,6 +35,7 @@ Documentation fixes.
|
||||
|
||||
Initial release
|
||||
|
||||
[unreleased]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-rt-v0.1.0...HEAD
|
||||
[unreleased]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-rt-v0.2.0...HEAD
|
||||
[v0.2.0]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-rt-v0.1.1...zynq7000-rt-v0.2.0
|
||||
[v0.1.1]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-rt-v0.1.0...zynq7000-rt-v0.1.1
|
||||
[v0.1.0]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/tag/zynq7000-rt-v0.1.0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "zynq7000-rt"
|
||||
version = "0.1.1"
|
||||
version = "0.2.0"
|
||||
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
|
||||
edition = "2024"
|
||||
description = "Run-time support for the Zynq7000 family of SoCs for running bare-metal applications"
|
||||
@@ -11,8 +11,8 @@ keywords = ["no-std", "rt", "cortex-a", "amd", "zynq7000"]
|
||||
categories = ["embedded", "no-std", "hardware-support"]
|
||||
|
||||
[dependencies]
|
||||
aarch32-rt = { version = "0.1", optional = true, features = ["fpu-d32"] }
|
||||
aarch32-cpu = { version = "0.1" }
|
||||
aarch32-rt = { version = "0.2", optional = true, features = ["fpu-d32"] }
|
||||
aarch32-cpu = { version = "0.2" }
|
||||
arbitrary-int = "2"
|
||||
zynq7000-mmu = { path = "../zynq7000-mmu", version = "0.1" }
|
||||
|
||||
|
||||
+112
-194
@@ -5,7 +5,6 @@
|
||||
//! but does NOT provide the L2 cache initialization.
|
||||
//!
|
||||
//! The boot routine includes stack, MMU and .bss/.data section initialization.
|
||||
use aarch32_cpu::register::{Cpsr, cpsr::ProcessorMode};
|
||||
use aarch32_rt as _;
|
||||
|
||||
// Start-up code for Armv7-A
|
||||
@@ -13,23 +12,23 @@ use aarch32_rt as _;
|
||||
// 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 PSS_L2CC_BASE_ADDR, 0xF8F02000
|
||||
.set PSS_SLCR_BASE_ADDR, 0xF8000000
|
||||
|
||||
.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 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 CRValMmuCac, 0b01000000000101 /* Enable IDC, and MMU */
|
||||
.set CRValHiVectorAddr, 0b10000000000000 /* Set the Vector address to high, 0xFFFF0000 */
|
||||
|
||||
.set SLCRlockKey, 0x767B /* SLCR lock key */
|
||||
.set SLCRUnlockKey, 0xDF0D /* SLCR unlock key */
|
||||
.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) */
|
||||
.set FPEXC_EN, 0x40000000 /* FPU enable bit, (1 << 30) */
|
||||
|
||||
.section .text.startup
|
||||
.align 0
|
||||
@@ -39,137 +38,98 @@ core::arch::global_asm!(
|
||||
_start:
|
||||
// only allow cpu0 through
|
||||
// Read MPIDR
|
||||
mrc p15,0,r1,c0,c0,5
|
||||
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
|
||||
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
|
||||
ldr r0, =EFUSEStatus
|
||||
// Read eFuse setting
|
||||
ldr r1, [r0]
|
||||
// Check whether device is having single core
|
||||
ands r1,r1,#0x80
|
||||
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,=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 */
|
||||
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 */
|
||||
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
|
||||
ldr r0, =_vector_table
|
||||
mcr p15, 0, r0, c12, c0, 0
|
||||
|
||||
/* Invalidate scu */
|
||||
ldr r7, =0xf8f0000c
|
||||
ldr r6, =0xffff
|
||||
str r6, [r7]
|
||||
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 */
|
||||
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 */
|
||||
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
|
||||
|
||||
// Set stack pointer (right after) and mask interrupts for IRQ mode (Mode 0x12)
|
||||
msr cpsr_c, {irq_mode}
|
||||
// IRQ stack pointer
|
||||
mov sp, r3
|
||||
ldr r1, =_irq_stack_size
|
||||
sub r3, r3, r1
|
||||
|
||||
// Set stack pointer (right after) and mask interrupts for Supervisor/SVC mode (Mode 0x13)
|
||||
msr cpsr_c, {svc_mode}
|
||||
// Supervisor stack pointer
|
||||
mov sp, r3
|
||||
ldr r1, =_svc_stack_size
|
||||
sub r3, r3, r1
|
||||
|
||||
// Set stack pointer (right after) and mask interrupts for Abort/ABT mode (Mode 0x17)
|
||||
msr cpsr_c, {abt_mode}
|
||||
// Abort stack pointer
|
||||
mov sp, r3
|
||||
ldr r1, =_abt_stack_size
|
||||
sub r3, r3, r1
|
||||
|
||||
// Set stack pointer (right after) and mask interrupts for FIQ mode (Mode 0x11)
|
||||
msr cpsr_c, {fiq_mode}
|
||||
// FIQ stack pointer
|
||||
mov sp, r3
|
||||
ldr r1, =_fiq_stack_size
|
||||
sub r3, r3, r1
|
||||
|
||||
// Set stack pointer (right after) and mask interrupts for Undefined/UND mode (Mode 0x1B)
|
||||
msr cpsr_c, {und_mode}
|
||||
// Undefined stack pointer
|
||||
mov sp, r3
|
||||
ldr r1, =_und_stack_size
|
||||
sub r3, r3, r1
|
||||
|
||||
// Set stack pointer (right after) and mask interrupts for System/SYS mode (Mode 0x1F)
|
||||
msr cpsr_c, {sys_mode}
|
||||
// System stack pointer (main stack)
|
||||
mov sp, r3
|
||||
bl _stack_setup_preallocated
|
||||
|
||||
// set scu enable bit in scu
|
||||
ldr r7, =0xf8f00000
|
||||
ldr r0, [r7]
|
||||
orr r0, r0, #0x1
|
||||
str r0, [r7]
|
||||
ldr r7, =0xf8f00000
|
||||
ldr r0, [r7]
|
||||
orr r0, r0, #0x1
|
||||
str r0, [r7]
|
||||
|
||||
/* 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*/
|
||||
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*/
|
||||
|
||||
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 */
|
||||
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 */
|
||||
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,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 */
|
||||
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
|
||||
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. */
|
||||
|
||||
@@ -199,20 +159,20 @@ data_init_done:
|
||||
/* enable MMU and cache */
|
||||
/* MMU Table is in .data, so this needs to be performed after .data is relocated */
|
||||
/* (Even if in most cases, .data is already in RAM and relocation is a no-op) */
|
||||
bl load_mmu_table
|
||||
bl load_mmu_table
|
||||
|
||||
mvn r0,#0 /* Load MMU domains -- all ones=manager */
|
||||
mcr p15,0,r0,c3,c0,0
|
||||
mvn r0,#0 /* Load MMU domains -- all ones=manager */
|
||||
mcr p15,0,r0,c3,c0,0
|
||||
|
||||
/* Enable mmu, icache 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 */
|
||||
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 */
|
||||
|
||||
// Jump to application
|
||||
// Load CPU ID 0, which will be used as a function argument to the boot_core function.
|
||||
mov r0, #0x0
|
||||
mov r0, #0x0
|
||||
bl kmain
|
||||
// In case the application returns, loop forever
|
||||
b .
|
||||
@@ -220,90 +180,48 @@ data_init_done:
|
||||
|
||||
.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 */
|
||||
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) */
|
||||
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) */
|
||||
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
|
||||
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
|
||||
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 */
|
||||
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
|
||||
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()
|
||||
},
|
||||
);
|
||||
|
||||
Generated
+4
-4
@@ -4,9 +4,9 @@ version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aarch32-cpu"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5db6700cf01549520abec199376115e1ceb6fde1d1de30064f0f230be8a0c305"
|
||||
checksum = "1417bbf608824a44cb2fa2ad74b5ec28c0ae4c83df62a4bd2b532bf04c241ade"
|
||||
dependencies = [
|
||||
"arbitrary-int 2.0.0",
|
||||
"arm-targets",
|
||||
@@ -702,7 +702,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zynq7000-mmu"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"aarch32-cpu",
|
||||
"arm-targets",
|
||||
@@ -725,7 +725,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zynq7000-rt"
|
||||
version = "0.1.1"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"aarch32-cpu",
|
||||
"arbitrary-int 2.0.0",
|
||||
|
||||
@@ -56,4 +56,4 @@ run binary:
|
||||
python3 {{justfile_directory()}}/scripts/zynq7000-init.py
|
||||
|
||||
# Run the GDB debugger in GUI mode.
|
||||
gdb-multiarch -q -x {{justfile_directory()}}/zynq/gdb.gdb {{binary}} -tui
|
||||
gdb-multiarch -q -x {{justfile_directory()}}/firmware/gdb.gdb {{binary}} -tui
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
MEMORY
|
||||
{
|
||||
/* Zedboard: 512 MB DDR3. Only use 63 MB for now, should be plenty for a bare-metal app.
|
||||
Leave 1 MB of memory which will be configured as uncached device memory by the MMU. This is
|
||||
recommended for something like DMA descriptors. */
|
||||
CODE(rx) : ORIGIN = 0x00100000, LENGTH = 63M
|
||||
/* Zedboard: 512 MB DDR3. Only use 62 MB for now, should be plenty for a bare-metal app.
|
||||
1 MB stack memory and 1 MB of memory which will be configured as uncached device memory by the
|
||||
MMU. This is recommended for something like DMA descriptors. */
|
||||
CODE(rx) : ORIGIN = 0x00100000, LENGTH = 62M
|
||||
STACKS : ORIGIN = 0x3F00000, LENGTH = 1M
|
||||
UNCACHED(rx): ORIGIN = 0x4000000, LENGTH = 1M
|
||||
OCM_UPPER(rx): ORIGIN = 0xFFFF0000, LENGTH = 64K
|
||||
}
|
||||
|
||||
REGION_ALIAS("DATA", CODE);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
MEMORY
|
||||
{
|
||||
/* The Zynq7000 has 192 kB of OCM memory which can be used for the FSBL */
|
||||
CODE(rx) : ORIGIN = 0x00000000, LENGTH = 192K
|
||||
/* The Zynq7000 has 256 kB of OCM memory of which 196 kB can be used for the FSBL */
|
||||
CODE(rx) : ORIGIN = 0x00000000, LENGTH = 196K
|
||||
OCM_UPPER(rx): ORIGIN = 0xFFFF0000, LENGTH = 64K
|
||||
/* Leave 1 MB of memory which will be configured as uncached device memory by the MMU. This can
|
||||
be used for something like DMA descriptors, but the DDR needs to be set up first in addition
|
||||
@@ -9,7 +9,10 @@ MEMORY
|
||||
UNCACHED(rx): ORIGIN = 0x4000000, LENGTH = 1M
|
||||
}
|
||||
|
||||
REGION_ALIAS("VECTORS", CODE);
|
||||
REGION_ALIAS("DATA", CODE);
|
||||
/* Use the upper OCM as the stack */
|
||||
REGION_ALIAS("STACKS", OCM_UPPER);
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
if {[info exists env(ip_address_hw_server)]} {
|
||||
set ip $env(ip_address_hw_server)
|
||||
if {[info exists env(XSCT_HW_SERVER_IP)]} {
|
||||
set ip $env(XSCT_HW_SERVER_IP)
|
||||
} else {
|
||||
set ip "localhost"
|
||||
}
|
||||
|
||||
@@ -22,8 +22,6 @@ def main():
|
||||
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"
|
||||
@@ -43,10 +41,13 @@ def main():
|
||||
help="No bitstream flashing for initialization with SDT.",
|
||||
)
|
||||
parser.add_argument("-a", "--app", dest="app", help="Path to the app to program")
|
||||
default_ip = os.getenv("HW_SERVER_IP")
|
||||
if not default_ip:
|
||||
default_ip = DEFAULT_IP_ADDRESS_HW_SERVER
|
||||
parser.add_argument(
|
||||
"-i",
|
||||
"--ip",
|
||||
default=DEFAULT_IP_ADDRESS_HW_SERVER,
|
||||
default=default_ip,
|
||||
help="The IP address of the hardware server (default: localhost)",
|
||||
)
|
||||
parser.add_argument(
|
||||
@@ -91,7 +92,7 @@ def main():
|
||||
print(f"The app '{args.app}' does not exist")
|
||||
sys.exit(1)
|
||||
|
||||
os.environ["IP_ADDRESS_HW_SERVER"] = args.ip
|
||||
os.environ["XSCT_HW_SERVER_IP"] = args.ip
|
||||
init_tcl = None
|
||||
bitstream = None
|
||||
if args.bit:
|
||||
|
||||
Reference in New Issue
Block a user