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

DM should ignore some bits while abstract command is executing #1046

Merged
merged 5 commits into from
Jul 23, 2024

Conversation

rtwfroody
Copy link
Collaborator

@rtwfroody rtwfroody commented Jun 13, 2024

This makes things work better in case the debugger wants to reset but doesn't know hartsel, as mentioned in #1021.

Also the debugger should write dmactive=0 to perform a reset, instead of "may".

Also the debugger should write dmcontrol=0 to perform a reset, instead
of "may".

Fixes #1021.

Alternate to #1040, after some discussion in the meeting. #1040 didn't
address what happens while dmactive is changing. This version is not a
substantive change, so also a bit easier to merge.
@rtwfroody
Copy link
Collaborator Author

@en-sc, can you take a look at this?

@rtwfroody
Copy link
Collaborator Author

Rather than allowing bits to be ignored depending on dmactive=0, does it make sense to ignore writes to hartsel, haltreq, resumereq, etc. whenever abstractcs.busy=1? That seems cleaner and more robust overall.

However, if we require this behavior it's not backwards compatible. We can say the hardware should do that, and debuggers should preserve the values, and add a note that when resetting it's sometimes unavoidable for the debugger to preserve them.

Thoughts?

@en-sc
Copy link
Contributor

en-sc commented Jun 24, 2024

Sorry for taking so long to reply.

Rather than allowing bits to be ignored depending on dmactive=0, does it make sense to ignore writes to hartsel, haltreq, resumereq, etc. whenever abstractcs.busy=1? That seems cleaner and more robust overall.

This is cleaner.

However, AFAIU, this complicates the HW and I'm not sure it is useful for the SW.

The thing is, after the External Debugger has connected to the DM, it knows the state of abstractcs.busy.

If for whatever reason it looses track of that state (abstractcs.busy is left high after some operation) (e.g. OpenOCD times out waiting for Abstract Command to complete), currently it should read abstractcs to check busy before attempting a change of hartsel and so on.

After the proposed change, the External Debugger would instead be required to read back the written value (in case of hartsel) or wait for the effect (haltreq, resumereq).

I think it will complicate error reporting . E.g.:

  • abstractcs.busy is high (e.g. OpenOCD timed out waiting for Abstract Command to complete).
  • haltreq was written and after a while the effect (dmstatus.[all|any]halted) has not been observed.
  • The debugger can only report something like "halt request failed, maybe an abstract command was not finished".

Currently the similar situation is processed like so:

  • Wait for abstractcs.busy to get low. If it does not, a clear and precise error message can be reported.
  • Wait for dmstatus.[all|any]halted, being sure it can not fail due to abstractcs.busy.

@rtwfroody
Copy link
Collaborator Author

@pdonahue-ventana can you comment here?

@pdonahue-ventana
Copy link
Collaborator

What about the dmactive recipe? You write 0 to dmactive and then poll until you see dmactive=0 on a read. What happens in between the write and the read with respect to any outstanding abstract command and the hartsel field?

There are two types of implementations:

  1. those that cannot tolerate hartsel changing during an abstract command
  2. those that can tolerate hartsel changing during an abstract command

