view release on metacpan or search on metacpan
0.72 2008-09-24
- Added a test suite pulled from the monkeynes project
* patched script_7C.txt to work properly
* patched script_94.txt to test proper mem location
* patched script_95.txt to test proper mem location
* patched script_96.txt to test proper mem location
* patched all branching tests to do proper negative branches
* patched script_40.txt and script_00.txt with proper diag info and proper
PC storage on BRK
- Fix PLP to clear B flag instead of setting it
- Fix TSX to set N and Z flag based on the value of X
- Emulate a page boundary bug in JMP instructions
- Fix BRK to set B flag
0.71 2007-11-08
- A new dawn in the struggle to free ourselves from the shackles of version
number oppression.
0.70 2007-11-07
- An end to version number madness. I hope.
0.0.6 2007-02-23
- Added machine readable license.
lib/Acme/6502.pm view on Meta::CPAN
ESCAPE_SIG => 0xAD
};
BEGIN {
for my $reg ( qw(a x y s p pc) ) {
no strict 'refs';
*{ __PACKAGE__ . "\::get_${reg}" } = sub {
my $self = shift;
return $self->{ reg }->{ $reg };
};
*{ __PACKAGE__ . "\::set_${reg}" } = sub {
my ( $self, $v ) = @_;
$self->{ reg }->{ $reg } = $v;
};
}
}
sub new {
my $class = shift;
my $self = bless { }, $class;
lib/Acme/6502.pm view on Meta::CPAN
_inst( _bfnz( _rel(), C ) ), # B0 BCS rel
_inst( _lod( _zpiy(), '$a' ) ), # B1 LDA (zp), y
_inst( _lod( _zpi(), '$a' ) ), # B2 LDA (zp)
$bad_inst, # B3
_inst( _lod( _zpx(), '$y' ) ), # B4 LDY zp, x
_inst( _lod( _zpx(), '$a' ) ), # B5 LDA zp, x
_inst( _lod( _zpy(), '$x' ) ), # B6 LDX zp, y
$bad_inst, # B7
_inst( '$p &= ~V;' ), # B8 CLV
_inst( _lod( _absy(), '$a' ) ), # B9 LDA abs, y
_inst( '$x = $s;', _set_nz( '$x' ) ), # BA TSX
$bad_inst, # BB
_inst( _lod( _absx(), '$y' ) ), # BC LDY abs, x
_inst( _lod( _absx(), '$a' ) ), # BD LDA abs, x
_inst( _lod( _absy(), '$x' ) ), # BE LDX abs, y
$bad_inst, # BF BBS3 rel
_inst( _cmp( _imm(), '$y' ) ), # C0 CPY #imm
_inst( _cmp( _zpix(), '$a' ) ), # C1 CMP (zp, x)
$bad_inst, # C2
$bad_inst, # C3
_inst( _cmp( _zp(), '$y' ) ), # C4 CPY zp
lib/Acme/6502.pm view on Meta::CPAN
if ( $self->{ mem }->[ $self->{ reg }->{ pc } ] != ESCAPE_SIG ) {
$bad_inst->( $self );
}
else {
$self->{ reg }->{ pc } += 2;
$self->call_os( $self->{ mem }->[ $self->{ reg }->{ pc } - 1 ] );
}
};
}
sub set_jumptab {
my $self = shift;
$self->{ jumptab } = shift;
}
sub get_state {
my $self = shift;
return @{ $self->{ reg } }{ qw( a x y s p pc ) };
}
sub get_xy {
my $self = shift;
return $self->get_x || ( $self->get_y << 8 );
}
sub set_xy {
my $self = shift;
my $v = shift;
$self->set_x( $v & 0xFF );
$self->set_y( ( $v >> 8 ) & 0xFF );
}
sub read_str {
my $self = shift;
my $addr = shift;
my $str = '';
while ( $self->{ mem }->[ $addr ] != 0x0D ) {
$str .= chr( $self->{ mem }->[ $addr++ ] );
}
lib/Acme/6502.pm view on Meta::CPAN
}
sub run {
my $self = shift;
my $ic = shift;
my $cb = shift;
while ( $ic-- > 0 ) {
my( $a, $x, $y, $s, $p, $pc ) = $self->get_state;
$cb->( $pc, $self->{ mem }->[ $pc ], $a, $x, $y, $s, $p ) if defined $cb;
$self->set_pc( $pc + 1 );
$self->{ ops }->[ $self->{ mem }->[ $pc ] ]->( $self );
}
}
sub make_vector {
my $self = shift;
my ( $call, $vec, $func ) = @_;
$self->{ mem }->[ $call ] = 0x6C; # JMP (indirect)
$self->{ mem }->[ $call + 1 ] = $vec & 0xFF;
$self->{ mem }->[ $call + 2 ] = ( $vec >> 8 ) & 0xFF;
my $jumptab = $self->{ jumptab };
my $addr = $jumptab;
$self->{ mem }->[ $jumptab++ ] = ESCAPE_OP;
$self->{ mem }->[ $jumptab++ ] = ESCAPE_SIG;
$self->{ mem }->[ $jumptab++ ] = $func;
$self->{ mem }->[ $jumptab++ ] = 0x60;
$self->set_jumptab( $jumptab );
$self->{ mem }->[ $vec ] = $addr & 0xFF;
$self->{ mem }->[ $vec + 1 ] = ( $addr >> 8 ) & 0xFF;
}
sub _inst {
my $src = join( "\n", @_ );
# registers
$src =~ s{\$(a|x|y|s|p|pc)\b}{\$self->{reg}->{$1}}g;
lib/Acme/6502.pm view on Meta::CPAN
sub _bad_inst {
my $self = shift;
my $pc = $self->get_pc;
croak sprintf( "Bad instruction at &%04x (&%02x)\n",
$pc - 1, $self->{ mem }->[ $pc - 1 ] );
}
# Functions that generate code fragments
sub _set_nz {
return
'$p &= ~(N|Z);' . 'if( '
. $_[0]
. ' & 0x80){ $p |= N }'
. 'elsif( '
. $_[0]
. ' == 0 ){ $p |= Z }';
}
sub _push {
lib/Acme/6502.pm view on Meta::CPAN
$r .= '$s = ($s + 1) & 0xFF; ' . $_ . ' = $mem[STACK + $s];' . "\n";
}
return $r;
}
sub _pop_p {
return '$s = ($s + 1) & 0xFF; $p = $mem[STACK + $s] | R; $p &= ~B;'
. "\n";
}
# Addressing modes return a list containing setup code, lvalue
sub _zpix {
return (
'my $ea = $mem[$pc++] + $x; '
. '$ea = $mem[$ea & 0xFF] | ($mem[($ea + 1) & 0xFF] << 8)' . ";\n",
'$mem[$ea]'
);
}
sub _zpi {
return (
lib/Acme/6502.pm view on Meta::CPAN
This document describes Acme::6502 version 0.76
=head1 SYNOPSIS
use Acme::6502;
my $cpu = Acme::6502->new();
# Set start address
$cpu->set_pc(0x8000);
# Load ROM image
$cpu->load_rom('myrom.rom', 0x8000);
# Run for 1,000,000 instructions then return
$cpu->run(1_000_000);
=head1 DESCRIPTION
Imagine the nightmare scenario: your boss tells you about a legacy
lib/Acme/6502.pm view on Meta::CPAN
=item C<get_xy()>
Read the value of X and Y as a sixteen bit number. X forms the lower 8
bits of the value and Y forms the upper 8 bits.
=item C<get_state()>
Returns an array containing the values of the A, X, Y, S, P and SP.
=item C<set_a( $value )>
Set the value of the processor A register (accumulator).
=item C<set_p( $value )>
Set the value of the processor status register.
=item C<set_pc( $value )>
Set the value of the program counter.
=item C<set_s( $value )>
Set the value of the stack pointer.
=item C<set_x( $value )>
Set the value of the X index register.
=item C<set_y( $value )>
Set the value of the Y index register.
=item C<set_xy( $value )>
Set the value of the X and Y registers to the specified sixteen bit
number. X gets the lower 8 bits, Y gets the upper 8 bits.
=item C<set_jumptab( $addr )>
Set the address of the block of memory that will be used to hold the
thunk blocks that correspond with vectored OS entry points. Each thunk
takes four bytes.
=item C<load_rom( $filename, $addr )>
Load a ROM image at the specified address.
=item C<make_vector( $jmp_addr, $vec_addr, $vec_number )>
lib/Acme/6502/Tube.pm view on Meta::CPAN
$self->make_vector( 'OSWORD', 0x20C, \&_osword );
$self->make_vector( 'OSWRCH', 0x20E, \&_oswrch );
$self->make_vector( 'OSRDCH', 0x210, \&_osrdch );
$self->make_vector( 'OSFILE', 0x212, \&_osfile );
$self->make_vector( 'OSARGS', 0x214, \&_osargs );
$self->make_vector( 'OSBGET', 0x216, \&_osbget );
$self->make_vector( 'OSBPUT', 0x218, \&_osbput );
$self->make_vector( 'OSGBPB', 0x21A, \&_osgbpb );
$self->make_vector( 'OSFIND', 0x21C, \&_osfind );
$self->set_jumptab( 0xFA00 );
}
sub _oscli {
my $self = shift;
my $blk = $self->get_xy();
my $cmd = '';
CH: for ( ;; ) {
my $ch = $self->read_8( $blk++ );
last CH if $ch < 0x20;
$cmd .= chr( $ch );
lib/Acme/6502/Tube.pm view on Meta::CPAN
system( $cmd );
}
}
sub _osbyte {
my $self = shift;
my $a = $self->get_a();
if ( $a == 0x7E ) {
# Ack escape
$self->write_8( 0xFF, 0 );
$self->set_x( 0xFF );
}
elsif ( $a == 0x82 ) {
# Read m/c high order address
$self->set_xy( 0 );
}
elsif ( $a == 0x83 ) {
# Read OSHWM (PAGE)
$self->set_xy( PAGE );
}
elsif ( $a == 0x84 ) {
# Read HIMEM
$self->set_xy( HIMEM );
}
elsif ( $a == 0xDA ) {
$self->set_xy( 0x0900 );
}
else {
die sprintf( "OSBYTE %02x not handled\n", $a );
}
}
sub _set_escape {
my $self = shift;
$self->write_8( 0xFF, 0xFF );
}
sub _osword {
my $self = shift;
my $a = $self->get_a();
my $blk = $self->get_xy();
if ( $a == 0x00 ) {
lib/Acme/6502/Tube.pm view on Meta::CPAN
my $y = 0;
if ( defined( my $in = <> ) ) {
my @c = map ord, split //, $in;
while ( @c && $len-- > 1 ) {
my $c = shift @c;
if ( $c >= $min && $c <= $max ) {
$self->write_8( $buf + $y++, $c );
}
}
$self->write_8( $buf + $y++, 0x0D );
$self->set_y( $y );
$self->set_p( $self->get_p() & ~$self->C );
}
else {
# Escape I suppose...
$self->set_p( $self->get_p() | $self->C );
}
}
elsif ( $a == 0x01 ) {
# Read clock
my $now = int( ( time() - $self->{ time_base } ) * 100 );
$self->write_32( $blk, $now );
$self->write_8( $blk + 4, 0 );
}
elsif ( $a == 0x02 ) {
# Set clock
lib/Acme/6502/Tube.pm view on Meta::CPAN
my $self = shift;
printf( "%c", $self->get_a() );
}
sub _osrdch {
my $self = shift;
Term::ReadKey::ReadMode( 4 );
eval {
my $k = ord( Term::ReadKey::ReadKey( 0 ) );
$k = 0x0D if $k == 0x0A;
$self->set_a( $k );
if ( $k == 27 ) {
$self->set_escape;
$self->set_p( $self->get_p() | $self->C );
}
else {
$self->set_p( $self->get_p() & ~$self->C );
}
};
Term::ReadKey::ReadMode( 0 );
die $@ if $@;
}
sub _osfile {
my $self = shift;
my $a = $self->get_a();
my $blk = $self->get_xy();
lib/Acme/6502/Tube.pm view on Meta::CPAN
my $start = $self->read_32( $blk + 10 );
my $end = $self->read_32( $blk + 14 );
# printf("%-20s %08x %08x %08x %08x\n", $name, $load, $exec, $start, $end);
if ( $a == 0x00 ) {
# Save
open my $fh, '>', $name or die "Can't write $name\n";
binmode $fh;
my $buf = $self->read_chunk( $start, $end );
syswrite $fh, $buf or die "Error writing $name\n";
$self->set_a( 1 );
}
elsif ( $a == 0xFF ) {
# Load
if ( -f $name ) {
open my $fh, '<', $name or die "Can't read $name\n";
binmode $fh;
my $len = -s $fh;
sysread $fh, my $buf, $len or die "Error reading $name\n";
$load = PAGE if $exec & 0xFF;
$self->write_chunk( $load, $buf );
$self->write_32( $blk + 2, $load );
$self->write_32( $blk + 6, 0x00008023 );
$self->write_32( $blk + 10, $len );
$self->write_32( $blk + 14, 0x00000000 );
$self->set_a( 1 );
}
elsif ( -d $name ) {
$self->set_a( 2 );
}
else {
$self->set_a( 0 );
}
}
else {
die sprintf( "OSFILE %02x not handled\n", $a );
}
}
sub _osargs {
die "OSARGS not handled\n";
}
lib/Acme/6502/Tube.pm view on Meta::CPAN
$self->write_16( ERROR, 0x7F00 );
$err =~ s/\s+/ /;
$err =~ s/^\s+//;
$err =~ s/\s+$//;
warn $err;
my $ep = ERROR + 2;
for ( map ord, split //, $err ) {
$self->write_8( $ep++, $_ );
}
$self->write_8( $ep++, 0x00 );
$self->set_pc( ERROR );
}
}
1;
__END__
=head1 NAME
Acme::6502::Tube - Acorn 65C02 Second Processor Simulator
lib/Acme/6502/Tube.pm view on Meta::CPAN
=head1 SYNOPSIS
use Acme::6502::Tube;
my $cpu = Acme::6502::Tube->new();
# Load BBC Basic
$cpu->load_rom('BASIC2.rom', 0x8000);
# Init registers
$cpu->set_pc(0x8000);
$cpu->set_a(0x01);
$cpu->set_s(0xFF);
$cpu->set_p(0x22);
# Run
$cpu->run(2000_000) while 1;
=head1 DESCRIPTION
Emulates an Acorn BBC Micro 6502 Tube second processor. You'll need
to find your own language ROM to load and it's only been tested with
BBC Basic II.
t/monkeynes.t view on Meta::CPAN
return $_[0]->get_p & $_[0]->I ? 1 : 0;
},
z => sub {
return $_[0]->get_p & $_[0]->Z ? 1 : 0;
},
c => sub {
return $_[0]->get_p & $_[0]->C ? 1 : 0;
},
);
my %regset_lut = (
ps => sub {
shift->set_p( shift );
},
pc => sub {
shift->set_pc( shift );
},
sp => sub {
shift->set_s( shift );
},
acc => sub {
shift->set_a( shift );
},
ix => sub {
shift->set_x( shift );
},
iy => sub {
shift->set_y( shift );
},
s => sub {
$_[0]->set_p( $_[0]->get_p & ~$_[0]->N );
$_[0]->set_p( $_[0]->get_p | $_[0]->N ) if $_[1];
},
v => sub {
$_[0]->set_p( $_[0]->get_p & ~$_[0]->V );
$_[0]->set_p( $_[0]->get_p | $_[0]->V ) if $_[1];
},
b => sub {
$_[0]->set_p( $_[0]->get_p & ~$_[0]->B );
$_[0]->set_p( $_[0]->get_p | $_[0]->B ) if $_[1];
},
d => sub {
$_[0]->set_p( $_[0]->get_p & ~$_[0]->D );
$_[0]->set_p( $_[0]->get_p | $_[0]->D ) if $_[1];
},
i => sub {
$_[0]->set_p( $_[0]->get_p & ~$_[0]->I );
$_[0]->set_p( $_[0]->get_p | $_[0]->I ) if $_[1];
},
z => sub {
$_[0]->set_p( $_[0]->get_p & ~$_[0]->Z );
$_[0]->set_p( $_[0]->get_p | $_[0]->Z ) if $_[1];
},
c => sub {
$_[0]->set_p( $_[0]->get_p & ~$_[0]->C );
$_[0]->set_p( $_[0]->get_p | $_[0]->C ) if $_[1];
},
);
my $glob = $ENV{TEST_OP} || '*';
my @files = glob( "t/monkeynes/script_${glob}.txt" );
for my $file ( @files ) {
open( my $script, $file ) || die qq(cannot load test script "$file");
_diag( qq(Running script "$file") );
my @lines = <$script>;
t/monkeynes.t view on Meta::CPAN
next if m{^\s*$};
next if m{^save};
if ( m{^# (.+)} ) {
_diag( $1 );
}
elsif ( $_ eq 'clear' ) {
next;
}
elsif ( $_ eq 'power on' ) {
$cpu = Acme::6502->new();
$cpu->set_s( 255 );
$cpu->set_p( $cpu->get_p | $cpu->R );
isa_ok( $cpu, 'Acme::6502' );
}
elsif ( $_ eq 'memclear' ) {
$cpu->poke_code( 0, ( 0 ) x 65536 );
_diag( 'Mem cleared' );
}
elsif ( $_ eq 'step' ) {
_diag( 'Running next instruction...' );
$cpu->run( 1 );
}
elsif ( m{^regset (.+) (.+)} ) {
$regset_lut{ lc $1 }->( $cpu, hex $2 );
_diag( "$1 set to $2" );
}
elsif ( m{^regs(?: (.+))?} ) {
diag_regs( $cpu, $1 );
}
elsif ( m{^memset (.+) (.+)} ) {
$cpu->write_8( hex $1, hex $2 );
is( $cpu->read_8( hex $1 ), hex $2, "Mem[$1] set to $2" );
}
elsif ( m{^test (.+) (.+) (.+)} ) {
my ( $op, @args ) = split( /:/, $1 );
my $cmp = $2;
$cmp = '==' if $cmp eq '=';
cmp_ok( $test_lut{ lc $op }->( $cpu, @args ),
$cmp, hex $3, "$1 $2 $3" );
}
elsif ( m{^op (.+)} ) {
my ( $op, $args_hex ) = split( ' ', $1 );
_diag( "OP: $1" );
$args_hex = '' unless defined $args_hex;
my @args = ( $args_hex =~ m{(..)}g );
my $pc = hex( 8000 );
$cpu->poke_code(
$pc,
map { hex( $_ || 0 ) } $op,
@args[ 0 .. 1 ]
);
$cpu->set_pc( $pc );
$cpu->run( 1 );
}
else {
use Data::Dumper;
warn Dumper $_;
}
}
}
sub diag_regs {
t/monkeynes/script_00.txt view on Meta::CPAN
# *** MODIFIED TEST FROM ORIGINAL MONKEYNES
# *** Proper diag info, "IRQ" not "NMI"
# *** BRK stores PC + 2
clear
power on
regs
# Load the IRQ Vector
memset fffe ef
memset ffff be
# Set some bits into the PS
memset dead ff
op 2c adde
# Should be: PS=E2
test ps = e2
op 00
# Should be: PC=BEEF, I=1, B=1
# SP=FC, Mem[$01FF]=80, Mem[$01FE]=02
# Mem[$01FD]=F2
t/monkeynes/script_05.txt view on Meta::CPAN
clear
power on
regs
# Base test --------------------
memset 00be 72
op a9 55
op 05 be
# Should be: ACC=77
test acc = 77
# Negative test --------------------
power on
memset 00be aa
op a9 55
op 05 be
# Should be: ACC=FF, S=1
test acc = ff
test s = 1
# Zero test ----------------
power on
memset 00be 00
op a9 00
op 05 be
# Should be: ACC=0, Z=1
test acc = 0
test z = 1
save verify_05.txt
t/monkeynes/script_0A.txt view on Meta::CPAN
clear
power on
regs
# No Flags Case -------------------------
regset acc 35
op 0a
# Should be: ACC=6A, C=0, Z=0, S=0
test acc = 6a
test c = 0
test z = 0
test s = 0
# Carry Case ----------------------------
regset acc ba
op 0a
# Should be: ACC=74, C=1, Z=0, S=0
test acc = 74
test c = 1
test z = 0
test s = 0
# Zero Case -----------------------------
regset acc 80
op 0a
# Should be: ACC=0, C=1, Z=1, S=0
test acc = 0
test c = 1
test z = 1
test s = 0
# Negative Case -------------------------
regset acc 4c
op 0a
# Should be: ACC=6A, C=0, Z=0, S=1
test acc = 98
test c = 0
test z = 0
test s = 1
save verify_0A.txt
t/monkeynes/script_0D.txt view on Meta::CPAN
clear
power on
regs
# Base test --------------------
memset beef 72
op a9 55
op 0d efbe
# Should be: ACC=77
test acc = 77
# Negative test --------------------
power on
memset beef aa
op a9 55
op 0d efbe
# Should be: ACC=FF, S=1
test acc = ff
test s = 1
# Zero test ----------------
power on
memset beef 00
op a9 00
op 0d efbe
# Should be: ACC=0, Z=1
test acc = 0
test z = 1
save verify_0D.txt
t/monkeynes/script_10.txt view on Meta::CPAN
# *** MODIFIED TEST FROM ORIGINAL MONKEYNES
# *** Now properly checks negative branching
clear
power on
regs
# Branch instructions cannot be tested using the op
# command, and are loaded into memory directly and
# setup to execute with the step command.
# Branch not taken --------------------------------
regset s 1
regset pc 9040
# Load op: BPL $40
memset 9040 10
memset 9041 40
step
# Should be: PC=9042, cycles=2
test pc = 9042
# Positive Branch taken to same page --------------
regset s 0
regset pc 9040
# Load op: BPL $40
memset 9040 10
memset 9041 40
step
# Should be: PC=9082, cycles=3
test pc = 9082
# Negative Branch taken to same page --------------
regset s 0
regset pc 9040
# Load op: BPL $A0
memset 9040 10
memset 9041 A0
step
# Should be: PC=8FE2, cycles=3
test pc = 8FE2
# Positive Branch taken to different page ---------
regset s 0
regset pc 90b0
# Load op: BPL $7F
memset 90b0 10
memset 90b1 7f
step
# Should be: PC=9131, cycles=4
test pc = 9131
# Negative Branch taken to different page ---------
regset s 0
regset pc 9040
# Load op: BPL $F7
memset 9040 10
memset 9041 F7
step
# Should be: PC=9039, cycles=4
test pc = 9039
save verify_10.txt
t/monkeynes/script_15.txt view on Meta::CPAN
clear
power on
regs
# Base test --------------------
memset 00c9 72
op a9 55
op a2 0b
op 15 be
# Should be: ACC=77, IX=0B
test acc = 77
test ix = 0b
# Negative test --------------------
power on
memset 00c9 aa
op a9 55
op a2 0b
op 15 be
# Should be: ACC=FF, IX=0B, S=1
test acc = ff
test ix = 0b
test s = 1
# Zero test ----------------
power on
memset 00c9 00
op a9 00
op a2 0b
op 15 be
# Should be: ACC=0, IX=0B, Z=1
test acc = 0
test ix = 0b
test z = 1
t/monkeynes/script_24.txt view on Meta::CPAN
clear
power on
regs
# use bit to turn on V
memset 00ab 40
op 24 ab
# V should be 1
test v = 1
# use bit to turn on S
memset 00ab 80
op 24 ab
# S should be 1
test s = 1
# this should turn off Z
memset 00ab 01
op a9 ff
op 24 ab
# Z should be 0
test z = 0
# this should turn on Z
memset 00ab 00
op 24 ab
# Z should be 1
test z = 1
save verify_24.txt
t/monkeynes/script_25.txt view on Meta::CPAN
clear
power on
regs
# Base test --------------------
memset 00be 72
op a9 55
op 25 be
# Should be: ACC=50
test acc = 50
# Zero test --------------------
power on
memset 00be aa
op a9 55
op 25 be
# Should be: ACC=0, Z=1
test acc = 0
test z = 1
# Negative test ----------------
power on
memset 00be aa
op a9 84
op 25 be
# Should be: ACC=80, S=1
test acc = 80
test s = 1
save verify_25.txt
t/monkeynes/script_2C.txt view on Meta::CPAN
clear
power on
regs
# use bit to turn on V
memset 1000 40
op 2c 0010
# V should be 1
test v = 1
# use bit to turn on S
memset 1000 80
op 2c 0010
# S should be 1
test s = 1
# this should turn off Z
memset 1000 01
op a9 ff
op 2c 0010
# Z should be 0
test z = 0
# this should turn on Z
memset 1000 00
op 2c 0010
# Z should be 1
test z = 1
save verify_2C.txt
t/monkeynes/script_2D.txt view on Meta::CPAN
clear
power on
regs
# Base test --------------------
memset beef 72
op a9 55
op 2d efbe
# Should be: ACC=50
test acc = 50
# Zero test --------------------
power on
memset beef aa
op a9 55
op 2d efbe
# Should be: ACC=0, Z=1
test acc = 0
test z = 1
# Negative test ----------------
power on
memset beef aa
op a9 84
op 2d efbe
# Should be: ACC=80, S=1
test acc = 80
test s = 1
save verify_2D.txt
t/monkeynes/script_30.txt view on Meta::CPAN
# *** MODIFIED TEST FROM ORIGINAL MONKEYNES
# *** Now properly checks negative branching
clear
power on
regs
# Branch instructions cannot be tested using the op
# command, and are loaded into memory directly and
# setup to execute with the step command.
# Branch not taken --------------------------------
regset s 0
regset pc 9040
# Load op: BMI $40
memset 9040 30
memset 9041 40
step
# Should be: PC=9042, cycles=2
test pc = 9042
# Positive Branch taken to same page --------------
regset s 1
regset pc 9040
# Load op: BMI $40
memset 9040 30
memset 9041 40
step
# Should be: PC=9082, cycles=3
test pc = 9082
# Negative Branch taken to same page --------------
regset s 1
regset pc 9040
# Load op: BMI $A0
memset 9040 30
memset 9041 A0
step
# Should be: PC=8FE2, cycles=3
test pc = 8FE2
# Positive Branch taken to different page ---------
regset s 1
regset pc 90b0
# Load op: BMI $7F
memset 90b0 30
memset 90b1 7f
step
# Should be: PC=9131, cycles=4
test pc = 9131
# Negative Branch taken to different page ---------
regset s 1
regset pc 9040
# Load op: BMI $F7
memset 9040 30
memset 9041 F7
step
# Should be: PC=9039, cycles=4
test pc = 9039
save verify_30.txt
t/monkeynes/script_35.txt view on Meta::CPAN
clear
power on
regs
# Base test --------------------
memset 00c9 72
op a9 55
op a2 0b
op 35 be
# Should be: ACC=50, IX=0B
test acc = 50
test ix = 0b
# Zero test --------------------
power on
memset 00c9 aa
op a9 55
op a2 0b
op 35 be
# Should be: ACC=0, IX=0B, Z=1
test acc = 0
test ix = 0b
test z = 1
# Negative test ----------------
power on
memset 00c9 aa
op a9 84
op a2 0b
op 35 be
# Should be: ACC=80, IX=0B, S=1
test acc = 80
test ix = 0b
test s = 1
t/monkeynes/script_40.txt view on Meta::CPAN
# *** MODIFIED TEST FROM ORIGINAL MONKEYNES
# *** Proper diag info, "IRQ" not "NMI"
# *** BRK stores PC + 2, RTI goes to adress from stack
clear
power on
regs
# Load the IRQ Vector
memset fffe ef
memset ffff be
# Set some bits into the PS
memset dead ff
op 2c adde
# Should be: PS=E2
test ps = e2
op 00
# Should be: PC=BEEF, I=1, B=1
# SP=FC, Mem[$01FF]=80, Mem[$01FE]=02
# Mem[$01FD]=F2
t/monkeynes/script_45.txt view on Meta::CPAN
clear
power on
regs
# Base test --------------------
memset 00be 72
op a9 55
op 45 be
# Should be: ACC=27
test acc = 27
# Negative test --------------------
power on
memset 00be aa
op a9 55
op 45 be
# Should be: ACC=FF, S=1
test acc = ff
test s = 1
# Zero test ----------------
power on
memset 00be 55
op a9 55
op 45 be
# Should be: ACC=0, Z=1
test acc = 0
test z = 1
save verify_45.txt
t/monkeynes/script_4D.txt view on Meta::CPAN
clear
power on
regs
# Base test --------------------
memset beef 72
op a9 55
op 4d efbe
# Should be: ACC=27
test acc = 27
# Negative test --------------------
power on
memset beef aa
op a9 55
op 4d efbe
# Should be: ACC=FF, S=1
test acc = ff
test s = 1
# Zero test ----------------
power on
memset beef 55
op a9 55
op 4d efbe
# Should be: ACC=0, Z=1
test acc = 0
test z = 1
save verify_4D.txt
t/monkeynes/script_50.txt view on Meta::CPAN
# *** MODIFIED TEST FROM ORIGINAL MONKEYNES
# *** Now properly checks negative branching
clear
power on
regs
# Branch instructions cannot be tested using the op
# command, and are loaded into memory directly and
# setup to execute with the step command.
# Branch not taken --------------------------------
regset v 1
regset pc 9040
# Load op: BVC $40
memset 9040 50
memset 9041 40
step
# Should be: PC=9042, cycles=2
test pc = 9042
# Positive Branch taken to same page --------------
regset v 0
regset pc 9040
# Load op: BVC $40
memset 9040 50
memset 9041 40
step
# Should be: PC=9082, cycles=3
test pc = 9082
# Negative Branch taken to same page --------------
regset v 0
regset pc 9040
# Load op: BVC $A0
memset 9040 50
memset 9041 A0
step
# Should be: PC=8FE2, cycles=3
test pc = 8FE2
# Positive Branch taken to different page ---------
regset v 0
regset pc 90b0
# Load op: BVC $7F
memset 90b0 50
memset 90b1 7f
step
# Should be: PC=9131, cycles=4
test pc = 9131
# Negative Branch taken to different page ---------
regset v 0
regset pc 9040
# Load op: BVC $F7
memset 9040 50
memset 9041 F7
step
# Should be: PC=9039, cycles=4
test pc = 9039
save verify_50.txt
t/monkeynes/script_55.txt view on Meta::CPAN
clear
power on
regs
# Base test --------------------
memset 00c9 72
op a9 55
op a2 0b
op 55 be
# Should be: ACC=27, IX=0B
test acc = 27
test ix = 0b
# Negative test --------------------
power on
memset 00c9 aa
op a9 55
op a2 0b
op 55 be
# Should be: ACC=FF, IX=0B, S=1
test acc = ff
test ix = 0b
test s = 1
# Zero test ----------------
power on
memset 00c9 55
op a9 55
op a2 0b
op 55 be
# Should be: ACC=0, IX=0B, Z=1
test acc = 0
test ix = 0b
test z = 1
t/monkeynes/script_65.txt view on Meta::CPAN
clear
power on
regs
# No flags case ----------------------------
memset 00be 12
op 18
op a9 55
op 65 be
# Should be: ACC=67, C=0, V=0, S=0, Z=0
test acc = 67
test c = 0
test v = 0
test s = 0
test z = 0
# Carry flag case --------------------------
memset 00be e7
op 18
op a9 fe
op 65 be
# Should be: ACC=E5, C=1, V=0, S=1, Z=0
test acc = e5
test c = 1
test v = 0
test s = 1
test z = 0
# Overflow and Negative flag case ----------
memset 00be 12
op 18
op a9 75
op 65 be
# Should be: ACC=67, C=0, V=1, S=1, Z=0
test acc = 87
test c = 0
test v = 1
test s = 1
test z = 0
# Zero flag case ---------------------------
memset 00be 8e
op 18
op a9 72
op 65 be
# Should be: ACC=0, C=1, V=0, S=0, Z=1
test acc = 0
test c = 1
test v = 0
test s = 0
test z = 1
# Use Carry Flag case ----------------------
memset 00be 12
op 38
op a9 55
op 65 be
# Should be: ACC=68, C=0, V=0, S=0, Z=0
test acc = 68
test c = 0
test v = 0
test s = 0
t/monkeynes/script_6C.txt view on Meta::CPAN
clear
power on
regs
# Normal case -------------------
memset beef ad
memset bef0 de
op 6c efbe
# Should be: PC=DEAD
test pc = dead
# Chip Bug case -----------------
power on
memclear
memset be00 de
memset beff ad
memset bf00 88
op 6c ffbe
# Should be: PC=DEAD (Not 88AD)
regs pc
test pc = dead
test pc != 88ad
save verify_6C.txt
t/monkeynes/script_6D.txt view on Meta::CPAN
clear
power on
regs
# No flags case ----------------------------
memset beef 12
op 18
op a9 55
op 6d efbe
# Should be: ACC=67, C=0, V=0, S=0, Z=0
test acc = 67
test c = 0
test v = 0
test s = 0
test z = 0
# Carry flag case --------------------------
memset beef e7
op 18
op a9 fe
op 6d efbe
# Should be: ACC=E5, C=1, V=0, S=1, Z=0
test acc = e5
test c = 1
test v = 0
test s = 1
test z = 0
# Overflow and Negative flag case ----------
memset beef 12
op 18
op a9 75
op 6d efbe
# Should be: ACC=67, C=0, V=1, S=1, Z=0
test acc = 87
test c = 0
test v = 1
test s = 1
test z = 0
# Zero flag case ---------------------------
memset beef 8e
op 18
op a9 72
op 6d efbe
# Should be: ACC=0, C=1, V=0, S=0, Z=1
test acc = 0
test c = 1
test v = 0
test s = 0
test z = 1
# Use Carry Flag case ----------------------
memset beef 12
op 38
op a9 55
op 6d efbe
# Should be: ACC=68, C=0, V=0, S=0, Z=0
test acc = 68
test c = 0
test v = 0
test s = 0
t/monkeynes/script_70.txt view on Meta::CPAN
# *** MODIFIED TEST FROM ORIGINAL MONKEYNES
# *** Now properly checks negative branching
clear
power on
regs
# Branch instructions cannot be tested using the op
# command, and are loaded into memory directly and
# setup to execute with the step command.
# Branch not taken --------------------------------
regset v 0
regset pc 9040
# Load op: BVS $40
memset 9040 70
memset 9041 40
step
# Should be: PC=9042, cycles=2
test pc = 9042
# Positive Branch taken to same page --------------
regset v 1
regset pc 9040
# Load op: BVS $40
memset 9040 70
memset 9041 40
step
# Should be: PC=9082, cycles=3
test pc = 9082
# Negative Branch taken to same page --------------
regset v 1
regset pc 9040
# Load op: BVS $A0
memset 9040 70
memset 9041 A0
step
# Should be: PC=8FE2, cycles=3
test pc = 8FE2
# Positive Branch taken to different page ---------
regset v 1
regset pc 90b0
# Load op: BVS $7F
memset 90b0 70
memset 90b1 7f
step
# Should be: PC=9131, cycles=4
test pc = 9131
# Negative Branch taken to different page ---------
regset v 1
regset pc 9040
# Load op: BVS $F7
memset 9040 70
memset 9041 F7
step
# Should be: PC=9039, cycles=4
test pc = 9039
save verify_70.txt
t/monkeynes/script_75.txt view on Meta::CPAN
clear
power on
regs
# No flags case ----------------------------
memset 00be 12
op 18
op a9 55
op 75 be
# Should be: ACC=67, C=0, V=0, S=0, Z=0
test acc = 67
test c = 0
test v = 0
test s = 0
test z = 0
# Carry flag case --------------------------
memset 00be e7
op 18
op a9 fe
op 75 be
# Should be: ACC=E5, C=1, V=0, S=1, Z=0
test acc = e5
test c = 1
test v = 0
test s = 1
test z = 0
# Overflow and Negative flag case ----------
memset 00be 12
op 18
op a9 75
op 75 be
# Should be: ACC=67, C=0, V=1, S=1, Z=0
test acc = 87
test c = 0
test v = 1
test s = 1
test z = 0
# Zero flag case ---------------------------
memset 00be 8e
op 18
op a9 72
op 75 be
# Should be: ACC=0, C=1, V=0, S=0, Z=1
test acc = 0
test c = 1
test v = 0
test s = 0
test z = 1
# Use Carry Flag case ----------------------
memset 00be 12
op 38
op a9 55
op 75 be
# Should be: ACC=68, C=0, V=0, S=0, Z=0
test acc = 68
test c = 0
test v = 0
test s = 0
t/monkeynes/script_7C.txt view on Meta::CPAN
# *** MODIFIED TEST FROM ORIGINAL MONKEYNES
# *** Now properly checks that it jumps to $mem[ $BEFA + $BEFB ]
clear
power on
regs
# Set jump location
memset befa ad
memset befb de
op a2 0b
op 7c efbe
# Should be: PC=DEAD
test pc = dead
save verify_7C.txt
t/monkeynes/script_84.txt view on Meta::CPAN
clear
power on
regs
# Set mem[$0072] to some other value 1st
memset 0072 ab
op a0 55
op 84 72
# mem[$0072] and IY should = $55
test iy = 55
test m:0072 = 55
save verify_84.txt
t/monkeynes/script_85.txt view on Meta::CPAN
clear
power on
regs
# Set mem[$0072] to some other value 1st
memset 0072 ab
op a9 55
op 85 72
# mem[$0072] and ACC should = $55
test acc = 55
test m:0072 = 55
save verify_85.txt
t/monkeynes/script_86.txt view on Meta::CPAN
clear
power on
regs
# Set mem[$0072] to some other value 1st
memset 0072 ab
op a2 55
op 86 72
# mem[$0072] and IX should = $55
test ix = 55
test m:0072 = 55
save verify_86.txt