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

Prepare for 64 PMP config registers #1926

Merged
merged 5 commits into from Jun 17, 2020
Merged

Conversation

alistair23
Copy link
Contributor

Pull Request Overview

This PR was supposed to add support for 64 PMP config register on RISC-V now that it is supported by the spec.

Instead this patch has turned more info converting the riscv-csr library to use the new inline assembly macro and to allow dynamic array access to the RISC-V registers.

This PR does a few things:

  • Converts the PMP CSRs to an array (to allow simplifying the PMP code)
  • Uses the new inline assembly. Unfortunately Rust won't let use access CSR dynamically like we used to (see Inline assembly Unable to dynamically access RISC-V CSRs rust-lang/rust#73220) so we now have a giant if statement to see which one to access. I couldn't see any other way to make the value const.
  • We also implement the register functions on specific types (u32) instead of generics. This is because with generics we can't dynamically access arrays of CSRs with the inline assembly.
  • Finally we clean up some of the PMP code.

Testing Strategy

None yet.

TODO or Help Wanted

Comments please, this is uglier then I would like it to be.

Documentation Updated

  • Updated the relevant files in /docs, or no updates are required.

Formatting

  • Ran make prepush.

@bradjc bradjc added the WG-OpenTitan In the purview of the OpenTitan working group. label Jun 11, 2020
bradjc
bradjc previously approved these changes Jun 12, 2020

// Set access to end address
csr::CSR.pmpcfg1.set(cfg_val << 8 | csr::CSR.pmpcfg0.get());
csr::CSR.pmpaddr5.set((start as u32 + size as u32) >> 2);
csr::CSR.pmpcfg[1].set(cfg_val << 8 | csr::CSR.pmpcfg[0].get());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be pmpcfg[1]
please see all places where changes are needed in #1932

Copy link
Contributor

@a-pronin a-pronin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's merge in the changes from #1932

Copy link
Contributor

@gendx gendx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a couple comments that are not 100% related to this change, but it seems to me that there is some overlap with what's available in libraries/tock-register-interface. Are there any limitations to the tock-register-interface that prevent using it here?

