Return to Guide Menu   Return to Main Menu

= = = 3. UNDERSTANDING DUO LIGHT BYTECODE = = =

Before you can write DUO Light assembly programs, you must first understand how DUO Light bytecode works.

Before a bytecode program is executed, the code is loaded from an SD card into RAM. Program variables are stored in dynamically allocated scopes located after the bytecode. The first 7 bytes of each scope are reserved for housekeeping information.

There are a handful of internal variables in a DLBC runtime environment:

A DLBC program consists of three parts:

(1 byte address size) (global scope size) (instructions)

It is worth noting that DLBC uses a little endian representation for all values.

Instructions are formatted like so:

(1 byte opcode) (argument?) (argument?) (argument?)...

Each opcode expects a certain amount of arguments.

Arguments are formatted like this:

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

Argument types are formatted in the following way:

(4 bit type identifier) (1 bit should load N as argument) (3 bit size)

The type identifier may have one of the following values:

If (1 bit should load N as argument) is set to 0, N is loaded as a binary literal. If the bit is set to 1, N is loaded as a nested argument.

The argument type size defines how many bytes are in N. When the size is zero (and type identifier is less than 0100), the size is loaded as a nested argument. The value of the size argument must have a size equal to the current address size.

You are probably confused right now, so here are some examples.

= EXAMPLES =

Consider the following bytecode program (represented in hexadecimal):

02 08 00 0B 02 01 00 01 32 01 63 22 07 00

Let's figure out what this program does. We know that a DLBC program always begins with 1 byte defining the address size. Therefore 02 is our address size.

Because the address size is 2, the next 2 bytes (08 00) must be the global scope size. The global scope size is 8.

Now the instructions begin. The opcode of our first instruction is 0B. If you look at the section below, you will find that opcode 11 is ADD. This instruction accepts four arguments.

The argument type of the first argument is 02. N is loaded as a constant, and the size of N is 2. Therefore N is equal to the next 2 bytes, 01 00. Our type identifier is 0, so our argument has a value equal to N (1).

The argument type of the second argument is 01. N is loaded as a constant again, but now the size of N is 1. Therefore N is equal to the next byte, 32. Our type identifier is 0, so the argument value is 32 (50 in decimal).

The argument type of the third argument is also 01. N is equal to the next byte, 63. The argument value is 63 (99 in decimal).

Our last argument is a little different. The argument type is 22. N is loaded as a constant, and the size of N is 2. Therefore N is equal to the next 2 bytes, 07 00. Our type identifier is 2, so the value of our argument is located at the global scope address + N (7).

So what will the program do? The program will add two constant integers, each one byte long. The integers have the values 50 and 99. The result will be stored in the global scope address + 7.

In reality, this program is not very useful. It does not write anything to the display. In addition, the computer will crash after execution proceeds beyond the contents of the program. However, the program is useful for demonstrating a simple DLBC instruction.

Now let's consider a slightly more useful program:

02 0A 00 00 02 01 00 01 03 22 09 00 00 02 02 00
02 09 00 22 07 00 3A 02 01 00 01 00 2A 22 07 00
00 02 0D 00 48 65 6C 6C 6F 20 77 6F 72 6C 64 21
00 00 02 02 00 02 31 00 40

The address size is 2, and the global scope size is 10.

The first instruction is WRT:

00 02 01 00 01 03 22 09 00

The instruction writes the constant 03 to global offset 09 00.

The second instruction is also WRT:

00 02 02 00 02 09 00 22 07 00

The instruction writes the constant 09 00 to global offset 07 00.

The third instruction is DWR. It has many argument bytes:

3A 02 01 00 01 00 2A 22 07 00 00 02 0D 00 48 65
6C 6C 6F 20 77 6F 72 6C 64 21 00

The X position for the text is 00.

The next argument type (2A) contains a 08 bit, so N is loaded from another argument. The Y position of the text is stored at the global offset AT the global offset 07 00.

