Skip to content

Commit

Permalink
Vendor libtock-rs (#52)
Browse files Browse the repository at this point in the history
We vendor it for a few reasons:

It simplifies our build, so that we no longer have to specify the LIBTOCK environment variables
We can make more easily make changes to accommodate our user-mod testing
We can integrate async support more seamlessly.
I also took this opportunity to rename pldm-app to example-app.

I ran cargo clippy --fix and did some other clippy fixes. (This also reordered some of the tests in other files.)

* Check in most of the libtock-rs code unmodified from f0fe5198524252887a71cea25093123afa6f429d
* Delete libtock stuff we don't need; add no-op impl for the host so that the compiles are clean
* Use local libtock; remane pldm-app to example-app
  • Loading branch information
swenson authored Dec 10, 2024
1 parent e543a67 commit 0829240
Show file tree
Hide file tree
Showing 230 changed files with 24,191 additions and 284 deletions.
523 changes: 368 additions & 155 deletions Cargo.lock

Large diffs are not rendered by default.

30 changes: 28 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,34 @@ members = [
"rom",
"romtime",
"runtime",
"runtime/apps/example",
"runtime/apps/libtock/apis/interface/buttons",
"runtime/apps/libtock/apis/interface/buzzer",
"runtime/apps/libtock/apis/interface/console",
"runtime/apps/libtock/apis/interface/leds",
"runtime/apps/libtock/apis/kernel/low_level_debug",
"runtime/apps/libtock/apis/peripherals/adc",
"runtime/apps/libtock/apis/peripherals/alarm",
"runtime/apps/libtock/apis/peripherals/gpio",
"runtime/apps/libtock/apis/peripherals/i2c_master",
"runtime/apps/libtock/apis/peripherals/i2c_master_slave",
"runtime/apps/libtock/apis/peripherals/rng",
"runtime/apps/libtock/apis/sensors/air_quality",
"runtime/apps/libtock/apis/sensors/ambient_light",
"runtime/apps/libtock/apis/sensors/ninedof",
"runtime/apps/libtock/apis/sensors/proximity",
"runtime/apps/libtock/apis/sensors/temperature",
"runtime/apps/libtock/apis/storage/key_value",
"runtime/apps/libtock/panic_handlers/debug_panic",
"runtime/apps/libtock/panic_handlers/small_panic",
"runtime/apps/libtock/platform",
"runtime/apps/libtock/runner",
"runtime/apps/libtock/runtime",
"runtime/apps/libtock/syscalls_tests",
"runtime/apps/libtock/tools/print_sizes",
"runtime/apps/libtock/ufmt",
"runtime/apps/libtock/unittest",
"runtime/capsules",
"runtime/apps/pldm",
"runtime/i3c",
"tests/hello",
"tests/integration",
Expand Down Expand Up @@ -98,4 +124,4 @@ opt-level = 3

# Keep debug symbols in the release ELF so that we can debug more easily.
[profile.release]
debug = true
debug = true
32 changes: 16 additions & 16 deletions emulator/app/src/dis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4538,22 +4538,6 @@ pub(crate) fn csr_name(csrno: i32) -> &'static str {
}
}

#[cfg(test)]
mod csr_tests {
use std::collections::HashSet;
#[test]
fn test_csrs_unique() {
let mut names = HashSet::new();
for i in 0..0x1000 {
let name = super::csr_name(i);
if !name.is_empty() {
assert!(!names.contains(name), "duplicate CSR name: {}", name);
names.insert(name);
}
}
}
}

