Add interrupts draft to spec

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2020-03-04 14:23:57 -05:00
parent 711bfeb7f9
commit bdd30274ed

115
vm.md
View File

@@ -25,8 +25,17 @@ CPU registers are addressed by a value between 0-63 (6 bits). All registers are
* FLAGS - CPU flags
* STATUS - Generic status code
* NIL - Always zero for reading and will never change after writing.
* IVT - Interrupt vector table pointer
* R0-R31
* (26 unused registers)
* (25 reserved registers)
The following registers are caller-save (i.e., their value may change after a function call):
* FLAGS
* STATUS
* IVT
The rest are callee-save.
## CPU Flags
@@ -190,6 +199,7 @@ wrapping around to 0.
* Push the current stack frame pointer
* Push the IP of the next instruction
* Update the IP (i.e., jump) to the value at the given source.
* Update the frame pointer to the current stack pointer - 16
* Ret
* Opcode: 0x2001
* When this instruction is executed, these actions occur:
@@ -209,6 +219,31 @@ wrapping around to 0.
* When this instruction is executed, these actions occur:
* Decrement the stack pointer by the size of value at the destination.
* Copy the value at the stack pointer into the destination.
* Int
* Opcode: 0x2004
* Params: Source, Source
* When this instruction is executed, these actions occur:
* Push the current stack frame pointer
* Push the IP of the next instruction to be called
* Push the FLAGS register
* Push the STATUS register
* Push the R0 register
* Push the R1 register
* Update the IP (i.e., jump) to the address of the given interrupt vector in the IVT
* Update the R0 register to the value in the first parameter
* Update the R1 register to the value in the second parameter
* Update the frame pointer to the current stack pointer - 48
* IRet
* Opcode: 0x2005
* When this instruction is executed, these actions occur:
* Update the stack pointer to the current frame pointer + 48
* Pop the old R1 value
* Pop the old R0 value
* Pop the old STATUS value
* Pop the old FLAGS value
* Pop the IP of the next instruction
* Pop the old stack frame
* Restore the last 6 values in an undefined order
## Data movement
@@ -225,6 +260,84 @@ wrapping around to 0.
* Dump
* Opcode: 0xF002
# Interrupts
Interrupts are signaled explicitly from software or from hardware signaling the CPU. When an
interrupt signal is set, the CPU will finish whatever instruction it is executing, and then begin
handling the interrupt whose signal was set. Software interrupts may be invoked using the `int`
instruction, supplying the index of the interrupt to invoke. Hardware interrupts are invoked
directly by a hardware event, e.g. a keypress. Hardware and software interrupts are treated equally
in the CPU, and as such, they are all maskable.
## Interrupt vector table
Interrupts are defined by the IVT register. The address stored in the IVT register must be a
multiple of 64. The IVT always has 512 entries, with 8 bytes for each entry. Thus, the entire table
is 512 * 8 = 4096 bytes, or one page.
## Interrupt table entries
Interrupt table entries make up the interrupt vector table, each entry being 64 bits (8 bytes) long.
* 1 bit - Enabled
* 4 bits - Reserved, set to 0
* 59 bits - Interrupt address, multiplied by 64 for the start address
## Interrupt handling
After an interrupt is signaled, the CPU looks up the index of the interrupt in the IVT, calculates
its address, sets up the stack for the interrupt handler, and jumps to the interrupt handler's
address.
The interrupt stack is structured similarly to a normal call stack, but since interrupts may be
invoked at any time, it saves additional state. Interrupt handlers have two explicit arguments: the
interrupt index itself, and an auxiliary 64-bit value or pointer specific to that interrupt. The
index is stored in the R0 register, and the auxiliary value is stored in the R1 register. These
registers, along with the FP, IP, FLAGS, and STATUS registers are saved on the stack before calling
an interrupt handler.
Before an interrupt handler is called, these actions occur:
* Push the current stack frame pointer
* Push the IP of the next instruction to be called
* Push the FLAGS register
* Push the STATUS register
* Push the R0 register
* Push the R1 register
Interrupt handlers must be exited using the `iret` instruction.
## Exceptions
The first 256 interrupt vectors are reserved for CPU and hardware-sourced events - these are known
as exceptions. Exceptions may occur for a number of reasons:
* Illegal operation attempted, e.g. divide by zero or accessing protected memory
* Illegal operation attempted while handling an interrupt (double fault)
* A hardware event occurred, e.g. a timer tick
The following list defines all exceptions that the CPU may invoke. All other vectors in 0-255 not
defined in this table are reserved and may be used in the future.
* Divide by zero
* Interrupt vector: 0
* Auxiliary: N/A
* Invoked upon a divide-by-zero
* Invalid opcode
* Interrupt vector: 1
* Auxiliary: N/A
* Attempted to invoke an illegal opcode
* Illegal memory address
* Interrupt vector: 2
* Auxiliary: Memory address causing the interrupt
* Attempted to access a memory address in an illegal way - either it's out of bounds or is
protected in some way.
* Hardware event
* Interrupt vector: 3
* Auxiliary: Pointer to the hardware event structure.
* A hardware device has an event that needs attention.
* Interrupt vector 4-255: Reserved for future use
# Binary object format
The binary object format is composed of a header followed by sections that make up the content of