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

Add Debug Native Trigger Support #573

Open
wants to merge 18 commits into
base: master
Choose a base branch
from

Conversation

YazanHussnain-10x
Copy link

@YazanHussnain-10x YazanHussnain-10x commented Oct 4, 2024

Debug native trigger support

This PR adds the debug native trigger support in sail RISC-V golden model. RISC-V Debug Specification

Parameter Details
CSRs Implemented Trigger Select, Trigger Data 1, Trigger Data 2, Trigger Data 3, Trigger Info, Trigger Control
No. of Supported Triggers 7
Supported Actions 0 - Currently Sail-RISC-V does not have support for debug mode, therefore, only breakpoint exception action is supported
Value of dmode 0 - Both Debug and M-mode can write the tdata registers
Supported Trigger Types Instruction Count, Interrupt Trigger, Exception Trigger, Match Control Type 6 Trigger, Disabled
Re-entrancy Solution Both solutions supported - Use --reent-opt1 flag to enable the second solution. Only one solution can be enabled at a time
Supported Match Options in MControl6 0: Equal, 1: NAPOT, 2: GE, 3: LT, 4: Mask Low, 5: Mask High, 6: Not Equal, 8: Not Equal, 9: Not NAPOT, 12: Not Mask Low, 13: Not Mask High

Implemented Functions

  • tdata1_write: Writes the tdata1 register at the selected tselect.
  • legalize_tdata1: Legalizes the values in tdata1 for the following triggers: icount, itrigger, etrigger, and mcontrol6.
  • tdata1_read: Reads the tdata1 register at the selected tselect.
  • tdata2_write: Writes the tdata2 register at the selected tselect.
  • tdata2_read: Reads the tdata2 register at the selected tselect.
  • tdata3_write: Writes the tdata3 register at the selected tselect.
  • tdata3_read: Reads the tdata3 register at the selected tselect.
  • legalize_tcontrol: Legalizes the tcontrol register: only mte and mpte fields are writable.
  • TriggerFireMatch: Checks re-entrancy and returns true if trigger matching and firing are valid.
  • icount_trigger_match: Checks for a match in the instruction count trigger.
  • IETrigger_match: Checks for a match in the interrupt and exception triggers.
  • instrDataMatch: Checks for matches in: Execute Address, Execute Instruction, Load Address, Load Data, Store Address, Store Data. Fires the trigger except in the Load Data case.
  • check_trigger_firing: Before fetching the next instruction, checks for any trigger firing: icount, itrigger, etrigger, and mcontrol6.

Files Changed

  1. riscv_csr_begin.sail: Created CSR map for tinfo and tcontrol.
  2. riscv_types.sail: Defined mappings for Trigger Type and Match Options.
  3. riscv_sys_regs.sail: Defined CSR read/write and legalization functions.
  4. riscv_sys_control.sail: Defined trigger match and trigger firing check functions.
  5. riscv_insts_zicsr.sail: Added read/write CSR definitions for the implemented CSRs.
  6. riscv_step.sail: Called instruction count, instruction match, and check trigger firing functions.
  7. riscv_insts_base.sail: Checked for Data Match trigger on Load/Store instructions.
  8. riscv_insts_aext.sail: Checked for Data Match trigger on Load/Store instructions.
  9. riscv_insts_zicboz.sail: Checked for Data Match trigger for cbo.zero.

Copy link

@rtwfroody rtwfroody left a 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.

c_emulator/riscv_sim.c Outdated Show resolved Hide resolved
@YazanHussnain-10x
Copy link
Author

@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.

@rtwfroody
Copy link

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?

Copy link

@rtwfroody rtwfroody left a 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...

model/riscv_sys_control.sail Outdated Show resolved Hide resolved
model/riscv_sys_control.sail Outdated Show resolved Hide resolved
model/riscv_sys_control.sail Outdated Show resolved Hide resolved
model/riscv_sys_control.sail Outdated Show resolved Hide resolved
model/riscv_sys_control.sail Show resolved Hide resolved
@YazanHussnain-10x
Copy link
Author

YazanHussnain-10x commented Oct 10, 2024

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?

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:

  1. ext_data_get_addr: Used to get the address (rs1 + imm).
  2. translateAddr: Translates VA -> PA.

