Skip to content

Add Smstateen/Ssstateen Extension and CSRs #592

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

Open
wants to merge 31 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
6a3c81c
add smstateen/ssstateen CSRs
neverlandiz Apr 4, 2025
be264c6
Merge branch 'main' into add-smstateen-sstateen
neverlandiz Apr 21, 2025
f981030
lots of minor fixes
neverlandiz Apr 24, 2025
4348f66
merging
neverlandiz Apr 24, 2025
f147046
merge
neverlandiz Apr 26, 2025
601efbe
lots of backticks
neverlandiz Apr 26, 2025
a5108d2
minor fixes
neverlandiz Apr 28, 2025
8bb0d30
modified descriptions
neverlandiz Apr 29, 2025
0807a91
Merge branch 'main' into add-smstateen-sstateen
neverlandiz Apr 29, 2025
e5fa958
remove pre-commit-config.yaml from pr
neverlandiz May 1, 2025
fffabda
remove pre-commit file changes
neverlandiz May 1, 2025
daa12b4
Merge branch 'main' into add-smstateen-sstateen
neverlandiz May 1, 2025
354ed45
add definedBy for fields
neverlandiz May 1, 2025
9484789
add sw_write and sw_read for alias
neverlandiz May 1, 2025
493e97c
add long names
neverlandiz May 5, 2025
843c1c6
structured format descriptions
neverlandiz May 5, 2025
a3f75bb
finish adding structured format
neverlandiz May 5, 2025
f4c73f3
change mstateen* reset values to 0
neverlandiz May 5, 2025
de434ae
docs(stateen): comment out Zfinx & Zdinx code + add sw_read
neverlandiz May 6, 2025
d074a3e
docs(stateen): change C field description
neverlandiz May 6, 2025
4321a85
Merge branch 'main' into add-smstateen-sstateen
neverlandiz May 6, 2025
efc3bff
docs(stateen): fix syntax errors
neverlandiz May 6, 2025
659aa3a
docs(stateen): syntax
neverlandiz May 6, 2025
405103b
docs(stateen): add sw_write for sstateen CSRs
neverlandiz May 8, 2025
240b895
docs(stateen): add sw_write for hstateen* CSRs
neverlandiz May 8, 2025
59a027a
Merge branch 'main' into add-smstateen-sstateen
neverlandiz May 8, 2025
838355d
docs(stateen): syntax fixes
neverlandiz May 8, 2025
eb9b003
docs(stateen): syntax fixes
neverlandiz May 8, 2025
5d4e1be
docs(stateen): more fixes
neverlandiz May 8, 2025
3bc9359
docs(stateen): syntax fix
neverlandiz May 8, 2025
a439395
fix
neverlandiz May 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 201 additions & 0 deletions arch/csr/hstateen0.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
# yaml-language-server: $schema=../../schemas/csr_schema.json

$schema: "csr_schema.json#"
kind: csr
name: hstateen0
long_name: Hypervisor State Enable 0 Register
address: 0x60C
priv_mode: S
length: MXLEN
description:
- id: csr-hstateen0-purpose
normative: true
text: |
Each bit of a `stateen` CSR controls less-privileged access to an extension’s state,
for an extension that was not deemed "worthy" of a full XS field in `sstatus` like the
FS and VS fields for the F and V extensions.
- id: csr-hstateen0-num-justification
normative: false
text: |
The number of registers provided at each level is four because it is believed that
4 * 64 = 256 bits for machine and hypervisor levels, and 4 * 32 = 128 bits for
supervisor level, will be adequate for many years to come, perhaps for as long as
the RISC-V ISA is in use.
The exact number four is an attempted compromise between providing too few bits on
the one hand and going overboard with CSRs that will never be used on the other.
- id: csr-hstateen0-scope
normative: true
text: |
The `stateen` registers at each level control access to state at all less-privileged
levels, but not at its own level.
- id: csr-hstateen0-effect
normative: true
text: |
When a `stateen` CSR prevents access to state for a privilege mode, attempting to execute
in that privilege mode an instruction that implicitly updates the state without reading
it may or may not raise an illegal instruction or virtual instruction exception.
Such cases must be disambiguated by being explicitly specified one way or the other.
In some cases, the bits of the `stateen` CSRs will have a dual purpose as enables for the
ISA extensions that introduce the controlled state.
- id: csr-hstateen0-encodings
normative: true
text: |
With the hypervisor extension, the `hstateen` CSRs have identical encodings to the `mstateen` CSRs,
except controlling accesses for a virtual machine (from VS and VU modes).
- id: csr-hstateen0-zero
normative: true
text: |
For every bit in an `hstateen` CSR that is zero (whether read-only zero or set to zero),
the same bit appears as read-only zero in `sstateen` when accessed in VS-mode.
- id: csr-hstateen0-read-only
normative: true
text: |
A bit in an `hstateen` CSR cannot be read-only one unless the same bit is read-only one
in the matching `mstateen` CSR.

