CHIP-48 - A CHIP-8 interpreter for the HP48SX (version 2.25) =========================================================== This CHIP-48, a CHIP-8 interpreter for the HP48SX, version 2.25. 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. * 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 8X06 VX := VX shr 1, VF := carry 8XY7 VX := VY - VX, VF := not borrow * 8X0E 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 Decode this using Bill Wickes' ASC-> program (posted to comp.sys.handhelds recently and available by FTP from several places including vega.hut.fi) and save it as CHIP. The checksum should be #9D0Eh and the length as calculated using "blue-arrow CHIP BYTES" should be 1738 bytes (slightly shorter that version 2.20). %%HP: T(1)A(D)F(.); "CCD20F8D008FFBA818FB976034EC607134152080863F08084315006A9184A345 C1008FD7B5013681AF0C134AF2154716F154716F370000100415C781AF143417 000C213434B550780821837BC13415507808218079B184A34000208FD7B50136 81AF0AAF0AF1AF2AF381AF123400400C213414713514334C2A208A6A11741438 18F843400C108B2606B311747D718F2D760174E78FB976081AF1A13481B43409 B00C2135808210515F0F217015C1161CC96CBE808FD281AF083200281AF0B81A F1434C2000C2134D21447E53D232831134146DA1468A68F8082408F000EF281A F017DE05A180874B98F2D760142164808C808F8F75D0081AF1BDA818F0181AF0 377C1135D217015701C0C6C681B4CA3483B00C2134D215E381B4CA81B5818F2B 0681B2460697F11B1088F735608FB97606F6F135147818F2F818F23144818F2F 818F2F818F21164A6C96C2E018A86115F015C0160170CC6AEF01715114E96AB2 161156090AF116015E2801BBE8082200C0E3215C2D232831134146DA1468A68F 8082408F000EF281AF118A6606F70D23108EA3408F000EF681AF0175C014E96A 80A6E14C16114E96A80A6E14C70C0320108018F06110DAD280115E31583FC0EF 68087400808700080873703010374701560FE8082010EF2154062EFD22215702 017114F1C101C681AF12C201D21570C681AF14C213401D23006BEFD230F62EFD 2310168DFD231116ECFD2312164CFD231416ABF7DAFD214E061727F9FD014A07 1C2011727C8F1C2D215E1067D7FD015A107DE01F6F680821100E62067A7F0714 C03C681B4CA34BA800C2134D215E08018F06110DAD280116015E00EF20113613 406762F81AF187BFE13507DA0179DEDAD2310E8A2D031EE8A2640281AF143417 000CA3104D5130146134AF2154716F154716F14C818F04A6D96D7D0381AF1434 C2000C21341428A800818F83140818F24C2134D215E381AF0B037F3E81AF0B03 81AF1434C2000C2134142818F24C213681AF131583136142818F0334040008B6 001406EAF7B0E17114B14E9664181AF2B818F2181AF2B0375ED17114B14E962E E69DF7E1E6CCF761E6AEF7FBD17114B1480370BD17114B14EA6214C0317115B0 1C1300906B076FD148033019060175ED0E6A15C103302906017FCD0E6215C103 303906D179BDAE80E690E62BEE0E6514C0330490601769DC215C161BD3059065 1708DBECC2E615C1669D30690691756DAEA8196215C1AE66B7D307906C0764DD E63CF30E90601743DC615C16F4D02769C81AF08037BAC768CD014AC281AF0B03 749C344010013615A113617114F1C10E6214C036561754B47F90A6F70E281AF1 8774C81AF08789CD731F10E6631F30E63171AE215F0A62AE53102B61550AE1AE 215F0B6980D080CF2EA82201C175037DB28EE0CFAE22E90A50B6614C200378DB D214E7A7CAE3A8717114B1C131E9962D0311A962E002AEBAE069CDAEBAE0699D 13606D3DB763C90E017E5A413B076AEF75AB314015C1744A471DB7A0C90E4E07 134AEB030702784B17114B1C131709668113606745B14A071361480331A09664 17B7F47014C03076AF831519662114E067A1B0714C0331819662114E067B0B07 14C0331E1966B1D214E81AF10A3A40081AF0003319296681D215E0DAC6C6C281 AF0803313396260639014EAE781B434FB300C2134D096B42AEB808A0C015E205 CA04162819636EDF02D881AF1880824DFF008B2007F1A134D4D2221500160154 016021150016015401602015001601540033155966537BCA14E14D1361348BAE 117116181AF18B3640081AF0866DF033156966337F8A14F14C1361348BA2E171 16181AF18B3640081AF0866DF0281AF14341B100C213481AF1814416481AF191 4416481AF1A14416481AF1B1441640181AF14341B100C213414681AF08164146 81AF0916414681AF0A16414681AF0B164012C300202C90E40C420D6C4C4C281A F14CA3417000C281AF09DB819F2819F2819F2C6C681AF0A31700E63C781B434C 3000C2CB81AF0B81AF1813415E1D1AE5136818F2181AF0881AF1B81B3C5C5C5C 5C5C5C5C581B434F1100CAD2A89C6C213414EAE7BF3BF3F5D2A89C6C213414EA E7BF3BF3F5D2A89C6C213414EAE7BF3BF3F5D2A89C6C213414EAE781AF111301 462C90E80818F04818F042081AF0181AF12C21343102B6280821809E650AE6A6 E80D01561A9A0E1791AF080FD2E30180FDA9F0E1AB9F0E1780FD2C90EB180FD1 54116F16F16115416B0080FD154120A4E94A6067AE01000C030FC0CCC3CF303C 333FF0FCF3FFF999F26227F1F8FF1F1F99F11F8F1FF8F9FF1244F9F9FF9F1FF9 F99E9E9EF888FE999EF8F8FF8F88100200400800610230460821148884824844 422824221812814121116A200430C4305930BB301D301E300F3050409D309E40 5F40C05073508C508560E0D9" * Sample game Not particularly exciting, but I had to include something to show how the interpreter is used. Decode this using ASC-> and store the resulting rather ugly string object as BRIX. The checksum should be #3B4Dh and the length as calculated using "blue-arrow BRIX BYTES" should be 285 bytes. Run with BRIX CHIP and play by pressing the keys 4 and 6. %%HP: T(1)A(R)F(,); "C2A2053200E6505600B660A6003AC0AD1BA740A3042180B720B3212160C602D6 F13A01CD1D226F060016003A210D1107803AE00D1106040F510F70030021436C F076E1861096FF3AE06D173A01CD1D06400E1AC7EF06600E1AC72006F3C820CD 1D3AE06D176848784906F3682016F1782174F121CA6400861064F386FF740096 106D17F31021AA74F121AA06500857F30021AA06100F81080616CF08213AC00D 1706EF9830226F5710226F540621ED216496FF0806085CF31021AC16200851F3 10210E0851F31021EE0851F310218E06020F813AE0E7FF080E084016000D11E3 00210321ED87FF84EF86FF21EE87108420861006400F8196FF21073A415F332F 561F92367346003D5437502F923D5400EE0E000800CF00AA0000000000D4B3" * 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 CHIP48 was written without any insider technical information on the HP48SX; it 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