Return to Menu


Assembly code:

Machine code:


Last update: 1/1/11 (Modified SVM to reflect actual wiring)


This description gives the details of DUO assembly syntax and commands.

Each command begins with an opcode or a function name. Opcodes have 3 letters. Examples of opcodes include SVM and GVL. There are either 2 or 3 arguments after each opcode. Spaces separate opcodes and arguments in a command. Newlines separate commands. An example command is shown below:

BON 10101010 4 253

Arguments can be given in a variety of forms:

The SVM (set VRAM) command accepts a 2 byte VRAM address and 1 byte to write in that address. This effectively displays a group of 8 pixels on the display. To try this command for yourself, copy the code below, paste it in the "assembly code" box, press "compile", then press "execute". You should see 4 white dots on the display.

SVM 32 48 01010101

There are 256 bytes of RAM. The NOT command accepts a byte, inverts the byte, then stores the result in a given address. Examine this code:

GVL 11000011 7
SVM 0 0 [7]

The first command stores the byte 11000011 in RAM address 7. The second command calls the data at that address by using brackets ([7]), then displays that byte on the screen. This command is effectively the same as SVM 0 0 11000011.

There are many commands which perform a calculation on arguments and store the result in RAM. The behavior of these commands is demonstrated below.

# Stores 5 in address 0, since 2 + 3 = 5.
ADD 2 3 0
# Stores 1, since 8 is equal to 8.
EQU 8 8 0
# Stores 0, since 3 is not equal to 16.
EQU 3 16 0
# Stores 0, since 24 is not greater than 39.
GRE 24 39 0
# Stores 00000001, the 6th bit in 01000100.
BGT 01001000 5 0
# Stores 00101111, the result when the 3rd bit in 00001111 is changed into a 1.
BON 00001111 2 0
# Stores 0, since 0 NOR 1 is 0.
NOR 0 1 0
# Stores 10001111, since 00110000 NOR 01010000 is 10001111.
NOR 00110000 01010000 0

On this page you will find a list of all the commands in DUO assembly.

After pixels have been drawn with SVM, they may be read with the command GVM (get VRAM):

SVM 0 0 11100101
# Copies the 8 pixels from one place to another.
GVM 0 0 25
SVM 40 0 [25]

All commands and long-term data are stored in 64 kilobytes of main memory. Unlike RAM, this memory is preserved after power to the machine is cut off. Using SMM (set main memory) and GMM (get main memory), a program can modify any byte in main memory.

# Stores 10010010 in address 1373 (5 * 256 + 93) of main memory.
SMM 10010010 93 5
# Recalls the data in address 1373 (5 * 256 + 93) of main memory
# and stores the data in address 0 of RAM.
GMM 93 5 0

The computer has a counter which determines the address of the current command to be executed in main memory. The value of this counter may be conditionally set by CGO (goto). This command effectively skips program execution to a specified location, but only if the boolean value given is false.

# Store 0 in RAM address 0.
GVL 0 0
# Execution skips to the command at address 11 in main memory.
CGO 11 0 0
# This command is skipped.
ADD [0] 1 0
# This command happens to be at address 11.
ADD [0] 1 0
# The data at RAM address 0 is now 1, since it was only incremented once.

Using main memory addresses directly is a somewhat cumbersome way to program, since they may change if the program is modified. To remedy this problem, the assembler supports the usage of labels. The program below is functionally identical to the one above:

# Store 0 in RAM address 0.
GVL 0 0
# Execution skips to the label.
# This command is skipped.
ADD [0] 1 0
# Execution continues at this label.
ADD [0] 1 0
# The data at RAM address 0 is now 1, since it was only incremented once.

Label names may not contain any spaces, must contain letters, and may not be a keyword recognized by the assembler. A label's address in main memory is declared by placing it on its own line. Main memory addresses are 2 bytes long; to access the more significant byte of a label's address, a caret (^) is placed before the label name. When there is no caret, the less significant byte is accessed.

The programmer may want to make code which modifies its own arguments. To do so, use the notation LABEL_NAME+OFFSET in combination with SMM:

# Modifies the 3rd argument of the SVM command.
# This label is located at the opcode of the following command.
SVM 120 16 0

The computer contains another 2 byte counter, called the timer, which provides a steady pace for programs when necessary. It increments at a constant rate of 64 times per second. The STM (set timer) and GTM (get timer) commands are used to get and set the value of the timer:

SVM 0 0 11111111
# Resets the timer.
STM 0 0
# Stores the less significant byte of the timer in RAM address 0.
GTM 0 0
# If the timer is greater than 128, exit the loop.
GRE [0] 128 1
SVM 8 0 11111111

This program will make a line, wait 2 seconds, then make the line longer. The program works by entering a loop in which it constantly checks to see if the timer has exceeded 128 beats. Once this is true, the loop terminates and a command is executed to extend the line.

The timer is particularly useful when creating music to play through the computer's speakers. Unfortunately, the SNT (set note) command does not work in this JavaScript emulator.

The GIN (get input) command lets the program read keyboard strokes. Whenever the user presses or releases a key, the 2 byte input register is modified. The GIN command accesses the last value stored in this register:

# Stores the last input in RAM address 0. The first argument determines
# which of the 2 bytes to access.
GIN 0 0
# Stores the data from the input register in RAM address 1.
GIN 0 1
# If the input register has changed, display what it is now.
EQU [0] [1] 2
NOR [2] [2] 2
GVL [1] 0
SVM 0 0 [0]

When the program is running, it will display the contents of the input register each time the user presses or releases a key.

If you still have questions about DUO assembly, please email me at esperantanaso at gmail.

Return to Menu

Return to the Ostracod Pond