Pandora is a tiny direct threaded subset of Forth for BOX-256, a stackless, registerless virtual computer with 256 bytes of memory designed by Juha Kiili.

Specification

The interpreter has 20 built in words and supports subroutine nesting and words written in Forth bytecode or BOX-256 assembly language. Words written in bytecode begin with JMP @E4 (enter) followed by a list of addresses terminated by 0DC (exit). Words written in assembly are terminated by JMP @D0 (next).

AddressCommandStack EffectDescription
0x20U<( x y -- flag )flag is true (0xFF) if x < y
0x30=( x y -- flag )flag is true (0xFF) if x = y
0x3C0branch x( flag -- )jump to x if flag = false
0x4Cbranch x( -- )jump to x
0x54P!( x y -- )set pixel y to colour x
0x60!( x y -- )store x in memory at y
0x6C@( x -- y )read y from memory at x
0x74lit x( -- x )place x on the stack
0x84rot( x y z -- y z x )rotate the top three entries on the stack
0x90over( x y -- x y x )place a copy of x on the stack
0x9Cdup( x -- x x )place a copy of x on the stack
0xA4swap( x y -- y x )swap x and y
0xAC*( x y -- z )z = x × y
0xB4/( x y -- z )z = x ÷ y
0xBCMOD( x y -- z )z = x % y
0xC4-( x y -- z )z = x − y
0xC8+( x y -- z )z = x + y
0xCCdrop( x -- )discard x
0xD0next( -- )execute the routine pointed to by the Forth IP
0xDCexit( -- )exit a Forth subroutine
0xE4enter( -- )enter a Forth subroutine

Example

The following example solves the BOX-256 checkerboard challenge in 0x47F8 cycles compared to 0x5FF cycles for the equivalent assembly language.

; BOX-256 Checkerboard solution in Pandora bytecode

JMP @E4 074 000 ; JMP ENTER / lit 0x00
09C 074 088 0AC ; dup lit 0x88 mul
074 080 0B4 074 ; lit 0x80 div lit
002 0C8 090 054 ; 0x02 add over p!
074 001 0C8 04C ; lit 0x01 add branch
004 000 000 000 ; 0x04

Interpreter

The Pandora interpreter needs to be loaded into memory at 0x20 and has a hard-coded stack depth of 0xA bytes and return stack of 0x5 bytes. The interpreter is also available in plain BOX-256 assembly language.

; Pandora v0.2 - a direct threaded subset of Forth for BOX-256

; 0x20, U<

JGR @F6 @F7 @34
JEQ @F6 @F7 @34
MOV 0FF @F6 001
JMP @CC

; 0x30, =

JEQ @F6 @F7 @28
MOV 000 @F6 001
JMP @CC

; 0x3C, 0branch

JEQ @F7 000 @48
ADD @FD 001 @FD
JMP @CC
MOV @EE @EF 009

; 0x4C, branch

MOV *FD @FD 001
JMP @D0

; 0x54, P!

PIX @F7 @F6 000
MOV @EE @F0 008
JMP @D0

; 0x60, !

MOV @F6 *F7 001
MOV @EE @F0 008
JMP @D0

; 0x6C, @

MOV *F7 @F7 001
JMP @D0

; 0x74, lit

MOV @EF @EE 009
MOV *FD @F7 001
ADD @FD 001 @FD
JMP @D0

; 0x84, rot

FLP @F5 @F6 001
FLP @F6 @F7 001
JMP @D0

; 0x90, over

MOV @EF @EE 009
MOV @F5 @F7 001
JMP @D0

; 0x9C, dup

MOV @EF @EE 009
JMP @D0

; 0xA4, swap

FLP @F6 @F7 001
JMP @D0

; 0xAC, *

MUL @F6 @F7 @F6
JMP @CC

; 0xB4, /

DIV @F6 @F7 @F6
JMP @CC

; 0xBC, MOD

MOD @F6 @F7 @F6
JMP @CC

; 0xC4, -

SUB 000 @F7 @F7

; 0xC8, +

ADD @F6 @F7 @F6

; 0xCC, drop

MOV @EE @EF 009

; 0xD0, next

MOV *FD @FE 001
ADD @FD 001 @FD
JMP *FE

; 0xDC, exit

MOV @F8 @F9 005
JMP @D0

; 0xE4, enter

MOV @F9 @F8 005
ADD @FE 002 @FD
JMP @D0

; 0xEE-0xF7, user stack
; 0xF8-0xFC, return stack
; 0xFD, Forth IP
; 0XFE, execution token
; 0xFF, BOX-256 PC