Skip to content
This repository has been archived by the owner on Sep 2, 2023. It is now read-only.

Define and implement an interrupt model #88

Open
mbitsnbites opened this issue Apr 11, 2019 · 0 comments
Open

Define and implement an interrupt model #88

mbitsnbites opened this issue Apr 11, 2019 · 0 comments

Comments

@mbitsnbites
Copy link
Member

mbitsnbites commented Apr 11, 2019

Execution model

  • Introduce two execution modes: SUPERVISOR MODE and USER MODE.
    • When the CPU boots (reset) it enters supervisor mode.
    • When an interrupt or exception occurs, the CPU enters supervisor mode.
    • To simplify things, interrupts are disabled in supervisor mode (we can revisit this decision later).
    • To exit supervisor mode and enter user mode, issue a "jump to user code" (JU) instruction.
  • Define a second scalar register file for supervisor mode (+30 scalar registers).
    • When the CPU is in supervisor mode, all regular instructions will access the supervisor scalar register file.
    • Add supervisor level instructions for transferring data between the user register file and the supervisor register file.
    • When an interrupt or exception occurs, the supervisor LR register will contain the address of the next user instruction to execute (so to terminate the ISR you issue ju lr).
  • The vector register file is shared between user mode and supervisor mode.

Interrupt vectors

  • Use a dedicated (hard coded) memory area for interrupt vectors.
    • For example: 0x00000200 ... ?
    • Possibly add a special purpose register for setting the interrupt vector base address (similar to the 68010 VBR).
  • Each interrupt vector is a piece of code that will be executed (i.e. on an interrupt, the supervisor PC is set the the vector address).
  • Let the size of each interrupt vector be about 32 bytes = 8 instructions.
    • Try to make the size equal to a cache line.
    • Let it be large enough to support some use cases:
      • Load a jump address from a secondary interrupt vector table (e.g. in RAM) and jump to it.
      • Do minimal real-time tasks (e.g. control an analog signal from an in-RAM value).
  • The reboot code should have a dedicated vector index (preferably index 0).

Required new instructions

  • MOVSU - MOVe from Supervisor to User
    • Two operands:
      • Source supervisor scalar register
      • Target user scalar register
  • MOVUS - MOVe from User to Supervisor
    • Two operands
      • Source user scalar register
      • Target supervisor scalar register
  • JU - Jump to User code
    • One operand (target address)
  • Possibly: Manipulate and move to/from special purpose registers.
    • E.g. inspired by the RISC-V ISA:
      • CSRRW - Exchange scalar register and special purpose register.
      • CSRRS - Read special purpose register and set bits in special purpose register.
      • CSRRC - Read special purpose register and clear bits in special purpose register.
    • Revisit CPUID, as it provides very similar functionality.

Open questions

  • What internal exceptions do we need? Suggestion:
    • System reboot.
    • Memory bus error.
    • Memory page fault (not yet implemented, but needed once we have an MMU).
    • Illegal instruction.
    • Privilege violation (e.g. a supervisor instruction is attempted in user mode).
    • Software trap (e.g. for debugging or for controlled privilege escalation).
    • For IEEE 754 (if required): "Invalid operation", "Division by zero", "Overflow", "Underflow", "Inexact".
    • Try to avoid "division by zero" and "illegal operation" as far as possible.
    • Max number of internal exceptions (power of two): 16
  • What external exceptions do we need? Suggestion:
    • Define a fixed number of external exceptions (e.g. 16).
  • How to control interrupt masking?
    • User operation or supervisor operation?
    • Special purpose register (along with new instructions for managing such registers) or a MMIO register?
  • In a hardware implementation: When/where is an interrupt and/or exception triggered?
    • Simply replacing the PC in the PC stage is attractive from a performance point of view (zero cycle interrupt handler).
    • Easier: Flush pipeline and trigger in the WB stage (or thereabout).
    • Speculative execution, branches and potential exceptions need to be handled correctly.
    • In one way or the other, the pipeline has to be flushed (more or less) to make sure that there will be no unhandled user space branches or exceptions that could interfere with the interrupt instruction(s).
    • In particular, the first interrupt instruction needs to set the supervisor LR register to the correct user space PC.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant