16-bit, big-endian, 16-bit address space, 16 general-purpose registers (R0-R15) and flag register, and a simple instruction set.
Register Usage:
R14 is the stack pointer (SP), and R15 is the program counter (PC), R0 is the zero register (always reads as 0, writes are ignored).
Register FLAG is the flag register (-----------IVCNZ), read-only.
I: interrupt enable flag, V: overflow flag, C: carry (borrow) flag, N: negative flag, Z: zero flag.
R1~R13 are general-purpose registers for arithmetic and data manipulation.
Instruction Format:
The CPU is Register-based, with each instruction being 32 bits long (RISC-like), with the following format:
R: [opcode (8 bits)][dest_reg (4 bits)][src1_reg (4 bits)][src2_reg (4 bits)][unused (12 bits)]
I: [opcode (8 bits)][dest_reg (4 bits)][src1_reg (4 bits)][imm_val (16 bits)]
each instruction consists of an opcode, two source registers, and a destination register or an immediate value.
Addressing Modes:
The CPU supports direct register addressing, immediate values, and memory addressing through registers (e.g., [R1] for memory access).
others can be added as needed, but the basic ones are sufficient for a simple emulator.
Relative jumps uses signed values, allowing for jumps forward and backward within a range of -32768 to +32767 bytes from the current PC.
Stacks:
The CPU has a simple stack mechanism, with the stack growing downwards in memory.
The stack pointer (SP) is initialized to the top of the stack area of memory (0xFE00) and is decremented on push and incremented on pop.
Max stack depth is 256 bytes (128 entries), and stack overflow/underflow should be handled gracefully.
Memory Map:
0x0000 - 0xFCFF: General-purpose memory for code and data
0xFD00 - 0xFDFF: Stack area (256 bytes, 128 entries of 16-bit data)
0xFE00 - 0xFEFF: Memory mapped I/O
0xFF00 - 0xFFFF: interrupt vector (256 bytes, 128 entries of 16-bit address)
Memory Banking in EL2:
0xFD00 - 0xFFFF will be fixed in bank 0, while 0x0000 - 0xFCFF can be switched between different memory banks to allow for more than 64KB of addressable memory.
Interrupts:
The CPU uses an interrupt vector table starting at address 0xFF00.
Each entry in the vector table is a 16-bit address pointing to an interrupt handler.
Interrupt vector address formula:
vector_address = 0xFF00 + (imm_val & 0x7F) * 2
PC = MEM16[vector_address]
INT instruction behavior:
push FLAGS
push PC
clear I flag
PC = MEM16[vector_address]
IRET instruction behavior:
pop PC
pop FLAGS
Hardware interrupts in EL2:
EL2 introduces a WAIT instruction that puts the CPU in a not running state until an interrupt occurs.
The CPU has 16 hardware interrupt lines (0-15), and when an interrupt is triggered, the corresponding bit in the interrupt status register is set.
With IRQ_STATUS and IRQ_MASK registers, the CPU can check for pending interrupts and their priority.
IRQ 0 is the highest priority and IRQ 15 is the lowest. When multiple interrupts are pending, the CPU will service the highest priority one first.
IRQ interrupt vector will be calculated as INT 0x70 + IRQ number, allowing for up to 16 hardware interrupts with their own handlers. (e.g., IRQ 4 will trigger INT 0x74)
I/O:
The CPU has a simple memory-mapped I/O system, with specific addresses reserved for input and output operations.
Note: LD, ST instructions in I/O address range (0xFE00-0xFEFF) will be treated as 8-bit I/O operations instead of 16-bit memory operations.
0xFE00: UART I/O Register (write to output a byte, read to input a byte. virtual UART is connected to console)
0xFE01: UART Status Register (bit 0: input ready, bit 1: output ready)
CPUID Instruction:
The CPUID instruction (opcode 0xFD) can be used to query information about the CPU, such as vendor ID, supported features, and extension level.
These values are returned in specific registers.
R1: Vendor ID (currently 0x0000 only)
R2: Extension Level (0 for EL0, 1 for EL1, etc.)
Instructions and Opcodes:
The CPU has a concept called "Extension Level" (EL) which allows for future expansion of the instruction set.
Extension level represents the set of instructions that the CPU supports, with higher levels including all instructions from lower levels plus additional ones.
All Extension levels are backwards compatible, meaning that a CPU with a higher EL can run programs designed for lower ELs, but not vice versa.
EL0 (Base Instructions, minimal set for basic operation):
Load/Store:
0x01: MOV dst_reg, src1_reg - Move data from src1_reg to dst_reg
0x02: LD dst_reg, [src1_reg] - Load data from memory address formed by src1_reg into dst_reg
0x03: ST [dst_reg], src1_reg - Store data from src1_reg into memory address formed by dst_reg
0x04: LDI dst_reg, imm_val - Load immediate value into dst_reg
ALU Operations:
0x05: ADD dst_reg, src1_reg, src2_reg - Add src1_reg and src2_reg, store result in dst_reg
0x06: SUB dst_reg, src1_reg, src2_reg - Subtract src2_reg from src1_reg, store result in dst_reg
Branching:
0x07: JMP imm_val - Jump to the specified address
0x08: JZ imm_val - Jump to the specified address if zero flag is set
0x09: JNZ imm_val - Jump to the specified address if zero flag is not set
Stack Operations:
0x0A: PUSH src_reg - Push data from src_reg onto the stack (SP decrements 2)
0x0B: POP dst_reg - Pop data from the stack into dst_reg (SP increments 2)
Subroutine Calls:
0x0C: CALL imm_val - Call subroutine at the specified address (push return address onto stack and jump)
0x0D: RET - Return from subroutine (pop return address from stack and jump)
Interrupts:
0x0E: INT imm_val - Trigger software interrupt
0x0F: IRET - Return from interrupt
0x10: EI - Enable interrupts (set I flag)
0x11: DI - Disable interrupts (clear I flag)
Special Instructions:
0x00: NOP - No operation
0xFD: CPUID - Return CPU information (e.g., vendor ID, extention level, supported features) in registers
0xFE: RESET - Reset the CPU to initial state
0xFF: HALT - Stop execution
EL1 (Extended Instructions, for more complex operations useful for operating systems and advanced programming):
Extended ALU Operations:
0x12: AND dst_reg, src1_reg, src2_reg - Perform bitwise AND between src1_reg and src2_reg, store result in dst_reg
0x13: OR dst_reg, src1_reg, src2_reg - Perform bitwise OR between src1_reg and src2_reg, store result in dst_reg
0x14: XOR dst_reg, src1_reg, src2_reg - Perform bitwise XOR between src1_reg and src2_reg, store result in dst_reg
0x15: SHL dst_reg, src1_reg, imm_val - Shift src1_reg left by imm_val bits, store result in dst_reg
0x16: SHR dst_reg, src1_reg, imm_val - Shift src1_reg right by imm_val bits, store result in dst_reg
0x17: CMP src1_reg, src2_reg - Compare src1_reg and src2_reg, update flags based on result (dst_reg is ignored)
0x18: TEST src1_reg, src2_reg - Perform bitwise AND between src1_reg and src2_reg, update flags based on result (dst_reg is ignored)
0x19: NOT dst_reg, src1_reg - Perform bitwise NOT on src1_reg, store result in dst_reg
0x1A: INC dst_reg - Increment dst_reg by 1, store result in dst_reg (src1_reg, src2_reg are ignored)
0x1B: DEC dst_reg - Decrement dst_reg by 1, store result in dst_reg (src1_reg, src2_reg are ignored)
0x1C: NEG dst_reg, src1_reg - Negate src1_reg (two's complement), store result in dst_reg (src2_reg is ignored)
Additional Stack Operations:
0x1D: PUSHI imm_val - Push immediate value onto stack (SP increments 2)
Additional Branching:
0x1E: JR src_reg - Jump relative. Jump to address PC + (src_reg value) (useful for loops and function returns without needing an immediate value)
0x1F: JZR src_reg - Jump relative if zero flag is set. Jump to address PC + (src_reg value) if zero flag is set
0x20: JNZR src_reg - Jump relative if zero flag is not set. Jump to address PC + (src_reg value) if zero flag is not set
0x21: JC src_reg - Jump if carry flag is set. Jump to address PC + (src_reg value) if carry flag is set
0x22: JNC src_reg - Jump if carry flag is not set. Jump to address PC + (src_reg value) if carry flag is not set
0x23: JRI imm_val - Jump relative immediate. Jump to address PC + imm_val
Additional Load/Store Instructions:
0x24: LEA dst_reg, src1_reg, imm_val - Load effective address. Calculate address by adding src1_reg and imm_val, store result in dst_reg (useful for accessing local variables on stack or array indexing)
0x25: STI dst_reg, imm_val - Store immediate value to memory address formed by dst_reg. Calculate address from dst_reg, store imm_val at that address (useful for quickly storing constants to memory without needing an extra register to hold the value)
0x26: LDB dst_reg, [src1_reg] - Load byte from memory address formed by src1_reg into dst_reg (similar to LD but for 8-bit data instead of 16-bit)
0x27: STB [dst_reg], src1_reg - Store byte from src1_reg into memory address formed by dst_reg (similar to ST but for 8-bit data instead of 16-bit)
EL2 (Hardware Interupt and Extended Memory Address, for supporting more than 64KB of memory in the future. Not implemented yet, but reserved for future expansion):
BANK, SWITCH, and other instructions for managing multiple memory banks to effectively increase addressable memory space beyond 16 bits.
WAIT, Timer and other hardware interrupt control instructions for more advanced interrupt handling capabilities.
Extended Registers:
Additional registers for managing memory banks, interrupt status, and other advanced features.
IRQ_STATUS: Register to check pending hardware interrupts (bit 0-15 correspond to IRQ 0-15)
IRQ_MASK: Register to enable/disable specific hardware interrupts (bit 0-15 correspond to IRQ 0-15)
BANK_SEL: Register to select active memory bank for extended addressing
BANK_ATTR: Register to set attributes for memory banks (e.g., read/write permissions, cache settings, etc.). It will also be used to determine system memory size during CPUID instruction (e.g., 0 for 64KB, 1 for 128KB, etc.)
Advanced Interrupt Control:
0x28: WAIT - Wait for interrupt (puts CPU in not running state until an interrupt occurs)
0x29: MASKIRQ imm_val - Mask (disable) specific IRQ line(s) based on imm_val bitmask
0x2A: UNMASKIRQ imm_val - Unmask (enable) specific IRQ line(s) based on imm_val bitmask
0x2B: ACKIRQ imm_val - Acknowledge specific IRQ line(s) based on imm_val bitmask (used to clear pending interrupt status after handling)
0x2C: READIRQ dst_reg - Read IRQ status into dst_reg (bit 0-15 correspond to IRQ 0-15 pending status)
Memory Bank Control:
0x2D: BANK dst_reg, imm_val - Select memory bank based on imm_val and store current bank in dst_reg
0x2E: SWITCH dst_reg, imm_val - Switch to memory bank specified by imm_val and store previous bank in dst_reg
EL3 (Paging MMU and Virtual Memory, Privileged Instructions, for implementing virtual memory and more advanced OS features. Not implemented yet, but reserved for future expansion):
In EL3, Supervisor mode instructions are introduced for managing virtual memory, page tables, and other MMU features.
Page fault, Privilege violation, and other exceptions are introduced for handling various error conditions that can occur in a more complex operating system environment.
src3453/cpu_edu
Folders and files
| Name | Name | Last commit date | ||
|---|---|---|---|---|