summaryrefslogtreecommitdiff
path: root/apps/plugins/pacbox/arcade.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/pacbox/arcade.c')
-rw-r--r--apps/plugins/pacbox/arcade.c577
1 files changed, 577 insertions, 0 deletions
diff --git a/apps/plugins/pacbox/arcade.c b/apps/plugins/pacbox/arcade.c
new file mode 100644
index 0000000000..e7bf124700
--- /dev/null
+++ b/apps/plugins/pacbox/arcade.c
@@ -0,0 +1,577 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Pacbox - a Pacman Emulator for Rockbox
11 *
12 * Based on PIE - Pacman Instructional Emulator
13 *
14 * Copyright (c) 1997-2003,2004 Alessandro Scotti
15 * http://www.ascotti.org/
16 *
17 * All files in this archive are subject to the GNU General Public License.
18 * See the file COPYING in the source tree root for full license agreement.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24
25#include "arcade.h"
26#include "hardware.h"
27#include <string.h>
28#include "plugin.h"
29
30extern struct plugin_api* rb;
31
32#ifndef HAVE_LCD_COLOR
33/* Convert RGB888 to 2-bit greyscale - logic taken from bmp2rb.c */
34static fb_data rgb_to_gray(unsigned int r, unsigned int g, unsigned int b)
35{
36 int brightness = ((3*r + 6*g + b) / 10);
37 return ((brightness & 0xc0) >> 6);
38}
39#endif
40
41unsigned char color_data_[256] = {
42 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0b, 0x01,
43 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0b, 0x03,
44 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0b, 0x05,
45 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0b, 0x07,
46 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x09,
47 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
48 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49 0x00, 0x0f, 0x00, 0x0e, 0x00, 0x01, 0x0c, 0x0f,
50 0x00, 0x0e, 0x00, 0x0b, 0x00, 0x0c, 0x0b, 0x0e,
51 0x00, 0x0c, 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00,
52 0x00, 0x01, 0x02, 0x0f, 0x00, 0x07, 0x0c, 0x02,
53 0x00, 0x09, 0x06, 0x0f, 0x00, 0x0d, 0x0c, 0x0f,
54 0x00, 0x05, 0x03, 0x09, 0x00, 0x0f, 0x0b, 0x00,
55 0x00, 0x0e, 0x00, 0x0b, 0x00, 0x0e, 0x00, 0x0b,
56 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0e, 0x01,
57 0x00, 0x0f, 0x0b, 0x0e, 0x00, 0x0e, 0x00, 0x0f,
58 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
59 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
62 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
63 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
64 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
65 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
66 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
67 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
68 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
69 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
70 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
71 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
72 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
73 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
74};
75
76unsigned char palette_data_[0x20] = {
77 0x00, 0x07, 0x66, 0xef, 0x00, 0xf8, 0xea, 0x6f,
78 0x00, 0x3f, 0x00, 0xc9, 0x38, 0xaa, 0xaf, 0xf6,
79 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
80 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
81};
82
83enum {
84 Normal = 0x00,
85 FlipY = 0x01,
86 FlipX = 0x02,
87 FlipXY = 0x03
88};
89
90fb_data palette[256]; /* Color palette */
91int vchar_to_x_[1024];
92int vchar_to_y_[1024];
93
94void init_PacmanMachine(int dip)
95{
96 int i;
97
98 /* Initialize the CPU and the RAM */
99 z80_reset();
100 rb->memset( &ram_[0x4000], 0xFF, 0x1000 );
101
102 /* Initialize parameters */
103 port1_ = 0xFF;
104 port2_ = 0xFF;
105 coin_counter_ = 0;
106
107 /* Reset the machine */
108 reset_PacmanMachine();
109
110 /* Set the DIP switches to a default configuration */
111 setDipSwitches( dip );
112
113 /* Initialize the video character translation tables: video memory has a
114 very peculiar arrangement in Pacman so we precompute a few tables to
115 move around faster */
116
117 for( i=0x000; i<0x400; i++ ) {
118 int x, y;
119
120 if( i < 0x040 ) {
121 x = 29 - (i & 0x1F);
122 y = 34 + (i >> 5);
123 }
124 else if( i >= 0x3C0 ) {
125 x = 29 - (i & 0x1F);
126 y = ((i-0x3C0) >> 5);
127 }
128 else {
129 x = 27 - ((i-0x40) >> 5);
130 y = 2 + ((i-0x40) & 0x1F);
131 }
132 vchar_to_x_[i] = x;
133 vchar_to_y_[i] = y;
134 if( (y >= 0) && (y < 36) && (x >= 0) && (x < 28) )
135 vchar_to_i_[i] = y*28 + x;
136 else
137 vchar_to_i_[i] = 0x3FF;
138 }
139}
140
141void reset_PacmanMachine(void)
142{
143 int i;
144
145 z80_reset();
146 output_devices_ = 0;
147 interrupt_vector_ = 0;
148
149 rb->memset( ram_+0x4000, 0, 0x1000 );
150 rb->memset( color_mem_, 0, sizeof(color_mem_) );
151 rb->memset( video_mem_, 0, sizeof(video_mem_) );
152 rb->memset( dirty_, 0, sizeof(dirty_) );
153
154 for( i=0; i<8; i++ ) {
155 sprites_[i].color = 0;
156 sprites_[i].x = ScreenWidth;
157 }
158}
159
160/*
161 Run the machine for one frame.
162*/
163int run(void)
164{
165 /* Run until the CPU has executed the number of cycles per frame
166 (the function returns the number of "extra" cycles spent by the
167 last instruction but that is not really important here) */
168
169 unsigned extraCycles = z80_run( CpuCyclesPerFrame );
170
171 /* Reset the CPU cycle counter to make sure it doesn't overflow,
172 also take into account the extra cycles from the previous run */
173
174 setCycles( extraCycles );
175
176 /* If interrupts are enabled, force a CPU interrupt with the vector
177 set by the program */
178
179 if( output_devices_ & InterruptEnabled ) {
180 z80_interrupt( interrupt_vector_ );
181 }
182
183 return 0;
184}
185
186/** Returns the status of the coin lockout door. */
187unsigned char getCoinLockout(void) {
188 return output_devices_ & CoinLockout ? 1 : 0;
189}
190
191static void decodeCharByte( unsigned char b, unsigned char * charbuf, int charx, int chary, int charwidth )
192{
193 int i;
194
195 for( i=3; i>=0; i-- ) {
196 charbuf[charx+(chary+i)*charwidth] = (b & 1) | ((b >> 3) & 2);
197 b >>= 1;
198 }
199}
200
201static void decodeCharLine( unsigned char * src, unsigned char * charbuf, int charx, int chary, int charwidth )
202{
203 int x;
204
205 for( x=7; x>=0; x-- ) {
206 decodeCharByte( *src++, charbuf, x+charx, chary, charwidth );
207 }
208}
209
210static void decodeCharSet( unsigned char * mem, unsigned char * charset )
211{
212 int i;
213
214 for( i=0; i<256; i++ ) {
215 unsigned char * src = mem + 16*i;
216 unsigned char * dst = charset + 64*i;
217
218 decodeCharLine( src, dst, 0, 4, 8 );
219 decodeCharLine( src+8, dst, 0, 0, 8 );
220 }
221}
222
223static void decodeSprites( unsigned char * mem, unsigned char * sprite_data )
224{
225 int i;
226
227 for( i=0; i<64; i++ ) {
228 unsigned char * src = mem + i*64;
229 unsigned char * dst = sprite_data + 256*i;
230
231 decodeCharLine( src , dst, 8, 12, 16 );
232 decodeCharLine( src+ 8, dst, 8, 0, 16 );
233 decodeCharLine( src+16, dst, 8, 4, 16 );
234 decodeCharLine( src+24, dst, 8, 8, 16 );
235 decodeCharLine( src+32, dst, 0, 12, 16 );
236 decodeCharLine( src+40, dst, 0, 0, 16 );
237 decodeCharLine( src+48, dst, 0, 4, 16 );
238 decodeCharLine( src+56, dst, 0, 8, 16 );
239 }
240}
241
242/*
243 Decode one byte from the encoded color palette.
244
245 An encoded palette byte contains RGB information bit-packed as follows:
246
247 bit: 7 6 5 4 3 2 1 0
248 color: b b g g g r r r
249*/
250static unsigned decodePaletteByte( unsigned char value )
251{
252 unsigned bit0, bit1, bit2;
253 unsigned red, green, blue;
254
255 bit0 = (value >> 0) & 0x01;
256 bit1 = (value >> 1) & 0x01;
257 bit2 = (value >> 2) & 0x01;
258 red = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
259
260 bit0 = (value >> 3) & 0x01;
261 bit1 = (value >> 4) & 0x01;
262 bit2 = (value >> 5) & 0x01;
263 green = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
264
265 bit0 = 0;
266 bit1 = (value >> 6) & 0x01;
267 bit2 = (value >> 7) & 0x01;
268 blue = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
269
270 return (blue << 16 ) | (green << 8) | red;
271}
272
273void decodeROMs(void)
274{
275 unsigned decoded_palette[0x20];
276 unsigned c;
277
278 int i;
279
280 decodeCharSet( charset_rom_, charmap_ );
281 decodeSprites( spriteset_rom_, spritemap_ );
282
283 for( i=0x00; i<0x20; i++ ) {
284 decoded_palette[i] = decodePaletteByte( palette_data_[i] );
285 }
286 for( i=0; i<256; i++ ) {
287 c = decoded_palette[ color_data_[i] & 0x0F ];
288#ifdef HAVE_LCD_COLOR
289 palette[i] = LCD_RGBPACK((unsigned char) (c),
290 (unsigned char) (c >> 8),
291 (unsigned char) (c >> 16));
292#else
293 palette[i] = rgb_to_gray(c, c >> 8, c >> 16);
294#endif
295 }
296}
297
298void getDeviceInfo( enum InputDevice device, unsigned char * mask, unsigned char ** port )
299{
300 static unsigned char MaskInfo[] = {
301 0x01 , // Joy1_Up
302 0x02 , // Joy1_Left
303 0x04 , // Joy1_Right
304 0x08 , // Joy1_Down
305 0x10 , // Switch_RackAdvance
306 0x20 , // CoinSlot_1
307 0x40 , // CoinSlot_2
308 0x80 , // Switch_AddCredit
309 0x01 , // Joy2_Up
310 0x02 , // Joy2_Left
311 0x04 , // Joy2_Right
312 0x08 , // Joy2_Down
313 0x10 , // Switch_Test
314 0x20 , // Key_OnePlayer
315 0x40 , // Key_TwoPlayers
316 0x80 // Switch_CocktailMode
317 };
318
319 *mask = MaskInfo[device];
320
321 switch( device ) {
322 case Joy1_Up:
323 case Joy1_Left:
324 case Joy1_Right:
325 case Joy1_Down:
326 case Switch_RackAdvance:
327 case CoinSlot_1:
328 case CoinSlot_2:
329 case Switch_AddCredit:
330 *port = &port1_;
331 break;
332 case Joy2_Up:
333 case Joy2_Left:
334 case Joy2_Right:
335 case Joy2_Down:
336 case Switch_Test:
337 case Key_OnePlayer:
338 case Key_TwoPlayers:
339 case Switch_CocktailMode:
340 *port = &port2_;
341 break;
342 default:
343 *port = 0;
344 break;
345 }
346}
347
348enum InputDeviceMode getDeviceMode( enum InputDevice device )
349{
350 unsigned char mask;
351 unsigned char * port;
352
353 getDeviceInfo( device, &mask, &port );
354
355 return (*port & mask) == 0 ? DeviceOn : DeviceOff;
356}
357
358/*
359 Fire an input event, telling the emulator for example
360 that the joystick has been released from the down position.
361*/
362void setDeviceMode( enum InputDevice device, enum InputDeviceMode mode )
363{
364 if( (getCoinLockout() == 0) && ((device == CoinSlot_1)||(device == CoinSlot_2)||(device == Switch_AddCredit)) ) {
365 // Coin slots are locked, ignore command and exit
366 return;
367 }
368
369 unsigned char mask;
370 unsigned char * port;
371
372 getDeviceInfo( device, &mask, &port );
373
374 if( mode == DeviceOn )
375 *port &= ~mask;
376 else if( mode == DeviceOff )
377 *port |= mask;
378 else if( mode == DeviceToggle )
379 *port ^= mask;
380}
381
382void setDipSwitches( unsigned value ) {
383 dip_switches_ = (unsigned char) value;
384
385 setDeviceMode( Switch_RackAdvance, value & DipRackAdvance_Auto ? DeviceOn : DeviceOff );
386 setDeviceMode( Switch_Test, value & DipMode_Test ? DeviceOn : DeviceOff );
387 setDeviceMode( Switch_CocktailMode, value & DipCabinet_Cocktail ? DeviceOn : DeviceOff );
388}
389
390unsigned getDipSwitches(void) {
391 unsigned result = dip_switches_;
392
393 if( getDeviceMode(Switch_RackAdvance) == DeviceOn ) result |= DipRackAdvance_Auto;
394 if( getDeviceMode(Switch_Test) == DeviceOn ) result |= DipMode_Test;
395 if( getDeviceMode(Switch_CocktailMode) == DeviceOn ) result |= DipCabinet_Cocktail;
396
397 return result;
398}
399
400static inline void drawChar( unsigned char * buffer, int index, int ox, int oy, int color )
401{
402 buffer += ox + oy*224; // Make the buffer point to the character position
403 index *= 64; // Make the index point to the character offset into the character table
404 color = (color & 0x3F)*4;
405 int x,y;
406
407 if( output_devices_ & FlipScreen ) {
408 // Flip character
409 buffer += 7*ScreenWidth;
410 for( y=0; y<8; y++ ) {
411 for( x=7; x>=0; x-- ) {
412 buffer[x] = charmap_[ index++ ] + color;
413 }
414 buffer -= ScreenWidth; // Go to the next line
415 }
416 }
417 else {
418 for( y=0; y<8; y++ ) {
419 for( x=0; x<=7; x++ ) {
420 buffer[x] = charmap_[ index++ ] + color;
421 }
422 buffer += ScreenWidth; // Go to the next line
423 }
424 }
425}
426
427inline void drawSprite( unsigned char * buffer, int index )
428{
429 struct PacmanSprite ps = sprites_[index];
430 int x,y;
431
432 // Exit now if sprite not visible at all
433 if( (ps.color == 0) || (ps.x >= ScreenWidth) || (ps.y < 16) || (ps.y >= (ScreenHeight-32)) ) {
434 return;
435 }
436
437 // Clip the sprite coordinates to cut the parts that fall off the screen
438 int start_x = (ps.x < 0) ? 0 : ps.x;
439 int end_x = (ps.x < (ScreenWidth-16)) ? ps.x+16 : ScreenWidth;
440
441 // Prepare variables for drawing
442 int color = (ps.color & 0x3F)*4;
443 unsigned char * spritemap_base = spritemap_ + ((ps.n & 0x3F)*256);
444
445 buffer += ScreenWidth*ps.y;
446
447 // Draw the 16x16 sprite
448 if( ps.mode == 0 ) { // Normal
449 // Draw the 16x16 sprite
450 for( y=0; y<16; y++ ) {
451 char* s = &spritemap_base[start_x-ps.x+y*16];
452 for( x=start_x; x<end_x; x++ ) {
453 int c = *(s++);
454 if( c ) {
455 buffer[x] = c + color;
456 }
457 }
458 buffer += ScreenWidth;
459 }
460 } else if( ps.mode == 1 ) { // Flip Y
461 for( y=0; y<16; y++ ) {
462 char* s = &spritemap_base[start_x-ps.x+(15-y)*16];
463 for( x=start_x; x<end_x; x++ ) {
464 int c = *(s++);
465 if( c ) {
466 buffer[x] = c + color;
467 }
468 }
469 buffer += ScreenWidth;
470 }
471 } else if( ps.mode == 2 ) { // Flip X
472 for( y=0; y<16; y++ ) {
473 char* s = &spritemap_base[15-start_x+ps.x+y*16];
474 for( x=start_x; x<end_x; x++ ) {
475 int c = *(s--);
476 if( c ) {
477 buffer[x] = c + color;
478 }
479 }
480 buffer += ScreenWidth;
481 }
482 } else { // Flip X and Y
483 for( y=0; y<16; y++ ) {
484 char* s = &spritemap_base[15-start_x+ps.x+(15-y)*16];
485 for( x=start_x; x<end_x; x++ ) {
486 int c = *(s--);
487 if( c ) {
488 buffer[x] = c + color;
489 }
490 }
491 buffer += ScreenWidth;
492 }
493 }
494}
495
496/*
497 Draw the video into the specified buffer.
498*/
499bool renderBackground( unsigned char * buffer )
500{
501 unsigned char * video = video_mem_;
502 unsigned char * color = color_mem_;
503 unsigned char * dirty = dirty_;
504 int x,y;
505 bool changed=false;
506
507 // Draw the background first...
508 if( output_devices_ & FlipScreen ) {
509 for( y=ScreenHeight-CharHeight; y>=0; y-=CharHeight ) {
510 for( x=ScreenWidth-CharWidth; x>=0; x-=CharWidth ) {
511 if (*dirty) {
512 drawChar( buffer, *video++, x, y, *color++ );
513 *(dirty++)=0;
514 changed=true;
515 } else {
516 dirty++;
517 video++;
518 color++;
519 }
520 }
521 }
522 }
523 else {
524 for( y=0; y<ScreenHeight; y+=CharHeight ) {
525 for( x=0; x<ScreenWidth; x+=CharWidth ) {
526 if (*dirty) {
527 drawChar( buffer, *video++, x, y, *color++ );
528 *(dirty++)=0;
529 changed=true;
530 } else {
531 dirty++;
532 video++;
533 color++;
534 }
535 }
536 }
537 }
538
539 return changed;
540}
541
542void renderSprites( unsigned char * buffer )
543{
544 int i;
545
546 // ...then add the sprites
547 for( i=7; i>=0; i-- ) {
548 drawSprite( buffer, i );
549 }
550}
551
552/* Enables/disables the speed hack. */
553int setSpeedHack( int enabled )
554{
555 int result = 0;
556
557 if( enabled ) {
558 if( (ram_[0x180B] == 0xBE) && (ram_[0x1FFD] == 0x00) ) {
559 // Patch the ROM to activate the speed hack
560 ram_[0x180B] = 0x01; // Activate speed hack
561 ram_[0x1FFD] = 0xBD; // Fix ROM checksum
562
563 result = 1;
564 }
565 }
566 else {
567 if( (ram_[0x180B] == 0x01) && (ram_[0x1FFD] == 0xBD) ) {
568 // Restore the patched ROM locations
569 ram_[0x180B] = 0xBE;
570 ram_[0x1FFD] = 0x00;
571
572 result = 1;
573 }
574 }
575
576 return result;
577}