Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] supporting other architectures #203

Open
japaric opened this issue Jun 14, 2019 · 9 comments

Comments

Projects
None yet
5 participants
@japaric
Copy link
Owner

commented Jun 14, 2019

Current state

cortex-m-rtfm is the main port of the RTFM framework. There are two outdated
ports of RTFM for MSP430 and RISCV and two experimental Cortex-R and Linux
ports. None of these ports shares code with one another so they have diverged or
stalled since their inception.

The cortex-m-rtfm port is under @japaric's GitHub account and currently has 3
people maintaining it.

Proposal

This RFC proposes refactoring out the RTFM syntax (meta-language) and analysis
pass that currently live in cortex-m-rtfm into a crate that can be used to
easily implement ports for different architectures.

Rationale

We want to make RTFM available on as many architectures as possible with minimal
maintenance effort and with as similar APIs / syntax as possible.

Detailed design

This RFC proposes the following crate hierarchy:

rtfm-core

This crate will only contain the Mutex trait and the Exclusive newtype and
it's meant to be used to implement generic library code.

pub trait Mutex {
    type Data;

    fn lock<T>(&mut self, f: impl FnOnce(&mut Self::Data) -> T) -> T;
}

pub struct Exclusive<T>(pub &'a mut T);

// trivial implementation (no-op)
impl<T> Mutex for Exclusive<T> { .. }

rtfm-syntax

This crate will contain the parser of the #[app] and the analysis pass (e.g.
priority ceiling analysis) of the RTFM specification.

The main function in this crate is the parse function which parse the input of
the #[app] attribute.

use syn::Parse;

use crate::{ast::App, analyze::Analysis};

pub fn parse(
    args: TokenStream,
    input: TokenStream,
    settings: Settings,
) -> parse::Result<(App, Analysis) {
    ..
}

To accommodate the different capabilities of the many RTFM ports this function
takes a Settings struct that indicates which extensions the port implements.

pub struct Settings {
    // multi-core support: `#[app(cores = ..)]`, `#[task(core = ..)]`, etc.
    pub parse_cores: bool,

    // `#[exception]`
    pub parse_exception: bool,

    // `#[interrupt]`
    pub parse_interrupt: bool,

    // `schedule` API
    pub parse_schedule: bool,

    // `extern { fn interrupt(); }`
    pub parse_extern_interrupt: bool,

    // ..
}

$ARCH-rtfm

These are the actual ports. These crates will use the rtfm-syntax crate to
implement the #[app] attribute and they'll re-export the rtfm-core API.

All ports must implement the following API:

  • the lock API
  • runtime initialized (late) resources
  • software #[task]s and spawn API

And they may implement any of these extensions:

  • #[exception] API

  • #[interrupt] API

  • schedule API

  • multi-core support

GitHub org

All these crates will be owned by the rtfm-rs GitHub organization and
maintained by the members of the organization. The idea is to grow the
membership of the organization to include people with expertise on
architectures other than ARM Cortex-M.


