# Space Invaders emulator in Factor

## Chris Double — 2005-09-11 02:45:19

    I've written a Space Invaders emulator in Factor. Screenshots here:

    http://factor.modalwebserver.co.nz/factor_space_invaders.jpg

    http://factor.modalwebserver.co.nz/factor_space_invaders2.jpg

    http://factor.modalwebserver.co.nz/factor_space_invaders3.jpg

    The code is in Factor CVS and in my darcs repository. I took a

    declarative approach to emulating the 8080 CPU. Using parser combinators

    I parsed a syntax for describing the instructions and generate the code

    to do the emulation from that. So the instructions look like:

    INSTRUCTION: DEC  DE      ; opcode 1B cycles 06

    INSTRUCTION: INC  E       ; opcode 1C cycles 05

    INSTRUCTION: DEC  E       ; opcode 1D cycles 05

    INSTRUCTION: LD   E,n     ; opcode 1E cycles 07

    INSTRUCTION: RRA          ; opcode 1F cycles 04

    INSTRUCTION: LD   HL,nn   ; opcode 21 cycles 10

    INSTRUCTION: LD   (nn),HL ; opcode 22 cycles 16

    INSTRUCTION: is a parsing word that, at parse time, uses the parser

    combinators to process the instruction body. It generates quoations for

    the registers being used, etc and looks up an 'instruction family',

    which contains a pattern of how that instruction should operate:

        [[ "POP-RR"    [ [ pop-sp ] keep $2 ] ]]

        [[ "PUSH-RR"   [ [ $1 ] keep push-sp ] ]]

        [[ "INC-R"     [ [ $1 ] keep [ inc-byte ] keep $2 ] ]]

        [[ "DEC-R"     [ [ $1 ] keep [ dec-byte ] keep $2 ] ]]

        [[ "INC-RR"    [ [ $1 ] keep [ inc-word ] keep $2 ] ]]

        [[ "DEC-RR"    [ [ $1 ] keep [ dec-word ] keep $2 ] ]]

    The $1 and $2 in these patterns are replaced by the actual code to

    retrieve and set values of registers that were produced by the parser

    combinators upon parsing the code. This helped reduce the amount of code

    I needed to write quite a bit.

    The generic 8080 emulator is seperated from the space invaders specific

    stuff:

    TUPLE: cpu b c d e f h l a pc sp halted? last-interrupt cycles ram ;

    GENERIC: reset        ( cpu            -- )

    GENERIC: update-video ( value addr cpu -- )

    GENERIC: read-port    ( port cpu       -- byte )

    GENERIC: write-port   ( value port cpu -- )

    By creating a tuple that delegates to the 'cpu' tuple, and adding

    methods to the generic functions you can create an emulator for any 8080

    based device:

    TUPLE: space-invaders port1 port2i port2o port3o port4lo port4hi port5o

    ;

    C: space-invaders ( cpu -- cpu )

      [ <cpu> swap set-delegate ] keep

      [ reset ] keep ;

    ...etc...

    I plan to add to the automatic emulation instruction generation to also

    automatically generate an assembler and disassembler. There's some old

    8080 code i'd like to try assembling and running (Forth, Basic, etc)

    just to try the system out.

    Overall I found Factor very easy to use for developing this. The main

    issues i had we working out how the 8080 worked rather than problems

    with using Factor or the concatenative approach.

    Chris.

    --

    http://radio.weblogs.com/0102385