/[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 148 - (show annotations)
Sun Aug 5 14:08:01 2007 UTC (16 years, 8 months ago) by dpavlin
File size: 9189 byte(s)
pod tweaks
1 package Orao;
2
3 use warnings;
4 use strict;
5
6 use Carp qw/confess/;
7 use File::Slurp;
8 use Data::Dump qw/dump/;
9 use M6502; # import @mem $PC and friends
10 use Screen qw/$white $black/;
11
12 use base qw(Class::Accessor VRac M6502 Screen Prefs Tape Session);
13 #__PACKAGE__->mk_accessors(qw());
14
15 =head1 NAME
16
17 Orao - Orao emulator
18
19 =head1 VERSION
20
21 Version 0.06
22
23 =cut
24
25 our $VERSION = '0.06';
26
27 =head1 SUMMARY
28
29 Emulator for Orao 8-bit 6502 machine popular in Croatia (especially schools)
30
31 =cut
32
33 =head1 FUNCTIONS
34
35 =head2 run
36
37 Start emulator, open L<Screen>, load initial ROM images, and start emulator loop
38
39 =cut
40
41 our $emu;
42
43 sub run {
44 my $self = shift;
45
46 warn "Orao calling upstream init\n";
47 $self->SUPER::init(
48 read => sub { $self->read( @_ ) },
49 write => sub { $self->write( @_ ) },
50 );
51
52 warn "Orao $Orao::VERSION emulation starting\n";
53
54 warn "emulating ", $#mem, " bytes of memory\n";
55
56 # $self->scale( 2 );
57 # $self->show_mem( 1 );
58
59 $self->open_screen;
60 $self->load_rom({
61 # 0x1000 => 'dump/SCRINV.BIN',
62 # should be 0x6000, but oraoemu has 2 byte prefix
63 # 0x5FFE => '/home/dpavlin/orao/dump/screen.dmp',
64 # 0xC000 => 'rom/Orao/BAS12.ROM',
65 # 0xE000 => 'rom/Orao/CRT12.ROM',
66 0xC000 => 'rom/Orao/BAS13.ROM',
67 0xE000 => 'rom/Orao/CRT13.ROM',
68 });
69
70 # $PC = 0xDD11; # BC
71 # $PC = 0xC274; # MC
72
73 $PC = 0xff89;
74
75 $emu = $self;
76
77 # $self->prompt( 0x1000 );
78
79 my ( $trace, $debug ) = ( $self->trace, $self->debug );
80 $self->trace( 0 );
81 $self->debug( 0 );
82
83 warn "rendering memory\n";
84 $self->render_mem( @mem );
85
86 if ( $self->show_mem ) {
87
88 my @mmap = (
89 0x0000, 0x03FF, 'nulti blok',
90 0x0400, 0x5FFF, 'korisnièki RAM (23K)',
91 0x6000, 0x7FFF, 'video RAM',
92 0x8000, 0x9FFF, 'sistemske lokacije',
93 0xA000, 0xAFFF, 'ekstenzija',
94 0xB000, 0xBFFF, 'DOS',
95 0xC000, 0xDFFF, 'BASIC ROM',
96 0xE000, 0xFFFF, 'sistemski ROM',
97 );
98
99 print "Orao memory map:";
100
101 while ( @mmap ) {
102 my ( $from, $to, $desc ) = splice(@mmap, 0, 3);
103 printf("%04x-%04x %s\n", $from, $to, $desc);
104 }
105
106 }
107
108 $self->trace( $trace );
109 $self->debug( $debug );
110
111 warn "Orao boot finished",
112 $self->trace ? ' trace' : '',
113 $self->debug ? ' debug' : '',
114 "\n";
115
116 M6502::reset();
117
118 # $self->load_tape( '../oraoigre/bdash.tap' );
119
120 $self->loop( sub {
121 my $run_for = shift;
122 warn sprintf("about to exec from PC %04x for %d cycles\n", $PC, $run_for) if $self->trace;
123 M6502::exec( $run_for );
124 $self->render_vram;
125 });
126 };
127
128
129 =head1 Helper functions
130
131 =head2 write_chunk
132
133 Write chunk directly into memory, updateing vram if needed
134
135 $emu->write_chunk( 0x1000, $chunk_data );
136
137 =cut
138
139 sub write_chunk {
140 my $self = shift;
141 my ( $addr, $chunk ) = @_;
142 $self->SUPER::write_chunk( $addr, $chunk );
143 my $end = $addr + length($chunk);
144 my ( $f, $t ) = ( 0x6000, 0x7fff );
145
146 if ( $end < $f || $addr >= $t ) {
147 warn "skip vram update\n";
148 return;
149 };
150
151 $f = $addr if ( $addr > $f );
152 $t = $end if ( $end < $t );
153
154 warn sprintf("refresh video ram %04x-%04x\n", $f, $t);
155 $self->render_vram;
156 $self->render_mem( @mem );
157 }
158
159 =head2 load_image
160
161 Load binary files, ROM images and Orao Emulator files
162
163 $emu->load_image( '/path/to/file', 0x1000 );
164
165 Returns true on success.
166
167 =cut
168
169 sub load_image {
170 my $self = shift;
171 my ( $path, $addr ) = @_;
172
173 if ( ! -e $path ) {
174 warn "ERROR: file $path doesn't exist\n";
175 return;
176 }
177
178 my $size = -s $path || confess "no size for $path: $!";
179
180 my $buff = read_file( $path );
181
182 if ( $size == 65538 ) {
183 $addr = 0;
184 warn sprintf "loading oraoemu 64k dump %s at %04x - %04x %02x\n", $path, $addr, $addr+$size-1, $size;
185 $self->write_chunk( $addr, substr($buff,2) );
186 return 1;
187 } elsif ( $size == 32800 ) {
188 $addr = 0;
189 warn sprintf "loading oraoemu 1.3 dump %s at %04x - %04x %02x\n", $path, $addr, $addr+$size-1, $size;
190 $self->write_chunk( $addr, substr($buff,0x20) );
191 return 1;
192 }
193
194 printf "loading %s at %04x - %04x %02x\n", $path, $addr, $addr+$size-1, $size;
195 $self->write_chunk( $addr, $buff );
196 return 1;
197 };
198
199
200 =head1 Memory management
201
202 Orao implements all I/O using mmap addresses. This was main reason why
203 L<Acme::6502> was just too slow to handle it.
204
205 =cut
206
207 =head2 read
208
209 Read from memory
210
211 $byte = read( $address );
212
213 =cut
214
215 my $keyboard_none = 255;
216
217 my $keyboard = {
218 0x87FC => {
219 'right' => 16,
220 'down' => 128,
221 'up' => 192,
222 'left' => 224,
223 'backspace' => 224,
224 },
225 0x87FD => sub {
226 my ( $self, $key ) = @_;
227 if ( $key eq 'return' ) {
228 M6502::_write( 0xfc, 13 );
229 warn "return\n";
230 return 0;
231 } elsif ( $key =~ m/ ctrl/ || $self->key_down( 'left ctrl' ) || $self->key_down( 'right ctrl' ) ) {
232 warn "ctrl\n";
233 return 16;
234 }
235 return $keyboard_none;
236 },
237 0x87FA => {
238 'f4' => 16,
239 'f3' => 128,
240 'f2' => 192,
241 'f1' => 224,
242 },
243 0x87FB => sub {
244 my ( $self, $key ) = @_;
245 if ( $key eq 'space' ) {
246 return 32;
247 } elsif ( $self->key_down( 'left shift' ) || $self->key_down( 'right shift' ) ) {
248 warn "shift\n";
249 return 16;
250 # } elsif ( $self->tape ) {
251 # warn "has tape!";
252 # return 0;
253 }
254 return $keyboard_none;
255 },
256 0x87F6 => {
257 '6' => 16,
258 't' => 128,
259 'y' => 192, # hr: z
260 'r' => 224,
261 },
262 0x87F7 => {
263 '5' => 32,
264 '4' => 16,
265 },
266 0x87EE => {
267 '7' => 16,
268 'u' => 128,
269 'i' => 192,
270 'o' => 224,
271 },
272 0x87EF => {
273 '8' => 32,
274 '9' => 16,
275 },
276 0x87DE => {
277 '1' => 16,
278 'w' => 128,
279 'q' => 192,
280 'e' => 224,
281 },
282 0x87DF => {
283 '2' => 32,
284 '3' => 16,
285 },
286 0x87BE => {
287 'm' => 16,
288 'k' => 128,
289 'j' => 192,
290 'l' => 224,
291 },
292 0x87BF => {
293 ',' => 32, # <
294 '.' => 16, # >
295 },
296 0x877E => {
297 'z' => 16, # hr:y
298 's' => 128,
299 'a' => 192,
300 'd' => 224,
301 },
302 0x877F => {
303 'x' => 32,
304 'c' => 16,
305 },
306 0x86FE => {
307 'n' => 16,
308 'g' => 128,
309 'h' => 192,
310 'f' => 224,
311 },
312 0x86FF => {
313 'b' => 32,
314 'v' => 16,
315 },
316 0x85FE => {
317 '<' => 16, # :
318 '\\' => 128, # ¾
319 '\'' => 192, # æ
320 ';' => 224, # è
321 },
322 0x85FF => {
323 '/' => 32,
324 'f11' => 16, # ^
325 },
326 0x83FE => {
327 'f12' => 16, # ;
328 '[' => 128, # ¹
329 ']' => 192, # ð
330 'p' => 224,
331 },
332 0x83FF => {
333 '-' => 32,
334 '0' => 16,
335 },
336 };
337
338 sub read {
339 my $self = shift;
340 my ($addr) = @_;
341 return if ( $addr > 0xffff );
342 my $byte = $mem[$addr];
343 confess sprintf("can't find memory at address %04x",$addr) unless defined($byte);
344 warn sprintf("# Orao::read(%04x) = %02x\n", $addr, $byte) if $self->trace;
345
346 # keyboard
347
348 if ( defined( $keyboard->{$addr} ) ) {
349 warn sprintf("keyboard port: %04x\n",$addr) if $self->trace;
350 my $key = $self->key_pressed;
351 if ( defined($key) ) {
352 my $ret = $keyboard_none;
353 my $r = $keyboard->{$addr} || confess "no definition for keyboard port found";
354 if ( ref($r) eq 'CODE' ) {
355 $ret = $r->($self, $key);
356 } elsif ( defined($r->{$key}) ) {
357 $ret = $r->{$key};
358 if ( ref($ret) eq 'CODE' ) {
359 $ret = $ret->($self);
360 }
361 } else {
362 warn sprintf("keyboard port: %04x unknown key: '%s'\n", $addr, $key) if $debug;
363 }
364 warn sprintf("keyboard port: %04x key:%s code:%d\n",$addr,$key,$ret) if ( $ret != $keyboard_none );
365 return $ret;
366 }
367 return $keyboard_none;
368 }
369
370 if ( $addr == 0x87ff ) {
371 return $self->read_tape;
372 }
373
374 $self->mmap_pixel( $addr, 0, $byte, 0 ) if $self->show_mem;
375 return $byte;
376 }
377
378 =head2 write
379
380 Write into emory
381
382 write( $address, $byte );
383
384 =cut
385
386 sub write {
387 my $self = shift;
388 my ($addr,$byte) = @_;
389 warn sprintf("# Orao::write(%04x,%02x)\n", $addr, $byte) if $self->trace;
390
391 if ( $addr == 0x8800 ) {
392 $self->write_tape( $byte );
393 warn sprintf "sound ignored: %x\n", $byte;
394 }
395
396 if ( $addr > 0xafff ) {
397 confess sprintf "write access 0x%04x > 0xafff aborting\n", $addr;
398 }
399
400 $self->mmap_pixel( $addr, $byte, 0, 0 ) if $self->show_mem;
401 $mem[$addr] = $byte;
402 return;
403 }
404
405 =head1 Architecture specific
406
407 =head2 render_vram
408
409 Render one frame of video ram
410
411 $self->render_vram;
412
413 =cut
414
415 my @flip;
416
417 foreach my $i ( 0 .. 255 ) {
418 my $t = 0;
419 $i & 0b00000001 and $t = $t | 0b10000000;
420 $i & 0b00000010 and $t = $t | 0b01000000;
421 $i & 0b00000100 and $t = $t | 0b00100000;
422 $i & 0b00001000 and $t = $t | 0b00010000;
423 $i & 0b00010000 and $t = $t | 0b00001000;
424 $i & 0b00100000 and $t = $t | 0b00000100;
425 $i & 0b01000000 and $t = $t | 0b00000010;
426 $i & 0b10000000 and $t = $t | 0b00000001;
427 #warn "$i = $t\n";
428 $flip[$i] = $t;
429 }
430
431
432 sub render_vram {
433 my $self = shift;
434
435 my $pixels = pack("C*", map { $flip[$_] } @mem[ 0x6000 .. 0x7fff ]);
436
437 my $vram = SDL::Surface->new(
438 -width => 256,
439 -height => 256,
440 -depth => 1, # 1 bit per pixel
441 -pitch => 32, # bytes per line
442 -from => $pixels,
443 );
444 $vram->set_colors( 0, $black, $white );
445
446 $self->render_frame( $vram );
447 }
448
449 =head2 cpu_PC
450
451 Helper metod to set or get PC for current architecture
452
453 =cut
454
455 sub cpu_PC {
456 my ( $self, $addr ) = @_;
457 if ( defined($addr) ) {
458 $PC = $addr;
459 warn sprintf("running from PC %04x\n", $PC);
460 };
461 return $PC;
462 }
463
464 =head1 SEE ALSO
465
466 L<VRac>, L<M6502>, L<Screen>, L<Tape>
467
468 =head1 AUTHOR
469
470 Dobrica Pavlinusic, C<< <dpavlin@rot13.org> >>
471
472 =head1 ACKNOWLEDGEMENTS
473
474 See also L<http://www.foing.hr/~fng_josip/orao.htm> which is source of all
475 info about this machine (and even hardware implementation from 2007).
476
477 =head1 COPYRIGHT & LICENSE
478
479 Copyright 2007 Dobrica Pavlinusic, All Rights Reserved.
480
481 This program is free software; you can redistribute it and/or modify it
482 under the same terms as Perl itself.
483
484 =cut
485
486 1; # End of Orao

  ViewVC Help
Powered by ViewVC 1.1.26