How to create your own virtual machine in a step-by-step tutorial
Brought to you by icemanind
2009
output. I’ve chosen to use $A000 - $AFA0. This area of memory will map to our screen. In most CPUs and
most virtual machines, this memory is mapped inside the video card memory, however, for simplicity; I
am going to share our 64K of memory with our video output. This memory will give us an 80x25 screen
(80 columns, 25 rows). You may be thinking right now, “I think your math is off dude. 80 times 25 is only
2000”. This is true; however, the extra 2000 bytes will be for an attribute.
For those of us old enough to remember programming assembly language, back in the old DOS
days, will already be familiar with an attribute byte. An attribute byte defines the foreground and
background color of our text. How it works is the last 3 bits of the byte make up the RGB or Red, Green,
Blue values of our foreground color. The 4
th
bit is an intensity flag. If this bit is 1 then the color is
brighter. The next 3 bits make up the RGB values of our background color. The last bit is not used (back
in DOS days, this bit was used to make text blink, but in B32, it is ignored). You will see later how colors
are created using this method.
The final part of this section will define the mnemonics and the bytecode that make up a B32
executable. Mnemonics are the building block of our assembly language code that will be assembled to
bytecode. For now, I am only going to introduce enough for us to get started and we will expand on our
list throughout this tutorial. The first mnemonic we will introduce is called “LDA”. “LDA” is short for
“Load A Register” and what it will do is assign a value to the A register. Now in most CPUs and virtual
machines, you have what’s called addressing modes. Addressing modes determine how a register gets
its value. For example, is the value specified directly on the operand (an operand is the data that follows
the mnemonic) or does it pull a value from somewhere in memory or is loaded from a value assigned to
another register? There can be dozens of addressing modes, depending on how complex of a virtual
machine you want to create. For now, our virtual machine will only pull data directly specified in the
operand. We will assign this mnemonic a bytecode value of $01. Since we decided earlier that the A
register can only hold an 8 bit value, we now that the entire length of a “LDA” mnemonic that pulls
direct data from the operand will be 2 bytes in length (1 byte for the mnemonic and 1 byte for the data).
The next mnemonic we will discuss will be called “LDX”. “LDX” is short for “Load X Register” and,
just like “LDA”, it will load a value directly into the X register from the operand. Another difference
between “LDX” and “LDA” is the length. Since our X register can hold 16 bits of data, that means the
total length of the bytecodes will be 3 bytes instead of 2 (1 byte for the mnemonic and 2 bytes for the
data). We will assign this mnemonic a bytecode of $02. If I lost you guys, keep reading and I promise this
will make sense when we look at some examples.
The next mnemonic we will discuss now will be called “STA”. “STA” is short for “Store A
Register” and its function will be to store the value contained in the A register into a location
somewhere in our 64K memory. Unlike our load mnemonics, which pulls the value directly from the
operand, our store mnemonic will pull its data from the value stored in one of the 16 bit registers. We
will assign this mnemonic a bytecode of $03.
The final mnemonic we will discuss is call “END”. “END” will do exactly that. It will terminate the
application. All B32 programs must have an END mnemonic as the last line of the program. The operand
for the END mnemonic will be a label that will point to where execution of our B32 program will begin.