In the file where ext_data_get_addr is defined, some basic user-defined functions are not accessible, which are required for the implementation. If I implement it inside translateAddr, it will lower the priority of the breakpoint compared to the misaligned exception.

One solution I can think of is to move both the trigger match check and the misaligned exception check inside translateAddr. However, this would be a major change, as it would need to be applied across many files.

I believe we should proceed with the current implementation, but if you have any other suggestions, please let me know.

@YazanHussnain-10x
Copy link
Author

Sorry to review so little each day, but I am working on it...

No worries at all

@rtwfroody
Copy link

@pmundkur Can you approve the workflow for this PR?

@arichardson
Copy link
Collaborator

@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

model/riscv_sys_control.sail Show resolved Hide resolved
model/riscv_sys_control.sail Show resolved Hide resolved
model/riscv_sys_control.sail Outdated Show resolved Hide resolved
Copy link

@pdonahue-ventana pdonahue-ventana left a 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.

model/riscv_types.sail Outdated Show resolved Hide resolved
model/riscv_sys_regs.sail Outdated Show resolved Hide resolved
model/riscv_sys_regs.sail Outdated Show resolved Hide resolved
model/riscv_sys_regs.sail Outdated Show resolved Hide resolved
model/riscv_sys_regs.sail Outdated Show resolved Hide resolved
model/riscv_sys_regs.sail Outdated Show resolved Hide resolved
model/riscv_sys_regs.sail Outdated Show resolved Hide resolved
model/riscv_sys_control.sail Outdated Show resolved Hide resolved
model/riscv_sys_control.sail Outdated Show resolved Hide resolved
model/riscv_sys_control.sail Outdated Show resolved Hide resolved
Copy link

@rtwfroody rtwfroody left a 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...

model/riscv_sys_control.sail Show resolved Hide resolved
model/riscv_sys_control.sail Outdated Show resolved Hide resolved
model/riscv_sys_control.sail Outdated Show resolved Hide resolved
model/riscv_sys_control.sail Outdated Show resolved Hide resolved
model/riscv_sys_control.sail Outdated Show resolved Hide resolved
model/riscv_sys_control.sail Show resolved Hide resolved
Copy link

@rtwfroody rtwfroody left a 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.

model/riscv_sys_control.sail Outdated Show resolved Hide resolved
model/riscv_sys_control.sail Outdated Show resolved Hide resolved
@tomaird
Copy link

tomaird commented Nov 8, 2024

There is trigger matching here for cbo.zero but not for the other cbo.* instructions, which are described in the debug spec as matching as stores

@YazanHussnain-10x
Copy link
Author

YazanHussnain-10x commented Nov 8, 2024

I had not added the trigger earlier due to the TODO comment on the remaining cbo instruction. I have now added the trigger, though it may require modifications once the TODO comment is addressed.

// TODO: This is incorrect since CHERI only requires at least one byte
// to be in bounds here, whereas `ext_data_get_addr()` checks that all bytes
// are in bounds. We will need to add a new function, parameter or access type.

Copy link

github-actions bot commented Nov 22, 2024

Test Results

396 tests  ±0   396 ✅ ±0   0s ⏱️ ±0s
  4 suites ±0     0 💤 ±0 
  1 files   ±0     0 ❌ ±0 

Results for commit 5ea9eec. ± Comparison against base commit b102d07.

♻️ This comment has been updated with latest results.

@YazanHussnain-10x
Copy link
Author

@Timmmm Any update on this?

@Timmmm
Copy link
Collaborator

Timmmm commented Dec 24, 2024

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.

@YazanHussnain-10x
Copy link
Author

@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.

@Timmmm Timmmm added the extension Adds support for a RISC-V extension label Jan 6, 2025
Copy link
Collaborator

@jrtc27 jrtc27 left a 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)
Copy link
Collaborator

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()) {
Copy link
Collaborator

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 = {
Copy link
Collaborator

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))
Copy link
Collaborator

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.

Copy link
Collaborator

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 {
Copy link
Collaborator

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 {
Copy link
Collaborator

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 */
Copy link
Collaborator

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 */
Copy link
Collaborator

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);
Copy link
Collaborator

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)
Copy link
Collaborator

Choose a reason for hiding this comment

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

?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
extension Adds support for a RISC-V extension
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants