mirror of
https://github.com/ChronosX88/YAVM.git
synced 2024-11-23 11:52:19 +00:00
init commit
This commit is contained in:
commit
caa26dd32a
9
README.md
Normal file
9
README.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# YAVM
|
||||||
|
|
||||||
|
YAVM *(yet another virtual machine)* - is a toy implementation of registry-based virtual (abstract) machine for simple assembler.
|
||||||
|
Features:
|
||||||
|
- Load number into register
|
||||||
|
- Add two numbers
|
||||||
|
- Substract two numbers
|
||||||
|
- Multiple two numbers
|
||||||
|
- Divide two numbers
|
18
main.go
Normal file
18
main.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
vm := NewVM()
|
||||||
|
vm.CurrentProgramBytecode = []uint8{
|
||||||
|
0, 0, 1, 244, // load $0 #500
|
||||||
|
0, 1, 1, 244, // load $1 #500
|
||||||
|
1, 0, 1, 2, // add $0 $1 $2 -> $2 = 1000
|
||||||
|
2, 0, 1, 2, // sub $0 $1 $2 -> $2 = 0
|
||||||
|
3, 0, 1, 2, // multiple $0 $1 $2 -> $2 = 250000
|
||||||
|
4, 0, 1, 2, // divide $0 $1 $2 -> $2 = 1
|
||||||
|
}
|
||||||
|
vm.Run()
|
||||||
|
fmt.Println("Current register state:", vm.Registers)
|
||||||
|
}
|
||||||
|
|
49
opcodes.go
Normal file
49
opcodes.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
type Opcode int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// LOAD is opcode for loading number into register
|
||||||
|
// Args:
|
||||||
|
// 1. register for loading number to
|
||||||
|
// 2. two bytes for number itself
|
||||||
|
LOAD Opcode = 0
|
||||||
|
|
||||||
|
// ADD is opcode for adding two number from register and storing to register which specified in bytecode
|
||||||
|
// Args:
|
||||||
|
// 1. first number from register
|
||||||
|
// 2. second number from register
|
||||||
|
// 3. to which register need to store result of adding
|
||||||
|
ADD Opcode = 1
|
||||||
|
SUB Opcode = 2
|
||||||
|
MULTIPLE Opcode = 3
|
||||||
|
DIVIDE Opcode = 4
|
||||||
|
HALT Opcode = 45
|
||||||
|
ILLEGAL Opcode = 50
|
||||||
|
)
|
||||||
|
|
||||||
|
func OpcodeFrom(b uint8) Opcode {
|
||||||
|
switch b {
|
||||||
|
case 0: {
|
||||||
|
return LOAD
|
||||||
|
}
|
||||||
|
case 1: {
|
||||||
|
return ADD
|
||||||
|
}
|
||||||
|
case 2: {
|
||||||
|
return SUB
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
return MULTIPLE
|
||||||
|
}
|
||||||
|
case 4: {
|
||||||
|
return DIVIDE
|
||||||
|
}
|
||||||
|
case 45: {
|
||||||
|
return HALT
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return ILLEGAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
87
vm.go
Normal file
87
vm.go
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type VM struct {
|
||||||
|
Registers []int32
|
||||||
|
CurrentProgramBytecode []uint8
|
||||||
|
CurrentProgramPos int
|
||||||
|
Remainder uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewVM() *VM {
|
||||||
|
return &VM {
|
||||||
|
Registers: make([]int32, 32),
|
||||||
|
CurrentProgramBytecode: make([]uint8, 0),
|
||||||
|
CurrentProgramPos: 0,
|
||||||
|
Remainder: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vm *VM) Run() {
|
||||||
|
for {
|
||||||
|
if vm.CurrentProgramPos >= len(vm.CurrentProgramBytecode) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
switch vm.decodeOpcode() {
|
||||||
|
case HALT: {
|
||||||
|
fmt.Println("HALT encountered")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case LOAD: {
|
||||||
|
register := uint(vm.next8Bits())
|
||||||
|
number := uint32(vm.next16Bits())
|
||||||
|
fmt.Println(register, number)
|
||||||
|
vm.Registers[register] = int32(number)
|
||||||
|
}
|
||||||
|
case ADD: {
|
||||||
|
number1 := vm.Registers[uint(vm.next8Bits())]
|
||||||
|
number2 := vm.Registers[uint(vm.next8Bits())]
|
||||||
|
targetRegister := vm.next8Bits()
|
||||||
|
vm.Registers[targetRegister] = number1 + number2
|
||||||
|
}
|
||||||
|
case SUB: {
|
||||||
|
number1 := vm.Registers[uint(vm.next8Bits())]
|
||||||
|
number2 := vm.Registers[uint(vm.next8Bits())]
|
||||||
|
targetRegister := vm.next8Bits()
|
||||||
|
vm.Registers[targetRegister] = number1 - number2
|
||||||
|
}
|
||||||
|
case MULTIPLE: {
|
||||||
|
number1 := vm.Registers[uint(vm.next8Bits())]
|
||||||
|
number2 := vm.Registers[uint(vm.next8Bits())]
|
||||||
|
targetRegister := vm.next8Bits()
|
||||||
|
vm.Registers[targetRegister] = number1 * number2
|
||||||
|
}
|
||||||
|
case DIVIDE: {
|
||||||
|
number1 := vm.Registers[uint(vm.next8Bits())]
|
||||||
|
number2 := vm.Registers[uint(vm.next8Bits())]
|
||||||
|
targetRegister := vm.next8Bits()
|
||||||
|
vm.Registers[targetRegister] = number1 / number2
|
||||||
|
vm.Remainder = uint32(number1 % number2)
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
fmt.Println("Unrecognized opcode, terminating VM...")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vm *VM) decodeOpcode() Opcode {
|
||||||
|
opcode := OpcodeFrom(vm.CurrentProgramBytecode[vm.CurrentProgramPos])
|
||||||
|
vm.CurrentProgramPos++
|
||||||
|
return opcode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vm *VM) next8Bits() uint8 {
|
||||||
|
result := vm.CurrentProgramBytecode[vm.CurrentProgramPos]
|
||||||
|
vm.CurrentProgramPos++
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vm *VM) next16Bits() uint16 {
|
||||||
|
result := ((uint16(vm.CurrentProgramBytecode[vm.CurrentProgramPos])) << 8) | uint16(vm.CurrentProgramBytecode[vm.CurrentProgramPos + 1])
|
||||||
|
vm.CurrentProgramPos += 2
|
||||||
|
return result
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user