--- M6502/M6502.pm 2007/07/30 14:23:22 26 +++ M6502/M6502.pm 2007/07/31 17:15:54 68 @@ -3,27 +3,174 @@ use strict; use warnings; -# Dobrica Pavlinusic, 07/30/07 13:23:19 CEST -# -# Simple Orao emulation +use Data::Dump qw/dump/; +use Carp qw/confess/; +use Exporter 'import'; +our @EXPORT = qw'@mem $PC $A $P $X $Y $S $IPeriod $run_for $debug'; -my $mem = (0) x 0x10000; # 64M +=head1 NAME + +M6502 - perl bindings for M6502 CPU emulator + +=cut + +my $debug = 0; + +our $VERSION = qw(0.0.1); + +our @mem = (0xff) x 0x10000; # 64M # program counter our $PC = 0xbeef; # CPU registars our ( $A, $P, $X, $Y, $S ) = (0) x 5; # Set IPeriod to number of CPU cycles between calls to Loop6502 -our $IPeriod = 20000; +our $IPeriod = 1; +# Exec6502 cycles +our $run_for = 0; -=head1 init +=head1 FUNCTIONS + +=head2 init Called before C =cut sub init { - warn "inside init\n"; - print "stdout\n"; + my $self = shift; + warn "inside init low-level M6502 from $self\n"; }; + +=head2 read + +Read from memory + + $byte = read( $address ); + +=cut + +sub read { + my ($addr) = @_; + my $byte = $mem[$addr]; + warn "## M6502::read(",dump(@_),") = ",dump( $byte ),"\n" if $debug; + return $byte; +} + +=head2 write + +Write into emory + + write( $address, $byte ); + +=cut + +sub write { + warn "## M6502::write(",dump(@_),")\n" if $debug; + my ($addr,$byte) = @_; + $mem[$addr] = $byte; +} + +=head2 poke_code + +Write series of bytes into memory passing through MMU (C and C) +functions. If you don't want to trigger MMU, use C. + + $emu->poke_code( 0xbeef, 0xff, 0x00, 0xff, 0x00, 0xaa ); + +=cut + +sub poke_code { + my $self = shift; + my $addr = shift; + warn sprintf("## M6502::poke_code(%04x,%s)\n", $addr, dump( @_ )) if $self->debug; + #$mem[$addr++] = $_ foreach @_; + # call low-level write + Arch::write($addr++, $_) foreach @_; +} + +=head2 ram + +Read series of bytes into memory without MMU interaction + + my @code = $emu->ram( 0xc000, 0xc1000 ); + +=cut + +sub ram { + my $self = shift; + my ( $from, $to ) = @_; + warn sprintf("## M6502::ram(%04x,%04x)\n", $from, $to) if $self->debug; + return @mem[ $from .. $to ]; +} + +=head2 write_chunk + +Low-level update of memory, overriding user specified MMU functions C and C + + $emu->write_chunk( $address, $chunk_of_data ); + +=cut + +sub write_chunk { + my ($self, $addr, $chunk) = @_; + my $len = length($chunk); + splice @mem, $addr, $len, unpack('C*', $chunk); +} + +=head2 prompt + +Call this after C<< $run_for >> cycles have been run on processor + +=cut + +sub prompt { + warn "prompt -- you should override this\n"; + return 1; +} + +=head2 push_R + +called by C to push changes in registars back to perl variables + +=cut + +sub push_R { + warn "## M6502::push_R(",dump(@_),")\n" if $debug; + my ( $a, $p, $x, $y, $s, $pc ) = @_; + $PC = $pc; + $S=$s; $X=$x; $Y=$y; $P=$p; $A=$a; + dump_R(); +} + +=head2 dump_R + +helper function which dumps registers in humanly readable form + + my $dump = dump_R; + +=cut + +sub dump_R { + my $dump = sprintf(" PC: %04x A:%02x P:%02x X:%02x Y:%02x S:%02x\n", $PC, $A, $P, $X, $Y, $S); + warn "## M6502::dump_R $dump" if $debug; + return $dump; +} + +=head1 SEE ALSO + +L is sample implementation using this module + +=head1 AUTHOR + +Dobrica Pavlinusic, C<< >> + +=head1 COPYRIGHT & LICENSE + +Copyright 2007 Dobrica Pavlinusic, All Rights Reserved. + +This program is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=cut 1;