Skip to content

Inconsistent Return Address Timing in PicoSoC IRQ Handler #277

@5S-MOHAMED-SHABAIK

Description

@5S-MOHAMED-SHABAIK

Hello,

During illegal instruction testing in PicoSoC, I observed inconsistent return address behavior between 32-bit and 16-bit illegal instructions in the IRQ handler.

Environment

  • PicoSoC configuration with ENABLE_IRQ=0, ENABLE_IRQ_QREGS=0
  • Compressed instructions enabled
  • Testing via ebreak & illegal instruction injection (.word 0x00000000, .hword 0x0000)

Observed Behavior

Test case with illegal instructions:

//in the .ELF dumpfile
100494: 00100073   ebreak        // 32-bit illegal instruction
100498: 0000       unimp         // 16-bit illegal instruction

Return address capture results:

// In C IRQ handler:
// 32-bit illegal: regs[0] = 0x100495  (PC+1)
// 16-bit illegal: regs[0] = 0x100498  (unchanged)

Contradiction with Documentation

What the README says:
"When support for compressed instructions is enabled, then the LSB of q0 is set when the interrupted instruction is a compressed instruction."

What was observed:

Instruction Type regs[0] Value LSB Bit Expected LSB
32-bit (ebreak) 0x100495 1 0
16-bit (unimp) 0x100498 0 1

The LSB behavior is backwards from what the documentation suggests!

Analysis

The return address capture appears to happen at different pipeline stages depending on instruction type:

From waveform analysis:

  • Both capture when irq_state[0] = 1
  • Both have reg_next_pc = current_pc at capture time
  • latched_compr is set at different times for each of the 32-bit or 16-bit instructions
  • Returned PC values differ: 32-bit gets PC+1, 16-bit gets PC unchanged
  • LSB indication is inverted from documented behavior

Impact

  • Makes consistent instruction fault analysis difficult
  • LSB bit doesn't reliably indicate instruction type as documented
  • Requires workarounds in the IRQ handler for reliable fault PC calculation
  • Contradicts documented compressed instruction behavior

Workaround

For reliable fault PC calculation in the irq handler function:

uint32_t fault_pc = (return_pc & 0x1) ? return_pc - 1 : return_pc;
// Note: LSB behavior is inverted from documentation

Questions

  1. Is this timing difference and inverted LSB behavior intentional or a bug?
  2. Should both instruction types show consistent relative timing and LSB behavior?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions