Tutorial - RichardMarks/dixy GitHub Wiki
DIXY Programming Tutorial
This tutorial is intended to cover just enough about programming with DIXY to get you started writing your own programs.
By the end of this tutorial you will have written your first DIXY program, learn to assemble your program, link your program, and finally you will run your program in the DIXY emulator. There is a lot to do, so let's get started!
DIXY programs are written in plain text files with a .das
file extension.
These .das
files are DIXY Assembly Source files and contain lines of mnemonics
for each instruction, and optionally instruction repeat counts.
The DIXY Assembly Language Instruction Set consists of sixteen (16) mnemonics.
We are going to use seven (7) of the instructions in this tutorial.
DDP, DVD, IDP, IVD, MV3, MVC, and OUT.
Before we dive into writing our first program in DIXY Assembly, you need to learn about the virtual hardware that your DIXY programs run on in the DIXY emulator.
The instructions and virtual hardware of the DIXY emulator are intentionally very simple and highly restrictive by their very nature.
There are four registers and 4k of available memory.
The data pointer register; D
, refers to the current selected memory location.
The instruction pointer register; I
, refers to the current instruction being
executed in the running program.
The general storage registers X
, and Y
are used by the instructions to perform
arithmetic and copy values to and from memory.
These four registers and the 4k of memory, and standard output and input are all that is available for you on this platform.
Okay, with that out of the way, we are going to write a simple "hello world" program in the DIXY Assembly language. There are many ways this program could be written, and this will be far from the most efficient way, but it works, and is straightforward to implement and follow along with the logic.
Create a file named hello.das
with your favorite plain text editor.
Write the code through out this tutorial that is between the ------ lines.
(Any line with a semi-colon ; may be omitted as it is a comment that will be ignored by the assembler and only exists for helping you to remember what the code is doing.)
Our program is going to work like this:
_________
| |
| START |
|_________|
|
v
_________________________________________
/ /
/ INITIALIZE MEMORY WITH STRING TO PRINT /
/________________________________________/
|
v
_______________________________________
/ /
/ MOVE DATA POINTER TO START OF STRING /
/______________________________________/
|
v
__________________________________________
/ /
/ PRINT EACH CHARACTER TO STANDARD OUTPUT /
/_________________________________________/
|
v
_______
| |
| END |
|_______|
First steps:
Looking at the very basic flowchart above you can see that the first thing we need to do is initialize the memory with the string to be printed.
In order to achieve this goal, we need to break down the string into each individual character, get the appropriate value to store into memory for the character, then use the DIXY Assembly instructions to put the values into memory.
The string that we will print is "Hello World"
with a newline at the end.
Each character of that string is represented by these numerical values:
H = 72
e = 101
l = 108
l = 108
o = 111
= 32
W = 87
o = 111
r = 114
l = 108
d = 100
\n= 10
Which means we need to put each of these numbers into memory in that order. We will use the IVD instruction to store the number in the current memory location, and the IDP instruction to advance the data pointer to the next memory location.
The IVD instruction adds one to the value in the current memory location.
The IDP instruction moves the data pointer one memory location forward.
Instructions that have a number following them are repeated that number
of times. So IDP 4
would move the data pointer forward 4 times.
The process we are going to use to initialize the memory for our string
is to IVD N
where N is the value to store in the current memory location
followed by IDP
to move to the next memory location.
Here are the instructions to put "Hello"
into memory.
-------
IVD 72
IDP
IVD 101
IDP
IVD 108
IDP
IVD 108
IDP
IVD 111
-------
You should be able to initialize the rest of the string on your own.
The next step in the flowchart from earlier is to move the data pointer to the start of the string. We do this with the DDP instruction.
The DDP instruction moves the data pointer one memory location back.
The number of repetitions that we need is equal to the number of characters that we have stored in memory, so we must move back 11 memory locations.
-------
DDP 11
-------
Now that we are at the start of the string, we can use the OUT instruction and the IDP instruction to print the current character and then move the data pointer forward.
The OUT instruction outputs the current memory location value as a character to standard output.
To print the first 3 characters of the string we can do this:
-------
OUT
IDP
OUT
IDP
OUT
-------
You should be able to handle printing the entire string on your own.
Here is the entire hello.das
for your reference along with comments to
explain what every line is doing. You can omit any line that begins with
a semicolon and you can omit from a semicolon to the end of the line.
Semicolons are not necessary. Instructions are separated by newlines.
-------
; hello.das
; Prints "Hello World" to standard output
; 1. Initialize memory with string to print
; "Hello World\n"
IVD 72 ; add one to value in current memory location 72 times (H = 72)
IDP ; move forward one memory location
IVD 101 ; e = 101
IDP ; move forward one memory location
IVD 108 ; l = 108
IDP ; move forward one memory location
IVD 108 ; l = 108
IDP ; move forward one memory location
IVD 111 ; o = 111
IDP ; move forward one memory location
IVD 32 ; = 32
IDP ; move forward one memory location
IVD 87 ; W = 87
IDP ; move forward one memory location
IVD 111 ; o = 111
IDP ; move forward one memory location
IVD 114 ; r = 114
IDP ; move forward one memory location
IVD 108 ; l = 108
IDP ; move forward one memory location
IVD 100 ; d = 100
IDP ; move forward one memory location
IVD 10 ; \n= 10
; 2. Move data pointer to start of string
; go back 11 memory locations
DDP 11
; 3. Print each character to standard output
OUT ; print H
IDP ; move forward one memory location
OUT ; print e
IDP ; move forward one memory location
OUT ; print l
IDP ; move forward one memory location
OUT ; print l
IDP ; move forward one memory location
OUT ; print o
IDP ; move forward one memory location
OUT ; print space
IDP ; move forward one memory location
OUT ; print W
IDP ; move forward one memory location
OUT ; print o
IDP ; move forward one memory location
OUT ; print r
IDP ; move forward one memory location
OUT ; print l
IDP ; move forward one memory location
OUT ; print d
IDP ; move forward one memory location
OUT ; print new line
-------
Now that we have our program written in DIXY Assembly language finished, we are going to need to go through a few short steps to see the results of our hard work in action.
- Assemble
hello.das
intohello.prg
- Link
hello.prg
intohello.dxy
- Run
hello.dxy
in emulator
First, we assemble the file using the assemble command like so
$ dixy assemble hello.das hello.prg
As long as everything went okay, you should have a file named hello.prg
If you open this file in your favorite plain text editor, you will see something like the following:
11111111111111111111111111111111
11111111111111111111111111111111
11111111011111111111111111111111
11111111111111111111111111111111
... cut for brevity ...
10111111111111111111111111111111
11111111111111111111111111111111
11111111111111111111111111111111
11111101111111111fffffffffff2020
20202020202020202026666666666666
That is the DIXY Bytecode which is conveniently plain text and nicely
aligned into 32 characters per line. (not required, but is how the DIXY
assembler writes the .prg automatically.) There is nothing stopping you
from writing your DIXY programs by hand in Bytecode. There are only 16
characters 0-9
and a-f
which not so coincidently is the full hexadecimal
set of characters.
With the hello.prg
in hand, we can move on to the next step, linking.
We use the link command to turn our text based uncompressed bytecode into a compact compressed binary file format that our emulator will execute.
$ dixy link hello.prg hello.dxy
As long as everything went okay, you should have a file named hello.dxy
You should also see something like this:
Compressing Program...
COMPRESSION STATS:
Uncompressed Size: 1124 bytes
Compressed Size: 80 bytes
Compression Ratio: 14.05
Total Savings: 92.8826 %
This is the #1 reason that we need to link our programs. We compressed our bytecode from 1124 bytes to only 80 bytes. Almost a 93% reduction in space!
This file cannot be read by your plain text editor as it is a binary file.
But once you have the hello.dxy
file you can finally use the run command to
launch your program in the emulator and see what all this madness does.
$ dixy run hello.dxy
Provided there were no problems, you should see something like this:
Checking Program File Signature OK
Decompression Complete: 76 bytes expanded to 1120 bytes.
-- Running Program
Hello World
-- Program End
And that part between the -- lines is the output of your program!
Congratulations! You are a DIXY programmer! I cannot wait to see what you are able to create with this little ecosystem of virtual hardware tooling!