Writing a programming language: First programs for DVM01

Anything that can be programmed must have a few things: Documentation, and a few examples. This being about programming, it’s tradition to write a “Hello World” program first. So without further ado, let’s have a go:

Hello World!

This program just writes out that well-known message to it’s output, then quits:

START

WRITEC 72
WRITEC 101
WRITEC 108
WRITEC 108
WRITEC 111

WRITEC 32

WRITEC 87
WRITEC 111
WRITEC 114
WRITEC 108
WRITEC 100
WRITEC 33

END

Pretty simple, huh? The numbers are just the ASCII (and, because of Javascript’s inner workings, also Unicode) representations of the letters, space and interpunction of the message. The only really important thing is this: The program MUST start with the “START” statement, and it MUST end. Why?

Intermission: VM guts

As described in the previous article, the VM doesn’t have any registers - it just uses a well-defined memory section for certain types of work. As a program gets executed, the VM needs to know which statement comes next. Traditionally, this information is stored in a place called the “program counter”. I didn’t want to make an exception to the above rule for this important piece of information, so, by convention, the program counter lives at the first location in memory, which is the address 0.

Now - The program, after having been parsed, is also loaded into memory. To not complicate it any further, the program starts at address 0. OOOOppps! When loading the program into memory, we just overwrite the program counter! Damn. This is how the START command came into life.

If you need any space to store temporary values, you can employ a technique called “NOP slide” to reserve memory at well-known locations that you can later use. Our next code example shows what I mean.

Implementing the Fibonacci series

Some interesting “problem” that shows up in many programming courses and examples is the generation of the Fibonacci series. Simply put, it’s a series of numbers, where each number is the sum of the previous two.

The series starts with the numbers 1, 1. The next value, then is the sum of both, 2. Summing up 1 and 2, we get 3. Repeat that with 2 and 3, and you get 5, and so on.

There are many ways to implement a program that outputs that series, most people prefer a recursive way (which however is not very efficient if you’re not careful). Our VM doesn’t support recursive function calls, or rather, we would have to write a lot of code to emulate it, so we take another route: Since the series only ever cares about the previous two numbers, it’s of no use to carry all the others with us - so we don’t.

Here’s the implementation. I’ve added plenty of comments, so you should get a rough idea of how it works.

# First, initialize a nop slide for "registers". Note that
# the first one is required, as address 0 is used by the
# VM to store the program counter.

START # 0: contains program counter
NOP   # 1: first accumulator
NOP   # 2: second accumulator
NOP   # 3: helper
NOP   # 4: loop counter
NOP   # 5: stores loop jump address

# Initialisation: Address 4 is used as a countdown loop counter.
# Set it to a higher number to get more fibonacci numbers :)
SET 4 30 

# Initialize accumulators 1 and 2
SET 1 1
SET 2 1

# Be clever: store the program counter to address 5 as a loop "marker".
# This way, we don't have to worry too much about changing the program -
# the marker will adjust accordingly.

SET 5 @0

# The loop begins here.

SET 3 @1  # Use the helper "register", put the value of accumulator 1 in it
ADD 3 @2  # Add value of accumulator 2 to the helper
WRITEI @1 # Output the value in accumulator 1
WRITEC 10 # Newline - we don't have explicit text support
SET 1 @2  # Add content of accumulator 2 to accumulator 1
SET 2 @3  # Set new sum of both accumulators in accumulator 2.

# Decrease iteration counter.
SUB 4 1

# Jump to beginning of the loop, unless the counter is zero.
# This uses the clever "marker" from further up to know where
# to jump.

JNZ @5 @4

# If the counter was zero, the jump didn't happen, and the program
# must end.

END

Okay, that’s two examples on how to program for the DVM01. I’m trying to come up with some more advanced programs next, implementing the Sieve of Eratosthenes for example, or implementing Subroutine calls. Those will be covered in another article, so stay tuned :)