BOX-256 MANUAL
==============

BOX-256 is a 8-bit fantasy computer, with 256 bytes of memory, 16 color 16x16 display. It is also a programming game, where the player tries to pass the graphics tests and optimize the code to perfection. The ultimate goal is to use as few CPU cycles or lines of code as possible, by employing multithreading and other optimization tricks.

Gameplay

Player writes the source code, executes the machine and tries to match the target output (bottom screen), with program output (top screen), with least amount of CPU cycles possible.

When the computer is not executing, the compiler tries actively to compile the source to machine code. This can be seen as memory changing, while the user is writing code. The execution can be started from the bottom using the PLAY button. It goes on forever, unless a) player stops it with STOP or STEP or b) the output screen matches the target and the level is passed.

If you want more challenge, cycle through the available levels with PREV and NEXT buttons.

Saving and Loading Your Code

Unfortunately WebGL doesn't directly support clipboard, but the game uses popup windows to give you ability to import & export code indirectly.

In the web version, clicking the SAVE button will open up a popup with your entire source code in it so you can copy it into your clipboard. In the standalone version there is no popup, but the source code is moved straight into clipboard.

Loading works similarly. In the web version you'll get a popup where you can paste your code and click load button to move it into the game. In the standalone version, clicking LOAD tries to load whatever text is in your clipboard currently.

NOTE: In the web version, drag-selecting text with mouse doesn't work. You have to use SHIFT+arrow keys to do it.

Editor

SHIFT+arrow keys lets you select code and CTRL-C & CTRL-V for copy-pasting. CTRL-Z and CTRL-Y for undo and redo. Use insert/delete/backspace/enter to move stuff around, too. For the expert players and people with weird keyboard layouts, the '@' and '*' characters can be also typed with comma (,) and period (.) hotkeys.

Hovering over memory or output screen gives you the address of the currently hovered slot.

Fixed Width Instruction Set

Source code is compiled to machine code in 4 byte chunks. In other words, the machine code is based on a fixed width instruction set. However, some instructions do not use all of the 4 bytes. Clever player may use this to her advantage. Note that even with the fixed width set, it is possible to force the program counter anywhere in memory, regardless of machine code alignment.

Program Counter

When the execution starts, the last memory slot (FF) is used as a program counter (PC). If a second thread is started, the additional PC will be in FE, the third will be in FD and so on. Since there is no memory protection, it is possible to write into PC directly and cause execution to jump. The behaviour is identical to using JMP instruction.

Multithreading

It is possible to start multiple threads with THR instruction. The threads are not really simultaneous and they are executed one after another. It is counted as single cycle for score keeping purposes. The memory reads for each thread are identical and based on the memory state cached at the beginning of the cycle. For conflicting writes to same memory address, the thread that writes last is the winner.

Because of cached reads, it is generally not possible for one thread to communicate with other thread simultaneously. HOWEVER two exceptions remains: An earlier thread can write to memory address later executed by later thread. So self-modifying code is possible. An earlier thread can also write to program counter (PC) owned by a later thread to cause an immediate jump.

Memory Addressing

There are three different prefixes in source code:

0 = Constant value
@ = Address in memory
* = Address pointed by another address (a.k.a pointer)

Example:

Address: 00 01 02 03 04 05 06 07 08 09 0A 0B ...
Value:   00 1A 22 2A 5B 23 4A 28 00 03 BB CA ...

009 evaluates to 09
@09 evaluates to 03
*09 evaluates to 2A

Memory Protection

There is no memory protection whatsoever. All executable machine code, your own variables and program counters happily co-exist in the same 00-FF memory space. You can read and write everywhere and everytime, as long as you live with the consequences :).

Creating your own levels

Creating your own level is done by using the BOX-256 computer. You need to make a program that outputs the new level into output display, and then press the URL button.

Popup will open that has an URL to the new level which is based on your current output display.

NOTE: You can pause execution during playback pressing STEP!

You can share the URL to other players. Clicking the URL opens the game with only your custom level available, titled as "CUSTOM".

In the standalone version, there is an extra button OPEN. By first copying the URL of a custom level into clipboard, and then clicking OPEN, you can open a custom level.



Instructions

The language consists of 11 possible instructions. These are compiled into 120 different opcodes by the compiler. Most of the different opcodes are just different permutations of the same instruction.

MOV

MOV A B C

Sets the value A into memory address B.

The parameter C can be used as length for arrays, when multiple values are moved at once.

MOV 025 @DE 000 // Move value 25 into memory address @DE
MOV @10 @20 000 // Move value from memory address @10 into memory address @20
MOV @A0 @B0 007 // Move seven values starting from address @A0 into address @B0
MOV *30 @40 000 // Move value from address pointed by value in @30, into address @40
MOV 007 @10 004 // Set constant value 7 four times, starting from address @10.

JMP

JMP A

Jumps the execution into A.

If A is a constant, it is an offset from current execution address, otherwise it is considered as an absolute address. It is normally a good idea to jump in multipliers of 4, because the instruction set is fixed width and the next instruction (usually) sits in the next 4 bytes.

Note that you can prefix the A with minus '-' to get negative values. They are not compiled negative in machine code, but JMP -1 compiles to JMP FF. This works, because the memory is exactly 256 bytes long and jumping FF means jumping through the entire memory and landing on to the previous memory address.

JMP 008 000 000 // Jump 8 steps forward. Basically jumping over the next instruction.
JMP -0C 000 000 // Jump 12 steps back. Basically jumping back three instructions.
JMP @A0 000 000 // Jump directly to memory address @A0.
JMP *C0 000 000 // Jump to memory address pointed by value in @C0.

PIX

PIX A B

Outputs a pixel into index A with color B.

The screen is 16x16 consisting of 256 pixels. The index grows left to right, top to bottom. The top-left index is 0, and bottom-right is 255. The available colors are from 0 to F, but it is fine to output value bigger than that, since the palette keeps cycling through.

PIX 020 009 000 // Output color 09 into pixel index of 20.
PIX @10 009 000 // Output color 09 into pixel pointed by value in @10.

JEQ

JEQ A B C

If A equals B, the execution jumps to C.

If C is a constant, it is an offset from current execution address, otherwise it is considered as an absolute address. It is normally a good idea to jump in multipliers of 4, because the instruction set is fixed width and the next instruction (usually) sits in the next 4 bytes.

Note that you can prefix the C with minus '-' to get negative values. They are not compiled negative in machine code, but JMP -1 compiles to JMP FF. This works, because the memory is exactly 256 bytes long and jumping FF means jumping through the entire memory and landing on to the previous memory address.

JEQ 020 @30 008 // if @30 has value 20, jump over the next instruction (8 bytes).
JEQ @A0 @B0 -04 // if value in @A0 equals to @B0, jump back to previous instruction.

JNE

JNE A B C

If A doesn't equal B, the execution jumps to C.

If C is a constant, it is an offset from current execution address, otherwise it is considered as an absolute address. It is normally a good idea to jump in multipliers of 4, because the instruction set is fixed width and the next instruction (usually) sits in the next 4 bytes.

Note that you can prefix the C with minus '-' to get negative values. They are not compiled negative in machine code, but JMP -1 compiles to JMP FF. This works, because the memory is exactly 256 bytes long and jumping FF means jumping through the entire memory and landing on to the previous memory address.

JNE 020 @30 008 // if @30 doesn't have value 20, jump over the next instruction (8 bytes).
JNE @A0 @B0 -04 // if value in @A0 doesn't equal to @B0, jump back to previous instruction.

JGR

JGR A B C

If A is greater than B, the execution jumps to C.

If C is a constant, it is an offset from current execution address, otherwise it is considered as an absolute address. It is normally a good idea to jump in multipliers of 4, because the instruction set is fixed width and the next instruction (usually) sits in the next 4 bytes.

Note that you can prefix the C with minus '-' to get negative values. They are not compiled negative in machine code, but JMP -1 compiles to JMP FF. This works, because the memory is exactly 256 bytes long and jumping FF means jumping through the entire memory and landing on to the previous memory address.

JGR @30 010 -04 // if value in @30 is greater than 10, jump back to previous instruction.
JGR 020 @30 -04 // if value in @30 is smaller or equal to 20, jump forward 4 steps (16 bytes).

FLP

FLP A B C

Flips the values between memory address A and memory address B.

The parameter C can be used as length for arrays, when multiple values are flipped at once.

FLP @25 @DE 000 // Flip the value between memory locations @25 and @DE
FLP @10 @20 004 // Flip four (4) values between memory spaces starting from @10 and @20

THR

THR A

Starts a new thread from memory address A

This means that the executable machine code instruction you want the new thread to start executing is sitting in memory address A.

THR @20 000 000 // Start executing new thread from memory address @20
THR *10 000 000 // Start executing new thread from memory address pointed by value in @10

ADD

ADD A B C

Adds values A and B together and stores the result in C

ADD @20 007 @89 // Add seven (7) to the value in address @20 and store the result in @89
ADD @10 @20 @30 // Add values in addresses @10 and @20 together and store it in @30

SUB

SUB A B C

Subtracts B from A and stores the result in C

SUB @20 007 @89 // Subtract seven (7) from the value in @20 and store the result in @89
SUB @10 @20 @30 // Subtract value in @20 from value in @10 and store result in @30

MUL

MUL A B C

Multiplies values A and B together and stores the result in C

MUL @20 007 @89 // Multiply value in address @20 with seven (7) and store the result in @89
MUL @10 @20 @30 // Multiply values in addresses @10 and @20 together and store result in @30

DIV

DIV A B C

Divides A with B and stores the result in C

Division with zero (0) always evaluates to 0.

DIV @20 007 @89 // Divide value in @20 with seven (7) and store the result in @89
DIV @10 @20 @30 // Divide value in @10 with value in @20 and store result in @30

MOD

MOD A B C

Take modulo of A and B and place the result in C

Modulo with zero (0) always evaluates to 0.

MOD @20 007 @89 // Take modulo of @20 and seven (7) and store the result in @89
MOD @10 @20 @30 // Take modulo of @10 and @20 and store the result in @30



Opcodes

The instructions in source code are compiled into machine code opcodes in the memory. These opcodes are the actual commands that the computer executes. An expert player can code programs directly by writing these values into the editor. It is also possible to change the executed memory at runtime, so everything is possible if you know what the different opcodes do.

Most of the opcodes are permutations of the same instruction. For example the ADD instruction has 8 different opcodes, depending on the 'memory depth' of the parameters.

There are three different 'depths' of parameter. Constant (0), Address (@) and pointer (*).

OPCODEInstructionP1P2P3Example
00000 (NOP)010000 000 000 000
 
01MOV0@0MOV 001 @02 003
02MOV0*0MOV 001 *02 003
03MOV@@0MOV @01 @02 003
04MOV@*0MOV @01 *02 003
05MOV*@0MOV *01 @02 003
06MOV**0MOV *01 *02 003
07MOV0@@MOV 001 @02 @03
08MOV0*@MOV 001 *02 @03
09MOV@@@MOV @01 @02 @03
0AMOV@*@MOV @01 *02 @03
0BMOV*@@MOV *01 @02 @03
0CMOV**@MOV *01 *02 @03
0DMOV0@*MOV 001 @02 *03
0EMOV0**MOV 001 *02 *03
0FMOV@@*MOV @01 @02 *03
10MOV@**MOV @01 *02 *03
11MOV*@*MOV *01 @02 *03
12MOV***MOV *01 *02 *03
 
13ADD@0@ADD @01 002 @03
14ADD*0@ADD *01 002 @03
15ADD@@@ADD @01 @02 @03
16ADD*@@ADD *01 @02 @03
17ADD@*@ADD @01 *02 @03
18ADD*0*ADD *01 002 *03
19ADD@0*ADD @01 002 *03
1AADD*@*ADD *01 @02 *03
1BADD@@*ADD @01 @02 *03
1CADD***ADD *01 *02 *03
 
1DSUB@0@SUB @01 002 @03
1ESUB0@@SUB 001 @02 @03
1FSUB@@@SUB @01 @02 @03
20SUB*0@SUB *01 002 @03
21SUB0*@SUB 001 *02 @03
22SUB*@@SUB *01 @02 @03
23SUB@*@SUB @01 *02 @03
24SUB**@SUB *01 *02 @03
25SUB@0*SUB @01 002 *03
26SUB0@*SUB 001 @02 *03
27SUB@@*SUB @01 @02 *03
28SUB*0*SUB *01 002 *03
29SUB0**SUB 001 *02 *03
2ASUB*@*SUB *01 @02 *03
2BSUB@**SUB @01 *02 *03
2CSUB***SUB *01 *02 *03
 
2DJEQ@00JEQ @01 002 003
2EJEQ@@0JEQ @01 @02 003
2FJEQ*00JEQ *01 002 003
30JEQ*@0JEQ *01 @02 003
31JEQ**0JEQ *01 *02 003
32JEQ@0@JEQ @01 002 @03
33JEQ@@@JEQ @01 @02 @03
34JEQ*0@JEQ *01 002 @03
35JEQ*@@JEQ *01 @02 @03
36JEQ**@JEQ *01 *02 @03
37JEQ@0*JEQ @01 002 *03
38JEQ@@*JEQ @01 @02 *03
39JEQ*0*JEQ *01 002 *03
3AJEQ*@*JEQ *01 @02 *03
3BJEQ***JEQ *01 *02 *03
 
