Acme-6502

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN


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



( run in 1.890 second using v1.01-cache-2.11-cpan-49f99fa48dc )