-
Notifications
You must be signed in to change notification settings - Fork 173
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
Add Debug Native Trigger Support #573
base: master
Are you sure you want to change the base?
Add Debug Native Trigger Support #573
Conversation
a70a138
to
67f737a
Compare
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've never written anything for sail, so take this feedback with a large grain of salt.
Looks like you're modifying each instruction that does a memory access, but I don't see this for vector operations. Did those get missed?
I only looked at the first half of this change so far. I'll read through the rest later.
1ec830e
to
ce3e483
Compare
@rtwfroody, Thanks for the initial feedback Actually, I have never worked on the vector extension, so I planned to do it later. Today, I looked into the vector code in sail-riscv and added the trigger for vector load/store. I asked one of my colleagues to write a basic vector load test and check the load address trigger, and it’s working. However, we need feature complete vector ACTs to verify the functionality. |
That's an interesting topic. The ACTs assume that all memory accesses are treated the same. In this SAIL implementation that is not the case, but I do feel that the SAIL implementation is unusual in that way. (E.g. spike has an MMU object and all memory accesses go through there, regardless of which instruction caused them.) Is there hardware where vector memory accesses are inadvertantly treated different from regular memory accesses? |
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.
Sorry to review so little each day, but I am working on it...
No, all memory accesses go through a function called translateAddr. However, my only concern in this case is that misaligned load/store addresses have a higher priority than breakpoint exceptions in the SAIL implementation. There are two functions common to all memory access:
In the file where One solution I can think of is to move both the trigger match check and the misaligned exception check inside I believe we should proceed with the current implementation, but if you have any other suggestions, please let me know. |
No worries at all |
@pmundkur Can you approve the workflow for this PR? |
The workflow is running but it is failing since you have trailing whitespace in the new files. See the log here: https://github.com/riscv/sail-riscv/actions/runs/11274637767/job/32185366539?pr=573 |
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 not a SAIL expert so I might miss some of the subtleties. It looks like @rtwfroody already commented on some of the other things I noticed, but here are my additional comments.
bb2e3bf
to
ff62e68
Compare
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.
Still working through this, slowly...
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.
The rest of this looks OK. Thank you.
There is trigger matching here for |
I had not added the trigger earlier due to the TODO comment on the remaining sail-riscv/model/riscv_insts_zicbom.sail Lines 49 to 51 in 0b9c639
|
c2e31a1
to
970cf85
Compare
970cf85
to
142e4b0
Compare
@Timmmm Any update on this? |
Co-authored-by: Tim Newsome <[email protected]> Signed-off-by: Yazan Hussnain <[email protected]>
Co-authored-by: Tim Newsome <[email protected]> Signed-off-by: Yazan Hussnain <[email protected]>
Co-authored-by: Paul Donahue <[email protected]> Signed-off-by: Yazan Hussnain <[email protected]>
Co-authored-by: Paul Donahue <[email protected]> Signed-off-by: Yazan Hussnain <[email protected]>
142e4b0
to
fb13ad0
Compare
Hey, sorry I'm probably not the best person to review this since I have roughly zero knowledge of the debug/triggers spec. I can review the low level Sail syntax if you like, but for functionality we probably need someone else. |
@Timmmm , the functionality has been reviewed by @rtwfroody. @arichardson requested a review from you, and I believe the focus of this review is on the Sail syntax, Please feel free to proceed with that aspect. |
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.
Whilst this may just about implement the spec correctly (some corner cases highlighted), this has not been properly reviewed from a code quality perspective.
From CODE_STYLE.md:
- Avoid unnecessary parentheses and curly braces unless doing so seriously hurts readability
These both seem to be in abundance.
Quite a lot of your functions also look, from their names and signatures, as if they're pure functions, but instead have side-effects like updating registers or even taking exceptions (e.g. instrDataMatch -> bool sounds like "is there a match?" not "handle a match").
I've also made quite a few other comments. These are not exhaustive, as some of them will motivate significant refactors, so there's not much point drilling down into all the details until the higher-level design is good. Thus addressing these comments is not sufficient for my approval and I will likely have further points to raise, but need to see the end result of this set before I know exactly what else I think should be changed.
@@ -62,6 +62,11 @@ bool sys_enable_zicbom(unit u) | |||
return rv_enable_zicbom; | |||
} | |||
|
|||
bool sys_reent_opt1(unit u) |
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.
This name doesn't mean much unless you know it relates to Sdtrig, which isn't clear. Also, is there a better name that captures what it actually does than "option 1"? Finally, without knowing the Sdtrig spec, the name doesn't make it clear what false, i.e. not "option 1", means.
} | ||
else { | ||
/* the extension hook interposes on the fetch result */ | ||
match ext_fetch_hook(fetch()) { |
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.
Why is there no split before/after check like for loads? Spike does it that way which makes more sense to me.
} | ||
|
||
/* Match Control Type 6 Trigger Match */ | ||
function instrDataMatch(cur_priv : Privilege, addr : xlenbits, data : xlenbits, match_size : matchSize, match_type : MatchType) -> bool = { |
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.
This is quite a big function. Can we split out the (side-effect-free) checking for a match from actually going and updating state as a result of it?
@@ -86,13 +86,20 @@ function clause execute(LOADRES(aq, rl, rs1, width, rd)) = { | |||
/* "LR faults like a normal load, even though it's in the AMO major opcode space." | |||
* - Andrew Waterman, isa-dev, 10 Jul 2018. | |||
*/ | |||
if not(is_aligned(virtaddr_bits(vaddr), width)) | |||
if (instrDataMatch(cur_privilege, virtaddr_bits(vaddr), zero_extend(0b0), matchSize_of_wordWidth(width), LOAD_MATCH_BEFORE)) |
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.
Passing 0b0 for every LOAD_MATCH_BEFORE is odd. Does that not mean a trigger on loading 0 will fire for every load? I imagine you instead want the data to be an optional type here and pass None() so it never matches. This is also what Spike implements. But I can't see this detail in the spec, not helped by the match algorithm being split across each field of the CSR.
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.
It may also make sense to have two functions, one for the cases where the exception is raised now, and one for the cases where the exception is raised later. Currently the code here is implicitly assuming that LOAD_MATCH_BEFORE raises an exception, since it returns RETIRE_FAIL, and that LOAD_MATCH_AFTER doesn't, since it continues on to return RETIRE_SUCCESS. Maybe the former should also have the handle_mem_exception call in the caller here like all the other ways this can fault.
(RETIRE_FAIL, true) | ||
/* If Etrigger, Icount, Itrigger and mcontrol6 after, matches, fire | ||
it before fetching the next instruction */ | ||
if (check_trigger_firing(cur_privilege)) then { |
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.
This handles them after interrupts, which isn't really a good idea given what triggers are for. For most interrupts you can defer them so it is legal, and a good idea, to prioritise triggers. In a few cases (e.g. xRET) deferring them isn't legal, but the Sdtrig spec failed to consider this interaction. There is a proposal to fix this in riscv/riscv-debug-spec#802 but it seems to have stalled. That makes the most sense to me though.
(InstrCount[count] != zero_extend(14, 0b0)) & | ||
(TriggerFireMatch(cur_priv))) then { /* Trigger Match valid? check re-enterancy */ | ||
/* Decrement the counter */ | ||
if (InstrCount[count] == zero_extend(14, 0b1)) then { |
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.
Why hard-code the width for the zero_extends here?
((InstrCount[u] == 0b1) & (cur_priv == User)) ) & /* Trigger is enabled in U-mode */ | ||
(InstrCount[count] != zero_extend(14, 0b0)) & | ||
(TriggerFireMatch(cur_priv))) then { /* Trigger Match valid? check re-enterancy */ | ||
/* Decrement the counter */ |
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.
This comment appears to be in the wrong place
{ tdata2_x.tdata2[index] = v; v } else { o } | ||
} | ||
|
||
/* Read TData2 of current trigger */ |
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.
Why are these capitalised in some comments?
let MCtrl6 : MatchControlType6 = Mk_MatchControlType6(v[26 .. 0]); | ||
let InstrCount : InstructionCount = Mk_InstructionCount(v[26 .. 0]); | ||
let IntrptTrigger : InterruptTrigger = Mk_InterruptTrigger(v); | ||
let ExcepTrigger : InterruptTrigger = Mk_InterruptTrigger(v); |
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.
These are odd abbreviations for interrupt and exception
register tcontrol : Tcontrol | ||
|
||
/* | ||
* The seed CSR (entropy source) |
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.
?
Debug native trigger support
This PR adds the debug native trigger support in sail RISC-V golden model. RISC-V Debug Specification
tdata
registers--reent-opt1
flag to enable the second solution. Only one solution can be enabled at a timeImplemented Functions
tdata1
register at the selectedtselect
.tdata1
for the following triggers:icount
,itrigger
,etrigger
, andmcontrol6
.tdata1
register at the selectedtselect
.tdata2
register at the selectedtselect
.tdata2
register at the selectedtselect
.tdata3
register at the selectedtselect
.tdata3
register at the selectedtselect
.tcontrol
register: onlymte
andmpte
fields are writable.true
if trigger matching and firing are valid.icount
,itrigger
,etrigger
, andmcontrol6
.Files Changed
riscv_csr_begin.sail
: Created CSR map fortinfo
andtcontrol
.riscv_types.sail
: Defined mappings for Trigger Type and Match Options.riscv_sys_regs.sail
: Defined CSR read/write and legalization functions.riscv_sys_control.sail
: Defined trigger match and trigger firing check functions.riscv_insts_zicsr.sail
: Added read/write CSR definitions for the implemented CSRs.riscv_step.sail
: Called instruction count, instruction match, and check trigger firing functions.riscv_insts_base.sail
: Checked for Data Match trigger on Load/Store instructions.riscv_insts_aext.sail
: Checked for Data Match trigger on Load/Store instructions.riscv_insts_zicboz.sail
: Checked for Data Match trigger forcbo.zero
.