/[VRac]/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 /Orao.pm

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26