[comp.sys.handhelds] Chipper Documentation

catto@bach.ecn.purdue.edu (Erin S Catto) (05/29/91)

I am just posting the document below; I have nothing to do with its
contents.  All stated below is good for Super Chip.

This document is also a good starting point to learn chip programming.
----------------------------------------------------------------------

Chipper V1.12 is a simple assembler for the HP48SX Chip-8 language.


Written by Christian Egeberg (egeberg@solan.unit.no) 2/11 .. 7/11-'90,
using Turbo Pascal V5.5, and Turbo Debugger V2.0 in 386 virtual mode.


In order to use Chipper V1.12 you need the following:

    *   An IBM compatible PC, preferably with 512k or more.
    *   A Hewlett Packard 48SX Calculator.
    *   A PC to HP48SX serial cable.
    *   A Kermit compatible PC based communication program.
    *   The CHIP-48 interpreter for HP48SX.


CHIP-48 is a video game language interpreter written by Andreas Gustafsson
(gson@niksula.hut.fi). It utilizes the original CHIP-8 instruction set
commonly used by RCA CDP1802 based home computers in the late 1970's.
CHIP-48 should be available by anonymous ftp from vega.hut.fi, directory
/pub/misc/hp48sx/asap.


CHIP-48 programs have access to 4k bytes of memory, addressed from #000 to
#FFF. The programs start at address #200, because of the memory requirements
of the original CHIP-8 interpreter. Instructions are 16 bits long and start
at even memory locations.


CHIP-48 has 16 general registers, named V0, V1, V2, ... , VE, VF. These are
8 bits wide. The VF register works as carry flag and collision indicator,
and is modified by certain instructions. A 16 bit I register also exists.
The lower 12 bits of this register are typically used as a memory pointer.
A delay timer and a sound timer is provided as well. These are 8 bits wide
and decrement around 60 times per second, until a value of 0 is reached.
The HP48SX beeper will buzz until the sound timer reaches 0.


CHIP-48 screen resolution is 64 pixels horisontal and 32 pixels vertical.
Screen origin is the upper left corner. A sprite is 8 pixels wide and from 1
to 15 pixels high. That is also from 1 to 15 bytes large. Upper row in the
first byte, leftmost pixel in the most significant bit. Sprites are XOR-ed
onto the background. If this causes any pixel to be erased, VF is set to
#01, else VF will be #00.


CHIP-48 programs may access 16 keys numbered from #0 to #F. The HP48SX
keyboard mapping is shown below:

    ( 7 )  ->  #1    ( 8 )  ->  #2    ( 9 )  ->  #3    ( / )  ->  #C
    ( 4 )  ->  #4    ( 5 )  ->  #5    ( 6 )  ->  #6    ( * )  ->  #D
    ( 1 )  ->  #7    ( 2 )  ->  #8    ( 3 )  ->  #9    ( - )  ->  #E
    ( 0 )  ->  #A    ( . )  ->  #0    ( _ )  ->  #B    ( + )  ->  #F