I have already done the refactor and have tested the portability of the
rtfm-syntax crate by implementing a Linux port (base features +
schedule + multi-core support) and the single-core and multi-core variants of
cortex-m-rtfm (see PR #205).

cc'ing people that may be interested in other ports:

@Disasm (rust-embedded/riscv)
@cr1901 @pftbest (rust-embedded/msp430)

@japaric japaric added the RFC label Jun 14, 2019

@japaric japaric added this to the v0.5.0 milestone Jun 14, 2019

@Disasm

This comment has been minimized.

Copy link

commented Jun 14, 2019

I'm interested in having RTFM for RISC-V, however I need to understand possible RISC-V-related limitations and how to deal with them (if possible).

  • We have "exception", "interrupt" and "IRQ" concepts. IRQs are different and defined on device-level and even may not exists at all.
  • SMP (not AMP) support on some chips.
  • We have priorities only for IRQs. Additionally, platform-dependent PLIC implementation can support an arbitrary (yet fixed) number of priorities.
  • Timers are accessed in a device-dependent way.
  • Some "devices" are FPGA softcores that do not have Privileged Architecture parts at all. No timers, no interrupts (standardized), no ability to check the current core id.

P.S. I'm not quite familiar with RTFM, so I need to study it first in detail.

@cr1901

This comment has been minimized.

Copy link

commented Jun 14, 2019

I need to view @korken89's presentation on RTFM before I could meaningfully contribute a port, but I am very interested and supportive of this proposal.

This would also be a good opportunity to flesh out what features are feasible to support on archs more constrained than cortex-m (e.g. msp430 has nowhere near the amount of priority levels NVIC does).

@japaric

This comment has been minimized.

Copy link
Owner Author

commented Jun 16, 2019

@Disasm I have a prototype implementation that targets the HiFive1 board here. The prototype implements the core API plus the schedule and #[interrupt] extensions.

IRQs are different and defined on device-level and even may not exists at all.

Even if you have zero IRQs, you can use the (machine) software (MSI) / timer (MTI) interrupt to implement (software) tasks.

We have priorities only for IRQs

But you can individually mask interrupts (MSIE, MTIE, etc.); it's possible to implement some form of prioritization (and critical sections) using interrupt masking.

SMP (not AMP) support on some chips.

(I have one of those K210 chips; too bad my "development" board has no on-board debugger (and I have no JTAG probe around) so I can't actually do any actual development on it ...)

Timers are accessed in a device-dependent way.

mtime and mtimecmp seem rather standard to me. They may be memory mapped registers and their address may be device-dependent but their binary interface and semantics are well specified. In any case, timers are not necessary to implement the core API.

Some "devices" are FPGA softcores that do not have Privileged Architecture parts at all.

We could state that some privileged parts are required to use RTFM on RISCV. If the softcore has zero support for interrupts / preemption then we can't run RTFM on it.

@Disasm

This comment has been minimized.

Copy link

commented Jun 16, 2019

@japaric Thanks for making the prototype!

too bad my "development" board has no on-board debugger (and I have no JTAG probe around)

I use BusBlaster based on FTDI chip, but I think that any JTAG adapter for FPGA would work.

mtime and mtimecmp seem rather standard to me. They may be memory mapped registers and their address may be device-dependent but their binary interface and semantics are well specified. In any case, timers are not necessary to implement the core API.

They are standard, but due to their device-dependent addressing I have no idea how to pass them to the RTFM implementation. Of cause, we could tie riscv-rtfm to the FE310 chip family, but this solution is far from perfect.

@japaric

This comment has been minimized.

Copy link
Owner Author

commented Jun 19, 2019

@Disasm

They are standard, but due to their device-dependent addressing I have no idea how to pass them to the RTFM implementation.

As part of the prototype I wrote a riscv crate from scratch (to force me to read the RISC-V spec). That crate contains an API to access the mtime and mtimecmp registers. To get around the device specific address I used symbols. In the riscv crate the address of the mtime register is an external symbol; this symbol must be provided by a device crate (PAC) like the hifive1 crate in that repository.

With this approach any crate can use the mtime register by depending only on riscv and not on any particular device crate. When building an application where the mtime API is used a device crate must appear in the dependency graph or you get a not really helpful error. The symbol, and the device crate, don't need to appear in the dependency graph when building libraries that use the mtime API.

There are other ways to pass device specific information to the RTFM runtime though. The Cortex-M port uses a device argument, which is a path to a module, in its #[app] attribute. This module is expected to contain an enumeration of all interrupts (Interrupt), the number of priority bits (const NVIC_PRIO_BITS: u8), etc. It's also possible for ports to define other custom #[app] arguments. One example is the monotonic argument proposed in RFC #200.

@korken89

This comment has been minimized.

Copy link
Collaborator

commented Jun 25, 2019

I think this is a great idea!
The power that SRP gives through this framework should fit a lot more than Cortex-M, and this is indeed a great way to get there.
I also hope that something like this would help with the readability of the code, as this is quite a challenge today.

@japaric

This comment has been minimized.

Copy link
Owner Author

commented Jun 29, 2019

This proposal has been well received so I'm going to FCP it with disposition to merge it.

We can start right away with the refactor and take our time to roll out the org. (One extra thing I'd like to do is create an rfcs repo and archive all these RFCs as proper markdown files).

@TeXitoi

This comment has been minimized.

Copy link
Collaborator

commented Jun 29, 2019

OK for me

@japaric

This comment has been minimized.

Copy link
Owner Author

commented Jul 8, 2019

🎉 This RFC has been formally approved. The refactor part is in PR #205.

@japaric japaric added S-accepted and removed disposition-merge labels Jul 8, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.