init commit

This commit is contained in:
ChronosX88 2020-02-17 20:55:41 +04:00
commit caa26dd32a
5 changed files with 166 additions and 0 deletions

9
README.md Normal file
View 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

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module github.com/ChronosX88/YAVM
go 1.13

18
main.go Normal file
View 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
View 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
View 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
}