3CMUL@0@MUL @01 002 @03
3DMUL@@@MUL @01 @02 @03
3EMUL*0@MUL *01 002 @03
3FMUL*@@MUL *01 @02 @03
40MUL**@MUL *01 *02 @03
41MUL@0*MUL @01 002 *03
42MUL@@*MUL @01 @02 *03
43MUL*0*MUL *01 002 *03
44MUL*@*MUL *01 @02 *03
45MUL***MUL *01 *02 *03
 
46DIV@0@DIV @01 002 @03
47DIV0@@DIV 001 @02 @03
48DIV@@@DIV @01 @02 @03
49DIV*0@DIV *01 002 @03
4ADIV*@@DIV *01 @02 @03
4BDIV@*@DIV @01 *02 @03
4CDIV**@DIV *01 *02 @03
4DDIV@0*DIV @01 002 *03
4EDIV0@*DIV 001 @02 *03
4FDIV@@*DIV @01 @02 *03
50DIV*0*DIV *01 002 *03
51DIV*@*DIV *01 @02 *03
52DIV@**DIV @01 *02 *03
53DIV***DIV *01 *02 *03
 
54JMP0JMP 001 000 000
55JMP@JMP @01 000 000
56JMP*JMP *01 000 000
 
57JGR0@0JGR 001 @02 003
58JGR@00JGR @01 002 003
59JGR@@0JGR @01 @02 003
5AJGR@*0JGR @01 *02 003
5BJGR*00JGR *01 002 003
5CJGR*@0JGR *01 @02 003
5DJGR**0JGR *01 *02 003
5EJGR0@@JGR 001 @02 @03
5FJGR@0@JGR @01 002 @03
60JGR@@@JGR @01 @02 @03
61JGR@*@JGR @01 *02 @03
62JGR*0@JGR *01 002 @03
63JGR*@@JGR *01 @02 @03
64JGR**@JGR *01 *02 @03
65JGR0@*JGR 001 @02 *03
66JGR@0*JGR @01 002 *03
67JGR@@*JGR @01 @02 *03
68JGR@**JGR @01 *02 *03
69JGR*0*JGR *01 002 *03
6AJGR*@*JGR *01 @02 *03
6BJGR***JGR *01 *02 *03
 
6CPIX00PIX 001 002 000
6DPIX0@PIX 001 @02 000
6EPIX0*PIX 001 *02 000
6FPIX@0PIX @01 002 000
70PIX@@PIX @01 @02 000
71PIX@*PIX @01 *02 000
72PIX*0PIX *01 002 000
73PIX*@PIX *01 @02 000
74PIX**PIX *01 *02 000
 
75FLP@@0FLP @01 @02 003
76FLP*@0FLP *01 @02 003
77FLP**0FLP *01 *02 003
78FLP@@@FLP @01 @02 @03
79FLP*@@FLP *01 @02 @03
7AFLP**@FLP *01 *02 @03
7BFLP@@*FLP @01 @02 *03
7CFLP*@*FLP *01 @02 *03
7DFLP***FLP *01 *02 *03
 
7ETHR0THR 001 000 000
7FTHR@THR @01 000 000
80THR*THR *01 000 000
 
81MOD@0@MOD @01 002 @03
82MOD0@@MOD 001 @02 @03
83MOD@@@MOD @01 @02 @03
84MOD*0@MOD *01 002 @03
85MOD0*@MOD 001 *02 @03
86MOD*@@MOD *01 @02 @03
87MOD@*@MOD @01 *02 @03
88MOD**@MOD *01 *02 @03
89MOD@0*MOD @01 002 *03
8AMOD0@*MOD 001 @02 *03
8BMOD@@*MOD @01 @02 *03
8CMOD*0*MOD *01 002 *03
8DMOD0**MOD 001 *02 *03
8EMOD*@*MOD *01 @02 *03
8DMOD@**MOD @01 *02 *03
90MOD***MOD *01 *02 *03
 
91JNE@00JNE @01 002 003
92JNE@@0JNE @01 @02 003
93JNE*00JNE *01 002 003
94JNE*@0JNE *01 @02 003
95JNE**0JNE *01 *02 003
96JNE@0@JNE @01 002 @03
97JNE@@@JNE @01 @02 @03
98JNE*0@JNE *01 002 @03
99JNE*@@JNE *01 @02 @03
9AJNE**@JNE *01 *02 @03
9BJNE@0*JNE @01 002 *03
9CJNE@@*JNE @01 @02 *03
9DJNE*0*JNE *01 002 *03
9EJNE*@*JNE *01 @02 *03
9FJNE***JNE *01 *02 *03
 
A0DIV0*@DIV 001 *02 @03
A1DIV0**DIV 001 *02 *03