|
Thursday, September 08, 2005 |
For the Space Invaders emulator in Factor
I wanted to automate the creation of the 8080 instruction emulation
words. To do this I used a format for describing the 8080 instructions
based on the Z80 equivalents and coded a Factor parsing word that
parsed this format and produced some of the code. For example, some
instructions are:
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 L,(HL) ; opcode 6E cycles 07
INSTRUCTION: LD L,A ; opcode 6F cycles 05
INSTRUCTION: LD (HL),B ; opcode 70 cycles 07
Using the parser combinators library
I write parsers that processed the instructions and seperated them into
families of instructions. For example, LD R,(RR) was the family for
loading an indirect register into a direct register. The parser
combinator word for this is:
: LD-R,(RR)-instruction "LD-R,(RR)" "LD" complex-instruction
8-bit-registers sp <&>
"," token <&
16-bit-registers indirect <&>
just [ unswons unswons >r swap append r> cons ] <@ ;
For LD R,R it is:
: LD-R,R-instruction
"LD-R,R" "LD" complex-instruction
8-bit-registers sp <&>
"," token <&
8-bit-registers <&>
just [ unswons unswons >r swap append r> cons ] <@ ;
Notice the change in the word is just whether it is for 8-bit or 16-bit
registers and whether it is an indirect access. The combinator produced
a list of words for retrieving and setting the relevant registers from
the CPU tuple and a pattern matcher replaced these words in a pattern
for that instruction family:
[[ "LD-R,(RR)" [ [ $3 ] keep [ read-byte ] keep $2 ] ]]
[[
"INC-R" [ [
$1 ] keep [ inc-byte ] keep $2 ] ]]
In this way I could write code for just the groups of instructions
and
at parse time Factor would generate code for the specific instructions.
This cut down on the amount of code to write. In the near future I plan
to extend this so that it will not only generate the emulation words,
but the assembler and disassembler words as well. It could even go
further and on seeing a '(RR)' on the right hand side, could generate
the '[ $3 ] keep' and reduce the instructions families that need to be
coded by hand even more. The code for this is in cpu.factor. This ability to do things at parse time is very similar to Lisp macros.
4:11:15 PM
|
|
I've been working on a Space Invaders emulator written in Factor. I
plan to make a generic 8080 emulator, assembler and disassembler.
Currently the emulator works for a lot of the instructions and can run
some parts of the Space Invaders arcade machine ROM. A screenshot of it running is here.
There's lots to be done but the current code is in Factor CVS and from my Factor Darcs repository. You will need to have your own invaders.rom file to test it though. There is a brief readme.txt file.
I'll post more on the design and implementation when I've got the main
part of the game running. And then work on the assembler and
disassembler.
As an example of the speedups obtained from optimisations in Factor
0.78, running 1,000,000 instructions in 0.77 took 3,174 milliseconds.
In 0.78 it took 2,293 milliseconds.
Even in 'interpreted' mode the emulator runs faster than normal speed. When compiled it is very fast.
1:57:40 PM
|
|
© Copyright 2005 Chris Double.
|
|
|