-
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?
Changes from all commits
0b55df2
9f9b2e6
3421b03
dd87a8a
b5c5a92
38a1670
97e77f5
2a6aa63
60e45de
0bd7e49
232d922
cab0f37
cd5eb34
b46a99a
b587644
40ad532
fb13ad0
5ea9eec
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 commentThe 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 commentThe 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. |
||
then { RETIRE_FAIL } | ||
else if not(is_aligned(virtaddr_bits(vaddr), width)) | ||
then { handle_mem_exception(vaddr, E_Load_Addr_Align()); RETIRE_FAIL } | ||
else match translateAddr(vaddr, Read(Data)) { | ||
TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, | ||
TR_Address(addr, _) => | ||
match mem_read(Read(Data), addr, width_bytes, aq, aq & rl, true) { | ||
MemValue(result) => { load_reservation(physaddr_bits(addr)); X(rd) = sign_extend(result); RETIRE_SUCCESS }, | ||
MemValue(result) => { | ||
load_reservation(physaddr_bits(addr)); | ||
X(rd) = sign_extend(result); | ||
let load_after_match : bool = instrDataMatch(cur_privilege, virtaddr_bits(vaddr), zero_extend(X(rd)), matchSize_of_wordWidth(width), LOAD_MATCH_AFTER); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why put the result in an unused variable? |
||
RETIRE_SUCCESS | ||
}, | ||
MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL } | ||
}, | ||
} | ||
|
@@ -112,6 +119,7 @@ mapping clause encdec = STORECON(aq, rl, rs2, rs1, size, rd) | |
/* NOTE: Currently, we only EA if address translation is successful. This may need revisiting. */ | ||
function clause execute (STORECON(aq, rl, rs2, rs1, width, rd)) = { | ||
let width_bytes = size_bytes(width); | ||
let dbg_store_data = X(rs2); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the actual store data, not just the debug value. But also it's weird to introduce a variable for the new code whilst not updating the existing code to use it. And you still have redundancy in slicing the right bytes out. Hoist the existing store code and use it for both. |
||
|
||
// This is checked during decoding. | ||
assert(width_bytes <= xlen_bytes); | ||
|
@@ -131,7 +139,9 @@ function clause execute (STORECON(aq, rl, rs2, rs1, width, rd)) = { | |
match ext_data_get_addr(rs1, zeros(), Write(Data), width_bytes) { | ||
Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, | ||
Ext_DataAddr_OK(vaddr) => { | ||
if not(is_aligned(virtaddr_bits(vaddr), width)) | ||
if (instrDataMatch(cur_privilege, virtaddr_bits(vaddr), zero_extend(dbg_store_data[width_bytes * 8 - 1 .. 0]), matchSize_of_wordWidth(width), STORE_MATCH)) | ||
then { RETIRE_FAIL } | ||
else if not(is_aligned(virtaddr_bits(vaddr), width)) | ||
then { handle_mem_exception(vaddr, E_SAMO_Addr_Align()); RETIRE_FAIL } | ||
else { | ||
match translateAddr(vaddr, Write(Data)) { /* Write and ReadWrite are equivalent here: | ||
|
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.