/[VRac]/M6502/Orao.pm
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /M6502/Orao.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 46 - (show annotations)
Tue Jul 31 10:13:13 2007 UTC (16 years, 8 months ago) by dpavlin
File size: 7888 byte(s)
added _write_chunk which fills in memory and refresh vram if needed
1 package Orao;
2
3 use warnings;
4 use strict;
5
6 use Carp;
7 use lib './lib';
8 #use Time::HiRes qw(time);
9 use File::Slurp;
10 use Data::Dump qw/dump/;
11 use M6502;
12
13 use base qw(Class::Accessor M6502 Screen);
14 __PACKAGE__->mk_accessors(qw(debug trace run_for mem_dump trace));
15
16 =head1 NAME
17
18 Orao - Orao emulator
19
20 =head1 VERSION
21
22 Version 0.02
23
24 =cut
25
26 our $VERSION = '0.02';
27
28 =head1 SUMMARY
29
30 Emulator or Orao 8-bit 6502 machine popular in Croatia
31
32 =cut
33
34 =head2 init
35
36 Start emulator
37
38 =cut
39
40 our $orao;
41
42 select(STDERR); $| = 1;
43
44 sub init {
45 my $self = shift;
46 warn "Orao calling upstream init\n";
47 $self->SUPER::init( $self, @_ );
48
49 warn "staring Orao $Orao::VERSION emulation\n";
50
51 $self->open_screen;
52 $self->load_rom({
53 0x1000 => 'dump/SCRINV.BIN',
54 0xC000 => 'rom/BAS12.ROM',
55 0xE000 => 'rom/CRT12.ROM',
56 });
57
58 $PC = 0xDD11; # BC
59 # $PC = 0xC274; # MC
60
61 $orao = $self;
62
63 # $self->prompt( 0x1000 );
64
65 my $trace = $self->trace;
66 $self->trace( 0 );
67
68 if ( $self->show_mem ) {
69
70 warn "rendering memory map\n";
71
72 my @mmap = (
73 0x0000, 0x03FF, 'nulti blok',
74 0x0400, 0x5FFF, 'korisnièki RAM (23K)',
75 0x6000, 0x7FFF, 'video RAM',
76 0x8000, 0x9FFF, 'sistemske lokacije',
77 0xA000, 0xAFFF, 'ekstenzija',
78 0xB000, 0xBFFF, 'DOS',
79 0xC000, 0xDFFF, 'BASIC ROM',
80 0xE000, 0xFFFF, 'sistemski ROM',
81 );
82
83 foreach my $i ( 0 .. $#mmap / 3 ) {
84 my $o = $i * 3;
85 my ( $from, $to, $desc ) = @mmap[$o,$o+1,$o+2];
86 printf "%04x - %04x - %s\n", $from, $to, $desc;
87 for my $a ( $from .. $to ) {
88 if ( $a >= 0x6000 && $a < 0x8000 ) {
89 my $b = $self->read( $a );
90 $self->vram( $a - 0x6000, $b );
91 } else {
92 $self->read( $a );
93 }
94 }
95 }
96
97 } else {
98
99 warn "rendering video memory\n";
100 for my $a ( 0x6000 .. 0x7fff ) {
101 $self->vram( $a - 0x6000, $mem[$a] );
102 }
103
104 }
105 $self->sync;
106 $self->trace( $trace );
107
108 #( $A, $P, $X, $Y, $S, $IPeriod ) = ( 1, 2, 3, 4, 5, 6 );
109
110 warn "Orao init finished", $self->trace ? ' trace on' : '', "\n";
111
112 }
113
114 =head2 load_rom
115
116 called to init memory and load initial rom images
117
118 $orao->load_rom;
119
120 =cut
121
122 sub load_rom {
123 my ($self, $loaded_files) = @_;
124
125 #my $time_base = time();
126
127 foreach my $addr ( sort keys %$loaded_files ) {
128 my $path = $loaded_files->{$addr};
129 $self->load_oraoemu( $path, $addr );
130 }
131 }
132
133
134 =head2 load_oraoemu
135
136 =cut
137
138 sub _write_chunk {
139 my $self = shift;
140 my ( $addr, $chunk ) = @_;
141 $self->write_chunk( $addr, $chunk );
142 my $end = $addr + length($chunk);
143 my ( $f, $t ) = ( 0x6000, 0x7fff );
144
145 if ( $end < $f || $addr >= $t ) {
146 warn "skip vram update\n";
147 return;
148 };
149
150 $f = $addr if ( $addr > $f );
151 $t = $end if ( $end < $t );
152
153 warn sprintf("refresh video ram %04x-%04x\n", $f, $t);
154 foreach my $a ( $f .. $t ) {
155 $self->vram( $a - 0x6000 , $mem[ $a ] );
156 }
157 }
158
159 sub load_oraoemu {
160 my $self = shift;
161 my ( $path, $addr ) = @_;
162
163 my $size = -s $path || confess "no size for $path: $!";
164
165 my $buff = read_file( $path );
166
167 if ( $size == 65538 ) {
168 $addr = 0;
169 warn sprintf "loading oraoemu 64k dump %s at %04x - %04x %02x\n", $path, $addr, $addr+$size-1, $size;
170 $self->_write_chunk( $addr, substr($buff,2) );
171 return;
172 } elsif ( $size == 32800 ) {
173 $addr = 0;
174 warn sprintf "loading oraoemu 1.3 dump %s at %04x - %04x %02x\n", $path, $addr, $addr+$size-1, $size;
175 $self->_write_chunk( $addr, substr($buff,0x20) );
176 return;
177 }
178 printf "loading %s at %04x - %04x %02x\n", $path, $addr, $addr+$size-1, $size;
179 return $self->_write_chunk( $addr, $buff );
180
181 my $chunk;
182
183 my $pos = 0;
184
185 while ( my $long = substr($buff,$pos,4) ) {
186 my @b = split(//, $long, 4);
187 $chunk .=
188 ( $b[3] || '' ) .
189 ( $b[2] || '' ) .
190 ( $b[1] || '' ) .
191 ( $b[0] || '' );
192 $pos += 4;
193 }
194
195 $self->_write_chunk( $addr, $chunk );
196
197 };
198
199 =head2 save_dump
200
201 $orao->save_dump( 'filename', $from, $to );
202
203 =cut
204
205 sub save_dump {
206 my $self = shift;
207
208 my ( $path, $from, $to ) = @_;
209
210 $from ||= 0;
211 $to ||= 0xffff;
212
213 open(my $fh, '>', $path) || die "can't open $path: $!";
214 print $fh $self->read_chunk( $from, $to );
215 close($fh);
216
217 my $size = -s $path;
218 warn sprintf "saved %s %d %x bytes\n", $path, $size, $size;
219 }
220
221 =head2 hexdump
222
223 $orao->hexdump( $address );
224
225 =cut
226
227 sub hexdump {
228 my $self = shift;
229 my $a = shift;
230 return sprintf(" %04x %s\n", $a,
231 join(" ",
232 map {
233 sprintf( "%02x", $_ )
234 } $self->ram( $a, $a+8 )
235 )
236 );
237 }
238
239 =head2 prompt
240
241 $orao->prompt( $address, $last_command );
242
243 =cut
244
245 sub prompt {
246 my $self = shift;
247 $self->app->sync;
248 my $a = shift;
249 my $last = shift;
250 print STDERR $self->hexdump( $a ),
251 $last ? "[$last] " : '',
252 "> ";
253 my $in = <STDIN>;
254 chomp($in);
255 $in ||= $last;
256 $last = $in;
257 return split(/\s+/, $in) if $in;
258 }
259
260 =head1 Memory management
261
262 Orao implements all I/O using mmap addresses. This was main reason why
263 L<Acme::6502> was just too slow to handle it.
264
265 =cut
266
267 =head2 read
268
269 Read from memory
270
271 $byte = read( $address );
272
273 =cut
274
275 sub read {
276 my $self = shift;
277 my ($addr) = @_;
278 my $byte = $mem[$addr];
279 warn sprintf("# Orao::read(%04x) = %02x\n", $addr, $byte) if $self->trace;
280 $self->mmap_pixel( $addr, 0, $byte, 0 );
281 return $byte;
282 }
283
284 =head2 write
285
286 Write into emory
287
288 write( $address, $byte );
289
290 =cut
291
292 sub write {
293 my $self = shift;
294 my ($addr,$byte) = @_;
295 warn sprintf("# Orao::write(%04x,%02x)\n", $addr, $byte) if $self->trace;
296
297 if ( $addr >= 0x6000 && $addr < 0x8000 ) {
298 $self->vram( $addr - 0x6000 , $byte );
299 }
300
301 if ( $addr > 0xafff ) {
302 warn sprintf "access to %04x above affff aborting\n", $addr;
303 return -1;
304 }
305 if ( $addr == 0x8800 ) {
306 warn sprintf "sound ignored: %x\n", $byte;
307 }
308
309 $self->mmap_pixel( $addr, $byte, 0, 0 );
310
311 $mem[$addr] = $byte;
312 return;
313 }
314
315 =head1 Command Line
316
317 Command-line debugging intrerface is implemented for communication with
318 emulated device
319
320 =head2 cli
321
322 $orao->cli();
323
324 =cut
325
326 my $last = 'r 1';
327
328 sub cli {
329 my $self = shift;
330 my $a = $PC || confess "no pc?";
331 while ( my @v = $self->prompt( $a, $last ) ) {
332 my $c = shift @v;
333 my $v = shift @v;
334 $v = hex($v) if $v && $v =~ m/^[0-9a-f]+$/;
335 printf "## [%s] %s\n", ($v || 'undef'), join(",",@v) if $self->debug;
336 @v = map { hex($_) } @v;
337 if ( $c =~ m/^[qx]/i ) {
338 exit;
339 } elsif ( $c eq '?' ) {
340 warn <<__USAGE__;
341 uage:
342 x|q\t\texit
343 e 6000 6010\tdump memory, +/- to walk forward/backward
344 m 1000 ff 00\tput ff 00 on 1000
345 j|u 1000\t\tjump (change pc)
346 r 42\t\trun 42 instruction opcodes
347 __USAGE__
348 } elsif ( $c =~ m/^e/i ) {
349 $a ||= $v;
350 my $to = shift @v;
351 $to = $a + 32 if ( ! $to || $to <= $a );
352 my $lines = int( ($to - $a - 8) / 8 );
353 printf "## m %04x %04x lines: %d\n", $a, $to, $lines;
354 while ( $lines ) {
355 print $self->hexdump( $a );
356 $a += 8;
357 $lines--;
358 }
359 $last = '+';
360 } elsif ( $c =~ m/^\+/ ) {
361 $a += 8;
362 } elsif ( $c =~ m/^\-/ ) {
363 $a -= 8;
364 } elsif ( $c =~ m/^m/i ) {
365 $a = $v;
366 $self->poke_code( $a, @v );
367 printf "poke %d bytes at %04x\n", $#v + 1, $a;
368 } elsif ( $c =~ m/^l/i ) {
369 my $to = shift @v || 0x1000;
370 $a = $to;
371 $self->load_oraoemu( $v, $a );
372 } elsif ( $c =~ m/^s/i ) {
373 $self->save_dump( $v || 'mem.dump', @v );
374 } elsif ( $c =~ m/^r/i ) {
375 $run_for = $v || 1;
376 print "run_for $run_for instructions\n";
377 last;
378 } elsif ( $c =~ m/^(u|j)/ ) {
379 my $to = $v || $a;
380 printf "set pc to %04x\n", $to;
381 $PC = $to; # remember for restart
382 $run_for = 1;
383 last;
384 } elsif ( $c =~ m/^t/ ) {
385 $self->trace( not $self->trace );
386 print "trace ", $self->trace ? 'on' : 'off', "\n";
387 } else {
388 warn "# ignore $c\n";
389 last;
390 }
391 }
392
393
394 }
395
396 =head1 AUTHOR
397
398 Dobrica Pavlinusic, C<< <dpavlin@rot13.org> >>
399
400 =head1 BUGS
401
402 =head1 ACKNOWLEDGEMENTS
403
404 See also L<http://www.foing.hr/~fng_josip/orao.htm> which is source of all
405 info about this machine (and even hardware implementation from 2007).
406
407 =head1 COPYRIGHT & LICENSE
408
409 Copyright 2007 Dobrica Pavlinusic, All Rights Reserved.
410
411 This program is free software; you can redistribute it and/or modify it
412 under the same terms as Perl itself.
413
414 =cut
415
416 1; # End of Orao

  ViewVC Help
Powered by ViewVC 1.1.26