Home
x86 Instruction Chart
9 Volt Battery Chargers
Library of Congress Classification System
SMPTE Colorbars Test Pattern (in Javascript)
255 Shades of Grey, Red, Green and Blue Test Pattern (in Javascript)
Spice BJT Model Viewer
Ohm's Law Calculator
Solid State Circuit Breaker (20V 650mA)
Example POV-Ray Animation
Example Virtual Machine
Salt Flats & Aeromods
Locating a Gunshot with an Array of Microphones
Power Supply References
Audio Amp + Spice References
Benchmarks
Image Processing
8087 FPU Instruction Chart
KFC 'Secret' Recipe
Neddy's Brownies
Ham and Cheese Muffins
Railroad Tracks
The Bike Shed
The Guy That Invented Fire
Mods for the TRS-80 Color Computer

Example Virtual Machine


Inukshuk
A Local Inukshuk

This is a small virtual machine that runs the Sieve of Eratosthenes and explores managing the instruction opcode set.


Sieve of Eratosthenes in 'C'

This is the original sieve.c program I downloaded from the Web. This is what I hand assembled into the VM language.

Some Opcode Management

These are the 3 files involved:

defines.v
defines.h
mkdefine.c

HALT is instruction 0. It is a reserved opcode. It helps to make the VM stop when it runs out of bounds.

Key the opcodes into defines.v.

Then compile and run mkdefine.c which generates define.h.

Why This is Good

  • Now you can use the opcode number to index into the defines[] table and retrieve the opcode name.

  • Or you can lookup a opcode name and retrieve the opcode number.

  • The use of the documented symbolic constant throughout the 'C' code, especially in the big switch, mades your code easier to read.

  • This allows you to experiment and change your instruction set.

  • Deliverables! The instruction set is documented!

  • It is now very easy to print out the opcode name rather than the opcode number. This is Good for debugging, tracing, single stepping and disassembly. The disassembler code shows an example of this.

  • An assembler can use the opcode table to turn the first token into an opcode. This really tightens up your design when the assembler and disassembler are driven from the same table.

Making

This is the Windows / Watcom batch file:

mkvmsieve.bat

This is the Unix / gcc script:

mkvmsieve.unix


vmsieve.c

This is the toplevel 'C' program.

vmsieve.c

It combines the subfiles into a complete program.


prog.s

This is the instruction word.

prog.s


main.c

This is the main program. Scroll to the bottom to see the main loop.

main.c

The virtual machine has 256 registers and a 10000 integer word memory.

The first part of the program is 2 hand assembled, hard coded programs in the virtual machine language.

The comments are from the original sieve.c.

I used a couple of hacks to make hand assembly easier.

There are 256 registers so the use of character 'A' translates to register 65 and register 'Z' is register 90. It makes the code a little more readable.

The goto labels are arbitrary numbers, not absolute jumps. The Linker turns the label numbers into absolute addresses. Hand assembly and absolute addresses are just too painful.

The p variable points to the program to be run.


Why the Disassembler?

Think of the disassembler as your own personal coding Yoda.

Having to implement each instruction twice makes you think.

A disassembler is a good tool to have when developing.

One function builds an instruction and another function executes it.

Being able to dump the instruction as it sits in memory allows you to see if the instruction was properly compiled.


Build all the Tools Together

A complete set of tools consists of a

  1. Assembler
  2. Disassembler
  3. Linker
  4. Virtual Machine
By building them all right from the start, you will have 4 program checking every decision.

Start with just the HALT and NOP instructions.


IF OPCODE[IP] == 0 THEN HALT

I borrowed the concept that opcode 0 should halt the machine from a CPU designer somewhere on the web. I would like to extend my thanks to this gentleman.

His theory was

"If the CPU hits a instruction with an opcode zero, it stops."
Because
"It is easy and fast to initialize a huge block of memory to all zeros. Setting unused or unknown values to zero is a common practice."
So that
"If something goes FUBAR, the preferred failure mode is to HALT."

Other than HALT == 0, there are no other opcode string to opcode number mappings with a special meaning.


Source Code
Back Next


sparksandflames.com
Sparks and Flames
Copyright © 2016