[comp.sys.handhelds] CHIP48 - A CHIP-8 interpreter for the HP48SX

gson@niksula.hut.fi (Andreas Gustafsson) (09/03/90)

This is the first release of CHIP-48, a CHIP-8 interpreter for the HP48SX.

For those who don't remember, the CHIP-8 programming language was used
in a number of home computers based on RCA's CDP1802 processor in the
late 1970's.  It's a small, interpreted language designed specifically
for writing simple video games.  It has less than 40 instructions,
including arithmetic, control flow, graphics, and sound.  The
instructions are all 16 bits long and are executed by a very compact
virtual machine interpreter (the 1802 implementation was 512 bytes long).
A simple Pong-style game can usually be written in about 256 bytes of
CHIP-8 and would usually be written directly in hexadecimal.

This posting includes documentation on CHIP-8 (terse but reasonably
complete), CHIP-48 itself, and a sample game.  Write more and post
them to comp.sys.handhelds!

Make sure you have your calculator backed up before you try running
CHIP-48.  The interpreter was written for a HP48SX with the Revision A
ROM.  It appears that it does _not_ work with other ROM revisions.
Hopefully users with newer ROMs will make the necessary changes and
mail them to me.


* Technical specification

The CHIP-8 virtual machine is byte-addressable and has an address
space of 4 kB at addresses 000-FFF hex.  However, addresses 000-1FF
are reserved (this is where the CHIP-8 interpreter used to reside).
Therefore, the CHIP-8 program itself begins at address 200.  All 
instructions are 16 bits long and by convention instructions always
start at an even address.

The machine has 16 8-bit general-purpose registers called V0..VF.  The
VF register is modified by certain instructions and works as a carry
flag and sprite collision indicator.  There is also a 16-bit pointer
register I (though only the low 12 bits are generally used).

A CHIP-8 program displays graphics by drawing sprites that are 8
pixels wide and 1..15 pixels high.  The screen resolution is 32 by 64
pixels.  The origin is the upper left corner of the screen, and all
coordinates are positive.  The sprites are stored in big-endian
format, i.e., the most significant bit corresponds to the leftmost
pixel.  All drawing is done in XOR mode.  If this causes one or
more pixels to be erased, VF is set to 01, otherwise 00.

There are two timers: the delay timer and the sound timer.  Both
timers count down about 60 times per second when nonzero; the speaker
will beep whenever the sound timer is nonzero.

In the instruction table below, NNN is a 12-bit address, KK is an
8-bit constant, and X and Y are 4-bit register numbers.  Hex
characters represent themselves.  The two first characters of the
instruction code form the lower-address byte of the instruction, the
first character being the more significant nibble.

0NNN	Call 1802 machine code subroutine at NNN
00E0	Clear display
00EE	Return from subroutine
1NNN	Jump to NNN
2NNN	Call subroutine at NNN
3XKK	Skip next instruction if VX == KK
4XKK	Skip next instruction if VX != KK
5XY0	Skip next instruction if VX == VY
6XKK	VX := KK
7XKK	VX := VX + KK
8XY0	VX := VY, VF may change
8XY1	VX := VX or VY, VF may change
8XY2	VX := VX and VY, VF may change
8XY3	VX := VX xor VY, VF may change *
8XY4	VX := VX + VY, VF := carry
8XY5	VX := VX - VY, VF := not borrow
8XY6	VX := VX shr 1, VF := carry
8XY7	VX := VY - VX, VF := not borrow *
8XYE	VX := VX shl 1, VF := carry
9XY0	Skip next instruction if VX != VY
ANNN	I := NNN
BNNN	Jump to NNN+V0
CXKK	VX := pseudorandom_number and KK
DXYN	Show N-byte sprite from M(I) at coords (VX,VY), VF := collision
EX9E	Skip next instruction if key VX pressed
EXA1	Skip next instruction if key VX not pressed
FX07	VX := delay_timer
FX0A	wait for keypress, store hex value of key in VX
FX15	delay_timer := VX
FX18	sound_timer := VX
FX1E	I := I + VX
FX29	Point I to 5-byte font sprite for hex character VX
FX33	Store BCD representation of VX in M(I)..M(I+2)
FX55	Store V0..VX in memory starting at M(I)
FX65	Read V0..VX from memory starting at M(I)

The instructions marked with * may have been undocumented (but
functional) in the original CHIP-8 interpreter for the 1802.


* Notes on the HP48SX implementation 

CHIP-8 programs are stored in the HP48SX as string objects containing
the bytes of the program in increasing address order, beginning with
the byte at 0200.  The interpreter itself is a machine code object
that should be run with the CHIP-8 program string on level 1.  4 kB of
free memory is needed.  If an error is detected during execution, the
address of the current CHIP-8 instruction is returned as a binary
integer on level 1.

The clock display should be turned off.  Otherwise, CHIP48 will not run
but will clear flag -40 so that the next attempt to run it may succeed.

To quit, press the backspace key.  Pressing ENTER restarts the CHIP-8
program, and the +/- key turns the sound off or on.

The 0NNN instruction is unimplemented (of course), except for 
NNN==0E0 or 0EE.  Subroutine nesting is limited to 16 levels.

Most chip-8 programs are written for a 16-key hex keyboard with 
following layout:

  1 2 3 C                                               7 8 9 /
  4 5 6 D    This keyboard is emulated on the HP48SX    4 5 6 *
  7 8 9 E    using the following keys:                  1 2 3 -
  A 0 B F                                               0 . _ +

This may cause some confusion with programs requiring numerical input.
The keys 2, 4, 6, and 8 are commonly used to represent directions.
The F key (+ on the HP48SX) is sometimes used as a Fire button.


* The interpreter

Below is a HP48SX machine code object that should be uudecoded and
then downloaded to the calculator using Kermit.

begin 644 chip
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
M.M [(#U@.F!+($R034!04%E08@                       !  !       
I                                                        
 
end


* Sample game

Not particularly exciting, but I had to include something to show how
the interpreter is used.  Uuencode, download to HP48SX using Kermit,
and run with BRIX CHIP.  Play by pressing the keys 4 and 6.

begin 644 brix
M2%!(4#0X+4$L*E C &X%90!K!FH HPS:L7H$.D 2"'L".Q(2!FP@;1^C$-S1
M(O9@ &$ HQ+0$7 (HP[0$6! \!7P!S  $C3&#V<>: %I_Z,.UG&C$-S18 3@
MH7S^8 ;@H7P"8#^, MS1HP[6<8:$AY1@/X8"81^'$D<?$JQ& &@!1C]H_T< 
M:0'6<3\!$JI''Q*J8 6 =3\ $JI@ ? 8@&!A_( 2HPS0<6#^B0,B]G4!(O9%
M8!+>$D9I_X!@@,4_ 1+*80* %3\!$N" %3\!$NZ %3\!$NA@(/ 8HPY^_X#@
M@ 1A - 1/@ 2,!+>>/](_FC_$NYX 4@": %@!/ 8:?\2<*,4]3/R9?$I8S=D
7 --%<P7R*=-% .[@ (  _ "J       "
 
end


* Source code availability

The source code for the interpreter is over 30 k of assembler, and to
assemble it you need my ASAP assembler which is about 25 k.  To run
the assembler, you need Perl 3.0 which is several hundred k.
Therefore, I am not posting all these to comp.sys.handhelds.  However,
the source to CHIP48 and ASAP are available by anonymous FTP from
vega.hut.fi, directory /pub/misc/hp48sx/asap.  The source to Perl 3.0
is available from numerous Unix archive sites.

Those who want to write their own machine code games may want to look
at the interpreter source for hints.  Please note that I have no
insider technical information on the HP48SX; CHIP-8 is based solely on
information posted to comp.sys.handhelds (in particular, Alonzo
Gariepy's excellent HP28S Processor Notes) and personal HP48SX machine
code hacking.


* Fine print

      CHIP-48 and BRIX are (C) Copyright 1990 Andreas Gustafsson

      Noncommercial distribution allowed, provided that this
      copyright message is preserved, and any modified versions
      are clearly marked as such.  

      CHIP-48 and BRIX make use of undocumented low-level features of
      the HP48SX calculator, and may or may not cause loss of data,
      excessive battery drainage, and/or damage to the calculator
      hardware.  The Author takes no responsibility whatsoever for 
      any damage caused by the use of this program.

      THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
      IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
      WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
      PURPOSE.

-- 
Andreas Gustafsson
Internet: gson@niksula.hut.fi
Voice: +358 0 563 5592

froula@motcid.UUCP (Don Froula) (09/11/90)

I've found that the CHIP-8 interpreter and sample BRIX program seems to work
just fine on my REV. D '48.  The speed is quite good.  Thanks for a nice
game development tool!

cruff@ncar.ucar.edu (Craig Ruff) (09/12/90)

In article <4412@apricot29.UUCP> froula@motcid.UUCP (Don Froula) writes:
>I've found that the CHIP-8 interpreter and sample BRIX program seems to work
>just fine on my REV. D '48.  The speed is quite good.

On my system, the game display seems to be skewed.  My guess is that the
screen buffer addresses are off somehow.
-- 
Craig Ruff      	NCAR			cruff@ncar.ucar.edu
(303) 497-1211  	P.O. Box 3000
			Boulder, CO  80307

moews@math.berkeley.edu (David Moews) (09/12/90)

Does anyone know how fast this interpreter is, compared to the original
one running on a 1.78 MHz 1802?
--
David Moews                        moews@math.berkeley.edu

bson@rice-chex.ai.mit.edu (Jan Brittenson) (09/12/90)

In article <1990Sep3.161605.14532@santra.uucp> 
   gson@niksula.hut.fi (Andreas Gustafsson) writes:

 > Below is a HP48SX machine code object that should be uudecoded and
 > then downloaded to the calculator using Kermit.

   Excuse me for asking, but how would you load it? The only way I
could load it was to strip off the archive header/code object
type/length, load it with kermit, and change the type from string to
code. It didn't work on my rev D, though (no surprise there).

gson@niksula.hut.fi (Andreas Gustafsson) (09/15/90)

moews@math.berkeley.edu (David Moews) writes:
> Does anyone know how fast this interpreter is, compared to the original
> one running on a 1.78 MHz 1802?

I haven't run any actual benchmarks, but they appear approximately
equal.  A 1.78 MHz 1802 is about 0.11 MIPS.

In the 1802 interpreter, the DXYN instruction waited for for the next
60 Hz interrupt in order to synchronize drawing with the display
refresh.  CHIP48 tries to emulate this behaviour by waiting for the
next 64 Hz timer increment, so most games run slightly faster on the
HP48SX.  Removing this synchronization causes typical programs such as
BRIX to run perhaps twice as fast, in both implementations.
-- 
Andreas Gustafsson
Internet: gson@niksula.hut.fi
Voice: +358 0 563 5592