[virtmach] Your VM

Thomas Fjellstrom virtmach@iecc.com
Tue, 29 May 2001 03:29:45 -0600

MickaŽl Pointier wrote:
> > I know you asked for every body elses ideas but the VM that
> > I made seems slow to me when thinking of the average number
> > of instructions per second that my VM does (600,000-800,000) but
> > after writing a small graphics demo (blits, putpixles,
> > textout, clear_to_color) it turns out that the VM is more
> > than fast enough to do what I need.
> Of course, if the script code is only used to sequence very high
> level/cpu intensive functions like those 2D treatments you're talking
> about, then the script code will almost not beeing visible on a profiling
> evaluation of the code :)

But if I compare this VM code:

MOVL %AC, 10000000
LOOP noop_loop

to this C code:

{ volatile int i=10000000; while(i--); }

the C code finishes in a few nano seconds, while
the VM code takes 5 seconds (at 2 million IPS)

speedy ;)

> > It only has 46 instructions
> What kind of instructions, does it look like say 6502 processor kind
> of instructions ? (load, store, shift left or right, and so on).

Sort of looks like the x86...
in short: (all are 'OP dest ?[, src]?', dest == mem/register
           src = mem/register/literal value)
          (dest and src can be modified by an ST prefix which
           makes the value a index into the stack)
MOV dest, src
ADD dest, src
SUB dest, src
MOD dest, src
DIV dest, src
SHL dest
SHR dest
LOR dest, src (logical or, ||)
LAND dest, src (logical and, &&)
PUSH src
POP dest
CALL src (call vm func)
CMP src, src
JLE src (jump if <=)
JGE src (jump if >=)
JL src (jump if <)
JG src (jump if >)
JE src (jump if ==)
JNE src (jump if !=)
JMP src (unconditional jump to 'src')
... (etc...)
INT src (call a native function, no return value)
CALLEX src (call a native function,
            ret value placed in %R register)
DUMP (dumps registers and flags to stdout in readable form)
HLT (halts the vm)

> > (so far), 36 (32bit) general registers where each byte, and
> > short (16bit) can be individualy accessed,
> Interesting, like accessing AL or AH on x86 registers ? (except you
> can do it for the upper part of EAX too :)

this is how you would move the literal integer value '32' into
register %AA : MOVL %AA, 32
and here is how you can move the same value to
the lower 16bits: MOVL %AASW1, 32
(change the 'S' to a 'U' for unsigned)
or the lowest 8bits: MOVL %AASB3, 32

(at least you can using the assembler that
 I wrote for it so I didn't have to twiddle
 bits till I went crazy...)

> > a stack pointer
> > register, a RET (return value, for functions) register,
> Does it support local variables ? Can you access any value
> directly from memory/stack, or should you load it into one
> of your 36 general registers first ?

you can access any point in the stack and memory at any time...

> > native code can be called from the VM,
> Seems obvious, since it's the only way to be able to access the
> core system functionalities, librairies, and such.
> > and VM code can be called by native code.
> Interesting. How do you "declare" to the code that a particular
> piece (function) of VM code exists, how do you handle parameters
> exchange between VM code and native code ?

Very carefully. You have to know how to call the VM func
before even trying. (or the stack could get seriously

> > This VM is one that I'll be using in a game I've
> > been planning, it will also be running code generated
> > by a higher level language compiler that I'm close
> > to completing. I do belive It will be fast enough.
> > Now I have a question: does any one know for sure
> > if an array of function pointers is faster than
> > a switch case?
> >From experience it depends both of the CPU type and
> quality of the compiler.
> For instance, it looks like Rx000 processors (mips core)
> have trouble to keep their cache state if you jump from
> a memory loaded adress. It results in a lot of clock cycles
> wasted because the branch prediction is broken. So it's
> better when you have very few cases to use many IF
> statements.
> For the switch, in general is a good idea to have values
> that follow in memory. With some (good) compilers, the
> code will be a computed jump on some other it will be a
> very long list of "IF not value then jump after"...
> But typically on a PC, using pointer tables (like in virtual
> function tables in C++) will almost never lead to bad
> performances. You have to consider too that the pointer
> list requires a good data cache, while the if based methods
> makes use of the code cache. Depending of the size of the
> executed code, and of the amount of data you manipulate
> it can be wise to use one or the other method !
> If you move a lot of data, there are risks for your data cache
> to be trashed => better use if based method :)
> Hope it helps

Thanks. It probably will :)

"Computer programmers don't byte, they nybble a bit."
Thomas Fjellstrom