MVM
MVM Architecture
List of available instructions:
| Op. code | Op. mnemo | Description |
|---|---|---|
0x00 |
NOP |
No operation |
0x01 |
HALT |
Stop the program execution |
0x02 |
PUSH x |
Push number to stack |
0x03 |
POP |
Pop number from a stack |
0x04 |
DUP |
Duplicate the top stack element |
0x05 |
SWAP |
Swap first and second stack elements |
0x06 |
ADD |
Pop 1st and 2nd stack elements, add them and push to stack |
0x07 |
SUB |
Pop 1st and 2nd stack elements, subtract them and push to stack |
0x08 |
MUL |
Pop 1st and 2nd stack elements, multiply them and push to stack |
0x09 |
DIV |
Pop 1st and 2nd stack elements, divide them and push to stack |
0x0A |
NEG |
Negate the top stack element |
0x0B |
NOT |
Pop top stack element. If it's equal to 0 then push 1, else push 0 |
0x0C |
CALL x |
Jump to the x address and push new stack frame |
0x0D |
RET |
Return to the caller and pop the stack frame |
0x0E |
JMP x |
Perform the unconditional jump to x address |
0x0F |
JE x |
Jump to x if top element == 0 |
0x10 |
JNE x |
Jump to x if top element != 0 |
0x11 |
JG x |
Jump to x if top element > 0 |
0x12 |
JL x |
Jump to x if top element < 0 |
0x13 |
JGE x |
Jump to x if top element >= 0 |
0x14 |
JLE x |
Jump to x if top element <= 0 |
0x15 |
LDA x |
Push local variable to stack |
0x16 |
IN |
Read input from stdin |
0x17 |
OUT |
Put top stack value to stdout as char |
0x18 |
CLR x |
Wipe out x values before the top value from the stack |
0x19 |
OVER |
Duplicate and push the second value from the top |
0x1A |
LDL x |
Lift the x from the fp variable to the top of the stack |
0x1B |
STL x |
Store the top stack value under the x from the fp variable |
Example
Example 1
The 2*3+5 formula written as the MVM assembly code:
main: push 2
push 3
call &prd
clr 2
push 5
call &sum
clr 2
halt
sum: lda 0
lda 1
add
ret
prd: lda 0
lda 1
mul
ret
The result of execution with the debug = True flag:
VM {_pc = 0, _fp = -1, _stack = fromList [], _halt = False, _debug = True}
0: Push 2
VM {_pc = 2, _fp = -1, _stack = fromList [2], _halt = False, _debug = True}
2: Push 3
VM {_pc = 4, _fp = -1, _stack = fromList [3,2], _halt = False, _debug = True}
4: Call 21
VM {_pc = 21, _fp = 2, _stack = fromList [6,-1,3,2], _halt = False, _debug = True}
21: Ld 0
VM {_pc = 23, _fp = 2, _stack = fromList [3,6,-1,3,2], _halt = False, _debug = True}
23: Ld 1
VM {_pc = 25, _fp = 2, _stack = fromList [2,3,6,-1,3,2], _halt = False, _debug = True}
25: Mul
VM {_pc = 26, _fp = 2, _stack = fromList [6,6,-1,3,2], _halt = False, _debug = True}
26: Ret
VM {_pc = 6, _fp = -1, _stack = fromList [6,3,2], _halt = False, _debug = True}
6: Clr 2
VM {_pc = 8, _fp = -1, _stack = fromList [6], _halt = False, _debug = True}
8: Push 5
VM {_pc = 10, _fp = -1, _stack = fromList [5,6], _halt = False, _debug = True}
10: Call 15
VM {_pc = 15, _fp = 2, _stack = fromList [12,-1,5,6], _halt = False, _debug = True}
15: Ld 0
VM {_pc = 17, _fp = 2, _stack = fromList [5,12,-1,5,6], _halt = False, _debug = True}
17: Ld 1
VM {_pc = 19, _fp = 2, _stack = fromList [6,5,12,-1,5,6], _halt = False, _debug = True}
19: Add
VM {_pc = 20, _fp = 2, _stack = fromList [11,12,-1,5,6], _halt = False, _debug = True}
20: Ret
VM {_pc = 12, _fp = -1, _stack = fromList [11,5,6], _halt = False, _debug = True}
12: Clr 2
VM {_pc = 14, _fp = -1, _stack = fromList [11], _halt = False, _debug = True}
14: Halt
Done:
VM {_pc = 14, _fp = -1, _stack = fromList [11], _halt = True, _debug = True}
Example 2
The base I/O example - simple echo:
read: in
dup
out
push 0x0A
sub
jne &read ; loop until the input != new line (0x0A)
halt
The execution for the input string Hello, world!:
Hello, world!
Done:
VM {_pc = 8, _fp = -1, _stack = fromList [], _halt = True, _debug = False}
Example 3
The power (2^10) computation - loop variant
push 2
push 10
call &pow
clr 2
halt
pow: lda 1 ; base
lda 0 ; exp
push 1 ; acc
; | Stack:
.loop: ldl 1 ; if exp == 0 | exp
je &.done ; then return | exp
pop ; |
; |
ldl 2 ; Evaluate | acc
ldl 0 ; next power | acc base
mul ; | acc*base
stl 2 ; |
; |
ldl 1 ; Decrement exp | exp
push 1 ; | exp 1
sub ; | exp-1
stl 1 ; |
jmp &.loop ; |
.done: ldl 2 ; | ... acc
ret ; | acc
The result of execution:
Done:
VM {_pc = 8, _fp = -1, _stack = fromList [1024], _halt = True, _debug = False}
Example 4
The power (2^10) computation - recursive variant
push 2 ; base
push 10 ; exp
call &pow
clr 2
halt
pow: lda 1 ; base
lda 0 ; exp
ldl 1 ; push exp to top
je &.edge ; the edge case: if exp == 0 then return 1
pop ; pop exp
; | Stack:
ldl 0 ; | base
ldl 1 ; | base exp
push 1 ; | base exp 1
sub ; | base exp-1
call &pow ; | base exp-1 base^(exp-1)]
clr 1 ; | base base^(exp-1)
mul ; | base*base^(exp-1)
ret ; | base*base^(exp-1)
.edge: pop
push 1 ; return 1
ret
The result of execution:
Done:
VM {_pc = 8, _fp = -1, _stack = fromList [1024], _halt = True, _debug = False}
Example 5
The N-th element of Fibbonaci sequence - recursive variant
push 6
call &fibb
clr 1
halt
fibb: lda 0 ; n | Stack:
ldl 0 ; n == 0 -> return 1 | n
je &.done0 ; | n
pop ; |
ldl 0 ; n == 1 -> return 1 | n
push 1 ; | n 1
sub ; | n-1
je &.done1 ; | n-1
dup ; Evaluate fibb | n-1 n-1
push 1 ; | n-1 n-1 1
sub ; | n-1 n-2
call &fibb ; | n-1 n-2 f(n-2)
clr 1 ; | n-1 f(n-2)
over ; | n-1 f(n-2) n-1
call &fibb ; | n-1 f(n-2) n-1 f(n-1)
clr 1 ; | n-1 f(n-2) f(n-1)
add ; | n-1 f(n-2)+f(n-1)
ret
.done1: pop
push 1
ret
.done0: pop
push 1
ret
The result of execution:
Done:
VM {_pc = 6, _fp = -1, _stack = fromList [13], _halt = True, _debug = False}
Description
Simple stack machine Haskell implementation for educational purposes. The project includes assembly language compiler.
Languages
Haskell
99.7%
Nix
0.3%