The argument type after that (00) has a zero size value, so the size of N is loaded from another argument. The size of N is 0D 00 (13). If we look at the next 13 bytes, we can see that they are the ASCII values for Hello world! ending with a null character.

The instruction will effectively write Hello world! to position (0, 3) on the display.

The last instruction is WRT:

00 02 02 00 02 31 00 40

The instruction will write 31 00 to the program counter, causing execution to loop back to the same instruction.

In summary, the program will do the following things:

  1. Store a number.
  2. Store a pointer to the number.
  3. Write Hello world! to the display. The Y position is the number at the pointer.
  4. Loop forever.

= LIST OF OPCODES =

Note: With the exception of WRT, all integer arguments must have a length of 1, 2, or 4.

0 (00): WRT (data len) (data) (dest) = Write
1 (01): NOT (data len) (data) (dest) = Bitwise NOT
2 (02): WRZ (cond len) (cond) (data len) (src) (dest) = Write if zero
3 (03): WNZ (cond len) (cond) (data len) (src) (dest) = Write if not zero

4 (04): OR (data len) (data) (data) (dest) = Bitwise OR
5 (05): AND (data len) (data) (data) (dest) = Bitwise AND
6 (06): XOR (data len) (data) (data) (dest) = Bitwise XOR

7 (07): BNT (data len) (data) (dest) = Boolean NOT
8 (08): GRE (num len) (num) (num) (dest) = Greater
9 (09): GRES (num len) (num) (num) (dest) = Greater signed
10 (0A): EQU (data len) (data) (data) (dest) = Equal

11 (0B): ADD (num len) (num) (num) (dest) = Add
12 (0C): SUB (num len) (num) (num) (dest) = Subtract
13 (0D): BSL (data len) (data) (data) (dest) = Bitshift left
14 (0E): BSR (data len) (data) (data) (dest) = Bitshift right

15 (0F): INC (num len) (dest) = Increment
16 (10): DEC (num len) (dest) = Decrement
17 (11): SLO (data len) (dest) = Bitshift left once
18 (12): SRO (data len) (dest) = Bitshift right once

Note: Function info has the following format.

(1 byte address size) (code address) (scope size) (1 byte number of arguments)

19 (13): FNC (info) (arg) (arg)... = Call function; arguments are passed by reference
20 (14): RET = Return from function call

21 (15): FIL (data len) (data) (amount len) (amount) (dest) = Fill
22 (16): FND (data len) (data) (size len) (size) (list) (dest) = Find

23 (17): CII (num len 1) (num) (num len 2) (dest) = Convert integer to integer
24 (18): CIIS (num len 1) (num) (num len 2) (dest) = Convert integer to integer signed

25 (19): MUL (num len) (num) (num) (dest) = Multiply
26 (1A): MULS (num len) (num) (num) (dest) = Multiply signed
27 (1B): DIV (num len) (num) (num) (dest) = Divide
28 (1C): DIVS (num len) (num) (num) (dest) = Divide signed
29 (1D): MOD (num len) (num) (num) (dest) = Modulus

Note: Floats have a length of 4 bytes.

30 (1E): ADDF (num) (num) (dest) = Add float
31 (1F): SUBF (num) (num) (dest) = Subtract float
32 (20): MULF (num) (num) (dest) = Multiply float
33 (21): DIVF (num) (num) (dest) = Divide float

34 (22): CIF (num len 1) (num) (dest) = Convert integer to float
35 (23): CIFS (num len 1) (num) (dest) = Convert integer to float signed
36 (24): CFI (num) (num len 2) (dest) = Convert float to integer
37 (25): CFIS (num) (num len 2) (dest) = Convert float to integer signed

Note: All text is null terminated.

38 (26): CIT (num len) (num) (dest) = Convert integer to text
39 (27): CITS (num len) (num) (dest) = Convert signed integer to text
40 (28): CFT (num) (dest) = Convert float to text
41 (29): CTI (text) (num len) (dest) = Convert text to integer
42 (2A): CTIS (text) (num len) (dest) = Convert text to integer signed
43 (2B): CTF (text) (dest) = Convert text to float