fn decode_inst_opcode_compressed_0(isa: RvIsa, inst: u64) -> Option<&'static RvOpcodeData> {
match (inst >> 13) & 7 {
0 => Some(&RV_OPCODE_DATA_caddi4spn),
Expand Down Expand Up @@ -5987,3 +5971,19 @@ pub fn disasm_inst(isa: RvIsa, pc: u64, inst: RvInst) -> String {
decode_inst_lift_pseudo(&mut dec);
decode_inst_format(&mut dec)
}

#[cfg(test)]
mod csr_tests {
use std::collections::HashSet;
#[test]
fn test_csrs_unique() {
let mut names = HashSet::new();
for i in 0..0x1000 {
let name = super::csr_name(i);
if !name.is_empty() {
assert!(!names.contains(name), "duplicate CSR name: {}", name);
names.insert(name);
}
}
}
}
2 changes: 1 addition & 1 deletion emulator/cpu/src/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1693,7 +1693,7 @@ mod tests {
#[test]
fn test_coverage() {
// represent program as an array of 16-bit and 32-bit instructions
let instructions = vec![
let instructions = [
Instr::Compressed(0x1234),
Instr::Compressed(0xABCD),
Instr::General(0xDEADBEEF),
Expand Down
4 changes: 2 additions & 2 deletions emulator/periph/src/spi_host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,7 @@ mod tests {
.for_each(|_| spi_host.write(RvSize::Byte, TX_FIFO_OFFSET, 0xff).unwrap());

let cs_high = xfer.dummy_clocks == 0 && xfer.receive_len == 0;
let spi_len: u32 = (xfer.mode_clocks / divisor - 1).try_into().unwrap();
let spi_len: u32 = (xfer.mode_clocks / divisor - 1).into();
spi_host
.write(
RvSize::Word,
Expand All @@ -732,7 +732,7 @@ mod tests {
// DummyCycles
if xfer.dummy_clocks != 0 {
let cs_high = xfer.receive_len == 0;
let spi_len: u32 = (xfer.dummy_clocks - 1).try_into().unwrap();
let spi_len: u32 = (xfer.dummy_clocks - 1).into();
spi_host
.write(
RvSize::Word,
Expand Down
138 changes: 69 additions & 69 deletions registers/systemrdl/src/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,75 @@ impl Instance {
}
}

fn is_intr_modifier(token: &Token) -> bool {
matches!(
*token,
Token::Identifier("posedge" | "negedge" | "bothedge" | "level" | "nonsticky" | "sticky")
)
}

struct PropertyAssignment<'a> {
prop_name: &'a str,
value: Value,
}

static INTR_BOOL_PROPERTY: PropertyMeta = PropertyMeta {
name: "intr",
ty: PropertyType::Boolean,
is_dynamic: true,
};
fn intr_bool_property<'a>(_name: &str) -> Result<'a, &'static PropertyMeta> {
Ok(&INTR_BOOL_PROPERTY)
}

impl<'a> PropertyAssignment<'a> {
fn parse(
tokens: &mut TokenIter<'a>,
parameters: Option<&ParameterScope<'_>>,
meta_lookup_fn: impl Fn(&'a str) -> Result<'a, &'static PropertyMeta>,
) -> Result<'a, Self> {
if is_intr_modifier(tokens.peek(0)) && *tokens.peek(1) == Token::Identifier("intr") {
let intr_modifier = tokens.expect_identifier()?;
// skip the bool tokens...
PropertyAssignment::parse(tokens, parameters, intr_bool_property)?;
return Ok(Self {
prop_name: "intr",
value: match intr_modifier {
"posedge" => InterruptType::PosEdge.into(),
"negedge" => InterruptType::NegEdge.into(),
"bothedge" => InterruptType::BothEdge.into(),
"level" => InterruptType::Level.into(),
"nonsticky" => InterruptType::NonSticky.into(),
"sticky" => InterruptType::Sticky.into(),
_ => InterruptType::Level.into(),
},
});
}

let prop_name = tokens.expect_identifier()?;
let prop_meta = meta_lookup_fn(prop_name)?;

let value = if *tokens.peek(0) == Token::Semicolon {
// This must be a boolean property set to true or an intr
if prop_meta.ty != PropertyType::Boolean
&& prop_meta.ty != PropertyType::BooleanOrReference
&& prop_meta.ty != PropertyType::FieldInterrupt
{
return Err(RdlError::UnexpectedPropertyType {
expected_type: prop_meta.ty,
value: true.into(),
});
}
true.into()
} else {
tokens.expect(Token::Equals)?;
prop_meta.ty.eval(tokens, parameters)?
};
tokens.expect(Token::Semicolon)?;
Ok(Self { prop_name, value })
}
}

#[cfg(test)]
mod tests {
use crate::{file_source::MemFileSource, value::AccessType, EnumReference};
Expand Down Expand Up @@ -1034,72 +1103,3 @@ mod tests {
);
}
}

fn is_intr_modifier(token: &Token) -> bool {
matches!(
*token,
Token::Identifier("posedge" | "negedge" | "bothedge" | "level" | "nonsticky" | "sticky")
)
}

struct PropertyAssignment<'a> {
prop_name: &'a str,
value: Value,
}

static INTR_BOOL_PROPERTY: PropertyMeta = PropertyMeta {
name: "intr",
ty: PropertyType::Boolean,
is_dynamic: true,
};
fn intr_bool_property<'a>(_name: &str) -> Result<'a, &'static PropertyMeta> {
Ok(&INTR_BOOL_PROPERTY)
}

impl<'a> PropertyAssignment<'a> {
fn parse(
tokens: &mut TokenIter<'a>,
parameters: Option<&ParameterScope<'_>>,
meta_lookup_fn: impl Fn(&'a str) -> Result<'a, &'static PropertyMeta>,
) -> Result<'a, Self> {
if is_intr_modifier(tokens.peek(0)) && *tokens.peek(1) == Token::Identifier("intr") {
let intr_modifier = tokens.expect_identifier()?;
// skip the bool tokens...
PropertyAssignment::parse(tokens, parameters, intr_bool_property)?;
return Ok(Self {
prop_name: "intr",
value: match intr_modifier {
"posedge" => InterruptType::PosEdge.into(),
"negedge" => InterruptType::NegEdge.into(),
"bothedge" => InterruptType::BothEdge.into(),
"level" => InterruptType::Level.into(),
"nonsticky" => InterruptType::NonSticky.into(),
"sticky" => InterruptType::Sticky.into(),
_ => InterruptType::Level.into(),
},
});
}

let prop_name = tokens.expect_identifier()?;
let prop_meta = meta_lookup_fn(prop_name)?;

let value = if *tokens.peek(0) == Token::Semicolon {
// This must be a boolean property set to true or an intr
if prop_meta.ty != PropertyType::Boolean
&& prop_meta.ty != PropertyType::BooleanOrReference
&& prop_meta.ty != PropertyType::FieldInterrupt
{
return Err(RdlError::UnexpectedPropertyType {
expected_type: prop_meta.ty,
value: true.into(),
});
}
true.into()
} else {
tokens.expect(Token::Equals)?;
prop_meta.ty.eval(tokens, parameters)?
};
tokens.expect(Token::Semicolon)?;
Ok(Self { prop_name, value })
}
}
21 changes: 21 additions & 0 deletions runtime/apps/example/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Licensed under the Apache-2.0 license

[package]
name = "example-app"
version.workspace = true
authors.workspace = true
edition.workspace = true

[dependencies]

[target.'cfg(target_arch = "riscv32")'.dependencies]
critical-section = "1.1.2"
embassy-executor = "0.5.0"
embedded-alloc = "0.5.1"
libtock = { path = "../libtock" }
libtock_alarm = { path = "../libtock/apis/peripherals/alarm" }
libtock_console = { path = "../libtock/apis/interface/console" }
libtock_debug_panic = { path = "../libtock/panic_handlers/debug_panic" }
libtock_platform = { path = "../libtock/platform" }
libtock_runtime = { path = "../libtock/runtime" }
portable-atomic = "1.7.0"
File renamed without changes.
File renamed without changes.
File renamed without changes.
4 changes: 4 additions & 0 deletions runtime/apps/libtock/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/Cargo.lock
/nightly/target
/target
/demos/*/target
51 changes: 51 additions & 0 deletions runtime/apps/libtock/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Releases

## 0.2.0 (WIP)

### Comprehensive Changes

- Many functions are asynchronous
- To create an `async` main function you can use the attribute `#[libtock::main]`
- To retrieve the value of an asynchronous `value`, use `value.await`
- This is only possible within an `async fn`, so either
- Make the caller `fn` of `.await` an `async fn`
- Not recommended: Use `libtock::executor::block_on(value)` to retrieve the `value`
- Most API functions, including `main()`, return a `Result<T, TockError>`
- All drivers can exclusively be retrieved by `retrieve_drivers` which returns a `Drivers` singleton. Drivers can be shared between different tasks only if it is safe to do so.
- The low-level functions have been moved to a new crate called `libtock-core`. This crate is intended to be less experimental and more stable.

### Changed APIs

- The basic APIs have been made consistent. They are initialized via driver factories and no longer require a `WithCallback` object, s.t. the callback subscription is more intuitive. The affected APIs are:
- LEDs
- Buttons
- GPIO
- Temperature
- ADC (partially)
- The timer API now supports concurrent sleep operations

### Syscalls

- `syscalls::subscribe` is actually usable
- `syscalls::yieldk_for` is no longer available
- Yielding manually is discouraged as it conflicts with Rust's safety guarantees. If you need to wait for a condition, use `futures::wait_until` and `.await`.
- `syscalls::yieldk` has become `unsafe` for the same reason
- `syscalls::command` is no longer `unsafe`
- The low-level syscalls have been moved to `syscalls::raw`
- `syscalls::subscribe_ptr` becomes `syscalls::raw::subscribe`
- `syscalls::allow_ptr` becomes `syscalls::raw::allow`

### Miscellaneous

- Flashing examples is no longer restricted to the nRF52 DK board
- `./run_example.sh` has been deleted
- Instead, use `PLATFORM=<platform> cargo r<arch> <your_app>`. This will build the app for your CPU architecture and platform-specific memory layout and flash it via J-Link to your board
- Targets without support for atomics can be built
- The `TockAllocator` is no longer included by default and needs to to be opted-in via `--features=alloc`
- `hardware_test.rs` is now called `libtock_test.rs` to make clear that the intent is to test the correctness of `libtock-rs`, not the hardware or the kernel
- The panic handler can now be customized using the `custom_panic_handler` feature
- The error alloc handler can now be customized using the `custom_alloc_error_handler` feature

## a8bb4fa9be504517d5533511fd8e607ea61f1750 (0.1.0)

- First and highly experimental `libtock-rs` API
45 changes: 45 additions & 0 deletions runtime/apps/libtock/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
[package]
authors = ["Tock Project Developers <[email protected]>"]
categories = ["embedded", "no-std", "os"]
description = """Tock Rust userspace library collection. Provides all the \
tools needed to create a Tock Rust process binary."""
edition = "2021"
license = "Apache-2.0 OR MIT"
name = "libtock"
repository = "https://www.github.com/tock/libtock-rs"
version = "0.1.0"

[features]
rust_embedded = [
"embedded-hal",
"libtock_platform/rust_embedded",
"libtock_gpio/rust_embedded",
]

[dependencies]
libtock_adc = { path = "apis/peripherals/adc" }
libtock_air_quality = { path = "apis/sensors/air_quality" }
libtock_alarm = { path = "apis/peripherals/alarm" }
libtock_ambient_light = { path = "apis/sensors/ambient_light" }
libtock_buttons = { path = "apis/interface/buttons" }
libtock_buzzer = { path = "apis/interface/buzzer" }
libtock_console = { path = "apis/interface/console" }
libtock_debug_panic = { path = "panic_handlers/debug_panic" }
libtock_gpio = { path = "apis/peripherals/gpio" }
libtock_i2c_master = { path = "apis/peripherals/i2c_master" }
libtock_ieee802154 = { path = "apis/net/ieee802154" }
libtock_i2c_master_slave = { path = "apis/peripherals/i2c_master_slave" }
libtock_key_value = { path = "apis/storage/key_value" }
libtock_leds = { path = "apis/interface/leds" }
libtock_low_level_debug = { path = "apis/kernel/low_level_debug" }
libtock_ninedof = { path = "apis/sensors/ninedof" }
libtock_platform = { path = "platform" }
libtock_proximity = { path = "apis/sensors/proximity" }
libtock_rng = { path = "apis/peripherals/rng" }
libtock_runtime = { path = "runtime" }
libtock_small_panic = { path = "panic_handlers/small_panic" }
libtock_sound_pressure = { path = "apis/sensors/sound_pressure" }
libtock_spi_controller = { path = "apis/peripherals/spi_controller" }
libtock_temperature = { path = "apis/sensors/temperature" }

embedded-hal = { version = "1.0", optional = true }
Loading

0 comments on commit 0829240

Please sign in to comment.