You may just want to run a little bytecode interpreter, period. This was the approach used to implement many languages on the 6502 and other 8-bitters. UCSD Pascal comes to mind, but I know it was used to implement some C versions as well.
Those architectures are just so painful for generating reasonable code, mostly with regards to size, that a clean 16 bit VM starts looking attractive. Memory use is often more critical than speed on an 8-bitter, and for large applications even with the interpreter the bytecode is almost always smaller.
And if you're doing a full VM, it's not too painful to add a memory protection check. One can sustain about 5 - 10K virtual instructions a second on a 6502 @ 1 MHz.
As insanely inefficient as this all sounds, it was actually done back in the day. One notable example would be the old Business Operating System which was basically a bytecode interpreter glued to a small multitasking operating system. All the compilers and applications and most of the OS itself ran in interpreted bytecode.
> As insanely inefficient as this all sounds, it was actually done back in the day.
Java, Python, Perl, Ruby, and a host of others say this isn't a dead technique.
Another reason for it back then was to only need to port the interpreter to each different architecture and platform, an important consideration in the 80s with the bloom of CPUs and machines.
Those architectures are just so painful for generating reasonable code, mostly with regards to size, that a clean 16 bit VM starts looking attractive. Memory use is often more critical than speed on an 8-bitter, and for large applications even with the interpreter the bytecode is almost always smaller.
And if you're doing a full VM, it's not too painful to add a memory protection check. One can sustain about 5 - 10K virtual instructions a second on a 6502 @ 1 MHz.
As insanely inefficient as this all sounds, it was actually done back in the day. One notable example would be the old Business Operating System which was basically a bytecode interpreter glued to a small multitasking operating system. All the compilers and applications and most of the OS itself ran in interpreted bytecode.