BOX-256

From Esolang
Jump to navigation Jump to search
BOX-256
Paradigm(s) imperative
Designed by Juha Kiili
Appeared in 2016
Computational class Finite state automaton
Reference implementation BOX-256
Influenced by assembly code

BOX-256 is a programming game and language created in 2016 by Juha Kiili. The objective is to write programs for drawing given images on a 16×16 16 color screen.

Virtual machine

The BOX-256 machine has 256 bytes main memory. It supports threads. Each thread has a single byte instruction pointer that is stored at the end of memory (at 0xFF for the first thread, at 0xFE for the second thread and so on).

Execution starts with a single thread with its instruction pointer set to 0.

Instructions

Instructions are 4 bytes in length, encoding an opcode (with addressing mode) and up to three operands.

Instructions do not have to be aligned to a multiple of 4, and can wrap around at the end of memory. However, the interface only recognizes mnemonics at addresses divisible by 4, so working with misaligned instructions requires the use of numerical opcodes.

There are 3 addressing modes: Immediate (prefix: 0; also - for negative immediates), direct memory (prefix: @), or indirect memory (prefix: *). Addresses are absolute, with the exception of jump and thread targets where immediates are offsets relative to the current instructions. The operations are:

Mnemonic Description
MOV A B C Copy a block of C bytes from A to B; if A is an immediate, replicate that C times.
PIX A B Set pixel A to color B.
JMP A Jump to A (0: relative, @: absolute, *: indirect)
JEQ A B C Jump to C if A = B
JGR A B C Jump to C if A > B
JNE A B C Jump to C if AB
FLP A B C Swap memory blocks of C bytes at A and B.
THR A Start a new thread at A (allocates a new instruction pointer)
ADD A B C C = A + B
SUB A B C C = A - B
MUL A B C C = A * B
DIV A B C C = A / B (or 0 if B = 0)
MOD A B C C = A % B (or 0 if B = 0)

Opcodes

Range Mnemonic Modes in ABC order Note
00 - - no operation
01-12 MOV 0@0, 0*0, @@0, @*0, *@0, **0, 0@@, 0*@, @@@, @*@, *@@, **@, 0@*, 0**, @@*, @**, *@*, ***
13-1C ADD @0@, *0@, @@@, *@@, **@, @0*, *0*, @@*, *@*, ***
1D-2C SUB @0@, 0@@, @@@, *0@, 0*@, *@@, @*@, **@, @0*, 0@*, @@*, *0*, 0**, *@*, @**, ***
2D-3B JEQ @00, @@0, *00, *@0, **0, @0@, @@@, *0@, *@@, **@, @0*, @@*, *0*, *@*, ***
3C-45 MUL @0@, @@@, *0@, *@@, **@, @0*, @@*, *0*, *@*, ***
46-53 DIV @0@, 0@@, @@@, *0@, *@@, @*@, **@, @0*, 0@*, @@*, *0*, *@*, @**, ***
54-56 JMP 0, @, *
57-6B JGR 0@0, @00, @@0, @*0, *00, *@0, **0, 0@@, @0@, @@@, @*@, *0@, *@@, **@, 0@*, @0*, @@*, @**, *0*, *@*, ***
6C-74 PIX 00, 0@, 0*, @0, @@, @*, *0, *@, **
75-7D FLP @@0, *@0, **0, @@@, *@@, **@, @@*, *@*, ***
7E-80 THR 0, @, *
81-90 MOD @0@, 0@@, @@@, *0@, 0*@, *@@, @*@, **@, @0*, 0@*, @@*, *0*, 0**, *@*, @**, *** since 1.1
91-9F JNE @00, @@0, *00, *@0, **0, @0@, @@@, *0@, *@@, **@, @0*, @@*, *0*, *@*, *** since 1.1
A0-A1 DIV 0*@, 0** since 1.1

Unassigned opcodes have no effect, but could be assigned later.

The assembler supports some combinations that are not listed by mapping them to existing ones. For example, ADD 012 @34 @56 gets translated as ADD @34 012 @56 and ADD 012 034 @56 becomes MOV 046 @56 001.

There are a few bugs as well (as of 1.2): The assembler does not recognize the 0** versions of DIV and MOD, nor the 0*@ version of MOD. Furthermore, in the provided documentation, opcodes 17-1B are wrong, flipping * and @ for the first argument.

Interestingly, there are no 0*0, 0*@, or 0** variants of JGR.

Execution model

In each cycle, the threads execute one instruction each, in order.

  • read and increment the instruction pointer
  • decode the instruction
  • execute the instruction; when reading memory, the state of the memory at the start of the cycle is used

Notably, decoding instructions sees changes made by earlier threads during the cycle, making self-modifying code quite powerful in multi-threaded programs.

There is no way to terminate a thread; however, the game will stop execution when the target picture is completed at the end of some cycle.

Example

The following example fills the whole screen with color 7 (white). The value provided is 0xA7 but the top nybble is ignored. Since there are no registers (except for the number of threads), self-modifying code is used to increment the address in the PIX instruction.

PIX 000 0A7 -00
ADD @01 001 @01
JMP @00 000 000