The COSMAC VIP had a 16-key hexadecimal keypad, and while modern computers rarely have a keyboard which directly mimics this arrangement, there are many approaches for adapting the input devices which are available to render Chip8 games playable. Many emulators offer custom keyboard or gamepad mappings for each program, and recently Octo has begun to offer "Adaptive Input" options to allow touch-based devices to play games.
It is often desirable to more directly expose the input capabilities of modern machines. This proposal outlines a pair of new instructions for XO-Chip which would expand it with text and pointer input, with room for future expansion. The instructions are as follows:
8NN8 # v0 := poll NN
8XY9 # event vx - vy
As input events occur, the XO-Chip interpreter will store them in a FIFO queue. The poll
instruction pops events from this queue, storing the type code of the event in the fixed register v0
. A type code of zero indicates that no events are currently available. Valid type codes each consist of a single set bit. The mask NN allows a programmer to indicate which events they are interested in; events will be drawn from the queue only if their typecode corresponds to a set bit in the mask. Consider, for example, a trivial loop which reads and discards any available events, halting when the queue is empty:
: drain
loop
v0 := poll 0xFF
while v0
again
Event codes correspond to one of the following constants. Each event type will be described in detail later:
OCTO_EVENT_NONE 0
OCTO_EVENT_CHAR 1
OCTO_EVENT_POINTER_DOWN 2
OCTO_EVENT_POINTER_DRAG 4
OCTO_EVENT_POINTER_UP 8
OCTO_EVENT_POINTERS { 2 | 4 | 8 }
Once an event has been selected via poll
, the event
instruction can be used to unpack the arguments for the event (if any) into the specified range of registers from vx
to vy
. If fewer arguments are available than there are registers given (or the current event is type 0 for "no event"), excess registers will be filled with zeroes.
Char events correspond to characters typed on a keyboard. This event will always have a single argument, consisting of a 7-bit ASCII character.
Pointer events unify a subset of the capabilities of mice, pen input, and multitouch input. An event fires when the pointer becomes active, as it is moved across the surface of the display or touchpad, and when it is lifted. These events all provide two arguments- the horizontal (X) and vertical (Y) position of the pointer relative to the screen, respectively, in pixels. Like the Chip8 drawing coordinate system, X coordinates count left-to-right from 0, and Y coordinates count top-to-bottom, from 0. The following example tracks the pointer with a sprite while it is active:
: main
i := hex v0
loop
# service events
if v3 != 0 then sprite v1 v2 5
loop
v0 := poll OCTO_EVENT_POINTERS
while v0
event v1 - v2
v3 := 0
if v3 != OCTO_EVENT_POINTER_UP then v3 := 1
again
if v3 != 0 then sprite v1 v2 5
# sync framerate
loop
vf := delay
if vf != 0 then
again
vf := 2
delay := vf
again
This proposal would substantially expand the options available to XO-Chip programmers for offering natural and flexible input capabilities on a broad range of devices. The event types, and their arguments, avoid tying programs to designs which would be limited to desktop computers or mobile devices, or complex device-dependent encoding systems. The event masking system makes it easy to write programs which ignore input they are uninterested in, and which are robust to the introduction of new event types in the future. The ranges of input codes and argument counts afforded by the instruction encoding likewise leave generous room for future expansion, should it prove necessary.
There are some risks or limitations to this design. The instruction encoding is forced to use the 8
prefix which is normally associated with arithmetic instructions, and which could be confusing to implementers. The mask nybbles of poll
are positioned across both bytes of the instruction, which breaks from convention with existing instructions and could make self-modifying code which modifies this field more difficult than necessary. Explicit events for keyboard key up/key down events are avoided as these can already be supported to some extent via normal Chip8 key input facilities. More importantly, representing arbitrary keyboards via scancodes in a portable fashion is a challenging specification problem which is best avoided entirely.
Using
vF
instead ofv0
forpoll
is a possibility. XO-Chip has indeed relaxed the constraints that forced the preference for low registers for temporary work.Most of the questions of how I handle encoding the new instructions aren't a big deal; I just felt they were worth mentioning as considerations.
I do forsee that the addition of these instructions would effectively divide programs into two styles: "keyboard and mouse" programs using the new mechanism and "gamepad" programs which continue to make use of the VIP input controls. The only downside to this, in my opinion, is that "keyboard and mouse" programs would probably not be adaptable to some of the esoteric/homebrew hardware platforms that CHIP-8 has been ported to, like the ESPBoy. So far, though, XO-Chip hasn't really seen adoption by third party emulator authors anyway.