Return to Guide Menu   Return to Main Menu

= = = 4. WRITING AND RUNNING ASSEMBLY PROGRAMS = = =

Note: This page assumes you have read the previous page about DUO Light bytecode.

DUO Light assembly is a low level language translated into DUO Light bytecode. DUO Light assembly closely matches the format of DLBC. Using DUO Light assembly is less convenient than using Pseudo C, but can result in faster programs.

To assemble a DUO Light assembly program, you must use the DUO Light assembler. Download the DUO Light assembler from this page. The assembler is a Python script.

Now create a plain text file (with the type .txt). Copy and paste the following code into the text document:

DWR # 2 D 2 1 # 1 D 1 0 # 1 D 1 0 # 0 # 2 D 2 13 "Hello world!" D 1 0
L endOfProgram
WRT # 2 D 2 2 # 2 endOfProgram PC 0

Finally, execute the assembler script in the command prompt using the text file as an argument. In other words, type this into your command prompt:

(path to assembler) (path to text file)

If everything goes well, the assembler will print a success message and create a .dlbc file in the same directory as the text file. This .dlbc file is a DUO Light bytecode program. You can confirm that the program works by using an actual DUO Light or the DUO Light emulator.

Now you are ready to write and compile your own DUO Light assembly programs!

= DUO LIGHT ASSEMBLY SYNTAX =

DUO Light assembly is whitespace sensitive. Each statement uses exactly one line.

To declare a variable, use the following syntax:

B (size) (variable name)

To declare a label, use this syntax:

L (label name)

To declare a function, use the syntax below:

F (function name) (variable name) (variable name)... [
(code)
]

In a similar fashion to DLBC, an argument consists of an argument type followed by additional arguments and/or a constant:

(argument type) (size argument?) (constant or argument "N")

Furthermore, an argument type is divided into several parts:

(type identifier) (size) (colon?)

The type identifier may be one of the following:

The size is an integer between 0 and 15 inclusive. If the size is zero (and the type identifier is either PC, GS, or LS), then a size argument is loaded.

If a colon present after the size, N is loaded as an embedded argument. If a colon is not present, N is loaded as a constant.

A constant may be one of the following:

Constants may be concatenated to form larger constants. For example, H 03 H F099 has an effective value of 03F099.

Warning: All decimal number constants must be preceded by D and a size. An orphaned number is insufficient because it does not convey size information!

An instruction is written by placing an opcode mnemonic followed by arguments:

(opcode mnemonic) (argument?) (argument?) (argument?)...

A list of opcodes is available on the previous page.

Finally, you can place an inline constant like so:

C (constant)

= EXAMPLES =

Here is an example assembly program which adds two numbers and displays the result:

B 1 left
B 1 right
B 1 result
B 10 buffer
WRT # 2 D 2 1 # 1 D 1 5 % 2 left
WRT # 2 D 2 1 # 1 D 1 8 % 2 right
ADD # 2 D 2 1 % 2 left % 2 right % 2 result
CIT # 2 D 2 1 % 2 result % 2 buffer
DWR # 2 D 2 1 # 1 D 1 0 # 1 D 1 0 % 2 buffer
L endOfProgram
WRT # 2 D 2 2 # 2 endOfProgram PC 0

The program contains four variables. Three of them (left, right, and result) are a single byte long, while the last one (buffer) stores 10 bytes. All of them are global, so they are access with the % type identifier.

The first WRT instruction stores the number 5 in left. Then the second WRT instruction stores 8 in right.

The ADD instruction adds left and right, then stores the result in result.

CIT converts result into a string stored in buffer. DWR displays the contents of buffer at position (0, 0).

The last WRT writes the label endOfProgram to the program counter. This effectively causes the program to loop forever.

Here is an example assembly program which compliments the user:

B 50 buffer
B 2 key
L loop
DCL
DWR # 2 D 2 1 # 1 D 1 0 # 1 D 1 0 # 0 # 2 D 2 11 "Your name?" D 1 0
WRT # 2 D 2 1 # 1 D 1 0 % 2 buffer
PTX # 2 D 2 1 # 1 D 1 1 % 2 buffer
FNC @ 2 compliment % 2 buffer
DCL
DWR # 2 D 2 1 # 1 D 1 0 # 1 D 1 0 % 2 buffer
PKY % 2 key
WRT # 2 D 2 2 # 2 loop PC 0
F compliment text [
B 2 tempPointer
B 1 randomNumber
RAN # 2 D 2 1 # 1 D 1 2 $ 2 randomNumber
WRZ # 2 D 2 1 $ 2 randomNumber # 2 D 2 2 # 2 complimentSkip1 PC 0
WRT # 2 D 2 2 # 2 firstCompliment $ 2 tempPointer
WRT # 2 D 2 2 # 2 complimentSkip2 PC 0
L complimentSkip1
WRT # 2 D 2 2 # 2 secondCompliment $ 2 tempPointer
L complimentSkip2
CONT @ 2 : $ 2 tempPointer @ 2 : $ 2 text
RET
]
L firstCompliment
C " is smart" D 1 0
L secondCompliment
C " is nice" D 1 0

This program demonstrates usage of functions. The function compliment accepts a name and converts the text into a random compliment. The function has two local variables excluding the argument: tempPointer and randomNumber. Note how these variables are accessed using the $ type identifier.

The line CONT @ 2 : $ 2 tempPointer @ 2 : $ 2 text uses colons to access the values at two pointers. Both variables tempPointer and text are stored in the local scope. Both contain absolute pointer addresses (relative to 0).

At the end of the program C defines two null terminated strings. These constants are accessed using the labels (firstCompliment and secondCompliment) placed before the constants.

Return to Guide Menu   Return to Main Menu

Return to the Ostracod Pond