--- M6502/M6502.pm 2007/07/31 23:48:19 74 +++ M6502/M6502.pm 2007/08/02 12:49:19 92 @@ -6,17 +6,20 @@ use Data::Dump qw/dump/; use Carp qw/confess/; use Exporter 'import'; -our @EXPORT = qw'@mem $PC $A $P $X $Y $S $IPeriod $ICount $IRequest $IAutoReset $TrapBadOps $Trap $Trace $run_for $debug'; +our @EXPORT = qw'dump_R @mem $PC $A $P $X $Y $S $IPeriod $ICount $IRequest $IAutoReset $TrapBadOps $Trap $Trace $run_for $debug'; +our $VERSION = '0.0.2'; +require XSLoader; +XSLoader::load('M6502', $VERSION); =head1 NAME M6502 - perl bindings for M6502 CPU emulator -=cut +=head1 FUNCTIONS -my $debug = 0; +=cut -our $VERSION = qw(0.0.1); +our $debug = 0; our @mem = (0xff) x 0x10000; # 64M @@ -36,47 +39,43 @@ # Exec6502 cycles our $run_for = 0; -=head1 FUNCTIONS - =head2 init -Called before C - -=cut - -sub init { - my $self = shift; - warn "inside init low-level M6502 from $self\n"; -}; - -=head2 read +Setup read and write memory hooks (to implement memory mapped devices) -Read from memory - - $byte = read( $address ); + $init->( + read => sub { + return $mem[$_[0]]; + }, + write => sub { + $mem[$_[0]] = $_[1]; + }, + ); =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 +our $_rw_hooks = { + read => sub { + warn sprintf("# callback read(%04x) not implemented", @_) if $debug; + return $mem[$_[0]]; + }, + write => sub { + warn sprintf("# callback write(%04x,%02x) not implemented", @_) if $debug; + $mem[$_[0]] = $_[1]; + }, +}; - write( $address, $byte ); +sub init { + my $self = shift; + my $args = {@_}; + warn "inside init low-level M6502 from ",ref($self),"\n"; -=cut + foreach my $p ( qw/read write/ ) { + confess "need $p argument as coderef" unless ( $args->{$p} && ref($args->{$p}) eq 'CODE' ); + $_rw_hooks->{$p} = $args->{$p}; + } -sub write { - warn "## M6502::write(",dump(@_),")\n" if $debug; - my ($addr,$byte) = @_; - $mem[$addr] = $byte; -} +}; =head2 poke_code @@ -93,7 +92,7 @@ warn sprintf("## M6502::poke_code(%04x,%s)\n", $addr, dump( @_ )) if $self->debug; #$mem[$addr++] = $_ foreach @_; # call low-level write - Arch::write($addr++, $_) foreach @_; + $_rw_hooks->{write}->( $addr++, $_ ) foreach @_; } =head2 ram @@ -136,14 +135,42 @@ return 1; } -=head2 push_R +=head1 XS Callbacks + +This functions are called from C + +=head2 _read + +Read from memory C callback + + $byte = M6502::_read( $address ); + +=cut + +sub _read { + return $_rw_hooks->{read}->( @_ ); +} + +=head2 _write + +Write into memory C callback -called by C to push changes in registars back to perl variables + M6502:_write( $address, $byte ); =cut -sub push_R { - warn "## M6502::push_R(",dump(@_),")\n" if $debug; +sub _write { + return $_rw_hooks->{write}->( @_ ); +} + +=head2 _update_perl_R + +called by C to push changes in registars back to perl variables + +=cut + +sub _update_perl_R { + warn "## M6502::update_perl_R(",dump(@_),")\n" if $debug; ( $A, $P, $X, $Y, $S, $PC, $IPeriod, $ICount, $IRequest, $IAutoReset, $TrapBadOps, $Trap, $Trace ) = @_; dump_R(); } @@ -166,6 +193,27 @@ return $dump; } +=head2 debug + +Turn perl and C-level debugging on/off + + $emu->debug( 0 ); + $emu->debug( 1 ); + print $emu->debug; + +=cut + +sub debug { + my $self = shift; + my $value = shift; + if (defined($value)) { + $debug = M6502::set_debug($value); + } else { + $debug = M6502::get_debug(); + } + return $debug; +} + =head1 SEE ALSO L is sample implementation using this module