space invaders: sync frame rate. reorganise code into generic 8080 and space invaders portions. remove dead

code.
cvs
Chris Double 2005-09-11 01:51:05 +00:00
parent d0312300b8
commit dede7e0dba
5 changed files with 261 additions and 588 deletions

View File

@ -2,36 +2,33 @@ USING: kernel lists math sequences errors vectors prettyprint io unparser namesp
words parser hashtables lazy parser-combinators kernel-internals strings ;
IN: cpu-8080
TUPLE: cpu b c d e f h l a pc sp halted? last-interrupt cycles port1 port2i port2o port3o port4lo port4hi port5o ram display ;
TUPLE: cpu b c d e f h l a pc sp halted? last-interrupt cycles ram ;
: valid-byte? ( b -- )
dup 0 >= swap HEX: FF <= and not [ "Invalid byte" throw ] when ;
GENERIC: reset ( cpu -- )
GENERIC: update-video ( value addr cpu -- )
GENERIC: read-port ( port cpu -- byte )
GENERIC: write-port ( value port cpu -- )
: valid-word? ( w -- )
dup 0 >= swap HEX: FFFF <= and not [ "Invalid word" throw ] when ;
M: cpu update-video ( value addr cpu -- )
3drop ;
M: cpu read-port ( port cpu -- byte )
#! Read a byte from the hardware port. 'port' should
#! be an 8-bit value.
2drop 0 ;
M: cpu write-port ( value port cpu -- )
#! Write a byte to the hardware port, where 'port' is
#! an 8-bit value.
3drop ;
: carry-flag HEX: 01 ; inline
: add-sub-flag HEX: 02 ; inline
: subtraction-flag HEX: 02 ; inline
: parity-flag HEX: 04 ; inline
: overflow-flag HEX: 04 ; inline
: flag3-flag HEX: 08 ; inline
: half-carry-flag HEX: 10 ; inline
: aux-carry-flag HEX: 10 ; inline
: interrupt-flag HEX: 20 ; inline
: flag5-flag HEX: 20 ; inline
: zero-flag HEX: 40 ; inline
: sign-flag HEX: 80 ; inline
: increment-8bit ( v -- v overflow? )
#! Increment an 8 bit value by 1. Return the new
#! value plus t if the value overflowed back to zero.
1 + dup 256 = [
drop 0 t
] [
f
] ifte ;
: >word< ( word -- byte byte )
#! Explode a word into its two 8 bit values.
dup HEX: FF bitand swap -8 shift HEX: FF bitand swap ;
@ -114,13 +111,13 @@ TUPLE: cpu b c d e f h l a pc sp halted? last-interrupt cycles port1 port2i port
cpu-ram nth
] [
2drop HEX: FF
] ifte dup valid-byte? ;
] ifte ;
: read-word ( addr cpu -- word )
#! Read a 16-bit word from memory at the specified address.
#! The address is 16-bit, but if a value greater than
#! 0xFFFF is provided then return a default value.
[ read-byte ] 2keep >r 1 + r> read-byte 8 shift bitor dup valid-word? ;
[ read-byte ] 2keep >r 1 + r> read-byte 8 shift bitor ;
: next-byte ( cpu -- byte )
#! Return the value of the byte at PC, and increment PC.
@ -136,23 +133,9 @@ TUPLE: cpu b c d e f h l a pc sp halted? last-interrupt cycles port1 port2i port
[ cpu-pc 2 + ] keep
set-cpu-pc ;
: update-video ( value addr cpu -- )
#! If a 'display' quotation is set for the cpu, call it
#! if the write to RAM is within video memory range.
over HEX: 2400 >= [
dup cpu-display [ ( value addr cpu quot -- )
call
] [
3drop
] ifte*
] [
3drop
] ifte ;
: write-byte ( value addr cpu -- )
#! Write a byte to the specified memory address.
pick valid-byte?
over valid-word?
over dup HEX: 2000 < swap HEX: FFFF > or [
3drop
] [
@ -163,34 +146,8 @@ TUPLE: cpu b c d e f h l a pc sp halted? last-interrupt cycles port1 port2i port
: write-word ( value addr cpu -- )
#! Write a 16-bit word to the specified memory address.
pick valid-word?
>r >r >word< r> r> [ write-byte ] 2keep >r 1 + r> write-byte ;
: read-port ( port cpu -- byte )
#! Read a byte from the hardware port. 'port' should
#! be an 8-bit value.
! 2dup drop "IN from " write number>string print
{
{ [ over 1 = ] [ nip [ cpu-port1 dup HEX: FE bitand ] keep set-cpu-port1 ] }
{ [ over 2 = ] [ nip [ cpu-port2i HEX: 8F bitand ] keep cpu-port1 HEX: 70 bitand bitor ] }
{ [ over 3 = ] [ nip [ cpu-port4hi 8 shift ] keep [ cpu-port4lo bitor ] keep cpu-port2o shift -8 shift HEX: FF bitand ] }
{ [ t ] [ 2drop 0 ] }
} cond dup valid-byte? ;
: write-port ( value port cpu -- )
#! Write a byte to the hardware port, where 'port' is
#! an 8-bit value.
pick valid-byte?
! 3dup drop "OUT to " write unparse write " value " write unparse print
{
{ [ over 2 = ] [ nip set-cpu-port2o ] }
{ [ over 3 = ] [ nip set-cpu-port3o ] }
{ [ over 4 = ] [ nip [ cpu-port4hi ] keep [ set-cpu-port4lo ] keep set-cpu-port4hi ] }
{ [ over 5 = ] [ nip set-cpu-port5o ] }
{ [ over 6 = ] [ 3drop ] }
{ [ t ] [ 3drop "Invalid port write" throw ] }
} cond ;
: cpu-a-bitand ( quot cpu -- )
#! A &= quot call
[ cpu-a swap call bitand ] keep set-cpu-a ; inline
@ -253,6 +210,7 @@ TUPLE: cpu b c d e f h l a pc sp halted? last-interrupt cycles port1 port2i port
#! is 0, (ie. if the result has even parity) this flag
#! is set, otherwise it is reset.
swap HEX: FF bitand 2 mod 0 = [ parity-flag set-flag ] [ parity-flag clear-flag ] ifte ;
: update-carry-flag ( result cpu -- )
#! If the instruction resulted in a carry (from addition)
#! or a borrow (from subtraction or a comparison) out of the
@ -277,32 +235,6 @@ TUPLE: cpu b c d e f h l a pc sp halted? last-interrupt cycles port1 port2i port
2dup update-sign-flag
update-zero-flag ;
: trigger-zero-flag ( n cpu -- )
#! Given the value n, set the zero flag if required.
swap HEX: FF bitand 0 = [ [ zero-flag ] swap cpu-f-bitor ] [ drop ] ifte ;
: trigger-sign-flag ( n cpu -- )
#! Given the value n, set the sign flag if required.
swap HEX: 80 bitand 0 = not [ [ sign-flag ] swap cpu-f-bitor ] [ drop ] ifte ;
: trigger-carry-flag ( n cpu -- )
#! Given the value n, set the carry flag if required.
swap HEX: 100 >= [ [ carry-flag ] swap cpu-f-bitor ] [ drop ] ifte ;
: trigger-half-carry-flag ( n a+n+cf cpu -- )
#! Given the value n, set the half carry flag if required.
-rot ( cpu n a+n+cf )
pick cpu-a bitxor bitxor HEX: 10 bitand 0 = not [ [ half-carry-flag ] swap cpu-f-bitor ] [ drop ] ifte ;
: trigger-overflow-flag ( n a+n+cf cpu -- )
#! Given the value n, set the half carry flag if required.
-rot ( cpu n a+n+cf )
over bitxor ( cpu n x^n )
pick cpu-a rot bitxor ( cpu x^n a^n )
bitand HEX: 80 bitand ( cpu v )
0 = not [ [ overflow-flag ] swap cpu-f-bitor ] [ drop ] ifte ;
: add-byte ( lhs rhs cpu -- result )
#! Add rhs to lhs
>r + r> [ update-flags ] 2keep drop HEX: FF bitand ;
@ -380,270 +312,6 @@ TUPLE: cpu b c d e f h l a pc sp halted? last-interrupt cycles port1 port2i port
: flags ( seq -- seq )
[ 0 [ execute bitor ] reduce ] map ;
SYMBOL: psz-vector
: psz ( -- vector )
psz-vector get ;
{
[ zero-flag parity-flag ]
[ ]
[ ]
[ parity-flag ]
[ ]
[ parity-flag ]
[ parity-flag ]
[ ]
[ ]
[ parity-flag ]
[ parity-flag ]
[ ]
[ parity-flag ]
[ ]
[ ]
[ parity-flag ]
[ ]
[ parity-flag ]
[ parity-flag ]
[ ]
[ parity-flag ]
[ ]
[ ]
[ parity-flag ]
[ parity-flag ]
[ ]
[ ]
[ parity-flag ]
[ ]
[ parity-flag ]
[ parity-flag ]
[ ]
[ ]
[ parity-flag ]
[ parity-flag ]
[ ]
[ parity-flag ]
[ ]
[ ]
[ parity-flag ]
[ parity-flag ]
[ ]
[ ]
[ parity-flag ]
[ ]
[ parity-flag ]
[ parity-flag ]
[ ]
[ parity-flag ]
[ ]
[ ]
[ parity-flag ]
[ ]
[ parity-flag ]
[ parity-flag ]
[ ]
[ ]
[ parity-flag ]
[ parity-flag ]
[ ]
[ parity-flag ]
[ ]
[ ]
[ parity-flag ]
[ ]
[ parity-flag ]
[ parity-flag ]
[ ]
[ parity-flag ]
[ ]
[ ]
[ parity-flag ]
[ parity-flag ]
[ ]
[ ]
[ parity-flag ]
[ ]
[ parity-flag ]
[ parity-flag ]
[ ]
[ parity-flag ]
[ ]
[ ]
[ parity-flag ]
[ ]
[ parity-flag ]
[ parity-flag ]
[ ]
[ ]
[ parity-flag ]
[ parity-flag ]
[ ]
[ parity-flag ]
[ ]
[ ]
[ parity-flag ]
[ parity-flag ]
[ ]
[ ]
[ parity-flag ]
[ ]
[ parity-flag ]
[ parity-flag ]
[ ]
[ ]
[ parity-flag ]
[ parity-flag ]
[ ]
[ parity-flag ]
[ ]
[ ]
[ parity-flag ]
[ ]
[ parity-flag ]
[ parity-flag ]
[ ]
[ parity-flag ]
[ ]
[ ]
[ parity-flag ]
[ parity-flag ]
[ ]
[ ]
[ parity-flag ]
[ ]
[ parity-flag ]
[ parity-flag ]
[ ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
[ sign-flag ]
[ sign-flag ]
[ sign-flag parity-flag ]
} flags psz-vector set
: decrement-sp ( n cpu -- )
#! Decrement the stackpointer by n.
[ cpu-sp ] keep
@ -678,56 +346,12 @@ SYMBOL: psz-vector
: call-sub ( addr cpu -- )
#! Call the address as a subroutine.
over valid-word?
dup push-pc
>r HEX: FFFF bitand r> set-cpu-pc ;
: clear-and-set-flags-psz ( cpu -- )
[ cpu-f flag3-flag flag5-flag bitor bitand ] keep
[ cpu-a psz nth bitor ] keep ( v cpu -- )
set-cpu-f ;
: dec-byte-old ( b cpu -- b )
over valid-byte?
[
cpu-f
zero-flag sign-flag half-carry-flag overflow-flag bitor bitor bitor
255 swap - bitand
add-sub-flag bitor
] keep
[ set-cpu-f ] keep ( b cpu -- )
[ swap HEX: 0f bitand 0 = [ [ half-carry-flag ] swap cpu-f-bitor ] [ drop ] ifte ] 2keep
>r 1 - HEX: FF bitand r>
[ swap HEX: 7F = [ [ overflow-flag ] swap cpu-f-bitor ] [ drop ] ifte ] 2keep
[ swap HEX: 80 bitand 0 = not [ [ sign-flag ] swap cpu-f-bitor ] [ drop ] ifte ] 2keep
[ swap HEX: 00 = [ [ zero-flag ] swap cpu-f-bitor ] [ drop ] ifte ] 2keep
drop dup valid-byte? ;
: ret-from-sub ( cpu -- )
[ pop-pc ] keep set-cpu-pc ;
: set-flags-psz ( cpu -- )
[ cpu-f parity-flag sign-flag zero-flag bitor bitor 255 swap - bitand ] keep
[ cpu-a psz nth bitor ] keep ( v cpu -- )
set-cpu-f ;
SYMBOL: cf
: sub-byte-old ( cf n cpu -- x )
#! Subtracts 'n' from the 'a' register. 'cf' is carry flag settings.
over valid-byte?
pick cf set
[ rot drop cpu-a swap - HEX: FF bitand ] 3keep ( x cf n cpu )
rot 0 = not [ >r >r 1 - HEX: FF bitand r> r> ] when ( x n cpu )
[ cpu-f flag3-flag flag5-flag bitor bitand subtraction-flag bitor ] keep ( x n f cpu )
[ set-cpu-f ] keep swapd ( n x cpu )
[ swap 0 = [ [ zero-flag ] swap cpu-f-bitor ] [ drop ] ifte ] 2keep
[ swap HEX: 80 bitand 0 = not [ [ sign-flag ] swap cpu-f-bitor ] [ drop ] ifte ] 2keep
[ swap over cpu-a >= ( n cpu >= ) rot cf get bitor 0 = not and [ [ carry-flag ] swap cpu-f-bitor ] [ drop ] ifte ] 3keep
[ dup >r cpu-a bitxor bitxor HEX: 10 bitand r> swap 0 = not [ [ half-carry-flag ] swap cpu-f-bitor ] [ drop ] ifte ] 3keep
[ dup >r cpu-a swapd bitxor swap r> dup >r cpu-a bitxor bitand HEX: 80 bitand r> swap 0 = not [ [ overflow-flag ] swap cpu-f-bitor ] [ drop ] ifte ] 3keep
drop nip dup valid-byte? ;
: interrupt ( number cpu -- )
#! Perform a hardware interrupt
! "***Interrupt: " write over 16 >base print
@ -742,7 +366,7 @@ SYMBOL: cf
#! Increment the number of cpu cycles
[ cpu-cycles + ] keep set-cpu-cycles ;
: instruction-cycles ( -- )
: instruction-cycles ( -- vector )
#! Return a 256 element vector containing the cycles for
#! each opcode in the 8080 instruction set.
{
@ -755,7 +379,7 @@ SYMBOL: cf
f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f
f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f } ;
: instructions ( -- )
: instructions ( -- vector )
#! Return a 256 element vector containing the emulation words for
#! each opcode in the 8080 instruction set.
{
@ -766,9 +390,9 @@ SYMBOL: cf
f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f
f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f
f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f
f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f } ;
f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f } ; inline
: reset ( cpu -- )
M: cpu reset ( cpu -- )
#! Reset the CPU to its poweron state
[ 0 swap set-cpu-b ] keep
[ 0 swap set-cpu-c ] keep
@ -783,16 +407,9 @@ SYMBOL: cf
[ HEX: FFFF 0 <repeated> >vector swap set-cpu-ram ] keep
[ f swap set-cpu-halted? ] keep
[ HEX: 10 swap set-cpu-last-interrupt ] keep
[ 0 swap set-cpu-port1 ] keep
[ 0 swap set-cpu-port2i ] keep
[ 0 swap set-cpu-port2o ] keep
[ 0 swap set-cpu-port3o ] keep
[ 0 swap set-cpu-port4lo ] keep
[ 0 swap set-cpu-port4hi ] keep
[ 0 swap set-cpu-port5o ] keep
0 swap set-cpu-cycles ;
C: cpu ( -- cpu )
C: cpu ( cpu -- cpu )
[ reset ] keep ;
: (load-rom) ( n ram -- )
@ -964,40 +581,53 @@ SYMBOL: $4
set-cpu-pc ;
: (emulate-RLCA) ( cpu -- )
dup cpu-a dup ( cpu a a )
1 shift HEX: FF bitand swap -7 shift HEX: FF bitand bitor ( cpu a )
HEX: FF bitand dup pick set-cpu-a
add-sub-flag half-carry-flag carry-flag bitor bitor HEX: FF swap - ( cpu a newf )
pick cpu-f bitand pick set-cpu-f
HEX: 01 bitand 0 = not [ dup cpu-f carry-flag bitor swap set-cpu-f ] [ drop ] ifte ;
#! The content of the accumulator is rotated left
#! one position. The low order bit and the carry flag
#! are both set to the value shifted out of the high
#! order bit position. Only the carry flag is affected.
[ cpu-a -7 shift ] keep
over 0 = [ dup carry-flag clear-flag ] [ dup carry-flag set-flag ] ifte
[ cpu-a 1 shift HEX: FF bitand ] keep
>r bitor r> set-cpu-a ;
: (emulate-RRCA) ( cpu -- )
dup cpu-a dup ( cpu a a )
-1 shift HEX: FF bitand swap 7 shift HEX: FF bitand bitor ( cpu a )
HEX: FF bitand dup pick set-cpu-a
add-sub-flag half-carry-flag carry-flag bitor bitor HEX: FF swap - ( cpu a newf )
pick cpu-f bitand pick set-cpu-f
HEX: 80 bitand 0 = not [ dup cpu-f carry-flag bitor swap set-cpu-f ] [ drop ] ifte ;
#! The content of the accumulator is rotated right
#! one position. The high order bit and the carry flag
#! are both set to the value shifted out of the low
#! order bit position. Only the carry flag is affected.
[ cpu-a 1 bitand 7 shift ] keep
over 0 = [ dup carry-flag clear-flag ] [ dup carry-flag set-flag ] ifte
[ cpu-a 254 bitand -1 shift ] keep
>r bitor r> set-cpu-a ;
: (emulate-RLA) ( cpu -- )
dup cpu-a dup ( cpu old-a new-a )
1 shift HEX: FF bitand pick set-cpu-a ( cpu old-a )
over flag-c? [ [ 1 ] pick cpu-a-bitor ] when
[ add-sub-flag half-carry-flag carry-flag bitor bitor 255 swap - ] pick cpu-f-bitand
HEX: 80 bitand 0 = not [ [ carry-flag ] over cpu-f-bitor ] when
drop ;
#! The content of the accumulator is rotated left
#! one position through the carry flag. The low
#! order bit is set equal to the carry flag and
#! the carry flag is set to the value shifted out
#! of the high order bit. Only the carry flag is
#! affected.
[ carry-flag swap flag-set? [ 1 ] [ 0 ] ifte ] keep
[ cpu-a 127 bitand 7 shift ] keep
dup cpu-a 128 bitand 0 = [ dup carry-flag clear-flag ] [ dup carry-flag set-flag ] ifte
>r bitor r> set-cpu-a ;
: (emulate-RRA) ( cpu -- )
dup cpu-a dup ( cpu old-a new-a )
-1 shift HEX: FF bitand pick set-cpu-a ( cpu old-a )
over flag-c? [ [ HEX: 80 ] pick cpu-a-bitor ] when
[ add-sub-flag half-carry-flag carry-flag bitor bitor 255 swap - ] pick cpu-f-bitand
HEX: 01 bitand 0 = not [ [ carry-flag ] over cpu-f-bitor ] when
drop ;
#! The content of the accumulator is rotated right
#! one position through the carry flag. The high order
#! bit is set to the carry flag and the carry flag is
#! set to the value shifted out of the low order bit.
#! Only the carry flag is affected.
[ carry-flag swap flag-set? [ BIN: 10000000 ] [ 0 ] ifte ] keep
[ cpu-a 254 bitand -1 shift ] keep
dup cpu-a 1 bitand 0 = [ dup carry-flag clear-flag ] [ dup carry-flag set-flag ] ifte
>r bitor r> set-cpu-a ;
: (emulate-CPL) ( cpu -- )
[ HEX: FF ] over cpu-a-bitxor
[ add-sub-flag half-carry-flag bitor ] swap cpu-f-bitor ;
#! The contents of the accumulator are complemented
#! (zero bits become one, one bits becomes zero).
#! No flags are affected.
HEX: FF swap cpu-a-bitxor= ;
: (emulate-DAA) ( cpu -- )
#! The eight bit number in the accumulator is
@ -1032,9 +662,9 @@ SYMBOL: $4
[[ "RST-30H" [ drop "RST 30H Not Implemented" throw ] ]]
[[ "RST-38H" [ drop "RST 38H Not Implemented" throw ] ]]
[[ "RET-F|FF" [ dup $1 [ 6 over inc-cycles ret-from-sub ] [ drop ] ifte ] ]]
[[ "CP-N" [ [ next-byte ] keep 0 -rot sub-byte-old drop ] ]]
[[ "CP-R" [ [ $1 ] keep 0 -rot sub-byte-old drop ] ]]
[[ "CP-(RR)" [ [ $1 ] keep [ read-byte ] keep 0 -rot sub-byte-old drop ] ]]
[[ "CP-N" [ [ cpu-a ] keep [ next-byte ] keep sub-byte drop ] ]]
[[ "CP-R" [ [ cpu-a ] keep [ $1 ] keep sub-byte drop ] ]]
[[ "CP-(RR)" [ [ cpu-a ] keep [ $1 ] keep [ read-byte ] keep sub-byte drop ] ]]
[[ "OR-N" [ [ cpu-a ] keep [ next-byte ] keep [ or-byte ] keep set-cpu-a ] ]]
[[ "OR-R" [ [ cpu-a ] keep [ $1 ] keep [ or-byte ] keep set-cpu-a ] ]]
[[ "OR-(RR)" [ [ cpu-a ] keep [ $1 ] keep [ read-byte ] keep [ or-byte ] keep set-cpu-a ] ]]

View File

@ -1,131 +0,0 @@
IN: cpu-8080
USING: kernel lists sdl sdl-event sdl-gfx sdl-video math styles sequences io namespaces generic kernel-internals ;
: plot-bits ( h w byte bit -- )
dup swapd -1 * shift 1 bitand 0 = [ ( h w bit -- )
swap 8 * + surface get -rot swap black rgb pixelColor
] [
swap 8 * + surface get -rot swap white rgb pixelColor
] ifte ;
: update-display ( cpu -- )
224 [ ( cpu h -- h )
32 [ ( cpu h w -- w )
[ swap 32 * + HEX: 2400 + swap cpu-ram nth ] 3keep ( byte cpu h w )
rot >r rot ( h w byte )
[ 0 plot-bits ] 3keep
[ 1 plot-bits ] 3keep
[ 2 plot-bits ] 3keep
[ 3 plot-bits ] 3keep
[ 4 plot-bits ] 3keep
[ 5 plot-bits ] 3keep
[ 6 plot-bits ] 3keep
[ 7 plot-bits ] 3keep
drop r> -rot
] repeat
] repeat drop ;
: gui-step ( cpu -- )
[ read-instruction ] keep ( n cpu )
over get-cycles over inc-cycles
[ swap instructions dispatch ] keep
[ cpu-pc HEX: FFFF bitand ] keep
set-cpu-pc ;
: gui-frame/2 ( cpu -- )
[ gui-step ] keep
[ cpu-cycles ] keep
over 16667 < [ ( cycles cpu )
nip gui-frame/2
] [
[ >r 16667 - r> set-cpu-cycles ] keep
dup cpu-last-interrupt HEX: 10 = [
HEX: 08 over set-cpu-last-interrupt HEX: 08 swap interrupt
] [
HEX: 10 over set-cpu-last-interrupt HEX: 10 swap interrupt
] ifte
] ifte ;
: gui-frame ( cpu -- )
dup gui-frame/2 gui-frame/2 ;
GENERIC: handle-si-event ( cpu event -- quit? )
M: object handle-si-event ( cpu event -- quit? )
2drop f ;
M: quit-event handle-si-event ( cpu event -- quit? )
2drop t ;
USE: prettyprint
M: key-down-event handle-si-event ( cpu event -- quit? )
keyboard-event>binding last car ( cpu key )
{
{ [ dup "ESCAPE" = ] [ 2drop t ] }
{ [ dup "BACKSPACE" = ] [ drop [ cpu-port1 1 bitor ] keep set-cpu-port1 f ] }
{ [ dup 1 = ] [ drop [ cpu-port1 4 bitor ] keep set-cpu-port1 f ] }
{ [ dup "LCTRL" = ] [ drop [ cpu-port1 HEX: 10 bitor ] keep set-cpu-port1 f ] }
{ [ dup "LEFT" = ] [ drop [ cpu-port1 HEX: 20 bitor ] keep set-cpu-port1 f ] }
{ [ dup "RIGHT" = ] [ drop [ cpu-port1 HEX: 40 bitor ] keep set-cpu-port1 f ] }
{ [ t ] [ . drop f ] }
} cond ;
M: key-up-event handle-si-event ( cpu event -- quit? )
keyboard-event>binding last car ( cpu key )
{
{ [ dup "ESCAPE" = ] [ 2drop t ] }
{ [ dup "BACKSPACE" = ] [ drop [ cpu-port1 255 1 - bitand ] keep set-cpu-port1 f ] }
{ [ dup 1 = ] [ drop [ cpu-port1 255 4 - bitand ] keep set-cpu-port1 f ] }
{ [ dup "LCTRL" = ] [ drop [ cpu-port1 255 HEX: 10 - bitand ] keep set-cpu-port1 f ] }
{ [ dup "LEFT" = ] [ drop [ cpu-port1 255 HEX: 20 - bitand ] keep set-cpu-port1 f ] }
{ [ dup "RIGHT" = ] [ drop [ cpu-port1 255 HEX: 40 - bitand ] keep set-cpu-port1 f ] }
{ [ t ] [ . drop f ] }
} cond ;
: event-loop ( cpu event -- )
dup SDL_PollEvent [
2dup handle-si-event [
2drop
] [
event-loop
] ifte
] [
[ over gui-frame ] with-surface
! [
! over update-display
! ] with-surface
event-loop
] ifte ;
: addr>xy ( addr -- x y )
#! Convert video RAM address to base X Y value
HEX: 2400 - ( n )
dup HEX: 1f bitand 8 * 255 swap - ( n y )
swap -5 shift swap ;
: plot-bits2 ( x y byte bit -- )
dup swapd -1 * shift 1 bitand 0 = [ ( x y bit -- )
- surface get -rot black rgb pixelColor
] [
- surface get -rot white rgb pixelColor
] ifte ;
: do-video-update ( value addr cpu -- )
drop addr>xy rot ( x y value )
[ 0 plot-bits2 ] 3keep
[ 1 plot-bits2 ] 3keep
[ 2 plot-bits2 ] 3keep
[ 3 plot-bits2 ] 3keep
[ 4 plot-bits2 ] 3keep
[ 5 plot-bits2 ] 3keep
[ 6 plot-bits2 ] 3keep
7 plot-bits2 ;
: display ( -- )
224 256 0 SDL_HWSURFACE [
test-cpu [ do-video-update ] over set-cpu-display dup
<event> event-loop
SDL_Quit
] with-screen ;

View File

@ -1,7 +1,11 @@
IN: scratchpad
USE: parser
USING: parser compiler words sequences io ;
"../parser-combinators/lazy.factor" run-file
"../parser-combinators/parser-combinators.factor" run-file
"cpu.factor" run-file
! "tests.factor" run-file
"cpu-8080.factor" run-file
"space-invaders.factor" run-file
"cpu-8080" words [ try-compile ] each
"Use 'run' in the 'space-invaders' vocabulary to start." print

View File

@ -2,27 +2,18 @@ This is a first cut at a simple space invaders emulator. The goal is
to produce an emulator, disassembler and assembler for the 8080
processor.
Running 'load.factor' will load the CPU emulation routines and
supporting code. Run 'gui.factor' to get the SDL based GUI code.
Running 'load.factor' will load all necessary files to run the game.
If you are in the space-invaders directory, and have the ROM as a file
'invaders.rom' in that same directory, the following starts the GUI:
"load.factor" run-file
"gui.factor" run-file
USE: cpu-8080
display
USE: space-invaders
run
This will run the emulator in interpreted mode. To compile the Factor
code do the following:
"cpu-8080" words [ try-compile ] each
display
This will run much faster.
'Backspace' inserts a coin and '1' is the one player button. The left
and right arrow keys move and the left control key fires.
'Backspace' inserts a coin, '1' is the one player button and '2' is
the two play button. The left and right arrow keys move and the left
control key fires.
If the ROM file you have is split into seperate files, you will need
to merge them into one 'invaders.rom' file. From Windows this is done
@ -34,5 +25,12 @@ Or Linux:
cat invaders.h invaders.g invaders.f invaders.e >invaders.rom
The emulator is actually a generic Intel 8080 and the code for this is
in cpu-8080.factor. The space invaders specific code is in
space-invaders.factor. It specializes generic functions defined by the
8080 emulator code to handle the space invaders display and
input/output ports.
For more information, contact the author, Chris Double, at
chris.double@double.co.nz or from my weblog http://radio.weblogs.com/0102385
chris.double@double.co.nz or from my weblog
http://radio.weblogs.com/0102385

View File

@ -0,0 +1,172 @@
IN: space-invaders
USING: cpu-8080 kernel lists sdl sdl-event sdl-gfx sdl-video math styles sequences io namespaces generic kernel-internals threads errors ;
TUPLE: space-invaders port1 port2i port2o port3o port4lo port4hi port5o ;
C: space-invaders ( cpu -- cpu )
[ <cpu> swap set-delegate ] keep
[ reset ] keep ;
M: space-invaders read-port ( port cpu -- byte )
#! Read a byte from the hardware port. 'port' should
#! be an 8-bit value.
{
{ [ over 1 = ] [ nip [ space-invaders-port1 dup HEX: FE bitand ] keep set-space-invaders-port1 ] }
{ [ over 2 = ] [ nip [ space-invaders-port2i HEX: 8F bitand ] keep space-invaders-port1 HEX: 70 bitand bitor ] }
{ [ over 3 = ] [ nip [ space-invaders-port4hi 8 shift ] keep [ space-invaders-port4lo bitor ] keep space-invaders-port2o shift -8 shift HEX: FF bitand ] }
{ [ t ] [ 2drop 0 ] }
} cond ;
M: space-invaders write-port ( value port cpu -- )
#! Write a byte to the hardware port, where 'port' is
#! an 8-bit value.
{
{ [ over 2 = ] [ nip set-space-invaders-port2o ] }
{ [ over 3 = ] [ nip set-space-invaders-port3o ] }
{ [ over 4 = ] [ nip [ space-invaders-port4hi ] keep [ set-space-invaders-port4lo ] keep set-space-invaders-port4hi ] }
{ [ over 5 = ] [ nip set-space-invaders-port5o ] }
{ [ over 6 = ] [ 3drop ] }
{ [ t ] [ 3drop "Invalid port write" throw ] }
} cond ;
M: space-invaders reset ( cpu -- )
[ delegate reset ] keep
[ 0 swap set-space-invaders-port1 ] keep
[ 0 swap set-space-invaders-port2i ] keep
[ 0 swap set-space-invaders-port2o ] keep
[ 0 swap set-space-invaders-port3o ] keep
[ 0 swap set-space-invaders-port4lo ] keep
[ 0 swap set-space-invaders-port4hi ] keep
0 swap set-space-invaders-port5o ;
: gui-step ( cpu -- )
[ read-instruction ] keep ( n cpu )
over get-cycles over inc-cycles
[ swap instructions dispatch ] keep
[ cpu-pc HEX: FFFF bitand ] keep
set-cpu-pc ;
: gui-frame/2 ( cpu -- )
[ gui-step ] keep
[ cpu-cycles ] keep
over 16667 < [ ( cycles cpu )
nip gui-frame/2
] [
[ >r 16667 - r> set-cpu-cycles ] keep
dup cpu-last-interrupt HEX: 10 = [
HEX: 08 over set-cpu-last-interrupt HEX: 08 swap interrupt
] [
HEX: 10 over set-cpu-last-interrupt HEX: 10 swap interrupt
] ifte
] ifte ;
: gui-frame ( cpu -- )
dup gui-frame/2 gui-frame/2 ;
GENERIC: handle-si-event ( cpu event -- quit? )
M: object handle-si-event ( cpu event -- quit? )
2drop f ;
M: quit-event handle-si-event ( cpu event -- quit? )
2drop t ;
USE: prettyprint
M: key-down-event handle-si-event ( cpu event -- quit? )
keyboard-event>binding last car ( cpu key )
{
{ [ dup "ESCAPE" = ] [ 2drop t ] }
{ [ dup "BACKSPACE" = ] [ drop [ space-invaders-port1 1 bitor ] keep set-space-invaders-port1 f ] }
{ [ dup 1 = ] [ drop [ space-invaders-port1 4 bitor ] keep set-space-invaders-port1 f ] }
{ [ dup 2 = ] [ drop [ space-invaders-port1 2 bitor ] keep set-space-invaders-port1 f ] }
{ [ dup "LCTRL" = ] [ drop [ space-invaders-port1 HEX: 10 bitor ] keep set-space-invaders-port1 f ] }
{ [ dup "LEFT" = ] [ drop [ space-invaders-port1 HEX: 20 bitor ] keep set-space-invaders-port1 f ] }
{ [ dup "RIGHT" = ] [ drop [ space-invaders-port1 HEX: 40 bitor ] keep set-space-invaders-port1 f ] }
{ [ t ] [ . drop f ] }
} cond ;
M: key-up-event handle-si-event ( cpu event -- quit? )
keyboard-event>binding last car ( cpu key )
{
{ [ dup "ESCAPE" = ] [ 2drop t ] }
{ [ dup "BACKSPACE" = ] [ drop [ space-invaders-port1 255 1 - bitand ] keep set-space-invaders-port1 f ] }
{ [ dup 1 = ] [ drop [ space-invaders-port1 255 4 - bitand ] keep set-space-invaders-port1 f ] }
{ [ dup 2 = ] [ drop [ space-invaders-port1 255 2 - bitand ] keep set-space-invaders-port1 f ] }
{ [ dup "LCTRL" = ] [ drop [ space-invaders-port1 255 HEX: 10 - bitand ] keep set-space-invaders-port1 f ] }
{ [ dup "LEFT" = ] [ drop [ space-invaders-port1 255 HEX: 20 - bitand ] keep set-space-invaders-port1 f ] }
{ [ dup "RIGHT" = ] [ drop [ space-invaders-port1 255 HEX: 40 - bitand ] keep set-space-invaders-port1 f ] }
{ [ t ] [ . drop f ] }
} cond ;
: sync-frame ( millis -- millis )
#! Sleep until the time for the next frame arrives.
1000 60 / >fixnum + millis - dup 0 > [ sleep ] [ drop ] ifte millis ;
: (event-loop) ( millis cpu event -- )
dup SDL_PollEvent [
2dup handle-si-event [
3drop
] [
(event-loop)
] ifte
] [
>r >r sync-frame r> r>
[ over gui-frame ] with-surface
(event-loop)
] ifte ;
: event-loop ( cpu event -- )
millis -rot (event-loop) ;
: addr>xy ( addr -- x y )
#! Convert video RAM address to base X Y value
HEX: 2400 - ( n )
dup HEX: 1f bitand 8 * 255 swap - ( n y )
swap -5 shift swap ;
: within ( n a b - bool )
#! n >= a and n <= b
rot tuck swap <= >r swap >= r> and ;
: color ( x y -- color )
#! Return the color to use for the given x/y position.
{
{ [ dup 184 238 within pick 0 223 within and ] [ 2drop green ] }
{ [ dup 240 247 within pick 16 133 within and ] [ 2drop green ] }
{ [ dup 247 215 - 247 184 - within pick 0 223 within and ] [ 2drop red ] }
{ [ t ] [ 2drop white ] }
} cond ;
: plot-bits ( x y byte bit -- )
dup swapd -1 * shift 1 bitand 0 = [ ( x y bit -- )
- surface get -rot black rgb pixelColor
] [
- surface get -rot 2dup color rgb pixelColor
] ifte ;
: do-video-update ( value addr cpu -- )
drop addr>xy rot ( x y value )
[ 0 plot-bits ] 3keep
[ 1 plot-bits ] 3keep
[ 2 plot-bits ] 3keep
[ 3 plot-bits ] 3keep
[ 4 plot-bits ] 3keep
[ 5 plot-bits ] 3keep
[ 6 plot-bits ] 3keep
7 plot-bits ;
M: space-invaders update-video ( value addr cpu -- )
over HEX: 2400 >= [
do-video-update
] [
3drop
] ifte ;
: run ( -- )
224 256 0 SDL_HWSURFACE [
<space-invaders> "invaders.rom" over load-rom
<event> event-loop
SDL_Quit
] with-screen ;