Yes, I know the post is super old. I'm currently working on a VM (for running the VM code) in Love 2D.
https://love2d.org Lua isn't my favorite language but once you get over a few quirks it's pretty easy to learn and use.
So far I have a working screen, keyboard, and it boots up a simple "no OS" firmware (compiled with Jack).
I've been tweaking it but at this point it supports all the VM instructions, so I'll be trying something a bit more advanced soon. You just drag and drop a folder with .VM files on top of the window and then it will load that into the VM and "reboot".
It's about 500 lines of Lua so far. Writing the VM was pretty trivial (far simpler than writing the VM translator IMHO). It just stores the textual instructions in a large indexed array. During preprocessing labels are prefixed with the filename and there is also a jump table for labels/functions to associate the name with the location. Otherwise it's just fetch/execute.
Actual opcodes look a bit like:
-- and
function op_and()
a = _pop()
b = _pop()
_push(bit.band(a,b))
end
-- return
function op_return()
-- save the end frame and return address so we don't clobber them
end_frame = ram[LCL]
returnaddress = ram[end_frame-5]
ram[ram[ARG]] = _pop() -- reposition the return value
-- restore our frame
ram[THAT] = ram[end_frame-1]
ram[THIS] = ram[end_frame-2]
ram[ARG] = ram[end_frame-3]
ram[LCL] = ram[end_frame-4]
PC = returnaddress -- jump to return address
end
It'd probably be even easier to actually emulate the lower-lever hardware than to emulate the VM. Only two instructions you have to worry about!