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 ; words parser hashtables lazy parser-combinators kernel-internals strings ;
IN: cpu-8080 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 -- ) GENERIC: reset ( cpu -- )
dup 0 >= swap HEX: FF <= and not [ "Invalid byte" throw ] when ; GENERIC: update-video ( value addr cpu -- )
GENERIC: read-port ( port cpu -- byte )
GENERIC: write-port ( value port cpu -- )
: valid-word? ( w -- ) M: cpu update-video ( value addr cpu -- )
dup 0 >= swap HEX: FFFF <= and not [ "Invalid word" throw ] when ; 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 : carry-flag HEX: 01 ; inline
: add-sub-flag HEX: 02 ; inline
: subtraction-flag HEX: 02 ; inline
: parity-flag HEX: 04 ; inline : parity-flag HEX: 04 ; inline
: overflow-flag HEX: 04 ; inline
: flag3-flag HEX: 08 ; inline
: half-carry-flag HEX: 10 ; inline : half-carry-flag HEX: 10 ; inline
: aux-carry-flag HEX: 10 ; inline
: interrupt-flag HEX: 20 ; inline : interrupt-flag HEX: 20 ; inline
: flag5-flag HEX: 20 ; inline
: zero-flag HEX: 40 ; inline : zero-flag HEX: 40 ; inline
: sign-flag HEX: 80 ; 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 ) : >word< ( word -- byte byte )
#! Explode a word into its two 8 bit values. #! Explode a word into its two 8 bit values.
dup HEX: FF bitand swap -8 shift HEX: FF bitand swap ; 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 cpu-ram nth
] [ ] [
2drop HEX: FF 2drop HEX: FF
] ifte dup valid-byte? ; ] ifte ;
: read-word ( addr cpu -- word ) : read-word ( addr cpu -- word )
#! Read a 16-bit word from memory at the specified address. #! Read a 16-bit word from memory at the specified address.
#! The address is 16-bit, but if a value greater than #! The address is 16-bit, but if a value greater than
#! 0xFFFF is provided then return a default value. #! 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 ) : next-byte ( cpu -- byte )
#! Return the value of the byte at PC, and increment PC. #! 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 [ cpu-pc 2 + ] keep
set-cpu-pc ; 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-byte ( value addr cpu -- )
#! Write a byte to the specified memory address. #! Write a byte to the specified memory address.
pick valid-byte?
over valid-word?
over dup HEX: 2000 < swap HEX: FFFF > or [ over dup HEX: 2000 < swap HEX: FFFF > or [
3drop 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-word ( value addr cpu -- )
#! Write a 16-bit word to the specified memory address. #! 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 ; >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 -- ) : cpu-a-bitand ( quot cpu -- )
#! A &= quot call #! A &= quot call
[ cpu-a swap call bitand ] keep set-cpu-a ; inline [ 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 0, (ie. if the result has even parity) this flag
#! is set, otherwise it is reset. #! is set, otherwise it is reset.
swap HEX: FF bitand 2 mod 0 = [ parity-flag set-flag ] [ parity-flag clear-flag ] ifte ; swap HEX: FF bitand 2 mod 0 = [ parity-flag set-flag ] [ parity-flag clear-flag ] ifte ;
: update-carry-flag ( result cpu -- ) : update-carry-flag ( result cpu -- )
#! If the instruction resulted in a carry (from addition) #! If the instruction resulted in a carry (from addition)
#! or a borrow (from subtraction or a comparison) out of the #! 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 2dup update-sign-flag
update-zero-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-byte ( lhs rhs cpu -- result )
#! Add rhs to lhs #! Add rhs to lhs
>r + r> [ update-flags ] 2keep drop HEX: FF bitand ; >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 ) : flags ( seq -- seq )
[ 0 [ execute bitor ] reduce ] map ; [ 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-sp ( n cpu -- )
#! Decrement the stackpointer by n. #! Decrement the stackpointer by n.
[ cpu-sp ] keep [ cpu-sp ] keep
@ -678,56 +346,12 @@ SYMBOL: psz-vector
: call-sub ( addr cpu -- ) : call-sub ( addr cpu -- )
#! Call the address as a subroutine. #! Call the address as a subroutine.
over valid-word?
dup push-pc dup push-pc
>r HEX: FFFF bitand r> set-cpu-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 -- ) : ret-from-sub ( cpu -- )
[ pop-pc ] keep set-cpu-pc ; [ 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 -- ) : interrupt ( number cpu -- )
#! Perform a hardware interrupt #! Perform a hardware interrupt
! "***Interrupt: " write over 16 >base print ! "***Interrupt: " write over 16 >base print
@ -742,7 +366,7 @@ SYMBOL: cf
#! Increment the number of cpu cycles #! Increment the number of cpu cycles
[ cpu-cycles + ] keep set-cpu-cycles ; [ cpu-cycles + ] keep set-cpu-cycles ;
: instruction-cycles ( -- ) : instruction-cycles ( -- vector )
#! Return a 256 element vector containing the cycles for #! Return a 256 element vector containing the cycles for
#! each opcode in the 8080 instruction set. #! 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
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 #! Return a 256 element vector containing the emulation words for
#! each opcode in the 8080 instruction set. #! 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 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 #! Reset the CPU to its poweron state
[ 0 swap set-cpu-b ] keep [ 0 swap set-cpu-b ] keep
[ 0 swap set-cpu-c ] keep [ 0 swap set-cpu-c ] keep
@ -783,16 +407,9 @@ SYMBOL: cf
[ HEX: FFFF 0 <repeated> >vector swap set-cpu-ram ] keep [ HEX: FFFF 0 <repeated> >vector swap set-cpu-ram ] keep
[ f swap set-cpu-halted? ] keep [ f swap set-cpu-halted? ] keep
[ HEX: 10 swap set-cpu-last-interrupt ] 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 ; 0 swap set-cpu-cycles ;
C: cpu ( -- cpu ) C: cpu ( cpu -- cpu )
[ reset ] keep ; [ reset ] keep ;
: (load-rom) ( n ram -- ) : (load-rom) ( n ram -- )
@ -964,40 +581,53 @@ SYMBOL: $4
set-cpu-pc ; set-cpu-pc ;
: (emulate-RLCA) ( cpu -- ) : (emulate-RLCA) ( cpu -- )
dup cpu-a dup ( cpu a a ) #! The content of the accumulator is rotated left
1 shift HEX: FF bitand swap -7 shift HEX: FF bitand bitor ( cpu a ) #! one position. The low order bit and the carry flag
HEX: FF bitand dup pick set-cpu-a #! are both set to the value shifted out of the high
add-sub-flag half-carry-flag carry-flag bitor bitor HEX: FF swap - ( cpu a newf ) #! order bit position. Only the carry flag is affected.
pick cpu-f bitand pick set-cpu-f [ cpu-a -7 shift ] keep
HEX: 01 bitand 0 = not [ dup cpu-f carry-flag bitor swap set-cpu-f ] [ drop ] ifte ; 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 -- ) : (emulate-RRCA) ( cpu -- )
dup cpu-a dup ( cpu a a ) #! The content of the accumulator is rotated right
-1 shift HEX: FF bitand swap 7 shift HEX: FF bitand bitor ( cpu a ) #! one position. The high order bit and the carry flag
HEX: FF bitand dup pick set-cpu-a #! are both set to the value shifted out of the low
add-sub-flag half-carry-flag carry-flag bitor bitor HEX: FF swap - ( cpu a newf ) #! order bit position. Only the carry flag is affected.
pick cpu-f bitand pick set-cpu-f [ cpu-a 1 bitand 7 shift ] keep
HEX: 80 bitand 0 = not [ dup cpu-f carry-flag bitor swap set-cpu-f ] [ drop ] ifte ; 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 -- ) : (emulate-RLA) ( cpu -- )
dup cpu-a dup ( cpu old-a new-a ) #! The content of the accumulator is rotated left
1 shift HEX: FF bitand pick set-cpu-a ( cpu old-a ) #! one position through the carry flag. The low
over flag-c? [ [ 1 ] pick cpu-a-bitor ] when #! order bit is set equal to the carry flag and
[ add-sub-flag half-carry-flag carry-flag bitor bitor 255 swap - ] pick cpu-f-bitand #! the carry flag is set to the value shifted out
HEX: 80 bitand 0 = not [ [ carry-flag ] over cpu-f-bitor ] when #! of the high order bit. Only the carry flag is
drop ; #! 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 -- ) : (emulate-RRA) ( cpu -- )
dup cpu-a dup ( cpu old-a new-a ) #! The content of the accumulator is rotated right
-1 shift HEX: FF bitand pick set-cpu-a ( cpu old-a ) #! one position through the carry flag. The high order
over flag-c? [ [ HEX: 80 ] pick cpu-a-bitor ] when #! bit is set to the carry flag and the carry flag is
[ add-sub-flag half-carry-flag carry-flag bitor bitor 255 swap - ] pick cpu-f-bitand #! set to the value shifted out of the low order bit.
HEX: 01 bitand 0 = not [ [ carry-flag ] over cpu-f-bitor ] when #! Only the carry flag is affected.
drop ; [ 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 -- ) : (emulate-CPL) ( cpu -- )
[ HEX: FF ] over cpu-a-bitxor #! The contents of the accumulator are complemented
[ add-sub-flag half-carry-flag bitor ] swap cpu-f-bitor ; #! (zero bits become one, one bits becomes zero).
#! No flags are affected.
HEX: FF swap cpu-a-bitxor= ;
: (emulate-DAA) ( cpu -- ) : (emulate-DAA) ( cpu -- )
#! The eight bit number in the accumulator is #! The eight bit number in the accumulator is
@ -1032,9 +662,9 @@ SYMBOL: $4
[[ "RST-30H" [ drop "RST 30H Not Implemented" throw ] ]] [[ "RST-30H" [ drop "RST 30H Not Implemented" throw ] ]]
[[ "RST-38H" [ drop "RST 38H 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 ] ]] [[ "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-N" [ [ cpu-a ] keep [ next-byte ] keep sub-byte drop ] ]]
[[ "CP-R" [ [ $1 ] keep 0 -rot sub-byte-old drop ] ]] [[ "CP-R" [ [ cpu-a ] keep [ $1 ] keep sub-byte drop ] ]]
[[ "CP-(RR)" [ [ $1 ] keep [ read-byte ] keep 0 -rot sub-byte-old 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-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-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 ] ]] [[ "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 IN: scratchpad
USE: parser USING: parser compiler words sequences io ;
"../parser-combinators/lazy.factor" run-file "../parser-combinators/lazy.factor" run-file
"../parser-combinators/parser-combinators.factor" run-file "../parser-combinators/parser-combinators.factor" run-file
"cpu.factor" run-file "cpu-8080.factor" run-file
! "tests.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 to produce an emulator, disassembler and assembler for the 8080
processor. processor.
Running 'load.factor' will load the CPU emulation routines and Running 'load.factor' will load all necessary files to run the game.
supporting code. Run 'gui.factor' to get the SDL based GUI code.
If you are in the space-invaders directory, and have the ROM as a file 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: 'invaders.rom' in that same directory, the following starts the GUI:
"load.factor" run-file "load.factor" run-file
"gui.factor" run-file USE: space-invaders
USE: cpu-8080 run
display
This will run the emulator in interpreted mode. To compile the Factor 'Backspace' inserts a coin, '1' is the one player button and '2' is
code do the following: the two play button. The left and right arrow keys move and the left
control key fires.
"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.
If the ROM file you have is split into seperate files, you will need 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 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 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 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 ;