2个版本
0.1.0-alpha.5 | 2020年4月14日 |
---|---|
0.1.0-alpha.4 | 2019年10月15日 |
0.1.0-alpha.3 |
|
0.1.0-alpha.2 |
|
0.1.0-alpha.1 |
|
10 在 #asymmetric 中排名
每月25 次下载
在 3 个crate中使用(通过 microamp)
5KB
78 行
μAMP
一个用于构建裸机AMP(非对称多处理)应用的(微)框架
特性
-
允许您编写单源多核应用程序
-
为处理器间通信提供零成本的共享内存抽象。
-
使用内置的的条件编译功能(
#[cfg(core = "0")]
/cfg!(core = "1")
)将您的应用程序分割到各个核心之间。
计划中的特性
- 多目标支持。
该框架目前使用所有核心的相同编译目标。这限制了支持的系统为同构多核设备(所有核心使用相同的指令集)和异构多核设备,其中核心共享最低的共同指令集(例如,Cortex-M4 + Cortex-M0设备中的两个核心都可以运行为thumbv6m-none-eabi
编译的程序)。
我们需要设计(并测试)一个命令行标志,用于指定或覆盖每个核心的编译目标。
已知限制
- 该框架目前仅支持ARM架构。
为了消除这个限制,我们需要在Rust中实现strip
命令的功能。具体来说,需要将以下调用移植到Rust中:strip -R '*' -R '!.shared' --strip-unneeded
。如果您知道任何可以做到这一点的crate,请在问题跟踪器中告诉我!
已知问题
- 在核心之间发送/共享函数指针或特质对象可能是不可靠的,或者至少是一个非常糟糕的想法,但对于函数指针来说,这并不是完全被拒绝的。
框架试图在编译时防止这种操作。目前所有特质对象都被拒绝,但只有0到12个参数的函数指针被拒绝。要拒绝所有函数指针,我们需要变长泛型(VG)语言特性。
示例
以下是一个在均匀双核设备(2x Cortex-R5核心)上运行的程序。
#![no_main]
#![no_std]
use core::sync::atomic::{AtomicU8, Ordering};
use arm_dcc::dprintln;
use microamp::shared;
use panic_dcc as _; // panic handler
use zup_rt::entry;
// non-atomic variable
#[shared] // <- means: same memory location on all the cores
static mut SHARED: u64 = 0;
// used to synchronize access to `SHARED`
#[shared]
static SEMAPHORE: AtomicU8 = AtomicU8::new(CORE0);
// possible values for SEMAPHORE
const CORE0: u8 = 0;
const CORE1: u8 = 1;
const LOCKED: u8 = 2;
#[entry]
fn main() -> ! {
let (our_turn, next_core) = if cfg!(core = "0") {
(CORE0, CORE1)
} else {
(CORE1, CORE0)
};
dprintln!("START");
let mut done = false;
while !done {
// try to acquire the lock
while SEMAPHORE
.compare_exchange(our_turn, LOCKED, Ordering::AcqRel, Ordering::Relaxed)
.is_err()
{
// busy wait if the lock is held by the other core
}
// we acquired the lock; now we have exclusive access to `SHARED`
unsafe {
if SHARED >= 10 {
// stop at some arbitrary point
done = true;
} else {
dprintln!("{}", SHARED);
SHARED += 1;
}
}
// release the lock & unblock the other core
SEMAPHORE.store(next_core, Ordering::Release);
}
dprintln!("DONE");
loop {}
}
在这个示例中,我们在共享内存中有两个静态变量,这两个变量对两个核心都是可见的(*)。其中一个变量SEMAPHORE
,用于同步对非原子的SHARED
变量的访问。两个核心都会在引导时执行main
函数,但由于使用了cfg!
宏,它们将执行略有不同的代码路径。
构建应用程序时,我们使用以下命令
$ cargo microamp --bin app --release
Compiling zup-rtfm v0.1.0 (/tmp/firmware)
Finished dev [unoptimized + debuginfo] target(s) in 0.32s
Compiling zup-rtfm v0.1.0 (/tmp/firmware)
Finished dev [unoptimized + debuginfo] target(s) in 0.12s
Compiling zup-rtfm v0.1.0 (/tmp/firmware)
Finished dev [unoptimized + debuginfo] target(s) in 0.12s
默认情况下,该命令会产生两个镜像,每个核心一个。
$ # image for first core
$ size -Ax target/armv7r-none-eabi/release/examples/app-0
target/armv7r-none-eabi/release/examples/app-0 :
section size addr
.text 0x360 0x0
.local 0x0 0x20000
.bss 0x0 0xfffc0000
.data 0x0 0xfffc0000
.rodata 0x40 0xfffc0000
.shared 0x10 0xfffe0000
$ # image for second core
$ size -Ax target/armv7r-none-eabi/release/examples/app-1
target/armv7r-none-eabi/release/examples/app-1 :
section size addr
.text 0x360 0x0
.local 0x0 0x20000
.bss 0x0 0xfffd0000
.data 0x0 0xfffd0000
.rodata 0x40 0xfffd0000
.shared 0x10 0xfffe0000
如果我们在这0号核心上运行镜像,我们会看到
$ # on another terminal: load and run the program
$ CORE=0 xsdb -interactive debug.tcl amp-shared-0
$ # output of core #0
$ tail -f dcc0.log
START
0
程序停止,因为它正在等待另一个核心。现在,我们在1号核心上运行另一个镜像。
$ # on another terminal: load and run the program
$ CORE=1 xsdb -interactive debug.tcl amp-shared-1
$ # output of core #1
$ tail -f dcc1.log
START
1
3
5
7
9
DONE
然后,我们会从0号核心获得新的输出。
$ # output of core #0
$ tail -f dcc0.log
START
0
2
4
6
8
DONE
(*)重要所有未标记为#[shared]
的静态变量将针对每个核心进行实例化,并且由于编译器优化和链接器脚本的不同,它们很可能有不同的地址(即使它们有相同的符号名)。例如,非#[shared]
变量static mut X: u32
在其中一个镜像中的地址可能是0xffe20000
,而在另一个镜像中的地址可能是0xffeb0000
。
要求
用户或crate必须为每个核心提供一个链接脚本。 cargo-microamp
工具将使用这些链接脚本为每个核心链接程序,并期望它们命名为core0.x
、core1.x
等。
cargo-microamp
将在链接每个镜像时传递一个名为microamp-data.o
的文件。这个目标文件包含所有标记为#[shared]
的变量,它们位于名为.shared
的段中。这些变量必须放置在名为.shared
的输出段中。这个段必须在所有镜像中位于相同的地址。例如
$ cat core0.x
SECTIONS
{
/* .. */
.shared : ALIGN(4)
{
KEEP(microamp-data.o(.shared));
. = ALIGN(4);
} > OCM0
/* .. */
}
$ cat core1.x
SECTIONS
{
/* .. */
/* NOTE(NOLOAD) core 0 will initialize this shared section */
.shared (NOLOAD) : ALIGN(4)
{
KEEP(microamp-data.o(.shared));
. = ALIGN(4);
} > OCM0
/* .. */
}
此外,还必须注意不要重复初始化这个.shared
链接部分。在上面的示例中,共享变量是在第一个图像被加载到内存时初始化的。
许可证
所有源代码(包括代码片段)都受以下其中一种许可证的许可:
-
Apache许可证,版本2.0 (LICENSE-APACHE 或 https://www.apache.org/licenses/LICENSE-2.0)
-
MIT许可证 (LICENSE-MIT 或 https://opensource.org/licenses/MIT)
由您选择。
书中的书面文字受Creative Commons CC-BY-SA v4.0许可证的条款约束 (LICENSE-CC-BY-SA 或 https://creativecommons.org/licenses/by-sa/4.0/legalcode)。
贡献
除非您明确表示,否则根据Apache-2.0许可证定义的,您有意提交供作品包含的贡献,将按上述许可进行许可,没有附加条款或条件。
依赖关系
~1.5MB
~36K SLoC