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:

Program counter : Stores the address of the instruction being executed.

: Stores the address of the instruction being executed. Global scope address : The starting address of the global scope. This scope may be accessed at any time and should have a constant address throughout runtime.

: The starting address of the global scope. This scope may be accessed at any time and should have a constant address throughout runtime. Local scope address : The starting address of the current local scope. Changes value when a new scope is allocated or an old scope is deallocated.

: The starting address of the current local scope. Changes value when a new scope is allocated or an old scope is deallocated. Address size: Determines the size of addresses in certain contexts. For the DUO Light, this variable should have a value of 2.

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:

0000 : Argument value is equal to N.

: Argument value is equal to N. 0001 : Argument value is at absolute address (relative to 0) equal to N.

: Argument value is at absolute address (relative to 0) equal to N. 0010 : Argument value is at global scope address + N.

: Argument value is at global scope address + N. 0011 : Argument value is at local scope address + N.

: Argument value is at local scope address + N. 0100 : Argument value is the program counter.

: Argument value is the program counter. 0101 : Argument value is the global scope address.

: Argument value is the global scope address. 0110 : Argument value is the local scope address.

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:

Store a number. Store a pointer to the number. Write Hello world! to the display. The Y position is the number at the pointer. 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