Skip to content

Commit 798af27

Browse files
Copilotjarz
authored andcommitted
dbdma: Fix update_irq bug in finish_cmd.
Co-authored-by: jarz <90255+jarz@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
1 parent dd1cc7d commit 798af27

2 files changed

Lines changed: 14 additions & 6 deletions

File tree

devices/common/dbdma.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,9 @@ void DMAChannel::finish_cmd() {
154154
// get command code
155155
this->cur_cmd = cmd_desc[3] >> 4;
156156

157+
// save interrupt bits from the completing command before cmd_ptr may change
158+
uint8_t saved_cmd_bits = cmd_desc[2];
159+
157160
// all commands except STOP update cmd.xferStatus and
158161
// perform actions under control of "i" interrupt, "b" branch, and "w" wait bits
159162
if (this->cur_cmd < DBDMA_Cmd::STOP) {
@@ -206,8 +209,9 @@ void DMAChannel::finish_cmd() {
206209
if (this->cur_cmd < DBDMA_Cmd::STOP && !branch_taken)
207210
this->cmd_ptr += 16;
208211

212+
// use the interrupt bits saved before cmd_ptr was advanced or branched
209213
if (this->cur_cmd < DBDMA_Cmd::STOP) {
210-
this->update_irq();
214+
this->update_irq(saved_cmd_bits);
211215
}
212216

213217
this->cmd_in_progress = false;
@@ -272,19 +276,22 @@ void DMAChannel::xfer_quad(const DMACmd *cmd_desc, DMACmd *cmd_host) {
272276
}
273277

274278
void DMAChannel::update_irq() {
275-
// obtain real pointer to the descriptor of the completed command
279+
// For abort path (called from reg_write when RUN is cleared): cmd_ptr still
280+
// points to the current command, so reading from it is correct here.
276281
MapDmaResult res = mmu_map_dma_mem(this->cmd_ptr, 16, false);
277-
uint8_t *cmd_desc = res.host_va;
282+
this->update_irq(res.host_va[2]);
283+
}
278284

285+
void DMAChannel::update_irq(uint8_t cmd_bits) {
279286
// STOP doesn't generate interrupts
280287
if (this->cur_cmd < DBDMA_Cmd::STOP) {
281288
// react to cmd.i (interrupt) bits
282-
if (cmd_desc[2] & 0x30) {
289+
if (cmd_bits & 0x30) {
283290
bool cond = true;
284-
if ((cmd_desc[2] & 0x30) != 0x30) {
291+
if ((cmd_bits & 0x30) != 0x30) {
285292
uint16_t int_mask = this->int_select >> 16;
286293
cond = (this->ch_stat & int_mask) == (this->int_select & int_mask);
287-
if ((cmd_desc[2] & 0x30) == 0x20) {
294+
if ((cmd_bits & 0x30) == 0x20) {
288295
cond = !cond; // generate interrupt if cond = false
289296
}
290297
}

devices/common/dbdma.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ class DMAChannel : public DmaBidirChannel, public DmaChannel {
137137
void finish_cmd();
138138
void xfer_quad(const DMACmd *cmd_desc, DMACmd *cmd_host);
139139
void update_irq();
140+
void update_irq(uint8_t cmd_bits);
140141
void xfer_from_device();
141142
void xfer_to_device();
142143

0 commit comments

Comments
 (0)