definedBy:
allOf:
- H
- Smstateen
- Ssstateen
fields:
SE0:
long_name: sstateen0 access control
location: 63
base: 64
description: |
The SE0 bit in `hstateen0` controls access to the `sstateen0` CSR.
type: RW
reset_value: UNDEFINED_LEGAL
sw_write(csr_value): |
if (CSR[mstateen0].SE0 == 1'b0){
return 0;
}
ENVCFG:
Copy link
Contributor

Choose a reason for hiding this comment

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

The {h/s}stateen bits are 0 if the corresponding mstateen bit is 0. It doesn't look like that is captured here right now. I assume this needs a sw_read() call to represent this?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yep, that's right.

Copy link
Contributor Author

@neverlandiz neverlandiz May 5, 2025

Choose a reason for hiding this comment

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

@jordancarlin Thanks for pointing that out! Could you check if this implementation is correct (for hstateen0)?

sw_read(): |
  # for every bit in an mstateen CSR that is zero, the same bit 
  # appears as read-only zero in the matching hstateen CSR

  Bit<64> mstateen0_mask = CSR[mstateen0].csr_value;
  Bit<64> hstateen0_value = csr_value & mstateen0_mask;
  return hstateen0_value;

Copy link
Contributor

Choose a reason for hiding this comment

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

I think that seems reasonable. For sstateen it will probably be a little more complicated since it changes depending on if the H extension is enabled.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks!

Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we need a sw_write() here, too, that enforces read-only for corresponding bits that are zero in mstateen0?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Would it make sense to use type() instead of sw_write() to set the specific field to RO whenever the corresponding field is zero? For example, when CSR[mstateen0].JVT is 0, then CSR[sstateen0].JVT would have type RO.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I understand type() to be an expression that must be knowable at compile time. Since JVT can vary during runtime, I believe it needs to be a dynamic check with each write operation.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I thought to look at the definition of that attribute in the schema to see if what I was saying was (1) accurate, and (2) documented, and nicely it is:

        "type()": {
          "type": "string",
          "description": "Function that returns a configuration-dependent type. The return value should be a CsrFieldType enum, and must be compile-time-known."
        },

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I see, thanks for the clarification!

long_name: senvcfg access control
location: 62
definedBy:
name: S
version: ">= 1.11"
base: 64
description: |
The ENVCFG bit in `hstateen0` controls access to the `senvcfg` CSRs.
type: RW
reset_value: UNDEFINED_LEGAL
sw_write(csr_value): |
if (CSR[mstateen0].ENVCFG == 1'b0){
return 0;
}
CSRIND:
long_name: siselect and sireg* access control
location: 60
definedBy: Sscsrind
base: 64
description: |
The CSRIND bit in `hstateen0` controls access to the `siselect` and the
`sireg*`, (really `vsiselect` and `vsireg*`) CSRs provided by the Sscsrind
extensions.
type: RW
reset_value: UNDEFINED_LEGAL
sw_write(csr_value): |
if (CSR[mstateen0].CSRIND == 1'b0){
return 0;
}
AIA:
long_name: Ssaia state access control
location: 59
definedBy: Ssaia
base: 64
description: |
The AIA bit in `hstateen0` controls access to all state introduced by
the Ssaia extension and is not controlled by either the CSRIND or the
IMSIC bits of `hstateen0`.
type: RW
reset_value: UNDEFINED_LEGAL
sw_write(csr_value): |
if (CSR[mstateen0].AIA == 1'b0){
return 0;
}
IMSIC:
long_name: IMSIC state access control
location: 58
definedBy: Ssaia
base: 64
description: |
The IMSIC bit in `hstateen0` controls access to the guest IMSIC state,
including CSRs `stopei` (really `vstopei`), provided by the Ssaia extension.

