From 7df10e6ea15a07bd37bc5fed97af8157e5405a50 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 15 May 2026 19:28:25 +0200 Subject: [PATCH 1/2] prepare next zynq7000 version --- firmware/zedboard-bsp/Cargo.toml | 2 +- firmware/zynq7000-hal/Cargo.toml | 2 +- firmware/zynq7000-hal/src/uart/mod.rs | 26 +++++------ firmware/zynq7000-hal/src/uart/rx.rs | 24 +++++----- firmware/zynq7000-hal/src/uart/tx.rs | 30 ++++++------- firmware/zynq7000-hal/src/uart/tx_async.rs | 6 +-- firmware/zynq7000/CHANGELOG.md | 6 +++ firmware/zynq7000/Cargo.toml | 2 +- firmware/zynq7000/src/gic.rs | 51 ++++++++++++++++++---- firmware/zynq7000/src/uart.rs | 48 ++++++++++---------- host/Cargo.lock | 2 +- 11 files changed, 118 insertions(+), 81 deletions(-) diff --git a/firmware/zedboard-bsp/Cargo.toml b/firmware/zedboard-bsp/Cargo.toml index f06f32a..21f49a6 100644 --- a/firmware/zedboard-bsp/Cargo.toml +++ b/firmware/zedboard-bsp/Cargo.toml @@ -10,7 +10,7 @@ keywords = ["no-std", "zedboard", "bare-metal", "amd", "zynq7000"] categories = ["embedded", "no-std", "hardware-support"] [dependencies] -zynq7000 = { path = "../zynq7000", version = "0.3" } +zynq7000 = { path = "../zynq7000", version = "0.4" } zynq7000-hal = { path = "../zynq7000-hal", version = "0.1" } bitbybit = "2" log = "0.4" diff --git a/firmware/zynq7000-hal/Cargo.toml b/firmware/zynq7000-hal/Cargo.toml index faa026c..9c67493 100644 --- a/firmware/zynq7000-hal/Cargo.toml +++ b/firmware/zynq7000-hal/Cargo.toml @@ -12,7 +12,7 @@ categories = ["embedded", "no-std", "hardware-support"] [dependencies] aarch32-cpu = { version = "0.3" } -zynq7000 = { path = "../zynq7000", version = "0.3" } +zynq7000 = { path = "../zynq7000", version = "0.4" } zynq7000-mmu = { path = "../zynq7000-mmu", version = "0.2" } static_assertions = "1.1" bitbybit = "2" diff --git a/firmware/zynq7000-hal/src/uart/mod.rs b/firmware/zynq7000-hal/src/uart/mod.rs index 161ceae..482322d 100644 --- a/firmware/zynq7000-hal/src/uart/mod.rs +++ b/firmware/zynq7000-hal/src/uart/mod.rs @@ -576,31 +576,27 @@ impl Uart { } enable_amba_peripheral_clock(periph_sel); reset(uart_id); - reg_block.modify_control(|mut v| { - v.set_tx_dis(true); - v.set_rx_dis(true); - v - }); + reg_block.modify_control(|v| v.with_tx_disable(true).with_rx_disable(true)); // Disable all interrupts. reg_block.write_interrupt_disable(InterruptControl::new_with_raw_value(0xFFFF_FFFF)); let mode = Mode::builder() .with_chmode(cfg.chmode) - .with_nbstop(match cfg.stopbits { + .with_stopbits(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 { + .with_parity(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 { + .with_charlen(match cfg.chrl { CharLen::SixBits => zynq7000::uart::CharLen::SixBits, CharLen::SevenBits => zynq7000::uart::CharLen::SevenBits, CharLen::EightBits => zynq7000::uart::CharLen::EightBits, }) - .with_clksel(cfg.clk_sel) + .with_clock_select(cfg.clk_sel) .build(); reg_block.write_mode(mode); reg_block.write_baudgen( @@ -615,8 +611,8 @@ impl Uart { ); // Soft reset for both TX and RX. reg_block.modify_control(|mut v| { - v.set_tx_rst(true); - v.set_rx_rst(true); + v.set_tx_reset(true); + v.set_rx_reset(true); v }); @@ -627,10 +623,10 @@ impl Uart { // Enable TX and RX. reg_block.modify_control(|mut v| { - v.set_tx_dis(false); - v.set_rx_dis(false); - v.set_tx_en(true); - v.set_rx_en(true); + v.set_tx_disable(false); + v.set_rx_disable(false); + v.set_tx_enable(true); + v.set_rx_enable(true); v }); diff --git a/firmware/zynq7000-hal/src/uart/rx.rs b/firmware/zynq7000-hal/src/uart/rx.rs index 1212d89..ebc200f 100644 --- a/firmware/zynq7000-hal/src/uart/rx.rs +++ b/firmware/zynq7000-hal/src/uart/rx.rs @@ -73,7 +73,7 @@ impl Rx { /// Read one byte from the FIFO in a non-blocking manner. #[inline] pub fn read_fifo(&mut self) -> nb::Result { - if self.regs.read_sr().rx_empty() { + if self.regs.read_status().rx_empty() { return Err(nb::Error::WouldBlock); } Ok(self.regs.read_fifo().fifo()) @@ -93,17 +93,17 @@ impl Rx { /// 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); + self.regs.write_rx_timeout(rto as u32); } /// Perform a soft-reset of the RX side of the UART. #[inline] pub fn soft_reset(&mut self) { self.regs.modify_control(|mut cr| { - cr.set_rx_rst(true); + cr.set_rx_reset(true); cr }); - while self.regs.read_control().rx_rst() {} + while self.regs.read_control().rx_reset() {} } /// Helper function to start the interrupt driven reception of data. @@ -141,7 +141,7 @@ impl Rx { InterruptControl::builder() .with_tx_over(false) .with_tx_near_full(false) - .with_tx_trig(false) + .with_tx_trigger(false) .with_rx_dms(false) .with_rx_timeout(true) .with_rx_parity(true) @@ -151,7 +151,7 @@ impl Rx { .with_tx_empty(false) .with_rx_full(true) .with_rx_empty(false) - .with_rx_trg(true) + .with_rx_trigger(true) .build(), ); } @@ -167,7 +167,7 @@ impl Rx { let mut result = RxInterruptResult::default(); let imr = self.regs.read_enabled_interrupts(); if !imr.rx_full() - && !imr.rx_trg() + && !imr.rx_trigger() && !imr.rx_parity() && !imr.rx_framing() && !imr.rx_over() @@ -176,9 +176,9 @@ impl Rx { return result; } let isr = self.regs.read_interrupt_status(); - if self.regs.read_interrupt_status().rx_trg() { + if self.regs.read_interrupt_status().rx_trigger() { // 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(); + let fifo_trigger = self.regs.read_rx_fifo_trigger().trigger().as_usize(); (0..fifo_trigger).for_each(|i| { buf[i] = self.read_fifo_unchecked(); }); @@ -204,7 +204,7 @@ impl Rx { // Handle timeout event. if isr.rx_timeout() && reset_rx_timeout { self.regs.modify_control(|mut cr| { - cr.set_rstto(true); + cr.set_restart_timeout(true); cr }); } @@ -229,7 +229,7 @@ impl Rx { .with_tx_empty(false) .with_rx_full(true) .with_rx_empty(true) - .with_rx_trg(true) + .with_rx_trigger(true) .build(), ); } @@ -262,7 +262,7 @@ impl embedded_io::Read for Rx { } let mut read = 0; loop { - if !self.regs.read_sr().rx_empty() { + if !self.regs.read_status().rx_empty() { break; } } diff --git a/firmware/zynq7000-hal/src/uart/tx.rs b/firmware/zynq7000-hal/src/uart/tx.rs index 839c914..823e10f 100644 --- a/firmware/zynq7000-hal/src/uart/tx.rs +++ b/firmware/zynq7000-hal/src/uart/tx.rs @@ -48,7 +48,7 @@ impl Tx { /// [nb] API which returns [nb::Error::WouldBlock] if the FIFO is full. #[inline] pub fn write_fifo(&mut self, word: u8) -> nb::Result<(), Infallible> { - if self.regs.read_sr().tx_full() { + if self.regs.read_status().tx_full() { return Err(nb::Error::WouldBlock); } self.write_fifo_unchecked(word); @@ -62,8 +62,8 @@ impl Tx { self.soft_reset(); } self.regs.modify_control(|mut val| { - val.set_tx_en(true); - val.set_tx_dis(false); + val.set_tx_enable(true); + val.set_tx_disable(false); val }); } @@ -72,8 +72,8 @@ impl Tx { #[inline] pub fn disable(&mut self) { self.regs.modify_control(|mut val| { - val.set_tx_en(false); - val.set_tx_dis(true); + val.set_tx_enable(false); + val.set_tx_disable(true); val }); } @@ -82,11 +82,11 @@ impl Tx { #[inline] pub fn soft_reset(&mut self) { self.regs.modify_control(|mut val| { - val.set_tx_rst(true); + val.set_tx_reset(true); val }); loop { - if !self.regs.read_control().tx_rst() { + if !self.regs.read_control().tx_reset() { break; } } @@ -94,7 +94,7 @@ impl Tx { /// Flushes the TX FIFO by blocking until it is empty. pub fn flush(&mut self) { - while !self.regs.read_sr().tx_empty() {} + while !self.regs.read_status().tx_empty() {} } /// Write a byte to the TX FIFO without checking if there is space available. @@ -110,7 +110,7 @@ impl Tx { InterruptControl::builder() .with_tx_over(true) .with_tx_near_full(false) - .with_tx_trig(tx_trig) + .with_tx_trigger(tx_trig) .with_rx_dms(false) .with_rx_timeout(false) .with_rx_parity(false) @@ -120,7 +120,7 @@ impl Tx { .with_tx_empty(true) .with_rx_full(false) .with_rx_empty(false) - .with_rx_trg(false) + .with_rx_trigger(false) .build(), ); } @@ -132,7 +132,7 @@ impl Tx { InterruptControl::builder() .with_tx_over(true) .with_tx_near_full(false) - .with_tx_trig(true) + .with_tx_trigger(true) .with_rx_dms(false) .with_rx_timeout(false) .with_rx_parity(false) @@ -142,7 +142,7 @@ impl Tx { .with_tx_empty(true) .with_rx_full(false) .with_rx_empty(false) - .with_rx_trg(false) + .with_rx_trigger(false) .build(), ); } @@ -164,7 +164,7 @@ impl Tx { .with_tx_empty(true) .with_rx_full(false) .with_rx_empty(false) - .with_rx_trg(false) + .with_rx_trigger(false) .build(), ); } @@ -181,7 +181,7 @@ impl embedded_hal_nb::serial::Write for Tx { } fn flush(&mut self) -> nb::Result<(), Self::Error> { - if self.regs.read_sr().tx_empty() { + if self.regs.read_status().tx_empty() { return Ok(()); } Err(nb::Error::WouldBlock) @@ -199,7 +199,7 @@ impl embedded_io::Write for Tx { } let mut written = 0; loop { - if !self.regs.read_sr().tx_full() { + if !self.regs.read_status().tx_full() { break; } } diff --git a/firmware/zynq7000-hal/src/uart/tx_async.rs b/firmware/zynq7000-hal/src/uart/tx_async.rs index 64d9ce4..db9f7dc 100644 --- a/firmware/zynq7000-hal/src/uart/tx_async.rs +++ b/firmware/zynq7000-hal/src/uart/tx_async.rs @@ -72,7 +72,7 @@ pub unsafe fn on_interrupt_tx(peripheral: UartId) { // Pump the FIFO. while context.progress < slice_len { - if tx_with_irq.regs().read_sr().tx_full() { + if tx_with_irq.regs().read_status().tx_full() { break; } // Safety: TX structure is owned by the future which does not write into the the data @@ -84,7 +84,7 @@ pub unsafe fn on_interrupt_tx(peripheral: UartId) { if remaining > FIFO_DEPTH { tx_with_irq.regs.write_tx_fifo_trigger( FifoTrigger::builder() - .with_trig(u6::new((FIFO_DEPTH / 2) as u8)) + .with_trigger(u6::new((FIFO_DEPTH / 2) as u8)) .build(), ); } @@ -148,7 +148,7 @@ impl<'uart> TxFuture<'uart> { if data.len() > FIFO_DEPTH { tx_with_irq.regs.write_tx_fifo_trigger( FifoTrigger::builder() - .with_trig(u6::new((FIFO_DEPTH / 2) as u8)) + .with_trigger(u6::new((FIFO_DEPTH / 2) as u8)) .build(), ); } diff --git a/firmware/zynq7000/CHANGELOG.md b/firmware/zynq7000/CHANGELOG.md index a756e5d..6ae8cf3 100644 --- a/firmware/zynq7000/CHANGELOG.md +++ b/firmware/zynq7000/CHANGELOG.md @@ -8,6 +8,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/). # [unreleased] +# [v0.4.0] 2026-05-15 + +- Better names for `uart` registers and register fields. Replaced various abbreviations. +- Update `gic` module: Add some better type for SGIR field. + # [v0.3.0] 2026-05-08 - Better names for various registers. Replaced abbreviations like SR, MR, CR, IER, IMR etc. @@ -31,6 +36,7 @@ Documentation fix Initial release [unreleased]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-v0.3.0...HEAD +[v0.4.0]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-v0.3.0...zynq7000-v0.4.0 [v0.3.0]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-v0.2.0...zynq7000-v0.3.0 [v0.2.0]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-v0.1.0...zynq7000-v0.2.0 [v0.1.1]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-v0.1.0...zynq7000-v0.1.1 diff --git a/firmware/zynq7000/Cargo.toml b/firmware/zynq7000/Cargo.toml index 706d032..9e6d57c 100644 --- a/firmware/zynq7000/Cargo.toml +++ b/firmware/zynq7000/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zynq7000" -version = "0.3.0" +version = "0.4.0" authors = ["Robin Mueller "] edition = "2024" description = "Peripheral Access Crate (PAC) for the Zynq7000 family of SoCs" diff --git a/firmware/zynq7000/src/gic.rs b/firmware/zynq7000/src/gic.rs index b2a8f68..9a775d0 100644 --- a/firmware/zynq7000/src/gic.rs +++ b/firmware/zynq7000/src/gic.rs @@ -1,6 +1,6 @@ //! # GIC (Generic Interrupt Controller) register module. pub use crate::mpcore::{GICC_BASE_ADDR, GICD_BASE_ADDR}; -use arbitrary_int::{u2, u3, u5, u10}; +use arbitrary_int::{u2, u3, u4, u5, u10, u11}; use static_assertions::const_assert_eq; /// Distributor Control Register @@ -55,9 +55,6 @@ pub struct InterruptProcessorTargetRegister { targets: [u2; 4], } -#[deprecated(note = "Use DistributorRegisters instead")] -pub type GicDistributorTyper = DistributorRegisters; - /// GIC Distributor registers. #[derive(derive_mmio::Mmio)] #[repr(C, align(8))] @@ -92,7 +89,7 @@ pub struct DistributorRegisters { /// Interrupt Priority Registers pub ipr: [u32; 0x18], _reserved_11: [u32; 0xE8], - /// Interrupt Processor Targes Registers + /// Interrupt Processor Targets Registers pub iptr_sgi: [InterruptProcessorTargetRegister; 0x4], /// These are read-only because they always target their private CPU. #[mmio(PureRead)] @@ -102,6 +99,7 @@ pub struct DistributorRegisters { _reserved_12: [u32; 0xE8], /// Interrupt Configuration Registers /// Interupt sensitivity register for software generated interrupts (SGI) + #[mmio(PureRead)] pub icfr_0_sgi: u32, /// Interupt sensitivity register for private peripheral interrupts (PPI) pub icfr_1_ppi: u32, @@ -115,7 +113,7 @@ pub struct DistributorRegisters { pub spi_status_1: u32, _reserved_14: [u32; 0x7D], /// Software Generated Interrupt Register. - pub sgir: u32, + pub sgir: SoftwareGeneratedInterruptRegister, _reserved_15: [u32; 0x33], pub pidr_4: u32, pub pidr_5: u32, @@ -182,8 +180,45 @@ pub struct InterruptSignalRegister { ack_int_id: u10, } -#[deprecated(note = "Use DistributorRegisters instead")] -pub type GicCpuInterfaceIar = CpuInterfaceRegisters; +#[bitbybit::bitenum(u1, exhaustive = true)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(Debug, PartialEq, Eq)] +pub enum SecurityCondition { + IfConfiguredAsSecure = 0, + IfConfiguredAsNonSecure = 1, +} + +#[bitbybit::bitenum(u2, exhaustive = true)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(Debug, PartialEq, Eq)] +pub enum TargetListFilter { + SendToCpusInTargetList = 0b00, + SendToAllOtherCpus = 0b01, + SendToSelf = 0b10, + Reserved = 0b11, +} + +#[bitbybit::bitfield( + u32, + default = 0x0, + debug, + defmt_bitfields(feature = "defmt"), + forbid_overlaps +)] +pub struct SoftwareGeneratedInterruptRegister { + #[bits(24..=25, rw)] + target_list_filter: TargetListFilter, + #[bits(16..=23, rw)] + cpu_target_list: u8, + /// SATT field. + #[bit(15, rw)] + security_condition: SecurityCondition, + /// Should be zero. + #[bits(4..=14, rw)] + sbz: u11, + #[bits(0..=3, rw)] + interrupt_id: u4, +} /// GIC CPU interface registers. #[derive(derive_mmio::Mmio)] diff --git a/firmware/zynq7000/src/uart.rs b/firmware/zynq7000/src/uart.rs index 66f002e..04df156 100644 --- a/firmware/zynq7000/src/uart.rs +++ b/firmware/zynq7000/src/uart.rs @@ -77,25 +77,25 @@ pub struct Control { startbrk: bool, /// Restart receiver timeout counter. #[bit(6, rw)] - rstto: bool, + restart_timeout: bool, /// TX disable. If this is 1, TX is disabled, regardless of TXEN. #[bit(5, rw)] - tx_dis: bool, + tx_disable: bool, /// TX enable. TX will be enabled if this bit is 1 and the TXDIS is 0. #[bit(4, rw)] - tx_en: bool, + tx_enable: bool, /// RX disable. If this is 1, RX is disabled, regardless of RXEN. #[bit(3, rw)] - rx_dis: bool, + rx_disable: bool, /// RX enable. RX will be enabled if this bit is 1 and the RXDIS is 0. #[bit(2, rw)] - rx_en: bool, + rx_enable: bool, /// TX soft reset. #[bit(1, rw)] - tx_rst: bool, + tx_reset: bool, /// RX soft reset. #[bit(0, rw)] - rx_rst: bool, + rx_reset: bool, } #[bitbybit::bitfield( @@ -109,14 +109,14 @@ pub struct Mode { #[bits(8..=9, rw)] chmode: ChMode, #[bits(6..=7, rw)] - nbstop: Option, + stopbits: Option, #[bits(3..=5, rw)] - par: Parity, + parity: Parity, /// Char length. #[bits(1..=2, rw)] - chrl: CharLen, + charlen: CharLen, #[bit(0, rw)] - clksel: ClockSelect, + clock_select: ClockSelect, } #[bitbybit::bitfield( @@ -162,7 +162,7 @@ pub struct Status { #[bit(14, r)] tx_near_full: bool, #[bit(13, r)] - tx_trig: Ttrig, + tx_trigger: Ttrig, #[bit(12, r)] flowdel: bool, /// Transmitter state machine active. @@ -181,7 +181,7 @@ pub struct Status { rx_empty: bool, /// RX FIFO trigger level was reached. #[bit(0, r)] - rx_trg: bool, + rx_trigger: bool, } #[bitbybit::bitfield( @@ -197,7 +197,7 @@ pub struct InterruptControl { #[bit(11, w)] tx_near_full: bool, #[bit(10, w)] - tx_trig: bool, + tx_trigger: bool, #[bit(9, w)] rx_dms: bool, /// Receiver timeout error interrupt. @@ -218,7 +218,7 @@ pub struct InterruptControl { #[bit(1, w)] rx_empty: bool, #[bit(0, w)] - rx_trg: bool, + rx_trigger: bool, } #[bitbybit::bitfield(u32, default = 0x0)] @@ -226,7 +226,7 @@ pub struct InterruptControl { #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct FifoTrigger { #[bits(0..=5, rw)] - trig: u6, + trigger: u6, } #[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"))] @@ -237,7 +237,7 @@ pub struct InterruptMask { #[bit(11, r)] tx_near_full: bool, #[bit(10, r)] - tx_trig: bool, + tx_trigger: bool, #[bit(9, r)] rx_dms: bool, /// Receiver timeout error interrupt. @@ -259,7 +259,7 @@ pub struct InterruptMask { rx_empty: bool, /// RX FIFO trigger level reached. #[bit(0, r)] - rx_trg: bool, + rx_trigger: bool, } #[bitbybit::bitfield( @@ -297,7 +297,7 @@ pub struct InterruptStatus { rx_empty: bool, /// RX FIFO trigger level reached. #[bit(0, rw)] - rx_trg: bool, + rx_trigger: bool, } impl InterruptStatus { @@ -315,7 +315,7 @@ impl InterruptStatus { .with_tx_empty(false) .with_rx_full(false) .with_rx_empty(false) - .with_rx_trg(false) + .with_rx_trigger(false) .build() } } @@ -343,16 +343,16 @@ pub struct Registers { /// Baudgen register baudgen: Baudgen, /// RX timeout register - rx_tout: u32, + rx_timeout: u32, /// RX FIFO trigger level register rx_fifo_trigger: FifoTrigger, /// Modem control register - modem_cr: u32, + modem_control: u32, /// Modem status register - modem_sr: u32, + modem_status: u32, /// Channel status register #[mmio(PureRead)] - sr: Status, + status: Status, /// FIFO register #[mmio(Read, Write)] fifo: Fifo, diff --git a/host/Cargo.lock b/host/Cargo.lock index 774fc6b..70830c2 100644 --- a/host/Cargo.lock +++ b/host/Cargo.lock @@ -647,7 +647,7 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "zynq7000" -version = "0.3.0" +version = "0.4.0" dependencies = [ "arbitrary-int 2.0.0", "bitbybit 2.0.0", -- 2.43.0 From bdc4780bcc2704741507d2b976fdeabf09a7e8eb Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 15 May 2026 19:29:58 +0200 Subject: [PATCH 2/2] small tweak --- firmware/zynq7000/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/zynq7000/CHANGELOG.md b/firmware/zynq7000/CHANGELOG.md index 6ae8cf3..5be8e2d 100644 --- a/firmware/zynq7000/CHANGELOG.md +++ b/firmware/zynq7000/CHANGELOG.md @@ -35,7 +35,7 @@ Documentation fix Initial release -[unreleased]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-v0.3.0...HEAD +[unreleased]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-v0.4.0...HEAD [v0.4.0]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-v0.3.0...zynq7000-v0.4.0 [v0.3.0]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-v0.2.0...zynq7000-v0.3.0 [v0.2.0]: https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/compare/zynq7000-v0.1.0...zynq7000-v0.2.0 -- 2.43.0