Skip to content

Instantly share code, notes, and snippets.

@JohnEarnest
Created October 31, 2019 01:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JohnEarnest/0c52e244d34120ca32728a42e90ee169 to your computer and use it in GitHub Desktop.
Save JohnEarnest/0c52e244d34120ca32728a42e90ee169 to your computer and use it in GitHub Desktop.
XO-Chip Event Queue Proposal

Input Events

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

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

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

Pros and Cons

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.

@tobiasvl
Copy link

This is a solid proposal! The functionality it offers is awesome. I just have a few nitpicky comments.

The poll instruction pops events from this queue, storing the type code of the event in the fixed register v0.

What about using vF instead? Why clobber a perfectly fine general-purpose register? After all, BNNN is the only instruction that explicitly needs to use v0, apart from FX55 and FX65 which XO-CHIP has supplanted with 5XY2 and 5XY3. There's also precedent for (and a big opportunity to) use more bits in vF than just the least significant one; DXYN in SCHIP 1.1 sets it to the number of rows with collisions (and some other extensions use it for stuff like remainder after a division instruction). Something to consider, perhaps.

The instruction encoding is forced to use the 8 prefix which is normally associated with arithmetic instructions, and which could be confusing to implementers.

Well, you've already "broken" the pattern by using the 5 prefix for memory saving and loading, so that shouldn't be a problem. In fact, why not continue to use 5 for these, or better yet, the E or F prefixes which already has IO instructions? The suffixes 4, 6, B, C, D and F seem free for both prefixes. Of course, then you break another "paradigm"; no E or F instruction uses NN or XY "arguments".

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.

Indeed, many CHIP-8 interpreters I've seen mask the arguments out when fetching the instruction, before decoding. Those would need to be rewritten to accommodate this instruction. Maybe not that big of a deal, but some are of course written in assembly or FPGAs (at least conceivably). But, well, there's no way around this one so it doesn't really matter.

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.

To some extent, yes. See #104 (although that does not actually require events for key up or down). Also, I believe it's implementation defined – on the COSMAC VIP, FX0A blocks for a keypress, but it's actually blocking for a key up event (unless I'm mistaken), ie. it doesn't consume the keypress until you press and then release a key.

You also have to think about what will happen with the hexadecimal keypad if this is implemented as proposed: It will likely die off. Sure, someone making an XO-CHIP game can choose whether to use the old hex input instructions or this new one for ASCII, but why use the ancient hex keys when you don't have to? Especially when most people use an "ASCII" keyboard to input CHIP-8 hex nowadays. That might be OK, maybe it's finally time to kill of the weird 1234QWERASDFZXCV mapping, but you have to be aware of what might happen. I'm reminded of the CHIP-8 AE extension for the ACE VDU computer, released in 1984 (coincidentally the same year as the release of another major new extension, Microbee Extended CHIP-8 V2.0, and also coincidentally the year CHIP-8 died out before being revived on the HP48), which didn't even bother to properly support hex input (for example, FX0A only supported 0–9, not A–F).

@JohnEarnest
Copy link
Author

Using vF instead of v0 for poll 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment