Skip to content

💾 A simple 8-bit virtual machine emulator written in Rust, designed for learning and experimentation.

License

Notifications You must be signed in to change notification settings

mi66mc/e8bit_emulator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

41 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

e8Bit Emulator

Crates.io Project GitHub mi66mc

This project is a simple 8-bit virtual machine (VM) emulator written in Rust. It simulates a basic CPU with registers, memory, and a set of instructions for performing arithmetic, memory operations, and control flow.

Features

  • Registers: Five general-purpose 8-bit registers (A, B, C, D, E).
  • Memory: 256 bytes of memory.
  • Instruction Set:
    • Arithmetic: ADD, SUB, MUL, DIV, MOD, MULH
    • Data Movement: MOV, STORE
    • Memory Access: Supports [0], [A], [B], etc.
    • Control Flow: JMP, JZ, JNZ, LOOP
    • Input/Output: INPUT, PRINT, PRINTCH
    • Program Termination: HALT
    • Screen Operations: DRAW, CLS, RENDER
    • Comparison: CMP
    • Random Number: RAND
  • Zero Flag: Indicates whether the result of the last operation is zero, often used for conditional branching or logical evaluations. Comparisons evaluate to false (non-zero) or true (zero), enabling conditional logic.
  • Custom Parsing: Accepts comments (//) and instruction separation via ; or by lines.
  • Character Literals: Supports character literals in instructions, e.g., MOV A 'p'. Characters are internally treated as their ASCII numeric values and must fit within 8 bits (0–255), just like any other number.
  • Debug Mode: Optional debug mode for detailed output during execution.
  • IDLE Mode: Allows direct input of instructions for testing and debugging.
  • Screen Rendering: Supports drawing characters on an 80 by 25 virtual screen and rendering it to the console.
  • Label Support: You can now use labels for control flow instructions (JMP, JZ, JNZ, LOOP) instead of numeric instruction indices.

Label Support

You can define a label by writing it at the start of a line followed by a colon, e.g. LOOP_START:.
You can then use the label name as the target for JMP, JZ, JNZ, or LOOP instructions:

MOV A 0
MOV B 10
LOOP_START:
ADD A 1
PRINT A
CMP A B
JNZ LOOP_START
HALT

This is equivalent to using numeric indices, but is easier to read and maintain.

Example Programs

The files game.e8, game2.e8, example.e8, example2.e8, example3.e8, example4.e8, example5.e8, example6.e8, example7.e8, and others contain example programs that demonstrate the use of registers, arithmetic operations, memory storage, loops, and conditional logic.

Even or Odd Example:

// EVEN OR ODD

INPUT A     // get number from user input
MOD A 2     // get remainder of A divided by 2
CMP A 0     // compare A with 0, if true, zero flag set to true
JZ EVEN     // EVEN (jump to label EVEN if zero)

MOV C 'O'   // ODD
PRINTCH C -N
MOV C 'D'
PRINTCH C -N
PRINTCH C -N
JMP END

EVEN:
MOV C 'E'   // EVEN
PRINTCH C -N
MOV C 'V'
PRINTCH C -N
MOV C 'E'
PRINTCH C -N
MOV C 'N'
PRINTCH C -N

END:
HALT        // end program

Factorial Example (example.e8):

// FACTORIAL SCRIPT

// registers
MOV A 1;           // A = 1 (result)
MOV B 5;           // B = 5 (number to get factorial)

LOOP_START:
MUL A B;           // A *= B
SUB B 1;           // B -= 1
LOOP LOOP_START B; // if B != 0 go to LOOP_START

// END
PRINT A;           // shows result
HALT;

How to Run

  1. Install Rust: Ensure you have Rust installed. You can download it from rust-lang.org.

  2. Compile the Program:

    cargo build --release
  3. Run the Emulator:

    cargo run example.e8 -d

    Replace example.e8 with the path to your program file.

    If no file is specified, it will run in IDLE mode, where you can enter instructions directly.

    The -d flag is optional and enables debug mode, which provides additional output for debugging purposes.

How to Write Programs

Programs for the emulator are written in a custom assembly-like language. Each instruction is written on a new line or separated by a semicolon and can include comments starting with //. Refer to the example programs above for syntax.

Instruction Set

Instruction Description
MOV A 10 Move value 10 into register A
MOV A 'p' Move character literal 'p' into register A (ASCII value)
MOV A [0] Move value from memory address 0 into A
MOV A [B] Move value from memory at index stored in B
ADD A B A = A + B
SUB A 1 A = A - 1
MUL A 2 A = A * 2
DIV A 2 A = A / 2
MOD A 2 A = A % 2 (remainder after division)
MULH A B C A = high byte of (B * C)
STORE A [0] Store A into memory[0]
STORE A [B] Store A into memory at index in B
INPUT A Read input (u8 or char) into register A
INKEY A Reads a single key press (non-blocking), stores ASCII code of the key in register A, or 0 if no key was pressed. Only character keys are returned.
JMP 10 / JMP LABEL Jump to instruction index 10 or to label LABEL
JZ 5 / JZ LABEL Jump to index 5 or label if last result was 0 (zero flag set)
JNZ 8 / JNZ LABEL Jump if last result was not zero (zero flag not set)
LOOP 3 C / LOOP LABEL C Jump to index 3 or label while C != 0
PRINT A Print value of A with newline
PRINT A -N Print value of A without newline
PRINTCH A Print character represented by value in A
PRINTCH A -N Print character without newline
DRAW X Y C Draw character C at screen position (X, Y)
CLS Clear the screen
CTS Clear the terminal screen
RENDER Render the screen to the console (80x25)
SLP 1000 Pause execution for 1 second (1000 ms)
HALT Stops program execution
CMP A 10 Compare register A with value 10. Sets the zero flag if equal.
RAND A Set register A to a random value between 0–255

Args Types

Type Example Description
Register A, B, C, D, E One of the five registers
Immediate Value 42, 'p' A literal number or character between 0–255
Memory Address [0] Direct access to memory index 0
Memory via Reg [A] Access memory using value in register A

Note: Square brackets ([]) are used to specify memory addresses. For example:

  • MOV A [0] loads the value from memory address 0 into register A.
  • STORE A [0] stores the value of register A into memory address 0.

Args Types Supported

Instruction Arg 1 Type Arg 2 Type Arg 3 Type
MOV Register Immediate Value, Register, or Memory Address ([0], [A], etc.) -
ADD Register Immediate Value, Register, or Memory Address -
SUB Register Immediate Value, Register, or Memory Address -
MUL Register Immediate Value, Register, or Memory Address -
DIV Register Immediate Value, Register, or Memory Address -
MOD Register Immediate Value, Register, or Memory Address -
MULH Register Register Register
STORE Register Memory Address ([0], [B], etc.) -
JMP Immediate Value - -
JZ Immediate Value - -
JNZ Immediate Value - -
LOOP Immediate Value (Instruction Index) Register -
PRINT Register Optional: -N to suppress newline -
PRINTCH Register Optional: -N to suppress newline -
INPUT Register - -
DRAW Immediate Value, Register, or Memory Address Immediate Value, Register, or Memory Address Immediate Value, Register, or Memory Address
CLS - - -
CTS - - -
RENDER - - -
SLP Milliseconds - -
HALT - - -
CMP Register Immediate Value, Register, or Memory Address -
RAND Register - -

Tips

  • Use the CTS instruction to clear the terminal screen and CLS to clear virtual screen.
  • Use the MOD instruction to easily check for even/odd numbers or perform modular arithmetic.
  • The CMP instruction is useful for conditional branching with JZ and JNZ.
  • Use PRINTCH for ASCII output and PRINT for numeric output.
  • The virtual screen is 80 columns by 25 rows; use DRAW, CLS, and RENDER for simple graphics.

Future Improvements

  • Add support for more instructions.
  • Implement debugging tools.
  • Enhance error handling for invalid programs.

License

This project is open-source and available under the MIT License.

Notes on INKEY

  • INKEY A reads a single key press (non-blocking) and stores the ASCII code of the pressed key in register A.
  • If no key was pressed, A is set to 0.
  • Only character keys are returned (e.g., letters, numbers, symbols). Special keys like arrows, F1, etc., are ignored or return 0.
  • The zero flag is set if no key was pressed (A == 0).
  • Useful for real-time input in games or interactive programs.

About

💾 A simple 8-bit virtual machine emulator written in Rust, designed for learning and experimentation.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages