-
Notifications
You must be signed in to change notification settings - Fork 241
Change is_CSR_accessible return type to CSRAccessResult enum #1357
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
base: master
Are you sure you want to change the base?
Conversation
model/core/sys_regs.sail
Outdated
| function clause is_CSR_accessible(0x142, _, _) = currentlyEnabled(Ext_S) // scause | ||
| function clause is_CSR_accessible(0x143, _, _) = currentlyEnabled(Ext_S) // stval | ||
| function clause is_CSR_accessible(0x140, _, _) = if currentlyEnabled(Ext_S) then CSRAccessSuccess else CSRNotExist // sscratch | ||
| function clause is_CSR_accessible(0x142, _, _) = if currentlyEnabled(Ext_S) then CSRAccessSuccess else CSRNotExist // scause |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| function clause is_CSR_accessible(0x142, _, _) = if currentlyEnabled(Ext_S) then CSRAccessSuccess else CSRNotExist // scause | |
| function clause is_CSR_accessible(0x142, _, _) = csrDefinedBy(Ext_S) // scause |
How about using a helper function (not sure what the best name is though) for the simple case where it just depends on an extension being enabled?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
existsIfEnabled(Ext_S) or accessibleIfEnabled(Ext_S)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either of these sound good to me. I think it might also make sense to have a variant for the *h CSRs to avoid complicated if then else
| match check_CSR(csr, cur_privilege, is_CSR_Write) { | ||
| CSRAccessSuccess => (), | ||
| CSRAccessIllegal => return Illegal_Instruction(), | ||
| CSRNotExist => return Illegal_Instruction(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So currently these have exactly the same effect? What will the difference be in future? I think we need a comment for that.
model/core/sys_regs.sail
Outdated
| function clause is_CSR_accessible(0x10A, _, _) = currentlyEnabled(Ext_S) // senvcfg | ||
| function clause is_CSR_accessible(0x30A, _, _) = if currentlyEnabled(Ext_U) then CSRAccessSuccess else CSRNotExist // menvcfg | ||
| function clause is_CSR_accessible(0x31A, _, _) = if currentlyEnabled(Ext_U) & (xlen == 32) then CSRAccessSuccess else CSRNotExist // menvcfgh | ||
| function clause is_CSR_accessible(0x10A, _, _) = if currentlyEnabled(Ext_S) then CSRAccessSuccess else CSRNotExist // senvcfg |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CSRNotExist at least doesn't feel like the right name here, even if it is the right behaviour. The CSR can still exist, but just be temporarily inaccessible if supervisor mode is disabled for example.
I guess you could say it effectively doesn't exist at that time... maybe we can think of a better name. Probably the names should refer to the actual effect that returning them has, but as it is the same at the moment I don't know what to suggest.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
then we use CSRNotEffective and CSREffectiveIfEnabled(Ext_S)? And only use CSRNotExist in fallback.
303d8e2 to
ab7fc10
Compare
|
I just split CSRNotExist into these two
I have also categorized things like xlen == 32 to CSRNotEnabled, because according to the manual, you can modify the width of a CSR by changing SXLEN at runtime. I also considered whether CSRNotEnabled needs to be further divided into
But you have to do a lot of work, for example function clause currentlyEnabled(Ext_U) = hartSupports(Ext_U) & misa[U] == 0b1 & currentlyEnabled(Ext_Zicsr)
function clause is_CSR_accessible(0x30A, _, _) = currentlyEnabled(Ext_U) // menvcfg
currentlyEnabled(Ext_U)
|
v
if hartSupports(Ext_U) & hartSupports(Ext_Zicsr) then
// Here you can just check `misa[U] == 0b1`, but you must carefully check
// the intersection of each `currentlyEnabled` and `hartSupports`.
if currentlyEnabled(Ext_U) & currentlyEnabled(Ext_Zicsr)
then CSRNotEnabled
else CSRAccessSuccess
else CSRNotSupportedConsidering we don't need such a detailed division at the moment, I don't really plan to do this. |
model/core/csr_begin.sail
Outdated
| // "When MXLEN=32, the SXL and UXL fields do not exist, and SXLEN=32 and UXLEN=32. | ||
| // When MXLEN=64, if S-mode is not supported, then SXL is read-only zero. Otherwise, | ||
| // it is a WARL field that encodes the current value of SXLEN." | ||
| CSRNotEnabled, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is this different from CSRAccessIllegal? I think those two cases could be merged?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am just thinking out loud here but CSRAccessIllegal could mean in the current context that U-mode is accessing an M-mode CSR or that the CSR does not exist, or writing into a read-only CSR. CSRNotEnabled would apply if FP or vector CSRs are currently disabled, so the CSR exists but access is not permitted at the moment. But my thoughts do not match the comments in the code above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess both of those are just a special case of the "illegal" case. Do we need to distinguish this for anything other than improved logging? Looking at the current diff, handling those specializations adds significant extra logic that could be simpler otherwise:
function clause is_CSR_accessible(0xC02, priv, _) = if currentlyEnabled(Ext_Zicntr) then
if currentlyEnabled(Ext_Zicntr) & counter_enabled(2, priv) then CSRAccessSuccess else CSRAccessIllegal
else CSRNotEnabled // instret
Could just be
function clause is_CSR_accessible(0xC02, priv, _) = CSREnabledIf(Ext_Zicntr, counter_enabled(2, priv)) // instret
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do think it's valuable to differentiate CSRAccessIllegal and CSRNotDefined, since the trace can then show "access to unknown CSR" and for CSRAccessIllegal "access constraints not met" or similar.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another reason for the distinction is that there are a few CSRs that are explicitly defined to throw illegal instruction exceptions, but the general case of accessing an undefined CSR is implementation dependent. Right now the model throws an illegal instruction exception, but it is equally legal to not take a trap and just continue execution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree this is confusing and I'm not sure it makes sense to distinguish these cases until we actually do do something different with them (e.g. log them differently or abort on reserved behaviour).
Alternatively perhaps the behavioural and non-behavioural information could be split by turning it into an enum where the Illegal variant has a reason enum, or something like that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I initially assumed that an external debugger would differentiate between these cases (see riscv/riscv-debug-spec#1140), but that does not seem to be the case (even though we could propagate this kind of information to an external debugger that certain CSR's are currently disabled if openocd plays along). Currently, we do not distinguish at all between not enabled and not implemented. I believe it would be beneficial to differentiate them for potential future use cases, logging as you described (or cases like the one @jordancarlin described).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm just a bit worried that because RISC-V itself doesn't make any distinction between them, and if we also don't make use of the distinction, then it's going to be really hard to tell what it actually means.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding a reason string would be a great solution. I've debugged issues in. Qemu in the past where a csr was incorrectly marked as inaccessible and if I'd had a trace telling me why I'm getting the illegal instruction fault that would have been so much easier to diagnose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm just a bit worried that because RISC-V itself doesn't make any distinction between them, and if we also don't make use of the distinction, then it's going to be really hard to tell what it actually means.
Yeah I agree it could get messy pretty quickly.
I like your idea of passing the reason as an enum we could use internally/logging, without tying it to the spec itself.
b88da4b to
d362a9e
Compare
|
Using a separate enum to represent the reason is indeed a good idea, now the code looks much better enum CSRAccessIllegalReason = {
// CSR is not defined in spec or not implemented by sail-model yet
CSRNotDefined,
// other
CSRNotAccessible,
}
union CSRAccessResult = {
CSRAccessSuccess : unit,
CSRAccessIllegal : CSRAccessIllegalReason,
}Now In addition, I just wrote a more aggressive version that distinguishes various unaccessible reasons in detail. see #1402 |
arichardson
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good to me
model/core/csr_begin.sail
Outdated
|
|
||
| function CSRDefinedIf(exist : bool) -> CSRAccessResult = if exist then CSRAccessSuccess() else CSRAccessIllegal(CSRNotDefined) | ||
|
|
||
| function CSRAccessibleIfBool(accessible : bool) -> CSRAccessResult = if accessible then CSRAccessSuccess() else CSRAccessIllegal(CSRNotAccessible) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| function CSRAccessibleIfBool(accessible : bool) -> CSRAccessResult = if accessible then CSRAccessSuccess() else CSRAccessIllegal(CSRNotAccessible) | |
| function CSRAccessibleIfBool(accessible : bool) -> CSRAccessResult = | |
| if accessible then CSRAccessSuccess() | |
| else CSRAccessIllegal(CSRNotAccessible) |
For consistency with the other functions?
d362a9e to
e6777ea
Compare
| privLevel_to_bits(p) >=_u csrPriv(csr) & not(csrAccess(csr) == 0b11) | ||
|
|
||
| // Check that the CSR access isn't a write to a read-only CSR. | ||
| function check_CSR_access(csr : csreg, access_type : CSRAccessType) -> bool = | ||
| not((access_type == CSRWrite | access_type == CSRReadWrite) & (csrAccess(csr) == 0b11)) | ||
| (access_type == CSRWrite | access_type == CSRReadWrite) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it's just me but I dont think we should check whether we access a read-only CSR (while performing a write, etc.) in check_CSR_priv(). This functions (according to the name) should only check whether we have the sufficient privileges. It might make sense to define a new function to check that?
| function CSRDefinedIf(exist : bool) -> CSRAccessResult = | ||
| if exist then CSRAccessSuccess() | ||
| else CSRAccessIllegal(CSRNotDefined) | ||
|
|
||
| function CSRAccessibleIfBool(accessible : bool) -> CSRAccessResult = | ||
| if accessible then CSRAccessSuccess() | ||
| else CSRAccessIllegal(CSRNotAccessible) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am curious what others think, but I feel it might be a bit unfortunate that we have two functions with the same signature, one overloaded and the other not. I understand the reasoning behind it, but I am not sure it would be immediately obvious to someone new contributing to the project.
They might have to dive deep into the code to notice the difference.
But to be honest, I dont have an alternative for now :D
No description provided.