If busy=1 prevents hartsel from changing then I guess that things will be fine with either implementation and then once dmactive actually goes 0 then hartsel will get reset to 0. If busy=1 does not prevent hartsel from changing then type 1 implementations will break, though type 2 implementations will be fine. So maybe we should at least allow implementations (particularly type 1 implementations) to ignore updates to certain fields when busy=1 (where "certain fields" doesn't include ndmreset).

@pdonahue-ventana
Copy link
Collaborator

On the other hand, if we ignore hartsel writes when busy=1 then what if I want to reset hart N (where N is not the hart where we're currently doing an abstract command)? I might want to write hartsel=N, hartreset=1 rather than doing the heavy ndmreset. Or do we have to wait for the command to complete before doing that? And if the command doesn't complete then presumably we want to hartreset the hart that was doing the command rather than some other hart (or we could ndmreset).

@rtwfroody
Copy link
Collaborator Author

what if I want to reset hart N (where N is not the hart where we're currently doing an abstract command)? I might want to write hartsel=N, hartreset=1 rather than doing the heavy ndmreset.

That's a good use case for changing hartsel while an abstract command is executing. Sounds like my "simple" proposal of just ignoring hartsel writes when busy=1 doesn't work.

@rtwfroody
Copy link
Collaborator Author

what if I want to reset hart N (where N is not the hart where we're currently doing an abstract command)? I might want to write hartsel=N, hartreset=1 rather than doing the heavy ndmreset.

That's a good use case for changing hartsel while an abstract command is executing. Sounds like my "simple" proposal of just ignoring hartsel writes when busy=1 doesn't work.

As discussed in the meeting, this use case is already disallowed. The spec says:

While an abstract command is executing ..., a debugger must not change {hartsel}, ...

@rtwfroody
Copy link
Collaborator Author

After the proposed change, the External Debugger would instead be required to read back the written value (in case of hartsel) or wait for the effect (haltreq, resumereq).

I don't think it's required, given that abstractcs.busy cannot spontaneously go high. It only goes high in response to a debugger request.

I think it will complicate error reporting . E.g.:

  • abstractcs.busy is high (e.g. OpenOCD timed out waiting for Abstract Command to complete).
  • haltreq was written and after a while the effect (dmstatus.[all|any]halted) has not been observed.
  • The debugger can only report something like "halt request failed, maybe an abstract command was not finished".

Currently the similar situation is processed like so:

  • Wait for abstractcs.busy to get low. If it does not, a clear and precise error message can be reported.
  • Wait for dmstatus.[all|any]halted, being sure it can not fail due to abstractcs.busy.

That will still work. The problem you describe only happens if the debugger asserts haltreq without first confirming that abstractcs.busy went low. In fact I would expect debuggers to confirm an abstract command has completed before trying anything different.

@pdonahue-ventana
Copy link
Collaborator

Since a debugger is not allowed to change hartsel (or haltreq, resumereq, ackhavereset, setresethaltreq, clrresethaltreq) while a command is busy, if we say that hardware may/should ignore changes to these fields while it's busy then there's no backward compatibility problem and no loss of functionality. We can say "may" along with a non-normative note that it's really a "should" for hartsel on implementations where unexpected hartsel changes will break a currently executing abstract command. Or we could simply say "should" for all of the fields and all implementations.

(I can imagine that unexpectedly changing hartsel is a problem on some implementations but I can't imagine how setting/clearing resethaltreq would be a problem. This is just an observation, not a proposal to treat that differently.)

This is a clean way to let a debugger reset a DM without having to know
what hartsel is first. It can simply write 0 then 1 to dmactive.

These new rules resolve the issue raised in #1021, that if the DM is
executing an abstract command when the debugger wants to reset it, the
debugger should not be expected to preserve hartsel.
debug_module.adoc Outdated Show resolved Hide resolved
rtwfroody and others added 2 commits July 12, 2024 09:20
Co-authored-by: Paul Donahue <[email protected]>
Signed-off-by: Tim Newsome <[email protected]>
This is what I want the spec to say. But it's not backwards compatible.
Can we get away with this?
Copy link
Collaborator

@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 OK with this clarification/recommendation (which is not a normative change that would delay anything).

This behavior is not backwards compatible. It would fix a corner case
where the DM is performing an abstract command and reading dmcontrol
returns in an error. That is so unlikely that it's not worth making a
backwards incompatible change for.
@rtwfroody rtwfroody changed the title DM may ignore things when dmactive is changing. DM should ignore some bits while abstract command is executing Jul 19, 2024
@rtwfroody
Copy link
Collaborator Author

This PR has morphed into recommending some more robust behavior while abstract commands are executing.

Copy link
Collaborator

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

This is good. Non-normative suggestions that are backward-compatible.

@rtwfroody rtwfroody merged commit bba8750 into main Jul 23, 2024
1 check passed
@rtwfroody rtwfroody deleted the dmactive branch July 23, 2024 16:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants