A few days before, I have read an article - write a very small stack-based virtual machine in C, It is very interesting, so I try to write it in Codea, please see the code below:
-- miniVM
-- Use this function to perform your initial setup
function setup()
print("Hello World! Welcome to miniVM")
step = false
running = true
-- instruction set
InstructionSet = {"PSH","ADD","POP","SET","HLT"}
Register = {A, B, C, D, E, F,NUM_OF_REGISTERS}
-- test program code
program = {"PSH", "5", "PSH", "6", "ADD", "POP", "HLT"}
-- instruction pointer, top of stack pointer, stack
IP = 1
SP = 0
stack = {0,0,0,0,0}
end
-- fetch the instruction
function fetch()
return program[IP]
end
-- evaluate
function eval(instr)
if instr == "HLT" then
running = false
elseif instr == "PSH" then
-- deal with PSH
SP = SP + 1
-- instruction pointer point to the next
IP = IP + 1
stack[SP] = program[IP]
elseif instr == "POP" then
-- deal with POP
local val_popped = stack[SP]
-- table.remove(stack)
SP = SP - 1
elseif instr == "ADD" then
-- deal with ADD
-- POP a value from stack
local a = stack[SP]
stack[SP] = 0
SP = SP - 1
-- POP a value from stack again
local b = stack[SP]
stack[SP] = 0
SP = SP - 1
-- add two value
local result = a + b
-- push the sum into the stack
SP = SP + 1
stack[SP] = result
-- print the status of the stack
print(stack[SP])
end
end
-- virtual machine main loop
function main()
running = true
while running do
eval(fetch())
IP = IP + 1
end
end
-- main()
-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(40, 40, 50)
if running then
if step then
step = false
eval(fetch())
IP = IP + 1
end
end
drawInstr()
drawStack()
end
function touched(touch)
if touch.state == ENDED then step = true end
end
VM = {}
-- draw the status of the instruction in the memory
function drawInstr()
local x,y=500,600
textMode(CORNER)
fontSize(30)
strokeWidth(2)
stroke(0, 21, 255, 255)
for k,v in ipairs(program) do
-- draw the instruction which will execute
local w,h = textSize(k)
fill(54, 61, 50, 255)
rect(x,y-(k-1)*h,w+80, h)
fill(95, 255, 0, 255)
text(v,x+10,y-(k-1)*h)
-- draw the memory address
fill(54, 61, 50, 255)
rect(x-w-20,y-(k-1)*h,w+20, h)
fill(0, 50, 255, 255)
text(k,x-w-20+10,y-(k-1)*h)
-- draw IP
fill(228, 11, 11, 255)
text("IP".."["..IP.."] ->",x-w-20+10-120,y-(IP-1)*h)
end
end
-- draw the status of stack
function drawStack()
local x,y=200,600
textMode(CORNER)
fontSize(30)
strokeWidth(2)
stroke(0, 21, 255, 255)
for k,v in ipairs(stack) do
-- draw the instruction pushed into the stack
local w,h = textSize(k)
fill(54, 61, 50, 255)
rect(x,y-(k-1)*h,w+80, h)
fill(95, 255, 0, 255)
text(v,x+10,y-(k-1)*h)
-- draw stack adress
fill(54, 61, 50, 255)
rect(x-w-20,y-(k-1)*h,w+20, h)
fill(0, 50, 255, 255)
text(k,x-w-20+10,y-(k-1)*h)
-- draw SP
fill(216, 210, 210, 255)
text("SP".."["..SP.."] ??",x-w-20+10-120,y-(SP-1)*h+5)
end
end
Here is the screenshot:
It is very simple, only to show the basic principle of a stack-based virtual machine, I am learning an more complex virtual system - Forth, and will post a more complex virtual machine code soon.