Setting the IMSIC bit in `hstateen0` to zero prevents a virtual machine
from accessing the hart’s IMSIC the same as setting `hstatus.`VGEIN = 0.
type: RW
reset_value: UNDEFINED_LEGAL
sw_write(csr_value): |
if (CSR[mstateen0].IMSIC == 1'b0){
return 0;
}
CONTEXT:
long_name: scontext access control
location: 57
definedBy: Sdtrig
base: 64
description: |
The CONTEXT bit in `hstateen0` controls access to the `scontext` CSR provided
by the Sdtrig extension.
type: RW
reset_value: UNDEFINED_LEGAL
sw_write(csr_value): |
if (CSR[mstateen0].CONTEXT == 1'b0){
return 0;
}
JVT:
long_name: jvt access control
location: 2
definedBy: Zcmt
description: |
The JVT bit controls access to the `jvt` CSR provided by the Zcmt extension.
type: RW
reset_value: UNDEFINED_LEGAL
sw_write(csr_value): |
if (CSR[mstateen0].JVT == 1'b0){
return 0;
}
FCSR:
long_name: fcsr access control
location: 1
#definedBy:
#anyOf: [Zfinx, Zdinx]
description: |
The FCSR bit controls access to `fcsr` for the case when floating-point instructions
operate on `x` registers instead of `f` registers as specified by the Zfinx and related
extensions (Zdinx, etc.). Whenever `misa.F` = 1, FCSR bit of `mstateen0` is read-only
zero (and hence read-only zero in `hstateen0` and `sstateen0` too). For convenience,
when the `stateen` CSRs are implemented and `misa.F` = 0, then if the FCSR bit of a
controlling `stateen0` CSR is zero, all floating-point instructions cause an illegal
instruction trap (or virtual instruction trap, if relevant), as though they all access
`fcsr`, regardless of whether they really do.
type: RW
reset_value: UNDEFINED_LEGAL
sw_write(csr_value): |
if (CSR[mstateen0].FCSR == 1'b0){
return 0;
}
C:
long_name: custom state access control
location: 0
description: |
The C bit controls access to any and all custom state. The C bit of these registers is
not custom state itself; it is a standard field of a standard CSR, either `mstateen0`,
`hstateen0`, or `sstateen0`.
type: RW
reset_value: UNDEFINED_LEGAL
sw_write(csr_value): |
if (CSR[mstateen0].C == 1'b0){
return 0;
}
sw_read(): |
# for every bit in an mstateen CSR that is zero, the same bit
# appears as read-only zero in the matching hstateen CSR

Bits<64> mstateen0_mask = $bits(CSR[mstateen0]);
Bits<64> hstateen0_value = $bits(CSR[hstateen0]) & mstateen0_mask;
return hstateen0_value;
142 changes: 142 additions & 0 deletions arch/csr/hstateen0h.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# yaml-language-server: $schema=../../schemas/csr_schema.json

$schema: "csr_schema.json#"
kind: csr
name: hstateen0h
long_name: Upper 32 bits of Hypervisor State Enable 0 Register
address: 0x61C
priv_mode: S
length: 32
base: 32
description:
- id: csr-hstateen0h-purpose
normative: true
text: |
For RV64 harts, the Smstateen/Ssstateen extension adds four new 64-bit CSRs at machine level: `mstateen0` (Machine State Enable 0),
`mstateen1`, `mstateen2`, and `mstateen3`. If supervisor mode is implemented, another four CSRs are defined at
supervisor level: `sstateen0`, `sstateen1`, `sstateen2`, and `sstateen3`. And if the hypervisor extension is implemented,
another set of CSRs is added: `hstateen0`, `hstateen1`, `hstateen2`, and `hstateen3`.

