/[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 87 - (show annotations)
Thu Aug 2 11:08:10 2007 UTC (16 years, 8 months ago) by dpavlin
File size: 10717 byte(s)
- transfer debug state into C, added accesor M6502->debug();
- update_*_R functions to keep perl vars in sync with C
- tests
1 package Orao;
2
3 use warnings;
4 use strict;
5
6 use Carp qw/confess/;
7 use lib './lib';
8 #use Time::HiRes qw(time);
9 use File::Slurp;
10 use Data::Dump qw/dump/;
11 use List::Util qw/first/;
12 use M6502;
13
14 use base qw(Class::Accessor M6502 Screen Prefs);
15 __PACKAGE__->mk_accessors(qw(run_for));
16
17 =head1 NAME
18
19 Orao - Orao emulator
20
21 =head1 VERSION
22
23 Version 0.02
24
25 =cut
26
27 our $VERSION = '0.02';
28
29 =head1 SUMMARY
30
31 Emulator or Orao 8-bit 6502 machine popular in Croatia
32
33 =cut
34
35 my @kbd_ports = (
36 0x87FC,0x87FD,0x87FA,0x87FB,0x87F6,0x87F7,
37 0x87EE,0x87EF,0x87DE,0x87DF,0x87BE,0x87BF,
38 0x877E,0x877F,0x86FE,0x86FF,0x85FE,0x85FF,
39 0x83FE,0x83FF,
40 );
41
42 =head2 boot
43
44 Start emulator, open L<Screen>, load initial ROM images, and render memory
45
46 my $orao = Orao->new({});
47 $orao->boot;
48
49 =cut
50
51 our $orao;
52
53 select(STDERR); $| = 1;
54
55 sub boot {
56 my $self = shift;
57 warn "Orao calling upstream init\n";
58 $self->SUPER::init( $self, @_ );
59
60 warn "Orao $Orao::VERSION emulation starting\n";
61
62 $self->open_screen;
63 $self->load_rom({
64 0x1000 => 'dump/SCRINV.BIN',
65 # should be 0x6000, but oraoemu has 2 byte prefix
66 0x5FFE => 'dump/screen.dmp',
67 0xC000 => 'rom/BAS12.ROM',
68 0xE000 => 'rom/CRT12.ROM',
69 });
70
71 # $PC = 0xDD11; # BC
72 # $PC = 0xC274; # MC
73
74 $PC = 0xff89;
75
76 $orao = $self;
77
78 # $self->prompt( 0x1000 );
79
80 my ( $trace, $debug ) = ( $self->trace, $self->debug );
81 $self->trace( 0 );
82 $self->debug( 0 );
83
84 $self->render( @mem[ 0x6000 .. 0x7fff ] );
85
86 if ( $self->show_mem ) {
87
88 warn "rendering memory map\n";
89
90 $self->render_mem( @mem );
91
92 my @mmap = (
93 0x0000, 0x03FF, 'nulti blok',
94 0x0400, 0x5FFF, 'korisnièki RAM (23K)',
95 0x6000, 0x7FFF, 'video RAM',
96 0x8000, 0x9FFF, 'sistemske lokacije',
97 0xA000, 0xAFFF, 'ekstenzija',
98 0xB000, 0xBFFF, 'DOS',
99 0xC000, 0xDFFF, 'BASIC ROM',
100 0xE000, 0xFFFF, 'sistemski ROM',
101 );
102
103 } else {
104
105 warn "rendering video memory\n";
106 $self->render( @mem[ 0x6000 .. 0x7fff ] );
107
108 }
109 $self->sync;
110 $self->trace( $trace );
111 $self->debug( $debug );
112
113 #( $A, $P, $X, $Y, $S, $IPeriod ) = ( 1, 2, 3, 4, 5, 6 );
114
115 warn "Orao boot finished",
116 $self->trace ? ' trace' : '',
117 $self->debug ? ' debug' : '',
118 "\n";
119
120 M6502::reset();
121
122 }
123
124 =head2 load_rom
125
126 called to init memory and load initial rom images
127
128 $orao->load_rom;
129
130 =cut
131
132 sub load_rom {
133 my ($self, $loaded_files) = @_;
134
135 #my $time_base = time();
136
137 foreach my $addr ( sort keys %$loaded_files ) {
138 my $path = $loaded_files->{$addr};
139 $self->load_oraoemu( $path, $addr );
140 }
141 }
142
143 # write chunk directly into memory, updateing vram if needed
144 sub _write_chunk {
145 my $self = shift;
146 my ( $addr, $chunk ) = @_;
147 $self->write_chunk( $addr, $chunk );
148 my $end = $addr + length($chunk);
149 my ( $f, $t ) = ( 0x6000, 0x7fff );
150
151 if ( $end < $f || $addr >= $t ) {
152 warn "skip vram update\n";
153 return;
154 };
155
156 $f = $addr if ( $addr > $f );
157 $t = $end if ( $end < $t );
158
159 warn sprintf("refresh video ram %04x-%04x\n", $f, $t);
160 # foreach my $a ( $f .. $t ) {
161 # $self->vram( $a - 0x6000 , $mem[ $a ] );
162 # }
163 $self->render( @mem[ 0x6000 .. 0x7fff ] );
164 $self->render_mem( @mem ) if $self->show_mem;
165 }
166
167 =head2 load_oraoemu
168
169 Load binary files, ROM images and Orao Emulator files
170
171 $orao->load_oraoemu( '/path/to/file', 0x1000 );
172
173 Returns true on success.
174
175 =cut
176
177 sub load_oraoemu {
178 my $self = shift;
179 my ( $path, $addr ) = @_;
180
181 if ( ! -e $path ) {
182 warn "ERROR: file $path doesn't exist\n";
183 return;
184 }
185
186 my $size = -s $path || confess "no size for $path: $!";
187
188 my $buff = read_file( $path );
189
190 if ( $size == 65538 ) {
191 $addr = 0;
192 warn sprintf "loading oraoemu 64k dump %s at %04x - %04x %02x\n", $path, $addr, $addr+$size-1, $size;
193 $self->_write_chunk( $addr, substr($buff,2) );
194 return 1;
195 } elsif ( $size == 32800 ) {
196 $addr = 0;
197 warn sprintf "loading oraoemu 1.3 dump %s at %04x - %04x %02x\n", $path, $addr, $addr+$size-1, $size;
198 $self->_write_chunk( $addr, substr($buff,0x20) );
199 return 1;
200 }
201 printf "loading %s at %04x - %04x %02x\n", $path, $addr, $addr+$size-1, $size;
202 $self->_write_chunk( $addr, $buff );
203 return 1;
204
205 my $chunk;
206
207 my $pos = 0;
208
209 while ( my $long = substr($buff,$pos,4) ) {
210 my @b = split(//, $long, 4);
211 $chunk .=
212 ( $b[3] || '' ) .
213 ( $b[2] || '' ) .
214 ( $b[1] || '' ) .
215 ( $b[0] || '' );
216 $pos += 4;
217 }
218
219 $self->_write_chunk( $addr, $chunk );
220
221 return 1;
222 };
223
224 =head2 save_dump
225
226 $orao->save_dump( 'filename', $from, $to );
227
228 =cut
229
230 sub save_dump {
231 my $self = shift;
232
233 my ( $path, $from, $to ) = @_;
234
235 $from ||= 0;
236 $to ||= 0xffff;
237
238 open(my $fh, '>', $path) || die "can't open $path: $!";
239 print $fh $self->read_chunk( $from, $to );
240 close($fh);
241
242 my $size = -s $path;
243 warn sprintf "saved %s %d %x bytes\n", $path, $size, $size;
244 }
245
246 =head2 hexdump
247
248 $orao->hexdump( $address );
249
250 =cut
251
252 sub hexdump {
253 my $self = shift;
254 my $a = shift;
255 return sprintf(" %04x %s\n", $a,
256 join(" ",
257 map {
258 if ( defined($_) ) {
259 sprintf( "%02x", $_ )
260 } else {
261 ' '
262 }
263 } @mem[ $a .. $a+8 ]
264 )
265 );
266 }
267
268 =head1 Memory management
269
270 Orao implements all I/O using mmap addresses. This was main reason why
271 L<Acme::6502> was just too slow to handle it.
272
273 =cut
274
275 =head2 read
276
277 Read from memory
278
279 $byte = read( $address );
280
281 =cut
282
283 sub read {
284 my $self = shift;
285 my ($addr) = @_;
286 my $byte = $mem[$addr];
287 warn sprintf("# Orao::read(%04x) = %02x\n", $addr, $byte) if $self->trace;
288
289 # keyboard
290
291 if ( first { $addr == $_ } @kbd_ports ) {
292 warn sprintf("keyboard port: %04x\n",$addr);
293 } elsif ( $addr == 0x87fc ) {
294 warn "0x87fc - arrows/back\n";
295 =for pascal
296 if VKey=VK_RIGHT then Result:=16;
297 if VKey=VK_DOWN then Result:=128;
298 if VKey=VK_UP then Result:=192;
299 if VKey=VK_LEFT then Result:=224;
300 if Ord(KeyPressed)=VK_BACK then Result:=224;
301 =cut
302 } elsif ( $addr == 0x87fd ) {
303 warn "0x87fd - enter\n";
304 =for pascal
305 if KeyPressed=Chr(13) then begin
306 Mem[$FC]:=13;
307 Result:=0;
308 end;
309 =cut
310 } elsif ( $addr == 0x87fa ) {
311 warn "0x87fa = F1 - F4\n";
312 =for pascal
313 if VKey=VK_F4 then Result:=16;
314 if VKey=VK_F3 then Result:=128;
315 if VKey=VK_F2 then Result:=192;
316 if VKey=VK_F1 then Result:=224;
317 =cut
318 } elsif ( $addr == 0x87fb ) {
319 warn "0x87fb\n";
320 =for pascal
321 if KeyPressed=Chr(32) then Result:=32;
322 if KeyPressed='"' then Result:=16;
323 if KeyPressed='!' then Result:=16;
324 if KeyPressed='$' then Result:=16;
325 if KeyPressed='%' then Result:=16;
326 if KeyPressed='&' then Result:=16;
327 if KeyPressed='(' then Result:=16;
328 if KeyPressed=')' then Result:=16;
329 if KeyPressed='=' then Result:=16;
330 if KeyPressed='#' then Result:=16;
331 if KeyPressed='+' then Result:=16;
332 if KeyPressed='*' then Result:=16;
333 if KeyPressed='?' then Result:=16;
334 if KeyPressed='<' then Result:=16;
335 if KeyPressed='>' then Result:=16;
336 if VKey=191 then Result:=16;
337 =cut
338 }
339
340 $self->mmap_pixel( $addr, 0, $byte, 0 );
341 return $byte;
342 }
343
344 =head2 write
345
346 Write into emory
347
348 write( $address, $byte );
349
350 =cut
351
352 sub write {
353 my $self = shift;
354 my ($addr,$byte) = @_;
355 warn sprintf("# Orao::write(%04x,%02x)\n", $addr, $byte) if $self->trace;
356
357 if ( $addr >= 0x6000 && $addr < 0x8000 ) {
358 $self->vram( $addr - 0x6000 , $byte );
359 }
360
361 if ( $addr == 0x8800 ) {
362 warn sprintf "sound ignored: %x\n", $byte;
363 }
364
365 if ( $addr > 0xafff ) {
366 warn sprintf "write access 0x%04x > 0xafff aborting\n", $addr;
367 return;
368 }
369
370 $self->mmap_pixel( $addr, $byte, 0, 0 );
371
372 $mem[$addr] = $byte;
373 return;
374 }
375
376 =head1 Command Line
377
378 Command-line debugging intrerface is implemented for communication with
379 emulated device
380
381 =head2 prompt
382
383 my ( $entered_line, @p ) = $orao->prompt( $address, $last_command );
384
385 =cut
386
387 my $last = 'r 1';
388
389 sub prompt {
390 my $self = shift;
391 $self->app->sync;
392 my $a = shift;
393 print STDERR $self->hexdump( $a ),
394 $last ? "[$last] " : '',
395 "> ";
396 my $in = <STDIN>;
397 chomp($in);
398 warn "## prompt got: $in\n" if $self->debug;
399 $in ||= $last;
400 $last = $in;
401 return ( $in, split(/\s+/, $in) ) if $in;
402 }
403
404 =head2 cli
405
406 $orao->cli();
407
408 =cut
409
410 my $show_R = 0;
411
412 sub cli {
413 my $self = shift;
414 my $a = $PC || confess "no pc?";
415 warn $self->dump_R() if $show_R;
416 while ( my ($line, @v) = $self->prompt( $a, $last ) ) {
417 my $c = shift @v;
418 next unless defined($c);
419 my $v = shift @v;
420 $v = hex($v) if $v && $v =~ m/^[0-9a-f]+$/;
421 @v = map { hex($_) } @v;
422 printf "## a: %04x parsed cli: c:%s v:%s %s\n", $a, $c, ($v || 'undef'), join(",",@v) if $self->debug;
423 if ( $c =~ m/^[qx]/i ) {
424 exit;
425 } elsif ( $c eq '?' ) {
426 my $t = $self->trace ? 'on' : 'off' ;
427 my $d = $self->debug ? 'on' : 'off' ;
428 warn <<__USAGE__;
429 Usage:
430
431 x|q\t\texit
432 e 6000 6010\tdump memory, +/- to walk forward/backward
433 m 1000 ff 00\tput ff 00 on 1000
434 j|u 1000\t\tjump (change pc)
435 r 42\t\trun 42 instruction opcodes
436 t\t\ttrace [$t]
437 d\t\tdebug [$d]
438
439 __USAGE__
440 warn $self->dump_R;
441 } elsif ( $c =~ m/^e/i ) {
442 $a = $v if defined($v);
443 my $to = shift @v;
444 $to = $a + 32 if ( ! $to || $to <= $a );
445 $to = 0xffff if ( $to > 0xffff );
446 my $lines = int( ($to - $a + 8) / 8 );
447 printf "## e %04x %04x (%d bytes) lines: %d\n", $a, $to, ($to-$a), $lines;
448 while ( --$lines ) {
449 print $self->hexdump( $a );
450 $a += 8;
451 }
452 $last = '+';
453 $show_R = 0;
454 } elsif ( $c =~ m/^\+/ ) {
455 $a += 8;
456 $show_R = 0;
457 } elsif ( $c =~ m/^\-/ ) {
458 $a -= 8;
459 $show_R = 0;
460 } elsif ( $c =~ m/^m/i ) {
461 $a = $v if defined($v);
462 $self->poke_code( $a, @v );
463 printf "poke %d bytes at %04x\n", $#v + 1, $a;
464 $last = '+';
465 $show_R = 0;
466 } elsif ( $c =~ m/^l/i ) {
467 my $to = shift @v || 0x1000;
468 $a = $to;
469 $self->load_oraoemu( $v, $a );
470 $last = '';
471 } elsif ( $c =~ m/^s/i ) {
472 $self->save_dump( $v || 'mem.dump', @v );
473 $last = '';
474 } elsif ( $c =~ m/^r/i ) {
475 $run_for = $v || 1;
476 print "run_for $run_for instructions\n";
477 $show_R = 1;
478 last;
479 } elsif ( $c =~ m/^(u|j)/ ) {
480 my $to = $v || $a;
481 printf "set pc to %04x\n", $to;
482 $PC = $to; # remember for restart
483 $run_for = 1;
484 $last = "r $run_for";
485 $show_R = 1;
486 last;
487 } elsif ( $c =~ m/^t/ ) {
488 $self->trace( not $self->trace );
489 print "trace ", $self->trace ? 'on' : 'off', "\n";
490 $last = '';
491 } elsif ( $c =~ m/^d/ ) {
492 $self->debug( not $self->debug );
493 print "debug ", $self->debug ? 'on' : 'off', "\n";
494 $last = '';
495 } else {
496 warn "# ignored $line\n" if ($line);
497 $last = '';
498 }
499 }
500
501 }
502
503 =head1 AUTHOR
504
505 Dobrica Pavlinusic, C<< <dpavlin@rot13.org> >>
506
507 =head1 BUGS
508
509 =head1 ACKNOWLEDGEMENTS
510
511 See also L<http://www.foing.hr/~fng_josip/orao.htm> which is source of all
512 info about this machine (and even hardware implementation from 2007).
513
514 =head1 COPYRIGHT & LICENSE
515
516 Copyright 2007 Dobrica Pavlinusic, All Rights Reserved.
517
518 This program is free software; you can redistribute it and/or modify it
519 under the same terms as Perl itself.
520
521 =cut
522
523 1; # End of Orao

  ViewVC Help
Powered by ViewVC 1.1.26