Comment on lines 281 to 337
#[cfg(not(any(target_arch = "riscv32", target_os = "none")))]
pub fn get(&self) -> T {
pub fn get(&self) -> u32 {
unimplemented!("reading RISC-V CSR {}", self.value)
}

#[cfg(not(any(target_arch = "riscv32", target_os = "none")))]
pub fn set(&self, _val_to_set: T) {
pub fn set(&self, _val_to_set: u32) {
unimplemented!("writing RISC-V CSR {}", self.value)
}

#[inline]
pub fn read(&self, field: Field<T, R>) -> T {
pub fn read(&self, field: Field<u32, R>) -> u32 {
(self.get() & (field.mask << field.shift)) >> field.shift
}

#[inline]
pub fn read_as_enum<E: TryFromValue<T, EnumType = E>>(&self, field: Field<T, R>) -> Option<E> {
let val: T = self.read(field);
pub fn read_as_enum<E: TryFromValue<u32, EnumType = E>>(
&self,
field: Field<u32, R>,
) -> Option<E> {
let val: u32 = self.read(field);

E::try_from(val)
}

#[inline]
pub fn extract(&self) -> LocalRegisterCopy<T, R> {
pub fn extract(&self) -> LocalRegisterCopy<u32, R> {
LocalRegisterCopy::new(self.get())
}

#[inline]
pub fn write(&self, field: FieldValue<T, R>) {
pub fn write(&self, field: FieldValue<u32, R>) {
self.set(field.value);
}

#[inline]
pub fn modify(&self, field: FieldValue<T, R>) {
let reg: T = self.get();
pub fn modify(&self, field: FieldValue<u32, R>) {
let reg: u32 = self.get();
self.set((reg & !field.mask) | field.value);
}

#[inline]
pub fn modify_no_read(&self, original: LocalRegisterCopy<T, R>, field: FieldValue<T, R>) {
pub fn modify_no_read(&self, original: LocalRegisterCopy<u32, R>, field: FieldValue<u32, R>) {
self.set((original.get() & !field.mask) | field.value);
}
#[inline]
pub fn is_set(&self, field: Field<T, R>) -> bool {
self.read(field) != T::zero()
pub fn is_set(&self, field: Field<u32, R>) -> bool {
self.read(field) != u32::zero()
}

#[inline]
pub fn matches_any(&self, field: FieldValue<T, R>) -> bool {
self.get() & field.mask != T::zero()
pub fn matches_any(&self, field: FieldValue<u32, R>) -> bool {
self.get() & field.mask != u32::zero()
}

#[inline]
pub fn matches_all(&self, field: FieldValue<T, R>) -> bool {
pub fn matches_all(&self, field: FieldValue<u32, R>) -> bool {
self.get() & field.mask == field.value
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of these functions look very similar to what's already available in libraries/tock-register-interface/src/registers.rs. Is there any reason not to use that?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading a CSR requires an assembly instruction, not accessing a memory location.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A lot of the logic still overlaps with methods such as FieldValue::matches_all. The only difference that I see is in the implementation of the set and get methods - all of the other methods are derived from it in the same manner as in the libraries/tock-register-interface library.

It looks like the ReadAble and WriteAble traits that I sketched in #1766 (comment) could be beneficial here as well.

Comment on lines 23 to 30
pub minstret: ReadWriteRiscvCsr<u32, minstret::minstret::Register>,
pub mcycleh: ReadWriteRiscvCsr<u32, mcycle::mcycleh::Register>,
pub mcycle: ReadWriteRiscvCsr<u32, mcycle::mcycle::Register>,
pub pmpcfg0: ReadWriteRiscvCsr<u32, pmpconfig::pmpcfg::Register>,
pub pmpcfg1: ReadWriteRiscvCsr<u32, pmpconfig::pmpcfg::Register>,
pub pmpcfg2: ReadWriteRiscvCsr<u32, pmpconfig::pmpcfg::Register>,
pub pmpcfg3: ReadWriteRiscvCsr<u32, pmpconfig::pmpcfg::Register>,
pub pmpaddr0: ReadWriteRiscvCsr<u32, pmpaddr::pmpaddr::Register>,
pub pmpaddr1: ReadWriteRiscvCsr<u32, pmpaddr::pmpaddr::Register>,
pub pmpaddr2: ReadWriteRiscvCsr<u32, pmpaddr::pmpaddr::Register>,
pub pmpaddr3: ReadWriteRiscvCsr<u32, pmpaddr::pmpaddr::Register>,
pub pmpaddr4: ReadWriteRiscvCsr<u32, pmpaddr::pmpaddr::Register>,
pub pmpaddr5: ReadWriteRiscvCsr<u32, pmpaddr::pmpaddr::Register>,
pub pmpaddr6: ReadWriteRiscvCsr<u32, pmpaddr::pmpaddr::Register>,
pub pmpaddr7: ReadWriteRiscvCsr<u32, pmpaddr::pmpaddr::Register>,
pub pmpaddr8: ReadWriteRiscvCsr<u32, pmpaddr::pmpaddr::Register>,
pub pmpaddr9: ReadWriteRiscvCsr<u32, pmpaddr::pmpaddr::Register>,
pub pmpaddr10: ReadWriteRiscvCsr<u32, pmpaddr::pmpaddr::Register>,
pub pmpaddr11: ReadWriteRiscvCsr<u32, pmpaddr::pmpaddr::Register>,
pub pmpaddr12: ReadWriteRiscvCsr<u32, pmpaddr::pmpaddr::Register>,
pub pmpaddr13: ReadWriteRiscvCsr<u32, pmpaddr::pmpaddr::Register>,
pub pmpaddr14: ReadWriteRiscvCsr<u32, pmpaddr::pmpaddr::Register>,
pub pmpaddr15: ReadWriteRiscvCsr<u32, pmpaddr::pmpaddr::Register>,
pub pmpcfg: [ReadWriteRiscvCsr<u32, pmpconfig::pmpcfg::Register>; 4],
pub pmpaddr: [ReadWriteRiscvCsr<u32, pmpaddr::pmpaddr::Register>; 16],
pub mie: ReadWriteRiscvCsr<u32, mie::mie::Register>,
pub mscratch: ReadWriteRiscvCsr<u32, mscratch::mscratch::Register>,
pub mepc: ReadWriteRiscvCsr<u32, mepc::mepc::Register>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this definition could use the register_structs macro defined in libraries/tock-register-interface/src/macros.rs. Is there any reason not to use it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alistair is just updating what is already there, I think it is fine to not add additional changes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: my question was beyond the scope of this PR, to see if there's any improvement that could be made in libraries/tock-register-interface to improve adoption of this library, not only in chips/ but in arch/ as well.

@ppannuto
Copy link
Member

bors d=alistair23,gendx

@bors
Copy link
Contributor

bors bot commented Jun 17, 2020

✌️ alistair23 can now approve this pull request. To approve and merge a pull request, simply reply with bors r+. More detailed instructions are available here.

@bors
Copy link
Contributor

bors bot commented Jun 17, 2020

✌️ gendx can now approve this pull request. To approve and merge a pull request, simply reply with bors r+. More detailed instructions are available here.

bors bot added a commit that referenced this pull request Jun 17, 2020
1939: Make the Field::mask and FieldValue::mask fields private. r=alistair23 a=gendx

### Pull Request Overview

The `mask` fields don't need to be exposed publicly, as their use cases overlap with the existing functions to manipulate fields.

- This pull request makes them private.
- As a side effect, the `libraries/riscv-csr/src/csr.rs` is refactored to use the unified arithmetic methods introduced in #1766.


### Testing Strategy

This pull request was tested by CI.


### TODO or Help Wanted

- These changes currently overlap with #1926, although are compatible with that PR, as discussed in #1926 (comment).
- The `Field::shift` field should also be made private, but is currently used in `chips/lowrisc/src/gpio.rs`. That code should probably be refactored so that the shift is not exposed as-is. https://github.com/tock/tock/blob/555b3a0441697d111a0330c01d392c15b36712f6/chips/lowrisc/src/gpio.rs#L94-L104
- Likewise, the `FieldValue::value` field should be made private, but is currently used in https://github.com/tock/tock/blob/555b3a0441697d111a0330c01d392c15b36712f6/libraries/riscv-csr/src/csr.rs#L76-L79


### Documentation Updated

- [x] Updated the relevant files in `/docs`, or no updates are required.

### Formatting

- [x] Ran `make prepush`.

Co-authored-by: Guillaume Endignoux <guillaumee@google.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
We need to manually split these out in order to access them from inline
assembly as part of the next patch.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
@alistair23
Copy link
Contributor Author

bors r+

@alistair23
Copy link
Contributor Author

bors r+

@hudson-ayers
Copy link
Contributor

bors r+

@bors bors bot merged commit dbe8af5 into tock:master Jun 17, 2020
@alistair23 alistair23 deleted the alistair/pmp-64 branch June 22, 2020 15:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
WG-OpenTitan In the purview of the OpenTitan working group.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants