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