Created
October 5, 2011 16:30
-
-
Save nileshtrivedi/1264930 to your computer and use it in GitHub Desktop.
A simple virtual machine to experiment with minimal instruction sets
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# My attempt to implement a simple virtual machine with a minimal instruction set | |
# 8-bit computer, fixed-size memory, single cpu, 0-registers, based on von-neumann architecture | |
# No support for interrupts or I/O although we cheat and provide a "print" instruction :) | |
# The goal is to find a minimal, but turing-complete, instruction set | |
# For simplicity, every instruction has two operands, which are located adjacent to it in the memory | |
# This code is just to experiment with various instruction sets and not to be taken seriously | |
# Next fun step would be to develop a language/compiler for this virtual machine | |
class Memory | |
def initialize(size, program) | |
puts "initialising memory of #{size} bytes..." | |
raise "cannot load a program larger than #{size} bytes" if program.size > size | |
@size = size | |
@bytes = program # TODO: we should check here that program is an array of 8-bit integers only | |
end | |
def read(address) | |
raise "attempt to read beyond address #{(@size -1)}: #{address}" if address >= @size | |
@bytes[address] | |
end | |
def write(address, value) | |
raise "attempt to write beyond address #{(@size -1)}: (#{address},#{value})" if address >= @size | |
raise "attempt to write a value bigger than 255: (#{address},#{value}" if value > 255 | |
raise "attempt to write a value lesser than 0: (#{address},#{value}" if value < 0 | |
@bytes[address] = value | |
end | |
end | |
class Computer | |
def initialize(mem_size, program) | |
# program is loaded into memory upon booting | |
@memory = Memory.new(mem_size, program) | |
puts "booting the os..." | |
execute(0) # start executing instructions from the first byte in the memory | |
end | |
def execute(address) | |
i = @memory.read(address) | |
# pre-fetch the operands even though one or both may be unnecessary. Scope for optimization here. | |
o1 = @memory.read(address + 1) | |
o2 = @memory.read(address + 2) | |
case i # this is where we implement our instruction set | |
when 0: | |
# conditional print - print value at address o1 (in decimal) if value at address o2 is non-zero | |
flag = @memory.read(o2) | |
if flag != 0 | |
v = @memory.read(o1) | |
puts v.to_s | |
end | |
when 1: | |
# write - value at address o2 is written to address o1: i.e. copy. | |
v = @memory.read(o2) | |
@memory.write(o1, v) | |
when 2: | |
# add - value at address o2 is added into value at address o1 | |
v = @memory.read(o2) | |
orig = @memory.read(o1) | |
@memory.write(o1, orig + v) | |
when 3: | |
# subtract - value at address o2 is subtracted from value at address o1 | |
v = @memory.read(o2) | |
orig = @memory.read(o1) | |
@memory.write(o1, orig - v) | |
when 4: | |
# multiply - value at address o2 is multiplied into value at address o1 | |
v = @memory.read(o2) | |
orig = @memory.read(o1) | |
@memory.write(o1, orig * v) | |
when 5: | |
# divide - value at address o1 is divided by value at address o2 | |
v = @memory.read(o2) | |
orig = @memory.read(o1) | |
@memory.write(o1, orig / v) | |
when 6: | |
# conditional jump - start executing from instruction at address o1 if value at address o2 is non-zero | |
v = @memory.read(o2) | |
execute(o1) if v != 0 | |
when nil: | |
raise "no instruction found at address: #{address}. Halting." | |
end | |
execute(address + 3) # move to the next instruction | |
end | |
end | |
# Sample programs to do some trivial tasks | |
# multiply 13 with 10 and print the result | |
Computer.new(64,[4,6,7,0,6,0,13,10]) | |
# infinite loop using jump which prints 111. Will halt with StackOverflow error. | |
Computer.new(64,[0,6,1,6,0,1,111]) | |
# TODO: program to print squares of 1 to 10 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment