3 |
use warnings; |
use warnings; |
4 |
use strict; |
use strict; |
5 |
|
|
6 |
use Carp qw/confess croak/; |
use Carp qw/confess croak cluck carp/; |
7 |
use File::Slurp; |
use File::Slurp; |
8 |
use Data::Dump qw/dump/; |
use Data::Dump qw/dump/; |
9 |
|
|
29 |
This project is homage to 8-bit computers in Croatia and former Yugoslavia |
This project is homage to 8-bit computers in Croatia and former Yugoslavia |
30 |
from 1980-1990. Word B<vrac> means also I<wizard> in Croatian. |
from 1980-1990. Word B<vrac> means also I<wizard> in Croatian. |
31 |
|
|
32 |
|
This project should enable anyone with limited knowledge of perl and 8-bit |
33 |
|
arhitecture of some machine to write emulator in an afternoon. To achieve this, |
34 |
|
code is written is as cleanly as possible. |
35 |
|
|
36 |
|
Porting existing emulators should be especially easy: you need passive |
37 |
|
understaning of language in which emulator is written and you can be on your |
38 |
|
way C<:-)> |
39 |
|
|
40 |
=cut |
=cut |
41 |
|
|
42 |
=head1 FUNCTIONS |
=head1 FUNCTIONS |
58 |
} |
} |
59 |
|
|
60 |
|
|
61 |
|
=head1 Memory management |
62 |
|
|
63 |
|
VRac implements callback for all I/O operations. This was main reason why |
64 |
|
L<Acme::6502> module with tied memory was too slow to emulate L<Orao>, so I |
65 |
|
had to write C binding for L<M6502>. |
66 |
|
|
67 |
|
B<This functions will die with stack trace when called>. They should be |
68 |
|
implemented for each architecture. |
69 |
|
|
70 |
|
=cut |
71 |
|
|
72 |
|
=head2 read |
73 |
|
|
74 |
|
Read from memory |
75 |
|
|
76 |
|
$byte = read( $address ); |
77 |
|
|
78 |
|
=cut |
79 |
|
|
80 |
|
sub read { |
81 |
|
my $self = shift; |
82 |
|
confess "please implement $self::read()"; |
83 |
|
} |
84 |
|
|
85 |
|
=head2 write |
86 |
|
|
87 |
|
Write into emory |
88 |
|
|
89 |
|
write( $address, $byte ); |
90 |
|
|
91 |
|
=cut |
92 |
|
|
93 |
|
sub write { |
94 |
|
my $self = shift; |
95 |
|
confess "please implement $self::write()"; |
96 |
|
} |
97 |
|
|
98 |
=head1 Helper functions |
=head1 Helper functions |
99 |
|
|
100 |
=head2 load_rom |
=head2 load_rom |
155 |
$from ||= 0; |
$from ||= 0; |
156 |
$to ||= 0xffff; |
$to ||= 0xffff; |
157 |
|
|
158 |
open(my $fh, '>', $path) || die "can't open $path: $!"; |
if ( open(my $fh, '>', $path) ) { |
159 |
print $fh $self->read_chunk( $from, $to ); |
print $fh $self->read_chunk( $from, $to ); |
160 |
close($fh); |
close($fh); |
161 |
|
|
162 |
|
my $size = -s $path; |
163 |
|
warn sprintf "saved %s %04x-%04x %d %x bytes\n", $path, $from, $to, $size, $size; |
164 |
|
} else { |
165 |
|
warn "can't create $path: $!"; |
166 |
|
} |
167 |
|
|
|
my $size = -s $path; |
|
|
warn sprintf "saved %s %d %x bytes\n", $path, $size, $size; |
|
168 |
} |
} |
169 |
|
|
170 |
=head2 hexdump |
=head2 hexdump |
190 |
); |
); |
191 |
} |
} |
192 |
|
|
193 |
=head1 Memory management |
=head2 append_to_file |
|
|
|
|
VRac implements all I/O using mmap addresses. This was main reason why |
|
|
L<Acme::6502> was just too slow to handle it. |
|
|
|
|
|
=cut |
|
|
|
|
|
=head2 read |
|
|
|
|
|
Read from memory |
|
194 |
|
|
195 |
$byte = read( $address ); |
$self->append_to_file( '/path/to/file', $byte, $byte ... ); |
196 |
|
|
197 |
=cut |
=cut |
198 |
|
|
199 |
sub read { |
sub append_to_file { |
200 |
my $self = shift; |
my $self = shift; |
201 |
confess "please implement $self::read()"; |
my $path = shift || confess "no path?"; |
202 |
} |
my $bytes = join('', @_); |
203 |
|
|
204 |
=head2 write |
my $size = -s $path || 0; |
205 |
|
my $len = length($bytes); |
|
Write into emory |
|
206 |
|
|
207 |
write( $address, $byte ); |
open(my $fh, '>>', $path) || confess "can't open $path: $!"; |
208 |
|
print($fh $bytes); |
209 |
|
my $pos = tell($fh); |
210 |
|
|
211 |
|
my $expected = $size + $len; |
212 |
|
if ( $pos != $expected ) { |
213 |
|
#cluck "BUG: file grows too big got $pos, expected $expected !"; |
214 |
|
truncate $fh, $expected; |
215 |
|
} |
216 |
|
|
217 |
=cut |
close($fh); |
218 |
|
|
219 |
sub write { |
warn sprintf("## append_to_file('%s',%s)\n", $path, dump($bytes)); |
|
my $self = shift; |
|
|
confess "please implement $self::write()"; |
|
220 |
} |
} |
221 |
|
|
222 |
=head1 Command Line |
=head1 Command Line |
364 |
return $run_for; |
return $run_for; |
365 |
} |
} |
366 |
|
|
367 |
|
=head1 SEE ALSO |
368 |
|
|
369 |
|
Components: L<M6502>, L<Z80>, L<Screen>, L<Tape>, L<Session> |
370 |
|
|
371 |
|
Emulators: L<Orao>, L<Galaksija> |
372 |
|
|
373 |
=head1 AUTHOR |
=head1 AUTHOR |
374 |
|
|
375 |
Dobrica Pavlinusic, C<< <dpavlin@rot13.org> >> |
Dobrica Pavlinusic, C<< <dpavlin@rot13.org> >> |
376 |
|
|
|
=head1 BUGS |
|
|
|
|
377 |
=head1 ACKNOWLEDGEMENTS |
=head1 ACKNOWLEDGEMENTS |
378 |
|
|
379 |
|
Structure and Interpretation of Computer Programs by Abelson, Sussman, and |
380 |
|
Sussman L<http://mitpress.mit.edu/sicp/> is a great book. It gave me idea |
381 |
|
that you should have wizard powers over your computer, even if it's 8 bit |
382 |
|
one. |
383 |
|
|
384 |
=head1 COPYRIGHT & LICENSE |
=head1 COPYRIGHT & LICENSE |
385 |
|
|
386 |
Copyright 2007 Dobrica Pavlinusic, All Rights Reserved. |
Copyright 2007 Dobrica Pavlinusic, All Rights Reserved. |