The following table contains valid CHIP-48 instruction codes and their
syntax in Chipper V1.12. NNN indicates a 12 bit address. KK is an 8 bit
constant. X and Y denote 4 bit register numbers. Hexadecimal characters
represent themselves. WordExpr means an expression resulting in a 16 bit
constant. AddrExpr is an expression resulting in a 12 bit address. ByteExpr
results in an 8 bit constant, NibbleExpr makes a 4 bit constant, and Expr is
a general expression. Char is an ASCII character. String is a sequence of
ASCII characters. Text in curly brackets is optional. Instruction codes are
written most significant byte first, least significant byte last.

    #0NNN  SYS   AddrExpr            ; Call 1802 code at NNN (not HP48SX)
    #00E0  CLS                       ; Clear display
    #00EE  RET                       ; Return from subroutine (16 levels)
    #1NNN  JP    AddrExpr            ; Jump to NNN
    #2NNN  CALL  AddrExpr            ; Call subroutine at NNN (16 levels)
    #3XKK  SE    VX, ByteExpr        ; Skip next instruction if VX = KK
    #4XKK  SNE   VX, ByteExpr        ; Skip next instruction if VX <> KK
    #5XY0  SE    VX, VY              ; Skip next instruction if VX = VY
    #6XKK  LD    VX, ByteExpr        ; VX := KK
    #7XKK  ADD   VX, ByteExpr        ; VX := VX + KK
    #8XY0  LD    VX, VY              ; VX := VY, VF updates
    #8XY1  OR    VX, VY              ; VX := VX OR VY, VF updates
    #8XY2  AND   VX, VY              ; VX := VX AND VY, VF updates
    #8XY3  XOR   VX, VY              ; VX := VX XOR VY, VF updates
    #8XY4  ADD   VX, VY              ; VX := VX + VY, VF := carry
    #8XY5  SUB   VX, VY              ; VX := VX - VY, VF := NOT borrow
    #8XY6  SHR   VX {, VY}           ; VX := VX SHR 1, VF := carry
    #8XY7  SUBN  VX, VY              ; VX := VY - VX, VF := NOT borrow
    #8XYE  SHL   VX {, VY}           ; VX := VX SHL 1, VF := carry
    #9XY0  SNE   VX, VY              ; Skip next instruction if VX <> VY
    #ANNN  LD    I, AddrExpr         ; I := NNN
    #BNNN  JP    V0, AddrExpr        ; Jump to NNN + V0
    #CXKK  RND   VX , ByteExpr       ; VX := random AND KK
    #DXYN  DRW   VX, VY, NibbleExpr  ; Draw N byte sprite from [I] at VX, VY
                                     ; ... VF := collision
    #EX9E  SKP   VX                  ; Skip next instruction if key VX down
    #EXA1  SKNP  VX                  ; Skip next instruction if key VX up
    #FX07  LD    VX, DT              ; VX := delaytimer
    #FX0A  LD    VX, K               ; VX := key, wait for keypress
    #FX15  LD    DT, VX              ; Delaytimer := VX
    #FX18  LD    ST, VX              ; Soundtimer := VX
    #FX1E  ADD   I, VX               ; I := I + VX
    #FX29  LD    F, VX               ; Point I to 5 byte sprite char for VX
    #FX33  LD    B, VX               ; Store BCD of VX in [I], [I+1], [I+2]
    #FX55  LD    [I], VX             ; Store V0 .. VX in [I] .. [I+X]
    #FX65  LD    VX, [I]             ; Read V0 .. VX from [I] .. [I+X]


Additional Chipper V1.12 directives are:

    SYMBOL  =        Expr              ;  Assign value to symbol
    SYMBOL  EQU      Expr              ;  Assign value to symbol
            DB       ByteExpr {, ...}  ;  Define byte(s) at current address
            DW       WordExpr {, ...}  ;  Define word(s) at current address
            DA       String            ;  Define string at current address
            DS       ByteExpr          ;  Define ByteExpr uninitialized
                                       ;  ... bytes at current address
            ORG      AddrExpr          ;  Set current address to AddrExpr
            END                        ;  This directive is ignored
            INCLUDE  SourceFileName    ;  Includes one more sourcefile


Chipper V1.12 accepts one label, or symbol, per line of source. This should
start with an alphabetic character, and not contain non alphanumeric
characters, otherwise the expression parser may get a bit confused. All
symbols will be converted to upper case, and may be prefixed by an
underscore character and / or suffixed by a colon. These will be stripped
off before the symbol is used. Each symbol contains a 32 bit signed integer
value, set to current address, unless defined by the = or EQU directives.


A symbol name or string containing lower case characters or non alphanumeric
characters (not in symbol names, I have told you that), should be contained
within apostrophes. Two apostrophes following eachother will produce one
resultant apostrophe. Some string examples:

    '11/6-'68'           ;  Is an unterminated string starting with 11/6-68
    11/6-''68            ;  Evaluates to 11/6-'68
    Christian Egeberg    ;  Evaluates to CHRISTIAN EGEBERG
    'Christian Egeberg'  ;  Evaluates to Christian Egeberg
    This, is a test      ;  Evaluates to THIS
                         ;  ... and      IS A TEST
    This',' is a test    ;  Evaluates to THIS, IS A TEST
    'This, is a test'    ;  Evaluates to This, is a test
    ''''                 ;  Evaluates to '''
    ''                   ;  Evaluates to '


A symbol primitive may be one of the following:

    SymbolName         ;  for instance LOOP
    DecimalValue       ;  for instance 1106
    #HexadecimalValue  ;  for instance #452
    $BinaryValue       ;  for instance $10001010010
    @OctalValue        ;  for instance @2122
    "Character         ;  for instance "'c'
    ?                  ;  This is always assigned to current address


An expression may consist of symbol primitives and the following operators.
Horisontal lines denote different priorities. Operators sharing priority
level are evaluated left to right:

    (  ;  Start parentheses expression
    )  ;  End of parentheses expression
    -----------------------------------
    +  ;  Unary plus sign
    -  ;  Unary minus sign
    ~  ;  Bitwise NOT operator
    -----------------------------------
    !  ;  Power of operator
    <  ;  Shift left number of bits
    >  ;  Shift right number of bits
    -----------------------------------
    *  ;  Multiply
    /  ;  Divide
    -----------------------------------
    +  ;  Add
    -  ;  Subtract
    -----------------------------------
    &  ;  Bitwise AND operator
    |  ;  Bitwise OR operator
    ^  ;  Bitwise XOR operator
    -----------------------------------
    \  ;  Low priority divide
    %  ;  Modulus operator

Some expression examples:

    (? + 15 \ 16) * 16         ;  Is a paragraph (16 bytes) alignment
    "'c' + @2 % #20            ;  Resolves to 5
    -3 * -( -7 + ~3)           ;  Resolves to -33
    -3 * -( -7 + ~3) & #FF     ;  Resolves to 223
    ( 2 + 1 )! 2 ^ $1101 > 2   ;  Resolves to 10
    (2+1)!2^$1101>2            ;  Resolves to 10
    TABLESTART + 4 * ITEMSIZE  ;  Resolves


Remarks are prefixed by semicolons, as in the above examples. Note that
Chipper V1.12 performs a word alignment after every line of source code.
This means that for instance two single parameter DB directives in rapid
succession will have an uninitialized separator byte between them. Avoid
this by defining any multiple of two bytes per DB directive.


A note concerning the CHIP-48 instruction set. The LD VX, [I] and LD [I], VX
instructions will change the value of the I register if VX is different from
V0. Actually, I think it is set to the address of the last byte / register
read or written. This may lead to rather obscure bugs. It took me a day's
worth of debugging to figure out why Blinky died, moving upwards on the
second screen, after updating a 16 bit score counter in memory... I had
overwritten the first byte of the Blinky facing up sprite definition, and
thus caused a collision detect.


Chipper V1.12 fatal error messages:

    No source file found         ;  Incorrect source file name
    Unable to open file          ;  Disk problem, no write access
    Outside legal address range  ;  Current address outside #200 .. #FFF


Chipper V1.12 warning messages:

    Incorrect number of parameters       ;  Too few or too many parameters
    No directive found                   ;  Two symbols defined on same line
    No symbol associated                 ;  = or EQU without a symbol
    Attempt to redefine existing symbol  ;  Symbol already exists, discarded
    Badly defined parameter              ;  Undefined symbol or bad syntax
                                         ;  ... in expression
    Parameter out of range               ;  Value too large or too small
    Register not found                   ;  Register operand expected
    Illegal register                     ;  Different register required
    Internal data structure mismatch     ;  C. Egeberg is a lousy programmer


Chipper V1.12 should be invoked with:

    CHIPPER sourcefilename destinationfilename listfilename

or just:

    CHIPPER

which will prompt for filenames. Default file extensions are .CHP, nothing
and .LST. Destination and listfiles will by default be named after source.
The destination file is a binary download mode HP48SX string. Kermit it to
the calculator, put the string on the stack, and run CHIP-48. The listfile
will contain all errors and warnings, hexdump of all generated instructions,
and a complete symboltable. The format is rather simple.


This document contains some information more or less copied directly off
the CHIP-48 documentation by Andreas Gustafsson, who has done a great job,
hacking for the HP48SX. The Chipper V1.12 syntax was inspired by the
SYZYGY game listing posted to comp.sys.handhelds by Roy Trevino. SYZYGY
is the best CHIP-48 game so far...


CHIP-48 is (C) Copyright 1990 Andreas Gustafsson.
Chipper is (C) Copyright 1990 Christian Egeberg.

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

    CHIP-48 and, because of that, programs written in Chipper make use of
    undocumented low-level features of the HP48SX calculator. They may or
    may not cause loss of data, excessive battery drainage, and / or
    damage to the calculator hardware. The authors take no responsibility
    whatsoever for any damage caused by the use of these programs.

    Chipper does all its I/O on the PC through the Turbo Pascal FExpand(),
    Assign(), ReSet(), ReWrite(), Read(), Write(), Eof() and Close() run
    time library functions, but the author takes no responsibility for
    loss of data, damage to any PC hardware, nor strange incidents 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.