A lightweight 16-bit virtual machine implementation in C that simulates a simplified x86-like architecture with custom instruction set.
This project implements a virtual machine with a 16-bit CPU architecture, 65KB memory space, and a custom instruction set designed for educational purposes and low-level system programming research.
- 16-bit CPU Architecture: Simulated processor with register-based operations
- 65KB Memory Space: Flat memory model with stack support
- Custom Instruction Set: 15+ opcodes including data movement, stack operations, and flag manipulation
- Error Handling: Comprehensive error codes and graceful failure modes
- Debugging Support: Memory inspection and register state output
graph TB
subgraph "Virtual Machine"
CPU[CPU Unit]
MEM[Memory 65KB]
STACK[Stack Pointer]
end
subgraph "CPU Registers"
AX[AX Register]
BX[BX Register]
CX[CX Register]
DX[DX Register]
SP[Stack Pointer]
IP[Instruction Pointer]
FLAGS[Flags Register]
end
CPU --> AX
CPU --> BX
CPU --> CX
CPU --> DX
CPU --> SP
CPU --> IP
CPU --> FLAGS
CPU <--> MEM
STACK -.-> MEM
flowchart TD
START([Program Start]) --> INIT[Initialize VM]
INIT --> FETCH[Fetch Instruction]
FETCH --> DECODE[Decode Opcode]
DECODE --> EXECUTE[Execute Instruction]
EXECUTE --> CHECK{Halt?}
CHECK -->|No| UPDATE[Update IP]
UPDATE --> FETCH
CHECK -->|Yes| OUTPUT[Print Registers]
OUTPUT --> END([Program End])
EXECUTE --> ERROR{Error?}
ERROR -->|Yes| ERR_HANDLE[Handle Error]
ERR_HANDLE --> END
graph LR
subgraph "Memory Space (65KB)"
LOW[0x0000<br/>Program Start]
PROG[Program Code]
DATA[Data Segment]
STACK_TOP[0xFFFF<br/>Stack Top]
end
STACK_TOP --> STACK_GROW[Stack Growth ↓]
- GCC compiler
- Make utility
- Standard C library
# Compile the virtual machine
make
# Clean build artifacts
make clean# Execute the virtual machine with example program
./virtual-machine| Opcode | Hex | Description | Arguments |
|---|---|---|---|
mov |
0x08-0x0F | Move data to register | 1-2 bytes |
push |
0x1A | Push register to stack | 1 byte |
pop |
0x1B | Pop from stack to register | 1 byte |
| Opcode | Hex | Description |
|---|---|---|
ste |
0x10 | Set Equal flag |
cle |
0x11 | Clear Equal flag |
stg |
0x12 | Set Greater-than flag |
clg |
0x13 | Clear Greater-than flag |
sth |
0x14 | Set Higher flag |
clh |
0x15 | Clear Higher flag |
stl |
0x16 | Set Lower flag |
cll |
0x17 | Clear Lower flag |
| Opcode | Hex | Description |
|---|---|---|
nop |
0x01 | No operation |
hlt |
0x02 | Halt execution |
- AX: Accumulator register (16-bit)
- BX: Base register (16-bit)
- CX: Count register (16-bit)
- DX: Data register (16-bit)
- SP: Stack Pointer (points to top of stack)
- IP: Instruction Pointer (current instruction address)
- FLAGS: Status flags register
graph LR
subgraph "FLAGS Register"
BIT7[Bit 7-4<br/>Reserved]
BIT3[Bit 3<br/>Equal Flag]
BIT2[Bit 2<br/>Greater Flag]
BIT1[Bit 1<br/>Higher Flag]
BIT0[Bit 0<br/>Lower Flag]
end
| Code | Hex | Description |
|---|---|---|
NoErr |
0x00 | No error |
SysHlt |
0x01 | System halt |
ErrMem |
0x02 | Memory error |
ErrSegv |
0x04 | Segmentation fault |
ErrInstr |
0x08 | Illegal instruction |
#include "Virchual-Machine.h"
int main() {
VM *vm = virtualmachine();
// Create a simple program
Program *prog = exampleprogram(vm,
i(i1(mov, 0x05)), // mov ax, 0x05
i(i0(ste)), // set equal flag
i(i1(push, 0x00)), // push ax
i(i1(0x09, 0x5005)), // mov bx, 0x5005
i(i1(pop, 0x01)), // pop bx
i(i0(hlt)) // halt
);
execute(vm);
return 0;
}graph TD
subgraph "Instruction Format"
OPCODE[Opcode: 1 byte]
ARG1[Argument 1: 1-2 bytes]
ARG2[Argument 2: 1-2 bytes]
end
OPCODE --> ARG1 --> ARG2
subgraph "Example: mov ax, 0x05"
OP[0x08<br/>mov ax]
ARG[0x05<br/>value]
end
OP --> ARG
Virtual-Machine-Platform/
├── Virchual-Machine.h # Header file with structures and declarations
├── Virchual-Machine.c # Main implementation
├── x86args.h # Assembly argument handling utilities
├── Makefile # Build configuration
└── README.md # This documentation
- Define opcode in
Virchual-Machine.henum - Add to
instrmaparray - Implement instruction function
- Add case in
execinstr()switch
The VM uses a flat memory model with 65KB addressable space:
graph TB
subgraph "Memory Map"
CODE[0x0000-0x7FFF<br/>Code Segment]
DATA[0x8000-0xBFFF<br/>Data Segment]
STACK[0xC000-0xFFFF<br/>Stack Segment]
end
- Architecture: 16-bit CISC-like
- Memory: 65KB flat address space
- Registers: 7 general-purpose + flags
- Instruction Set: 15+ opcodes
- Stack: Full-descending, grows toward lower addresses
- Endianness: Little-endian
- Programming Language: C99
- Fork the repository
- Create a feature branch
- Implement your changes
- Add tests if applicable
- Submit a pull request
This project is provided for educational and research purposes. Please see the license file for details.
- Inspired by x86 architecture principles
- Designed for low-level programming education
- Built with standard C99 for maximum portability