44 (2C): WRTT (text) (dest) = Write text
45 (2D): EQUT (text) (text) (dest) = Equal text
46 (2E): FNDT (pattern) (text) (idx len) (dest) = Find text
47 (2F): LENT (text) (len len) (dest) = Get text length
48 (30): SUBT (text) (idx len) (idx) (idx) (dest) = Get text substring
49 (31): CONT (text) (dest) = Concatenate text

50 (32): SDL (text) (len len) (dest) = Get space delimited text length
51 (33): SDS (text) (idx len) (idx) (dest) = Get space delimited text element

52 (34): RAN (num len) (max) (dest) = Generate random number; exclusive maximum
53 (35): SIN (num) (dest) = Sine of float

54 (36): TWR (num len) (num) = Write time in milliseconds
55 (37): TRD (num len) (dest) = Read time
56 (38): TSL (num len) (num) = Sleep

57 (39): DCL = Clear display
58 (3A): DWR (pos len) (posX) (posY) (text) = Write text to display
59 (3B): DRD (pos len) (posX) (posY) (size len) (size) (dest) = Read text from display

60 (3C): CKT (key) (shift) (dest) = Convert key to text
61 (3D): CTK (text) (dest) = Convert text to key

62 (3E): KIP (key) (dest) = Key is pressed
63 (3F): PKY (dest) = Prompt key
64 (40): PTX (pos len) (posY) (dest) = Prompt text
65 (41): PSL (num len) (num) (text) (dest) = Prompt selection; text must contain null delimited elements
66 (42): PFL (num len) (dest) = Prompt file

67 (43): XSM (mode) (pin) = Set pin mode
68 (44): XDR (pin) (dest) = Digital read pin
69 (45): XDW (src) (pin) = Digital write pin
70 (46): XAR (pin) (dest) = Digital read pin

Note: File entry addresses are 4 bytes long. If the file cannot be found, the address is -1.

71 (47): RNF (num len) (dest) = Get number of files
72 (48): RGAI (idx len) (idx) (dest) = Get file entry address by index
73 (49): RGAN (text) (dest) = Get file entry address by name
74 (4A): RGAA (addr) (dest) = Get file entry address after file entry address
75 (4B): RCR (text) (size len) (size) (dest) = Create file
76 (4C): RRD (addr) (dest) = Read file
77 (4D): RWR (data) (addr) = Write file
78 (4E): RGN (addr) (dest) = Get file name
79 (4F): RGS (addr) (size len) (dest) = Get file size
80 (50): RDL (addr) = Delete file
81 (51): RRN (addr) = Run fule
82 (52): QUIT = Quit

83 (53): CTO (text) (dest) = Convert text to opcode
84 (54): CIH (num) (dest) = Convert integer byte to hexadecimal text
85 (55): CHI (text) (dest) = Convert hexadecimal text to integer byte

86 (56): ALLO (size len) (size) (dest) = Allocate memory in heap; stores a pointer
87 (57): FREE (addr) = Deallocate memory in heap

88 (58): DSC (direction) (text) = Scroll video buffer and write row or column of text; 0 = left, 1 = right, 2 = up, 3 = down
89 (59): DDX (num len) (dest) = Get display character width
90 (5A): DDY (num len) (dest) = Get display character height

91 (5B): GMLF (dim len) (dimX) (dimY) (data) (dest) = Step one generation in Conway's game of life
92 (5C): MNDL (real) (imag) (offset) (iter len) (iter) (dest) = Determine whether four points are in Mandelbrot set

93 (5D): POW (num) (num) (dest) = Raise number to power
94 (5E): LOG (num) (num) (dest) = Take log of number with base

In the next section, you will learn how to use the assembler to produce bytecode without a hex editor.

Return to Guide Menu   Return to Main Menu

Return to the Ostracod Pond