Add interrupts draft to spec
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
115
vm.md
115
vm.md
@@ -25,8 +25,17 @@ CPU registers are addressed by a value between 0-63 (6 bits). All registers are
|
|||||||
* FLAGS - CPU flags
|
* FLAGS - CPU flags
|
||||||
* STATUS - Generic status code
|
* STATUS - Generic status code
|
||||||
* NIL - Always zero for reading and will never change after writing.
|
* NIL - Always zero for reading and will never change after writing.
|
||||||
|
* IVT - Interrupt vector table pointer
|
||||||
* R0-R31
|
* 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
|
## CPU Flags
|
||||||
|
|
||||||
@@ -190,6 +199,7 @@ wrapping around to 0.
|
|||||||
* Push the current stack frame pointer
|
* Push the current stack frame pointer
|
||||||
* Push the IP of the next instruction
|
* Push the IP of the next instruction
|
||||||
* Update the IP (i.e., jump) to the value at the given source.
|
* Update the IP (i.e., jump) to the value at the given source.
|
||||||
|
* Update the frame pointer to the current stack pointer - 16
|
||||||
* Ret
|
* Ret
|
||||||
* Opcode: 0x2001
|
* Opcode: 0x2001
|
||||||
* When this instruction is executed, these actions occur:
|
* When this instruction is executed, these actions occur:
|
||||||
@@ -209,6 +219,31 @@ wrapping around to 0.
|
|||||||
* When this instruction is executed, these actions occur:
|
* When this instruction is executed, these actions occur:
|
||||||
* Decrement the stack pointer by the size of value at the destination.
|
* Decrement the stack pointer by the size of value at the destination.
|
||||||
* Copy the value at the stack pointer into 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
|
## Data movement
|
||||||
|
|
||||||
@@ -225,6 +260,84 @@ wrapping around to 0.
|
|||||||
* Dump
|
* Dump
|
||||||
* Opcode: 0xF002
|
* 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
|
# Binary object format
|
||||||
|
|
||||||
The binary object format is composed of a header followed by sections that make up the content of
|
The binary object format is composed of a header followed by sections that make up the content of
|
||||||
|
|||||||
Reference in New Issue
Block a user