https://github.com/deshrike/intmachine
A virtual computer written in python, with assembler and debugger.
https://github.com/deshrike/intmachine
assembler cpu debugger intcode preprocessor virtual-machine
Last synced: about 1 month ago
JSON representation
A virtual computer written in python, with assembler and debugger.
- Host: GitHub
- URL: https://github.com/deshrike/intmachine
- Owner: DeShrike
- License: gpl-3.0
- Created: 2020-05-03T09:01:06.000Z (about 6 years ago)
- Default Branch: master
- Last Pushed: 2021-01-04T15:05:56.000Z (over 5 years ago)
- Last Synced: 2025-03-29T13:51:50.787Z (about 1 year ago)
- Topics: assembler, cpu, debugger, intcode, preprocessor, virtual-machine
- Language: Python
- Homepage:
- Size: 256 KB
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# IntMachine
A virtual computer/CPU written in python, with an assembler and debugger.
Has a 16 bit CPU with 4 all-purpose registers.
Assembly language based loosely on 8086.
Can use 64K 2-byte memory locations.

## Usage
```
python Main.py [--debug]
```
Example:
```
python Main.py programs/prog0.iasm --debug
```
Running without the debugger currently just runs the program and then shows the variables and their final value.
## Sample Program
```
// Calculate Number1 * Number2 and store result in Product
DATA // Start the DATA block
Number1: 7, word[1] // Reserve a location in memory to hold a number and initialize it to 7
Number2: 6, word[1] // A second variable with value 6
Product: 0, word[1] // A third veriable
Stack: 0x5555, word[32] // Reserve 32 words for the stack (not used in this program)
CODE // Start the CODE block
Main: // Entry point
JMP DummyLabel // Jump to DummyLabel
PUSH AX // PUSH the value of register on the stack (this code is never reached)
POP AX // POP a value from the stack and place it in register AX
DummyLabel: // Define a label
MOV AX, Number1 // Load address of Number1 in AX
MOV BX, [AX] // Load value of Number1 in BX
MOV AX, Number2 // Load address of Number2 in AX
MOV CX, [AX] // Load value of Number2 in CX
MUL CX, BX // CX = CX * BX
MOV AX, Product // Load address of Product in AX
STOR CX, [AX] // Store value of CX in memory location of Product
HLT // Halt the CPU
```
## TODO
- Implement NOT
- Implement/Fix CF and OF
- Check setting of CPU Flags
- Test on Linux
- Test on Mac
- Scope variables to the file they are defined in
- Add support for 'System-Code': code that always runs at full speed in the debugger
- Add support for #define to preprocessor
- Implement array initializers to assembler
- Add new screenshot(s)
# Dependancies
None
# Compatibility
Tested with Python 3.7.0, but should also work with 3.5.0 and above.
Developed on Windows 10.
Runs in terminal (CMD.exe), powershell terminal and mintty (Git Bash).
Tested on a Raspberry PI 3B+ using PuTTY.
# Source Code
## Program.py
Contains:
- sourcecode
- preprocessor result
- assembler result, this is the intcode for the CPU
## Display.py
A 64 x 16 8 color text display.
## Preprocessor.py
Preprocesses source files, preparing them for the assembler. This includes processing IMPORT statements.
## Assembler.py
Can convert preprocessed assembler code into intcode.
## Compiler.py
Not implemented yet
## Computer.py
Contains:
- Memory: 64K 2-byte words
- CPU
The computer can load a program into memory and use the CPU to execute it
## Cpu.py
Has access to the computers memory.
Can execute intcode instructions from memory.
## Label.py
Defines labels/variables.
## Instruction.py
Defines a CPU instruction.
## Parameter.py
Defines a patrameter to an instruction.
## Debugger.py
Displays memory contents, CPU registers and flags, current intruction and variables.
Allows executing a program step by step.
## Definitions.py
Misc definitions used by all modules.
## Ansi.py
Used by the debugger to write to the screen.
## KeyGetter.py
Used by the debugger to process keystrokes.
# Assembly language
The CPU is loosely based on the 8086 and so are the mnemonics.
## Conventions
A program must have a label called Main. This is where execution will start.
A program must also have a variable called Stack. The stackpointer will be pointed to that variable when execution starts.
There is no guard against stack overflow, so make the stack large enough.
## Variables
The assembler currently supports 3 data types: word, byte and string.
Examples:
```
TheAnswer: 42, word[1]
Greeting: "Hello world", string[30]
OtherNumber: 7, byte[1]
Stack: 0x5555, word[32]
```
Currently there is no variable scope; all variables are global.
Variable names are truncated to 12 characters.
## Bootstrap
The assembler adds 2 instructions to the beginning of the program:
```
MOV SP, Stack // Initialize the stackpointer
JMP Main // Jump to Main
```
## Registers
IP : Instruction pointer
SP : Stack pointer
IX : Index register
AX
BX
CX
DX
## Flags
SF : Sign flag
OF : Overflow flag
ZF : Zero flag
CF : Carry flag
PF : Parity flag
IF : Interrupt flag (Not used yet)
## Instructions
#### JMP
Unconditional jump
```
JMP Labelname
```
#### MOV
Move values to registers
```
MOV AX, BX
MOV BX, 1234
MOV CX, 0xABBA
MOV DX, 0b11110000
MOV AX, [BX]
MOV BX, Labelname
```
#### STOR
Set memorylocation to a value
```
STOR 123, [AX]
STOR BX, [CX]
```
#### CALL
Calls a subroutine.
```
CALL Subroutine
```
#### RET
Return from a subroutine.
```
RET
```
#### PUSH
Push a value on the stack
```
PUSH AX
PUSH BX
```
#### POP
Pop a value from the stack
```
POP BX
POP AX
```
#### PUSHF
Push the flags to the stack
```
PUSHF
```
#### POPF
Pop the flags from the stack
```
POPF
```
#### ADD
Addition.
```
ADD AX, 7 // AX = AX + 7
ADD BX, CX // BX = BX + AX
ADD CX, 0x10 // CX = CX + 16
```
#### SUB
Subtraction.
```
SUB AX, 7 // AX = AX - 7
SUB BX, CX // BX = BX - AX
SUB CX, 0x10 // CX = CX - 16
```
#### MUL
Multiplication.
```
MUL AX, 7 // AX = AX * 7
MUL BX, CX // BX = BX * AX
MUL CX, 0x10 // CX = CX * 16
```
#### DIV
Integer division. Remainder is in DX.
```
DIV AX, 7 // AX = AX / 7
DIV BX, CX // BX = BX / AX
DIV CX, 0x10 // CX = CX / 16
CMP DX, 0
JZ NoRemainder
```
#### AND
Bitwise AND.
```
AND AX, 7
AND BX, CX
AND CX, 0b10101010
```
#### OR
Bitwise OR.
```
OR AX, 7
OR BX, CX
OR CX, 0b10101010
```
#### XOR
Bitwise XOR.
```
XOR AX, 7
XOR BX, CX
XOR CX, 0b10101010
```
#### NOT
#### DEC
Decrement.
```
DEC AX // AX = AX - 1
```
#### INC
Increment.
```
INC BX // BX = BX - 1
```
#### SHL
Bit shift left.
```
SHL AX
```
#### SHR
Bit shift right.
```
SHR BX
```
#### JZ
Jump if ZF is set.
```
CMP AX, 10
JZ Loop
```
#### JNZ
Jump if ZF is not set.
```
CMP AX, 10
JNZ Loop
```
#### JO
Jump if OF is set.
```
MUL AX, 10
JO Loop
```
#### JNO
Jump if OF is not set.
```
MUL AX, 10
JNO Loop
```
#### JC
Jump if CF is set.
```
ADD AX, 10
JC Loop
```
#### JNC
Jump if CF is not set.
```
ADD AX, 10
JNC Loop
```
#### JL
#### JLE
#### JG
#### JGE
#### NOP
No operation. Does nothing.
```
NOP
```
#### HLT
Halts the CPU.
```
HLT
```
## Addressing modes
### Direct
The value for the parameter is provided in the instruction:
```
MOV AX, 5
MOV AX, 0xABBA
MOV BX, 0b10101010
MOV CX, Variablename
```
### Register
When the parameter is a register
```
MOV AX, BX
CMP AX, CX
NOT DX
```
### Reference
To reference memory, the address must be loaded in one of the registers, like so:
```
MOV AX, VariableName // Loads the address of 'VariableName' in AX.
```
Then that memory location can be accessed:
```
MOV BX, [AX] // Load the value at memorylocation [AX] in BX.
STOR CX, [AX] // Store the value of CX at the memory location AX is pointing at.
```
### Indexed
```
MOV BX, [AX+IX] // Load the value at memorylocation [AX+IX] in BX.
STOR CX, [AX+IX] // Store the value of CX at the memory location AX+IX is pointing at.
```
# Roadmap
- Add support for floating point instructions.
- Add support for input.
- Write a library with common functions.
- Add a compiler that can compile (transpile ?) a higher level language to assembly sourcecode.