-
Notifications
You must be signed in to change notification settings - Fork 16
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
retirement: Disable side effects on exception #493
Conversation
I believe that:
And, unrelated to your changes:
@lekcyjna123, @piotro888: what are your thoughts? |
Actually precommit is a special method and therefore executes every cycle until the instruction gets committed, so I am pretty sure it also works. I also don't quite like it, we should probably make it fit transactron ecosystem better.
Right, this has a worse implication: if there are two failed reads in the pipeline, the fresh one takes precedence. A simple and versatile fix would be to ignore exception causes right in retirement stage if
This is actually counter-intuitively easier and already correct: This brings me to an idea of even dumber dummyLSU: assume all L/S is MMIO & only do it during precommit (horrible performance, but its code would be clean as never before; sounds like a Good First Issue for educational purposes). This would of course impair throughput, which is not nice, so it could only be useful as an extra option for debugging, not a replacement. |
If read started an execution it have to be fully executed, to don't left garbage in the data bus. I see two ways to take care about this:
|
|
||
rp_freed = Signal(self.gen_params.phys_regs_bits) | ||
with m.If(side_fx): | ||
m.d.comb += rp_freed.eq(rat_out.old_rp_dst) |
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 can be assigned in av_comb
.
I believe you are right - this is probably just fine.
This is exactly the problem I'm talking about - the code as it is written allows MMIO reads to go out to the bus before we know they should actually happen. And, as I said, there is a simple way to correct this: just make the MMIO reads (but not memory reads) wait for precommit, just like all writes do currently. |
coreblocks/stages/retirement.py
Outdated
with m.If(rat_out.old_rp_dst): # don't put rp0 to free list - reserved to no-return instructions | ||
self.free_rf_put(m, rat_out.old_rp_dst) | ||
with m.If(rp_freed): # don't put rp0 to free list - reserved to no-return instructions | ||
self.free_rf_put(m, rp_freed) | ||
|
||
self.instret_csr.increment(m) |
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.
instret
CSR should only be incremented on side_fx
instructions (and without rob_entry.exception
instruction too)
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.
and that is additional source of possible side effects and should be considered in future FUs
I checked the reads and it wouldn't work:
|
Short and dirty fix: @def_method(m, self.precommit)
def _(rob_id: Value, side_fx: Value):
with m.If(~side_fx):
m.d.comb += result_ready.eq(internal.fsm.state=="Start") and instr_ready = (
(self.current_instr.rp_s1 == 0)
& (self.current_instr.rp_s2 == 0)
& self.current_instr.valid
& ~self.result_ready
& self.side_fx
) So instr is ready only if |
Isn't this equivalent to removing the Geez, DummyLSU is still a giant liability. |
Shouldn't we also check with m.If(~side_fx & current_instr.valid & (rob_id == current_instr.rob_id)):
m.d.comb += result_ready.eq(internal.fsm.state=="Start") ? |
I'm assuming the following invariant: once a precommit is sent for a given I see two solutions: one quick and dirty (and probably fine for now), and one which requires some additional thought. The simple one: just remove the The complex one: vary the behavior depending on the current state of processing the request. If the request was not sent yet, ensure that it will not be sent (possibly by modifying the condition in the |
I think it will work just fine. Only other special effect of exceptions is setting of And I noticed one thing to remember for next part of exceptions integration - we should call
I'm obviously for the complex solution, and I don't think it will be that difficult to implement. But obviously, as always, this can be done later in other PR (with simple solution workaround for now). And I think it is the right thing to do now - to not delay this PR and exception development. |
This was an idea behind my changes proposition. Adding
No, it isn't. I my proposition we still can run loads 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.
Left comments from meeting. Otherwise looks good
|
||
self.rf_free(m, rat_out.old_rp_dst) | ||
rp_freed = Signal(self.gen_params.phys_regs_bits) | ||
with m.If(side_fx): |
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.
First instruction with rob_entry.exception
is incorrectly retired here (because of synchronous setting of side_fx
- takes effect at next cycle). Breaks register values (RAT) and insret
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.
Please add "MMIO only" parameter to LSU. It could be easly done by disabling is_load
part in with m.If(instr_ready & (self.execute | is_load)):
Made some changes on a branch. In particular, I switched to the new, not-yet-merged LSU. |
This was merged through #512. |
Split from #348 to make review easier and get somewhere in finite time.
In scope of this PR:
side_fx
inputside_fx
inputside_fx
input (simply skips callingread
/write
handlers)frat.rename
; they won't starve for sure, but flushing might get faster, I don't know)Out of scope:
side_fx=0
itself without the rest of the core? I hope they are out of scope, otherwise help is desperately needed. Might actually help diagnosing B'.stall()
exported as a method.