rust-embedded / riscv

Low level access to RISC-V processors
822 stars 160 forks source link

ACLINT and CLINT peripherals #135

Closed romancardenas closed 11 months ago

romancardenas commented 1 year ago

This PR provides a generic implementation of the ACLINT and CLINT peripherals.

As suggested by @Dirbaio, I'm using a completely different approach compared to the PLIC peripheral. Instead of using a register block and the volatile-register, I use raw pointers and read_volatile and write_volatile.

Personally, I like this new approach more, as it makes it more ergonomic to interface with the registers. The const generic things turned out to be a little bit limiting, especially when dealing with multi-HART architectures.

As a side note, I added to the peripheral::common module the WARL register type. In essence, it is just an RW register (i.e., it does not have anything special). However, it implies that only legal values will be written, and therefore you cannot assume that the register will hold any value.

Please take a look and provide me with all the feedback you can. If you prefer this way (as I do), I'll happily rework the PLIC peripheral and add it to this PR before merging it.

romancardenas commented 1 year ago

No const fn with generics on stable Rust 1.59 :( Any suggestion?

romancardenas commented 1 year ago

I checked and the new MRSV would be 1.61.0. I think it is rather an important upgrade... How bad would it be if we remove the const for creating new Reg structs?

romancardenas commented 1 year ago

I've been looking at the Peripherals struct of the PACs generated by svd2rust and they are not const, so it does not make sense to keep these peripheral things const and bump the MSRV.

romancardenas commented 1 year ago

I did a rework of the peripherals with all the comments @Dirbaio gave me:

There is still something "funny" that deserves a discussion:

Personally, I think this approach is conceptually sound: it is a volatile register so you can safely write on it any bit stream with no meaning but 1s and 0s. But if your intention is to set_priority of an interrupt source (i.e., you are providing more context), then you must consider additional issues such as breaking critical sections. Somehow, both approaches live together currently, which is quite flexible. However, these things deserve further discussion to come up with a "formal"/"consistent" design pattern and document it.

romancardenas commented 1 year ago

I modified the peripheral macros to address the aforementioned issue more elegantly:

This new approach should be OK. I'll test the peripherals with my E310x board before asking the @rust-embedded/riscv team to review and merge them to master.

romancardenas commented 11 months ago

Closing this now. I'm developing RISC-V peripherals in the riscv-peripheral crate. My plan is, once we have a decent version of this crate, to nominate it to leave the RISC-V team to maintain it. Eventually, we can add all the peripherals to riscv again once we are happy with the result.