Skip to content

Commit f96c103

Browse files
authored
refac(D1): pull most of the code back into a core crate (#283)
By reintroducing a `mnemos-d1-core` crate, we can put most of the platform implementation in a crate without a `forced-target`, allowing us to run unit tests for the platform impl on the build host. The actual dependencies on `riscv` and `riscv-rt`, which won't build for the host's target, are now `cfg`-gated. We must still have the crate containing the top-level binaries have a `forced-target`, or else we hit weird cargo bugs I don't understand, but it's now a thin wrapper around the `core` crate which has a `forced-target` and defines the board binaries. This also has the side benefit of letting us put the `d1-core` crate in the workspace's `default-members`, so it gets seen by `cargo test`/`cargo fmt`/etc without having to pass it explicitly. And, we can have tests now!
1 parent 24e6939 commit f96c103

File tree

22 files changed

+181
-79
lines changed

22 files changed

+181
-79
lines changed

.vscode/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,5 @@
1818
"--all-targets"
1919
],
2020
"rust-analyzer.workspace.symbol.search.scope": "workspace_and_dependencies",
21-
"rust-analyzer.typing.continueCommentsOnNewline": false
21+
"rust-analyzer.typing.continueCommentsOnNewline": false,
2222
}

Cargo.lock

Lines changed: 17 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ members = [
2828
# platforms
2929
"platforms/allwinner-d1",
3030
"platforms/allwinner-d1/d1-config",
31+
"platforms/allwinner-d1/d1-core",
3132
"platforms/beepy",
3233
"platforms/esp32c3-buddy",
3334
"platforms/melpomene",
@@ -55,6 +56,8 @@ default-members = [
5556
# platforms
5657
"platforms/melpomene",
5758
"platforms/melpomene/melpo-config",
59+
"platforms/allwinner-d1/d1-config",
60+
"platforms/allwinner-d1/d1-core",
5861
]
5962
# this isn't actually a crate
6063
exclude = ["source/notes"]

platforms/allwinner-d1/Cargo.toml

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ default = ["i2c_puppet", "sharp-display", "serial-trace"]
3333
# enable i2c_puppet driver
3434
i2c_puppet = ["mnemos-beepy"]
3535
# enable the SHARP Memory Display driver
36-
sharp-display = []
36+
sharp-display = ["mnemos-d1-core/sharp-display"]
3737
# enable `mnemos-trace-proto` serial tracing.
3838
serial-trace = ["mnemos/serial-trace"]
3939

@@ -48,7 +48,7 @@ miette = "5.10.0"
4848
serde = { version = "1.0.178", features = ["derive"], default-features = false }
4949
d1-config = { path = "./d1-config" }
5050
mnemos-config = { path = "../../source/config" }
51-
mnemos-bitslab = { path = "../../source/bitslab" }
51+
mnemos-d1-core = { path = "./d1-core" }
5252

5353
d1-pac = "0.0.31"
5454
critical-section = "1.1.1"
@@ -68,14 +68,6 @@ version = "0.1.37"
6868
features = ["attributes"]
6969
default-features = false
7070

71-
[dependencies.embedded-graphics]
72-
version = "0.7.1"
73-
74-
[dependencies.futures]
75-
version = "0.3.21"
76-
features = ["async-await"]
77-
default-features = false
78-
7971
[dependencies.riscv]
8072
version = "0.10"
8173
features =[ "critical-section-single-hart"]

platforms/allwinner-d1/README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,21 @@ This directory contains MnemOS platform support for the Allwinner D1 RISC-V SoC.
44

55
## Folder Layout
66

7-
* [`src/`]: Rust source code for the Allwinner D1 platform implementation.
7+
* [`src/`]: The top-level crate that produces MnemOS binaries for the Allwinner
8+
D1.
89
* [`board-configs/`]: [`mnemos-config`] configurations for supported D1
910
single-board computers.
11+
* [`d1-core/`]: Core MnemOS implementation for the Allwinner D1. This is
12+
factored out into a separate crate so that it can be built without
13+
`forced-target="riscv64imac-unknown-none-elf"` (unlike the top-level
14+
`mnemos-d1` crate), so that unit tests for the platform implementation can
15+
be run on development host targets.
1016
* [`d1-config/`]: [`mnemos-config`] type definition crate for the Allwinner D1.
1117

1218
[`src/`]: ./boards/
1319
[`board-configs/`]: ./board-configs/
1420
[`d1-config/`]: ./d1-config/
21+
[`d1-core/`]: ./d1-core/
1522

1623
## Getting started with MnemOS on the D1
1724

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
2+
cargo-features = ["per-package-target", "profile-rustflags"]
3+
4+
[package]
5+
name = "mnemos-d1-core"
6+
version = "0.1.0"
7+
edition.workspace = true
8+
repository.workspace = true
9+
homepage.workspace = true
10+
license.workspace = true
11+
12+
13+
[features]
14+
# enable the SHARP Memory Display driver
15+
sharp-display = []
16+
17+
[dependencies]
18+
serde = { version = "1.0.178", features = ["derive"], default-features = false }
19+
mnemos-bitslab = { path = "../../../source/bitslab" }
20+
21+
d1-pac = "0.0.31"
22+
critical-section = "1.1.1"
23+
24+
[target.'cfg(any(target_arch = "riscv64", target_arch = "riscv32"))'.dependencies]
25+
riscv = "0.10.0"
26+
riscv-rt = "0.11"
27+
28+
# kernel
29+
[dependencies.mnemos]
30+
path = "../../../source/kernel"
31+
default-features = false
32+
33+
[dependencies.tracing]
34+
version = "0.1.37"
35+
features = ["attributes"]
36+
default-features = false
37+
38+
[dependencies.embedded-graphics]
39+
version = "0.7.1"
40+
41+
[dependencies.futures]
42+
version = "0.3.21"
43+
features = ["async-await"]
44+
default-features = false
File renamed without changes.

platforms/allwinner-d1/src/clint.rs renamed to platforms/allwinner-d1/d1-core/src/clint.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ impl Clint {
3535
}
3636

3737
/// Get the (machine) time value.
38+
#[cfg(not(any(target_arch = "riscv64", target_arch = "riscv32")))]
39+
pub fn get_mtime(&self) -> usize {
40+
unimplemented!("called `Clint::get_mtime` on a non-RISC-V architecture, this shouldn't happen while running host tests!")
41+
}
42+
43+
/// Get the (machine) time value.
44+
#[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))]
3845
pub fn get_mtime(&self) -> usize {
3946
// Note that the CLINT of the C906 core does not implement
4047
// the `mtime` register and we need to get the time value
File renamed without changes.

platforms/allwinner-d1/src/dmac/mod.rs renamed to platforms/allwinner-d1/d1-core/src/dmac/mod.rs

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ pub struct Dmac {
5151
///
5252
/// The DMA controller owns a shared pool of 16 DMA channels, which may be used
5353
/// by drivers to initiate DMA transfers. Channels can be acquired from the
54-
/// shared pool using the [`Dmac::claim`] and [`Dmac::try_claim`] methods.
55-
/// Dropping a `Channel` releases it back to the shared pool, allowing it to be
56-
/// claimed by other drivers.
54+
/// shared pool using the [`Dmac::claim_channel`] and
55+
/// [`Dmac::try_claim_channel`] methods. Dropping a `Channel` releases it back
56+
/// to the shared pool, allowing it to be claimed by other drivers.
5757
pub struct Channel {
5858
idx: u8,
5959
xfer_done: &'static WaitCell,
@@ -298,7 +298,7 @@ impl Dmac {
298298
}
299299

300300
/// Handle a DMAC interrupt.
301-
pub(crate) fn handle_interrupt() {
301+
pub fn handle_interrupt() {
302302
let dmac = unsafe { &*DMAC::PTR };
303303
// there are two registers that contain DMA channel IRQ status bits,
304304
// `DMAC_IRQ_PEND0` and `DMAC_IRQ_PEND1`. the first 8 channels (0-7) set
@@ -334,7 +334,12 @@ impl Dmac {
334334
///
335335
/// This is generally used when shutting down the system, such as in panic
336336
/// and exception handlers.
337-
pub(crate) unsafe fn cancel_all() {
337+
///
338+
/// # Safety
339+
///
340+
/// Cancelling DMA transfers abruptly might put peripherals in a weird state
341+
/// i guess?
342+
pub unsafe fn cancel_all() {
338343
for (i, channel) in STATE.channel_wait.iter().enumerate() {
339344
channel.close();
340345
Channel {
@@ -444,10 +449,7 @@ impl Channel {
444449
/// flight on this channel. This is ensured when using the
445450
/// [`Channel::transfer`] method, which mutably borrows the channel while
446451
/// the transfer is in progress, preventing the channel modes from being
447-
/// changed. However, if a transfer is started with
448-
/// [`Channel::start_descriptor`], it is possible to manipulate the channel
449-
/// modes while a transfer is in progress. I don't know what happens if you
450-
/// do this, but it's probably bad.
452+
/// changed.
451453
pub unsafe fn set_channel_modes(&mut self, src: ChannelMode, dst: ChannelMode) {
452454
self.mode_reg().write(|w| {
453455
match src {
@@ -662,15 +664,6 @@ fn queue_irq_en_offset(idx: u8) -> u8 {
662664
(idx * 4) + 2
663665
}
664666

665-
// Unfortunately, we can't define tests in this crate and have them run on the
666-
// development host machine, because the `mnemos-d1` crate has a `forced-target`
667-
// in its `Cargo.toml`, and will therefore not compile at all for host
668-
// architectures, even just to run tests. In the future, we should look into
669-
// whether it's possible to change our build configurations to allow host tests
670-
// in this crate.
671-
// TODO(eliza): if we can run tests for this crate on the build host, we should
672-
// uncomment these tests.
673-
/*
674667
#[cfg(test)]
675668
mod tests {
676669
use super::*;
@@ -687,4 +680,3 @@ mod tests {
687680
assert_eq!(dbg!(queue_irq_en_offset(7)), 30);
688681
}
689682
}
690-
*/

0 commit comments

Comments
 (0)