Return to Menu
= = = DUO COMPACT FABRICATION COMPILER = = =
Architecture and Compiler by Jack Eisenmann

Fabrication Code:

Machine Code:



= FABRICATION CODE GUIDE =

Fabrication code is an arbitrary higher level language to be compiled into machine code for the DUO Compact.

Each line of fabrication code is comprised of a command name followed by arguments. Each term is separated by a space, and each line is separated by a newline. Overloading is permissible for commands.

The single DUO Compact processor operation is represented by the command NFC. (This name stands for "NOR and fork conditionally".) The command is overloaded with two forms:

NFC [src] [dest]: performs the NOR operation, skips to the next command in sequence regardless of resulting value.

NFC [src] [dest] [pointer1] [pointer2]: performs NOR operation, skips to second pointer if result was zero, otherwise first pointer.

An argument given as a number is treated as an explicit address. A number in parenthesis, such as (29), represents an address to a constant byte in memory. The keyword next may be used as an argument to represent the address of the next command.

A macro is a block of machine code repeated whenever it is called. Macros are intended for simple operations involving a small number of commands. It is more speed efficient in runtime to use macros, but they use a significant amount of space. A macro is declared in this fashion:

macro [command name] [arg name] [arg name] [arg name]
[code involving arg names]
end

To call a macro elsewhere, use the same syntax as in calling a command. Do NOT use recursive macros, or you will surely die.

A static variable is used to store a byte in a pre-allocated space. The block for static variables is the last block of RAM. To declare one or more static variables, use the syntax below:

static [name] [name] [name]...

When the variable name appears as an argument in a command, the variable's address is used as the value. To free space, use this line:

free [name] [name] [name]...

To avoid an excessive number of static variables, use the free command as frequently as possible! Note that both the static and free commands do not affect runtime speed.

Define a label definition with this command:

label [name]

A label points to a location in the program. Call the label name as an argument to refer to the label's address. Also use the syntax labelName+[number] to point to a label with an offset, _labelName to access the lower byte, ^labelName for the upper byte, and !labelName to invert the value.

Use this command to jump to an address or label:

follow [address]

When using the follow command, no extra code is added; instead, the compiler retroactively modifies the previous command to jump to the desired address.

In some cases, you may want to align code to an address. To do so, use this command:

buffer [address]

This will shift all code below until it reaches the given address.

To insert sequential values into memory, use the sequence command with the syntax below:

sequence [value] [value] [value] [value]...

These values should not be in parentheses.

To indicate the start of code in flash memory, use the FLASH keyword. You can also reset the relative address for labels with the RESET_ADDRESS command:

[...code...]
FLASH
RESET_ADDRESS
[...code...]

= EXAMPLES =

This example code writes the value 27 to the debug output port.

macro clear dest
NFC (255) dest
end
macro logicalNOT src dest
clear dest
NFC src dest
end
macro jump pointer
static a
NFC a a pointer pointer
free a
end
macro output src dest
static a
logicalNOT src a
NFC a dest
free a
end
output (27) 49158
label loopStart
jump loopStart

The example below indicates whether the debug input is less than 16.

macro clear dest
NFC (255) dest
end
macro logicalNOT src dest
clear dest
NFC src dest
end
macro logicalANDNOT src1 src2 dest
logicalNOT src1 dest
NFC src2 dest
end
macro jump pointer
static a
NFC a a pointer pointer
free a
end
macro conditionalFork src pointer1 pointer2
static a
logicalNOT src a
NFC a a pointer1 pointer2
free a
end
macro output src dest
static a
logicalNOT src a
NFC a dest
free a
end
label loopStart
static a
logicalANDNOT 49162 (15) a
conditionalFork a case1 case2
free a
label case1
output (0) 49158
jump loopStart
label case2
output (1) 49158
jump loopStart

This next example code adds 1 to the debug input.

macro clear dest
NFC (255) dest
end
macro logicalNOT src dest
clear dest
NFC src dest
end
macro invert dest
NFC dest dest
end
macro getBitAndFork src data address
static a
logicalNOT data a
NFC src a address next
free a
end
macro NFCPairAndJump src1 src2 dest1 dest2 address
NFC src1 dest1
NFC src2 dest2 address address
end
macro increment src dest
static a b
clear a
clear b
getBitAndFork src (1) carry1
getBitAndFork src (2) carry2
getBitAndFork src (4) carry3
getBitAndFork src (8) carry4
getBitAndFork src (16) carry5
getBitAndFork src (32) carry6
getBitAndFork src (64) carry7
getBitAndFork src (128) carry8
NFC (255) dest finish finish
label carry1
NFCPairAndJump (254) (255) a b skip
label carry2
NFCPairAndJump (253) (254) a b skip
label carry3
NFCPairAndJump (251) (252) a b skip
label carry4
NFCPairAndJump (247) (248) a b skip
label carry5
NFCPairAndJump (239) (240) a b skip
label carry6
NFCPairAndJump (223) (224) a b skip
label carry7
NFCPairAndJump (191) (192) a b skip
label carry8
NFCPairAndJump (127) (128) a b skip
label skip
clear dest
NFC src dest
NFC b dest
NFC a dest
invert dest
free a b
label finish
end
macro jump pointer
static a
NFC a a pointer pointer
free a
end
macro output src dest
static a
logicalNOT src a
NFC a dest
free a
end
label loopStart
static a
increment 49162 a
output a 49158
free a
jump loopStart

In this case, it is actually more efficient to use a lookup table when incrementing a byte. The code below uses this method.

macro clear dest
NFC (255) dest
end
macro logicalNOT src dest
clear dest
NFC src dest
end
macro invert dest
NFC dest dest
end
macro move src dest
logicalNOT src dest
invert dest
end
macro jump pointer
static a
NFC a a pointer pointer
free a
end
macro invertAndOutput src dest
NFC src dest
end
move (2) 40961
move (8) 40962
move (160) 40963
move readReturnAddress 40964
move readReturnAddress+1 40965
move readReturnAddress 40966
move readReturnAddress+1 40967
label loopStart
move 49162 40960
clear 40968
jump 40960
label readReturn
invertAndOutput 40968 49158
jump loopStart
label readReturnAddress
sequence _readReturn ^readReturn
buffer 512
sequence 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 0
Return to Menu
Return to the Ostracod Pond