feat(all): implement DMA functions with example and add D-cache operations#16
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds first-class DMA support to the HAL/runtime (including cache-maintenance helpers needed for DMA coherency) and introduces a new pbp-dma example, while updating CI to test chip features via a matrix rather than --all-features.
Changes:
- Add DMA channel/task abstractions in
artinchip-hal(plusDmaExt::split()for ergonomic channel access). - Add D-cache clean/invalidate range helpers in
artinchip-rtand use them in a newpbp-dmaexample. - Update workspace/CI to include the new example and run clippy with a per-feature matrix.
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| examples/pbp/pbp-dma/src/main.rs | New DMA mem2mem example using task descriptors + D-cache operations for coherency. |
| examples/pbp/pbp-dma/build.rs | Linker script arg for the new example (consistent with other examples). |
| examples/pbp/pbp-dma/README.md | Build/pack instructions for the new example. |
| examples/pbp/pbp-dma/Cargo.toml | Defines the pbp-dma example crate and its chip feature wiring. |
| artinchip-rt/src/lib.rs | Exposes a new core module from artinchip-rt. |
| artinchip-rt/src/core.rs | Adds the cache submodule entry point. |
| artinchip-rt/src/core/cache.rs | Implements D-cache clean+invalidate and invalidate-by-range helpers. |
| artinchip-rt/Cargo.toml | Adds xuantie-riscv dependency used by cache asm helpers. |
| artinchip-hal/src/lib.rs | Exposes DmaExt in the HAL prelude for .split() ergonomics. |
| artinchip-hal/src/dma.rs | Wires up new DMA modules and re-exports channel/task APIs. |
| artinchip-hal/src/dma/instance.rs | Implements DmaExt::split() returning typed DMA channels. |
| artinchip-hal/src/dma/dma_ext.rs | Introduces the DmaExt trait. |
| artinchip-hal/src/dma/channel.rs | Adds typed per-channel DMA API (start/stop/irq/status/etc.). |
| artinchip-hal/src/dma/task.rs | Introduces DmaTask descriptor and task chaining helper. |
| artinchip-hal/src/dma/register.rs | Refactors DMA register helper APIs (channel args now u8), adds zeroed constructors, handshake bit helpers, etc. |
| aicfwc/Cargo.toml | Adds empty chip features to support feature-matrix clippy invocation. |
| Cargo.toml | Adds examples/pbp/pbp-dma to the workspace. |
| .github/workflows/Cargo.yml | Switches clippy to a feature matrix and adds pbp-dma to the example build list. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @@ -0,0 +1,13 @@ | |||
| # PBP Dma | |||
| #[repr(C, align(8))] | ||
| struct MemBuf([u32; 2000]); | ||
|
|
||
| static mut MEM_SRC: MemBuf = MemBuf([0u32; 2000]); | ||
| static mut MEM_DST: MemBuf = MemBuf([0xDEAD_BEEFu32; 2000]); |
| #[cfg(any( | ||
| feature = "d12x", | ||
| feature = "d13x", | ||
| feature = "g73x", | ||
| feature = "m6800" | ||
| ))] | ||
| const CACHE_LINE: usize = 32; | ||
| #[cfg(feature = "d21x")] | ||
| const CACHE_LINE: usize = 64; | ||
|
|
| pub struct DmaChannel<'a, const I: u8> { | ||
| pub reg: &'a RegisterBlock, | ||
| } | ||
|
|
||
| impl<'a, const I: u8> DmaChannel<'a, I> { | ||
| /// Create a new DMA channel. | ||
| pub fn __new(reg: &'a RegisterBlock, cmu: &Cmu) -> Self { | ||
| let clk = &cmu.register_block().clock_dma; | ||
| if !clk.read().is_bus_clk_enabled() { | ||
| unsafe { | ||
| // Initialize module clock. | ||
| // Reference: https://aicdoc.artinchip.com/topics/ic/cmu/cmu-function2-d13x.html#topic_yvp_f24_4bc__table_qb3_bn5_ydc | ||
| clk.modify(|v| v.enable_bus_clk()); | ||
| clk.modify(|v| v.enable_module_reset()); | ||
| riscv::asm::delay(500); | ||
| clk.modify(|v| v.disable_module_reset()); | ||
| } | ||
| } | ||
| Self { reg } | ||
| } | ||
|
|
||
| /// Get a reference to the DMA channel's register. | ||
| fn channel(&self) -> &DmaCh { | ||
| &self.reg.groups[I as usize] | ||
| } |
| /// Physical address of next task (0xFFFFF800 = end). | ||
| pub p_next: u32, | ||
|
|
||
| // ========== Software-only fields (not directly used by DMA controller) ========== | ||
| /// Handshake mode | ||
| pub mode: ChMode, | ||
| /// Virtual pointer to next task. | ||
| pub v_next: Option<NonNull<DmaTask>>, | ||
| } | ||
|
|
||
| impl DmaTask { | ||
| /// End of DMA task chain end flag. | ||
| pub const TASK_END: u32 = 0xFFFFF800; | ||
| /// Default delay value. | ||
| pub const DEFAULT_DELAY: u32 = 0x40; | ||
|
|
||
| pub fn append(&mut self, next: &mut DmaTask) { | ||
| let mut last = self; | ||
|
|
||
| for _ in 0..1_000 { | ||
| if let Some(mut next_ptr) = last.v_next { | ||
| last = unsafe { next_ptr.as_mut() }; | ||
| } else { | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| if last.v_next.is_some() { | ||
| panic!("DMA task chain too long or contains a cycle"); | ||
| } | ||
|
|
||
| last.p_next = next as *const DmaTask as u32; | ||
| last.v_next = Some(NonNull::from(next)); | ||
| } |
| pub const fn enable_channel_addr_req_err(self, channel: u8) -> Self { | ||
| let mask = match channel { | ||
| DmaChannel::Ch0 => Self::CH0_ADDR_REQ_ERR_EN, | ||
| DmaChannel::Ch1 => Self::CH1_ADDR_REQ_ERR_EN, | ||
| DmaChannel::Ch2 => Self::CH2_ADDR_REQ_ERR_EN, | ||
| DmaChannel::Ch3 => Self::CH3_ADDR_REQ_ERR_EN, | ||
| DmaChannel::Ch4 => Self::CH4_ADDR_REQ_ERR_EN, | ||
| DmaChannel::Ch5 => Self::CH5_ADDR_REQ_ERR_EN, | ||
| DmaChannel::Ch6 => Self::CH6_ADDR_REQ_ERR_EN, | ||
| DmaChannel::Ch7 => Self::CH7_ADDR_REQ_ERR_EN, | ||
| 0x0 => Self::CH0_ADDR_REQ_ERR_EN, | ||
| 0x1 => Self::CH1_ADDR_REQ_ERR_EN, | ||
| 0x2 => Self::CH2_ADDR_REQ_ERR_EN, | ||
| 0x3 => Self::CH3_ADDR_REQ_ERR_EN, | ||
| 0x4 => Self::CH4_ADDR_REQ_ERR_EN, | ||
| 0x5 => Self::CH5_ADDR_REQ_ERR_EN, | ||
| 0x6 => Self::CH6_ADDR_REQ_ERR_EN, | ||
| 0x7 => Self::CH7_ADDR_REQ_ERR_EN, | ||
| _ => unreachable!(), |
| strategy: | ||
| matrix: | ||
| PACKAGE: [artinchip-hal, artinchip-rt, aicfwc] | ||
| FEATURES: [d12x, d13x, d21x, g73x, m6800] | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - uses: actions-rust-lang/setup-rust-toolchain@v1 | ||
| with: | ||
| toolchain: stable | ||
| components: clippy | ||
| - name: Run cargo clippy | ||
| run: cargo clippy -p ${{ matrix.PACKAGE }} --all-targets --all-features -- -D warnings | ||
| run: cargo clippy -p ${{ matrix.PACKAGE }} --all-targets --features ${{ matrix.FEATURES }} -- -D warnings |
luojia65
left a comment
There was a problem hiding this comment.
LGTM with minor modifications.
| @@ -71,14 +71,15 @@ jobs: | |||
| strategy: | |||
| matrix: | |||
| PACKAGE: [artinchip-hal, artinchip-rt, aicfwc] | |||
There was a problem hiding this comment.
We can split aicfwc check from artinchip-hal and artinchip-rt as it typically runs on host computer, other than on bare-metal chips. aicfwc may not have chip-specific features, as it would support multiple chips without compilation gates.
| #[cfg(any( | ||
| feature = "d12x", | ||
| feature = "d13x", | ||
| feature = "g73x", | ||
| feature = "m6800" | ||
| ))] | ||
| const CACHE_LINE: usize = 32; | ||
| #[cfg(feature = "d21x")] | ||
| const CACHE_LINE: usize = 64; |
There was a problem hiding this comment.
Can we move CACHE_LINE to module level? Different functions may share the same CACHE_LINE const without duplicated code. For example, we can have artinchip_rt::core::cache::CACHE_LINE which is a usize with different values according to chip features.
| artinchip-rt-macros = { version = "0.0.0", path = "macros" } | ||
| artinchip-hal = { version = "0.0.0", path = "../artinchip-hal" } | ||
| paste = "1.0" | ||
| xuantie-riscv = {git = "https://github.com/rustsbi/xuantie.git", branch = "main"} |
There was a problem hiding this comment.
| xuantie-riscv = {git = "https://github.com/rustsbi/xuantie.git", branch = "main"} | |
| xuantie-riscv = { git = "https://github.com/rustsbi/xuantie.git", branch = "main" } |
There are no cargo fmt guarantees on TOML files, we should keep a note on formatting manually.
…ions - Split CI `--all-features` into MATRIX features to avoid conflicts. Signed-off-by: Chongbing Yu <nanahigh@openatom.club>
|
Modifications are completed. |
--all-featuresinto MATRIX features to avoid conflicts.pbp-dmaexample tests on kunlunpi v1.1