For RV32, the registers listed above are 32-bit, and for the machine-level and hypervisor CSRs there is a corresponding
set of high-half CSRs for the upper 32 bits of each register: `mstateen0h`, `mstateen1h`, `mstateen2h`, `mstateen3h`, `hstateen0h`,
`hstateen1h`, `hstateen2h`, and `hstateen3h`.

definedBy:
allOf:
- H
- Smstateen
- Ssstateen
fields:
SE0:
long_name: sstateen0 access control
location: 31
alias: hstateen0.SE0
sw_write(csr_value): |
if (CSR[mstateen0].SE0 == 1'b0){
return 0;
}
else{
CSR[hstateen0].SE0 = csr_value.SE0;
return csr_value.SE0;
}
description: |
The SE0 bit in `hstateen0h` controls access to the `sstateen0` CSR.
type: RW
reset_value: UNDEFINED_LEGAL
ENVCFG:
long_name: senvcfg access control
location: 30
definedBy:
name: S
version: ">= 1.11"
alias: hstateen0.ENVCFG
sw_write(csr_value): |
if (CSR[mstateen0].ENVCFG == 1'b0){
return 0;
}
else{
CSR[hstateen0].ENVCFG = csr_value.ENVCFG;
return csr_value.ENVCFG;
}
description: |
The ENVCFG bit in `hstateen0h` controls access to the `senvcfg` CSRs.
type: RW
reset_value: UNDEFINED_LEGAL
CSRIND:
long_name: siselect and sireg* access control
location: 28
definedBy: Sscsrind
alias: hstateen0.CSRIND
sw_write(csr_value): |
if (CSR[mstateen0].CSRIND == 1'b0){
return 0;
}
else{
CSR[hstateen0].CSRIND = csr_value.CSRIND;
return csr_value.CSRIND;
}
description: |
The CSRIND bit in `hstateen0h` controls access to the `siselect` and the
`sireg*`, (really `vsiselect` and `vsireg*`) CSRs provided by the Sscsrind
extensions.
type: RW
reset_value: UNDEFINED_LEGAL
AIA:
long_name: Ssaia state access control
location: 27
definedBy: Ssaia
alias: hstateen0.AIA
sw_write(csr_value): |
if (CSR[mstateen0].AIA == 1'b0){
return 0;
}
else{
CSR[hstateen0].AIA = csr_value.AIA;
return csr_value.AIA;
}
description: |
The AIA bit in `hstateen0h` controls access to all state introduced by
the Ssaia extension and is not controlled by either the CSRIND or the
IMSIC bits of `hstateen0`.
type: RW
reset_value: UNDEFINED_LEGAL
IMSIC:
long_name: IMSIC state access control
location: 26
definedBy: Ssaia
alias: hstateen0.IMSIC
sw_write(csr_value): |
if (CSR[mstateen0].IMSIC == 1'b0){
return 0;
}
else{
CSR[hstateen0].IMSIC = csr_value.IMSIC;
return csr_value.IMSIC;
}
description: |
The IMSIC bit in `hstateen0h` controls access to the guest IMSIC state,
including CSRs `stopei` (really `vstopei`), provided by the Ssaia extension.

Setting the IMSIC bit in `hstateen0h` to zero prevents a virtual machine
from accessing the hart’s IMSIC the same as setting `hstatus.`VGEIN = 0.
type: RW
reset_value: UNDEFINED_LEGAL
CONTEXT:
long_name: scontext access control
location: 25
definedBy: Sdtrig
alias: hstateen0.CONTEXT
sw_write(csr_value): |
if (CSR[mstateen0].CONTEXT == 1'b0){
return 0;
}
else{
CSR[hstateen0].CONTEXT = csr_value.CONTEXT;
return csr_value.CONTEXT;
}
description: |
The CONTEXT bit in `hstateen0h` controls access to the `scontext` CSR provided
by the Sdtrig extension.
type: RW
reset_value: UNDEFINED_LEGAL
sw_read(): return $bits(CSR[hstateen0])[63:32];
Loading
Loading