1
0
Fork 0
forked from len0rd/rockbox

pacbox - a Pacman arcade machine emulator. Currently working for all colour targets and the iriver H1x0. Requires the Pacman arcade machine ROMs in /.rockbox/pacman/

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@9001 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Dave Chapman 2006-03-11 15:44:35 +00:00
parent 1246668a78
commit a814584c87
13 changed files with 11079 additions and 1 deletions

View file

@ -410,6 +410,14 @@ static const struct plugin_api rockbox_api = {
/* new stuff at the end, sort into place next time
the API gets incompatible */
#if CONFIG_KEYPAD == IRIVER_H300_PAD || CONFIG_KEYPAD == IPOD_4G_PAD
/* NOTE: This is already in the plugin api for the H100 - but we put it
at the end for other targets to keep the plugin api compatible */
button_hold,
#endif
/* options */
set_option,
};
int plugin_load(const char* plugin, void* parameter)

View file

@ -99,7 +99,7 @@
#define PLUGIN_MAGIC 0x526F634B /* RocK */
/* increase this every time the api struct changes */
#define PLUGIN_API_VERSION 11
#define PLUGIN_API_VERSION 12
/* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any
@ -476,6 +476,16 @@ struct plugin_api {
/* new stuff at the end, sort into place next time
the API gets incompatible */
#if CONFIG_KEYPAD == IRIVER_H300_PAD || CONFIG_KEYPAD == IPOD_4G_PAD
/* NOTE: This is already in the plugin api for the H100 - but we put it
at the end for other targets to keep the plugin api compatible */
bool (*button_hold)(void);
#endif
/* options */
bool (*set_option)(const char* string, void* variable,
enum optiontype type, const struct opt_items* options,
int numoptions, void (*function)(int));
};
/* plugin header */

View file

@ -77,6 +77,12 @@ ifneq (-DIRIVER_IFP7XX,$(TARGET))
endif
endif
# For all the colour targets and iriver H1x0
ifneq (,$(strip $(foreach tgt,IPOD_VIDEO IPOD_NANO IPOD_COLOR IRIVER \
IAUDIO_X5 GIGABEAT,$(findstring $(tgt),$(TARGET)))))
SUBDIRS += pacbox
endif
.PHONY: $(SUBDIRS)
all: $(BUILDDIR)/libplugin.a $(ROCKS) $(SUBDIRS) $(DEPFILE)

View file

@ -0,0 +1,113 @@
# __________ __ ___.
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
# \/ \/ \/ \/ \/
# $Id$
#
INCLUDES = -I$(APPSDIR) -I.. -I. -I$(FIRMDIR)/include -I$(FIRMDIR)/export \
-I$(FIRMDIR)/common -I$(FIRMDIR)/drivers -I$(OUTDIR) -I$(BUILDDIR)
CFLAGS = $(INCLUDES) $(GCCOPTS) -O2 $(TARGET) $(EXTRA_DEFINES) \
-DTARGET_ID=$(TARGET_ID) -DMEM=${MEMORYSIZE} -DPLUGIN
ifdef APPEXTRA
INCLUDES += $(patsubst %,-I$(APPSDIR)/%,$(subst :, ,$(APPEXTRA)))
endif
LINKFILE := $(OBJDIR)/link.lds
DEPFILE = $(OBJDIR)/dep-pacbox
SRC = arcade.c pacbox.c hardware.c z80.c
SOURCES = $(SRC)
OBJS := $(SRC:%.c=$(OBJDIR)/%.o)
DIRS = .
LDS := ../plugin.lds
OUTPUT = $(OUTDIR)/pacbox.rock
all: $(OUTPUT)
ifndef SIMVER
$(OBJDIR)/pacbox.elf: $(OBJS) $(LINKFILE)
@echo "LD "`basename $@`
@$(CC) $(GCCOPTS) -O -nostdlib -o $@ $(OBJS) -L$(BUILDDIR) -lplugin -lgcc \
-T$(LINKFILE) -Wl,-Map,$(OBJDIR)/pacbox.map
$(OUTPUT): $(OBJDIR)/pacbox.elf
@echo "OBJCOPY "`basename $@`
@$(OC) -O binary $< $@
else
ifeq ($(SIMVER), x11)
###################################################
# This is the X11 simulator version
$(OUTPUT): $(OBJS)
@echo "LD $<"
@$(CC) $(CFLAGS) -shared $(OBJS) -L$(BUILDDIR) -lplugin -o $@
ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN)
# 'x' must be kept or you'll have "Win32 error 5"
# $ fgrep 5 /usr/include/w32api/winerror.h | head -1
# #define ERROR_ACCESS_DENIED 5L
else
@chmod -x $@
endif
else # end of x11-simulator
ifeq ($(SIMVER), sdl)
###################################################
# This is the SDL simulator version
$(OUTPUT): $(OBJS)
@echo "LD $<"
@$(CC) $(CFLAGS) -shared $(OBJS) -L$(BUILDDIR) -lplugin -o $@
ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN)
# 'x' must be kept or you'll have "Win32 error 5"
# $ fgrep 5 /usr/include/w32api/winerror.h | head -1
# #define ERROR_ACCESS_DENIED 5L
else
@chmod -x $@
endif
else # end of sdl-simulator
###################################################
# This is the win32 simulator version
DLLTOOLFLAGS = --export-all
DLLWRAPFLAGS = -s --entry _DllMain@12 --target=i386-mingw32 -mno-cygwin
$(OUTPUT): $(OBJS)
@echo "DLL "`basename $@`
@$(DLLTOOL) $(DLLTOOLFLAGS) -z $(OBJDIR)/$*.def $(OBJS)
@$(DLLWRAP) $(DLLWRAPFLAGS) --def $(OBJDIR)/$*.def $(OBJS) \
$(BUILDDIR)/libplugin.a -o $@
ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN)
# 'x' must be kept or you'll have "Win32 error 5"
# $ fgrep 5 /usr/include/w32api/winerror.h | head -1
# #define ERROR_ACCESS_DENIED 5L
else
@chmod -x $@
endif
endif # end of win32-simulator
endif
endif # end of simulator section
include $(TOOLSDIR)/make.inc
# MEMORYSIZE should be passed on to this makefile with the chosen memory size
# given in number of MB
$(LINKFILE): $(LDS)
@echo "build "`basename $@`
@cat $< | $(CC) -DMEMORYSIZE=$(MEMORYSIZE) $(INCLUDES) $(TARGET) \
$(DEFINES) -E -P - >$@
clean:
@echo "cleaning pacbox"
@rm -rf $(OBJDIR)/pacbox
@rm -f $(OBJDIR)/pacbox.* $(DEPFILE)
-include $(DEPFILE)

View file

@ -0,0 +1,577 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Pacbox - a Pacman Emulator for Rockbox
*
* Based on PIE - Pacman Instructional Emulator
*
* Copyright (c) 1997-2003,2004 Alessandro Scotti
* http://www.ascotti.org/
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "arcade.h"
#include "hardware.h"
#include <string.h>
#include "plugin.h"
extern struct plugin_api* rb;
#ifndef HAVE_LCD_COLOR
/* Convert RGB888 to 2-bit greyscale - logic taken from bmp2rb.c */
static fb_data rgb_to_gray(unsigned int r, unsigned int g, unsigned int b)
{
int brightness = ((3*r + 6*g + b) / 10);
return ((brightness & 0xc0) >> 6);
}
#endif
unsigned char color_data_[256] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0b, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0b, 0x03,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0b, 0x05,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0b, 0x07,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x09,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0f, 0x00, 0x0e, 0x00, 0x01, 0x0c, 0x0f,
0x00, 0x0e, 0x00, 0x0b, 0x00, 0x0c, 0x0b, 0x0e,
0x00, 0x0c, 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x02, 0x0f, 0x00, 0x07, 0x0c, 0x02,
0x00, 0x09, 0x06, 0x0f, 0x00, 0x0d, 0x0c, 0x0f,
0x00, 0x05, 0x03, 0x09, 0x00, 0x0f, 0x0b, 0x00,
0x00, 0x0e, 0x00, 0x0b, 0x00, 0x0e, 0x00, 0x0b,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0e, 0x01,
0x00, 0x0f, 0x0b, 0x0e, 0x00, 0x0e, 0x00, 0x0f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
unsigned char palette_data_[0x20] = {
0x00, 0x07, 0x66, 0xef, 0x00, 0xf8, 0xea, 0x6f,
0x00, 0x3f, 0x00, 0xc9, 0x38, 0xaa, 0xaf, 0xf6,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
enum {
Normal = 0x00,
FlipY = 0x01,
FlipX = 0x02,
FlipXY = 0x03
};
fb_data palette[256]; /* Color palette */
int vchar_to_x_[1024];
int vchar_to_y_[1024];
void init_PacmanMachine(int dip)
{
int i;
/* Initialize the CPU and the RAM */
z80_reset();
rb->memset( &ram_[0x4000], 0xFF, 0x1000 );
/* Initialize parameters */
port1_ = 0xFF;
port2_ = 0xFF;
coin_counter_ = 0;
/* Reset the machine */
reset_PacmanMachine();
/* Set the DIP switches to a default configuration */
setDipSwitches( dip );
/* Initialize the video character translation tables: video memory has a
very peculiar arrangement in Pacman so we precompute a few tables to
move around faster */
for( i=0x000; i<0x400; i++ ) {
int x, y;
if( i < 0x040 ) {
x = 29 - (i & 0x1F);
y = 34 + (i >> 5);
}
else if( i >= 0x3C0 ) {
x = 29 - (i & 0x1F);
y = ((i-0x3C0) >> 5);
}
else {
x = 27 - ((i-0x40) >> 5);
y = 2 + ((i-0x40) & 0x1F);
}
vchar_to_x_[i] = x;
vchar_to_y_[i] = y;
if( (y >= 0) && (y < 36) && (x >= 0) && (x < 28) )
vchar_to_i_[i] = y*28 + x;
else
vchar_to_i_[i] = 0x3FF;
}
}
void reset_PacmanMachine(void)
{
int i;
z80_reset();
output_devices_ = 0;
interrupt_vector_ = 0;
rb->memset( ram_+0x4000, 0, 0x1000 );
rb->memset( color_mem_, 0, sizeof(color_mem_) );
rb->memset( video_mem_, 0, sizeof(video_mem_) );
rb->memset( dirty_, 0, sizeof(dirty_) );
for( i=0; i<8; i++ ) {
sprites_[i].color = 0;
sprites_[i].x = ScreenWidth;
}
}
/*
Run the machine for one frame.
*/
int run(void)
{
/* Run until the CPU has executed the number of cycles per frame
(the function returns the number of "extra" cycles spent by the
last instruction but that is not really important here) */
unsigned extraCycles = z80_run( CpuCyclesPerFrame );
/* Reset the CPU cycle counter to make sure it doesn't overflow,
also take into account the extra cycles from the previous run */
setCycles( extraCycles );
/* If interrupts are enabled, force a CPU interrupt with the vector
set by the program */
if( output_devices_ & InterruptEnabled ) {
z80_interrupt( interrupt_vector_ );
}
return 0;
}
/** Returns the status of the coin lockout door. */
unsigned char getCoinLockout(void) {
return output_devices_ & CoinLockout ? 1 : 0;
}
static void decodeCharByte( unsigned char b, unsigned char * charbuf, int charx, int chary, int charwidth )
{
int i;
for( i=3; i>=0; i-- ) {
charbuf[charx+(chary+i)*charwidth] = (b & 1) | ((b >> 3) & 2);
b >>= 1;
}
}
static void decodeCharLine( unsigned char * src, unsigned char * charbuf, int charx, int chary, int charwidth )
{
int x;
for( x=7; x>=0; x-- ) {
decodeCharByte( *src++, charbuf, x+charx, chary, charwidth );
}
}
static void decodeCharSet( unsigned char * mem, unsigned char * charset )
{
int i;
for( i=0; i<256; i++ ) {
unsigned char * src = mem + 16*i;
unsigned char * dst = charset + 64*i;
decodeCharLine( src, dst, 0, 4, 8 );
decodeCharLine( src+8, dst, 0, 0, 8 );
}
}
static void decodeSprites( unsigned char * mem, unsigned char * sprite_data )
{
int i;
for( i=0; i<64; i++ ) {
unsigned char * src = mem + i*64;
unsigned char * dst = sprite_data + 256*i;
decodeCharLine( src , dst, 8, 12, 16 );
decodeCharLine( src+ 8, dst, 8, 0, 16 );
decodeCharLine( src+16, dst, 8, 4, 16 );
decodeCharLine( src+24, dst, 8, 8, 16 );
decodeCharLine( src+32, dst, 0, 12, 16 );
decodeCharLine( src+40, dst, 0, 0, 16 );
decodeCharLine( src+48, dst, 0, 4, 16 );
decodeCharLine( src+56, dst, 0, 8, 16 );
}
}
/*
Decode one byte from the encoded color palette.
An encoded palette byte contains RGB information bit-packed as follows:
bit: 7 6 5 4 3 2 1 0
color: b b g g g r r r
*/
static unsigned decodePaletteByte( unsigned char value )
{
unsigned bit0, bit1, bit2;
unsigned red, green, blue;
bit0 = (value >> 0) & 0x01;
bit1 = (value >> 1) & 0x01;
bit2 = (value >> 2) & 0x01;
red = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
bit0 = (value >> 3) & 0x01;
bit1 = (value >> 4) & 0x01;
bit2 = (value >> 5) & 0x01;
green = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
bit0 = 0;
bit1 = (value >> 6) & 0x01;
bit2 = (value >> 7) & 0x01;
blue = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
return (blue << 16 ) | (green << 8) | red;
}
void decodeROMs(void)
{
unsigned decoded_palette[0x20];
unsigned c;
int i;
decodeCharSet( charset_rom_, charmap_ );
decodeSprites( spriteset_rom_, spritemap_ );
for( i=0x00; i<0x20; i++ ) {
decoded_palette[i] = decodePaletteByte( palette_data_[i] );
}
for( i=0; i<256; i++ ) {
c = decoded_palette[ color_data_[i] & 0x0F ];
#ifdef HAVE_LCD_COLOR
palette[i] = LCD_RGBPACK((unsigned char) (c),
(unsigned char) (c >> 8),
(unsigned char) (c >> 16));
#else
palette[i] = rgb_to_gray(c, c >> 8, c >> 16);
#endif
}
}
void getDeviceInfo( enum InputDevice device, unsigned char * mask, unsigned char ** port )
{
static unsigned char MaskInfo[] = {
0x01 , // Joy1_Up
0x02 , // Joy1_Left
0x04 , // Joy1_Right
0x08 , // Joy1_Down
0x10 , // Switch_RackAdvance
0x20 , // CoinSlot_1
0x40 , // CoinSlot_2
0x80 , // Switch_AddCredit
0x01 , // Joy2_Up
0x02 , // Joy2_Left
0x04 , // Joy2_Right
0x08 , // Joy2_Down
0x10 , // Switch_Test
0x20 , // Key_OnePlayer
0x40 , // Key_TwoPlayers
0x80 // Switch_CocktailMode
};
*mask = MaskInfo[device];
switch( device ) {
case Joy1_Up:
case Joy1_Left:
case Joy1_Right:
case Joy1_Down:
case Switch_RackAdvance:
case CoinSlot_1:
case CoinSlot_2:
case Switch_AddCredit:
*port = &port1_;
break;
case Joy2_Up:
case Joy2_Left:
case Joy2_Right:
case Joy2_Down:
case Switch_Test:
case Key_OnePlayer:
case Key_TwoPlayers:
case Switch_CocktailMode:
*port = &port2_;
break;
default:
*port = 0;
break;
}
}
enum InputDeviceMode getDeviceMode( enum InputDevice device )
{
unsigned char mask;
unsigned char * port;
getDeviceInfo( device, &mask, &port );
return (*port & mask) == 0 ? DeviceOn : DeviceOff;
}
/*
Fire an input event, telling the emulator for example
that the joystick has been released from the down position.
*/
void setDeviceMode( enum InputDevice device, enum InputDeviceMode mode )
{
if( (getCoinLockout() == 0) && ((device == CoinSlot_1)||(device == CoinSlot_2)||(device == Switch_AddCredit)) ) {
// Coin slots are locked, ignore command and exit
return;
}
unsigned char mask;
unsigned char * port;
getDeviceInfo( device, &mask, &port );
if( mode == DeviceOn )
*port &= ~mask;
else if( mode == DeviceOff )
*port |= mask;
else if( mode == DeviceToggle )
*port ^= mask;
}
void setDipSwitches( unsigned value ) {
dip_switches_ = (unsigned char) value;
setDeviceMode( Switch_RackAdvance, value & DipRackAdvance_Auto ? DeviceOn : DeviceOff );
setDeviceMode( Switch_Test, value & DipMode_Test ? DeviceOn : DeviceOff );
setDeviceMode( Switch_CocktailMode, value & DipCabinet_Cocktail ? DeviceOn : DeviceOff );
}
unsigned getDipSwitches(void) {
unsigned result = dip_switches_;
if( getDeviceMode(Switch_RackAdvance) == DeviceOn ) result |= DipRackAdvance_Auto;
if( getDeviceMode(Switch_Test) == DeviceOn ) result |= DipMode_Test;
if( getDeviceMode(Switch_CocktailMode) == DeviceOn ) result |= DipCabinet_Cocktail;
return result;
}
static inline void drawChar( unsigned char * buffer, int index, int ox, int oy, int color )
{
buffer += ox + oy*224; // Make the buffer point to the character position
index *= 64; // Make the index point to the character offset into the character table
color = (color & 0x3F)*4;
int x,y;
if( output_devices_ & FlipScreen ) {
// Flip character
buffer += 7*ScreenWidth;
for( y=0; y<8; y++ ) {
for( x=7; x>=0; x-- ) {
buffer[x] = charmap_[ index++ ] + color;
}
buffer -= ScreenWidth; // Go to the next line
}
}
else {
for( y=0; y<8; y++ ) {
for( x=0; x<=7; x++ ) {
buffer[x] = charmap_[ index++ ] + color;
}
buffer += ScreenWidth; // Go to the next line
}
}
}
inline void drawSprite( unsigned char * buffer, int index )
{
struct PacmanSprite ps = sprites_[index];
int x,y;
// Exit now if sprite not visible at all
if( (ps.color == 0) || (ps.x >= ScreenWidth) || (ps.y < 16) || (ps.y >= (ScreenHeight-32)) ) {
return;
}
// Clip the sprite coordinates to cut the parts that fall off the screen
int start_x = (ps.x < 0) ? 0 : ps.x;
int end_x = (ps.x < (ScreenWidth-16)) ? ps.x+16 : ScreenWidth;
// Prepare variables for drawing
int color = (ps.color & 0x3F)*4;
unsigned char * spritemap_base = spritemap_ + ((ps.n & 0x3F)*256);
buffer += ScreenWidth*ps.y;
// Draw the 16x16 sprite
if( ps.mode == 0 ) { // Normal
// Draw the 16x16 sprite
for( y=0; y<16; y++ ) {
char* s = &spritemap_base[start_x-ps.x+y*16];
for( x=start_x; x<end_x; x++ ) {
int c = *(s++);
if( c ) {
buffer[x] = c + color;
}
}
buffer += ScreenWidth;
}
} else if( ps.mode == 1 ) { // Flip Y
for( y=0; y<16; y++ ) {
char* s = &spritemap_base[start_x-ps.x+(15-y)*16];
for( x=start_x; x<end_x; x++ ) {
int c = *(s++);
if( c ) {
buffer[x] = c + color;
}
}
buffer += ScreenWidth;
}
} else if( ps.mode == 2 ) { // Flip X
for( y=0; y<16; y++ ) {
char* s = &spritemap_base[15-start_x+ps.x+y*16];
for( x=start_x; x<end_x; x++ ) {
int c = *(s--);
if( c ) {
buffer[x] = c + color;
}
}
buffer += ScreenWidth;
}
} else { // Flip X and Y
for( y=0; y<16; y++ ) {
char* s = &spritemap_base[15-start_x+ps.x+(15-y)*16];
for( x=start_x; x<end_x; x++ ) {
int c = *(s--);
if( c ) {
buffer[x] = c + color;
}
}
buffer += ScreenWidth;
}
}
}
/*
Draw the video into the specified buffer.
*/
bool renderBackground( unsigned char * buffer )
{
unsigned char * video = video_mem_;
unsigned char * color = color_mem_;
unsigned char * dirty = dirty_;
int x,y;
bool changed=false;
// Draw the background first...
if( output_devices_ & FlipScreen ) {
for( y=ScreenHeight-CharHeight; y>=0; y-=CharHeight ) {
for( x=ScreenWidth-CharWidth; x>=0; x-=CharWidth ) {
if (*dirty) {
drawChar( buffer, *video++, x, y, *color++ );
*(dirty++)=0;
changed=true;
} else {
dirty++;
video++;
color++;
}
}
}
}
else {
for( y=0; y<ScreenHeight; y+=CharHeight ) {
for( x=0; x<ScreenWidth; x+=CharWidth ) {
if (*dirty) {
drawChar( buffer, *video++, x, y, *color++ );
*(dirty++)=0;
changed=true;
} else {
dirty++;
video++;
color++;
}
}
}
}
return changed;
}
void renderSprites( unsigned char * buffer )
{
int i;
// ...then add the sprites
for( i=7; i>=0; i-- ) {
drawSprite( buffer, i );
}
}
/* Enables/disables the speed hack. */
int setSpeedHack( int enabled )
{
int result = 0;
if( enabled ) {
if( (ram_[0x180B] == 0xBE) && (ram_[0x1FFD] == 0x00) ) {
// Patch the ROM to activate the speed hack
ram_[0x180B] = 0x01; // Activate speed hack
ram_[0x1FFD] = 0xBD; // Fix ROM checksum
result = 1;
}
}
else {
if( (ram_[0x180B] == 0x01) && (ram_[0x1FFD] == 0xBD) ) {
// Restore the patched ROM locations
ram_[0x180B] = 0xBE;
ram_[0x1FFD] = 0x00;
result = 1;
}
}
return result;
}

View file

@ -0,0 +1,199 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Pacbox - a Pacman Emulator for Rockbox
*
* Based on PIE - Pacman Instructional Emulator
*
* Copyright (c) 1997-2003,2004 Alessandro Scotti
* http://www.ascotti.org/
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef ARCADE_H_
#define ARCADE_H_
#include "plugin.h"
#include "z80.h"
#include "hardware.h"
extern fb_data palette[256]; /* Color palette in native Rockbox format */
/**
Pacman sprite properties.
This information is only needed by applications that want to do their own
sprite rendering, as the renderVideo() function already draws the sprites.
@see PacmanMachine::renderVideo
*/
/** Machine hardware data */
enum {
ScreenWidth = 224,
ScreenHeight = 288,
ScreenWidthChars = 28,
ScreenHeightChars = 36,
CharWidth = 8,
CharHeight = 8,
VideoFrequency = 60,
CpuClock = 3072000,
SoundClock = 96000, // CPU clock divided by 32
CpuCyclesPerFrame = CpuClock / VideoFrequency
};
/** Input devices and switches */
enum InputDevice {
Joy1_Up = 0,
Joy1_Left,
Joy1_Right,
Joy1_Down,
Switch_RackAdvance,
CoinSlot_1,
CoinSlot_2,
Switch_AddCredit,
Joy2_Up,
Joy2_Left,
Joy2_Right,
Joy2_Down,
Switch_Test,
Key_OnePlayer,
Key_TwoPlayers,
Switch_CocktailMode
};
/** Input device mode */
enum InputDeviceMode {
DeviceOn,
DevicePushed = DeviceOn,
DeviceOff,
DeviceReleased = DeviceOff,
DeviceToggle
};
/** DIP switches */
enum {
DipPlay_Free = 0x00, // Coins per play
DipPlay_OneCoinOneGame = 0x01,
DipPlay_OneCoinTwoGames = 0x02,
DipPlay_TwoCoinsOneGame = 0x03,
DipPlay_Mask = 0x03,
DipLives_1 = 0x00, // Lives per game
DipLives_2 = 0x04,
DipLives_3 = 0x08,
DipLives_5 = 0x0C,
DipLives_Mask = 0x0C,
DipBonus_10000 = 0x00, // Bonus life
DipBonus_15000 = 0x10,
DipBonus_20000 = 0x20,
DipBonus_None = 0x30,
DipBonus_Mask = 0x30,
DipDifficulty_Normal = 0x40, // Difficulty
DipDifficulty_Hard = 0x00,
DipDifficulty_Mask = 0x40,
DipGhostNames_Normal = 0x80, // Ghost names
DipGhostNames_Alternate = 0x00,
DipGhostNames_Mask = 0x80,
DipMode_Play = 0x0000, // Play/test mode
DipMode_Test = 0x0100,
DipMode_Mask = 0x0100,
DipCabinet_Upright = 0x0000, // Cabinet upright/cocktail
DipCabinet_Cocktail = 0x0200,
DipCabinet_Mask = 0x0200,
DipRackAdvance_Off = 0x0000, // Automatic level advance
DipRackAdvance_Auto = 0x0400,
DipRackAdvance_Mask = 0x0400
};
void init_PacmanMachine(int dip);
int run(void);
void reset_PacmanMachine(void);
void decodeROMs(void);
/**
Tells the emulator that the status of an input device has changed.
*/
void setDeviceMode( enum InputDevice device, enum InputDeviceMode mode );
/**
Returns the value of the DIP switches.
*/
unsigned getDipSwitches(void);
/**
Sets the value of the DIP switches that control several game settings
(see the Dip... constants above).
Most of the DIP switches are read at program startup and take effect
only after a machine reset.
*/
void setDipSwitches( unsigned value );
/**
Draws the current video into the specified buffer.
The buffer must be at least 224*288 bytes long. Pixels are stored in
left-to-right/top-to-bottom order starting from the upper left corner.
There is one byte per pixel, containing an index into the color palette
returned by getPalette().
It's up to the application to display the buffer to the user. The
code might look like this:
<BLOCKQUOTE>
<PRE>
@@ unsigned char video_buffer[ PacmanMachine::ScreenWidth * PacmanMachine::ScreenHeight ];
@@ unsigned char * vbuf = video_buffer;
@@ const unsigned * palette = arcade.getPalette();
@@
@@ arcade.renderVideo( vbuf );
@@
@@ for( int y=0; y<PacmanMachine::ScreenHeight; y++ ) {
@@ for( int x=0; x<PacmanMachine::ScreenWidth; x++ ) {
@@ unsigned color = palette[ *vbuf++ ];
@@ unsigned char red = color & 0xFF;
@@ unsigned char green = (color >> 8) & 0xFF;
@@ unsigned char blue = (color >> 16) & 0xFF;
@@
@@ setPixel( x, y, red, green, blue );
@@ }
@@ }
</PRE>
</BLOCKQUOTE>
*/
bool renderBackground( unsigned char * buffer );
void renderSprites( unsigned char * buffer );
/**
Enables/disables a common speed hack that allows Pacman to
move four times faster than the ghosts.
@param enabled true to enabled the hack, false to disable
@return 0 if successful, otherwise the patch could not be applied
(probably because the loaded ROM set does not support it)
*/
int setSpeedHack( int enabled );
/* Implementation of the Z80 Environment interface */
unsigned char readByteHigh( unsigned addr );
void writeByte( unsigned, unsigned char );
unsigned char readPort( unsigned port );
void writePort( unsigned, unsigned char );
#endif // ARCADE_H_

View file

@ -0,0 +1,197 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Pacbox - a Pacman Emulator for Rockbox
*
* Based on PIE - Pacman Instructional Emulator
*
* Copyright (c) 1997-2003,2004 Alessandro Scotti
* http://www.ascotti.org/
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "plugin.h"
#include "hardware.h"
extern struct plugin_api* rb;
/* The main data for Pacman */
unsigned char ram_[20*1024] IBSS_ATTR; // ROM (16K) and RAM (4K)
unsigned char charset_rom_[4*1024] IBSS_ATTR; // Character set ROM (4K)
unsigned char spriteset_rom_[4*1024] IBSS_ATTR; // Sprite set ROM (4K)
unsigned char dirty_[1024] IBSS_ATTR;
unsigned char video_mem_[1024] IBSS_ATTR; // Video memory (1K)
unsigned char color_mem_[1024] IBSS_ATTR; // Color memory (1K)
unsigned char charmap_[256*8*8]; /* Character data for 256 8x8 characters */
unsigned char spritemap_[64*16*16]; /* Sprite data for 64 16x16 sprites */
unsigned char output_devices_ IBSS_ATTR; /* Output flip-flops set by the game program */
unsigned char interrupt_vector_ IBSS_ATTR;
unsigned coin_counter_ IBSS_ATTR;
unsigned char port1_ IBSS_ATTR;
unsigned char port2_ IBSS_ATTR;
unsigned char dip_switches_ IBSS_ATTR;
/* Internal tables and structures for faster access to data */
struct PacmanSprite sprites_[8]; /* Sprites */
short vchar_to_i_[1024];
/*
For Z80 Environment: write a byte to memory.
*/
void writeByte( unsigned addr, unsigned char b )
{
addr &= 0x7FFF;
if( addr < 0x4000 ) {
// This is a ROM address, do not write into it!
}
else if( addr < 0x4400 ) {
// Video memory
if (ram_[addr] != b) {
int x = vchar_to_i_[addr-0x4000];
ram_[addr] = b;
dirty_[x] = 1;
video_mem_[x] = b;
}
}
else if( addr < 0x4800 ) {
// Color memory
if (ram_[addr] != b) {
int x = vchar_to_i_[addr-0x4400];
ram_[addr] = b;
dirty_[x] = 1;
color_mem_[x] = b;
}
}
else if( addr < 0x4FF0 ) {
// Standard memory
ram_[addr] = b;
}
else if( addr < 0x5000 ) {
// Sprites
ram_[addr] = b;
unsigned idx = (addr - 0x4FF0) / 2;
if( addr & 1 ) {
sprites_[ idx ].color = b;
}
else {
sprites_[ idx ].n = b >> 2;
sprites_[ idx ].mode = b & 0x03;
}
}
else {
// Memory mapped ports
switch( addr ) {
case 0x5000:
// Interrupt enable
setOutputFlipFlop( InterruptEnabled, b & 0x01 );
break;
case 0x5001:
// Sound enable
setOutputFlipFlop( SoundEnabled, b & 0x01 );
break;
case 0x5002:
// Aux board enable?
break;
case 0x5003:
// Flip screen
setOutputFlipFlop( FlipScreen, b & 0x01 );
break;
case 0x5004:
// Player 1 start light
setOutputFlipFlop( PlayerOneLight, b & 0x01 );
break;
case 0x5005:
// Player 2 start light
setOutputFlipFlop( PlayerTwoLight, b & 0x01 );
break;
case 0x5006:
// Coin lockout: bit 0 is used to enable/disable the coin insert slots
// (0=disable).
// The coin slot is enabled at startup and (temporarily) disabled when
// the maximum number of credits (99) is inserted.
setOutputFlipFlop( CoinLockout, b & 0x01 );
break;
case 0x5007:
// Coin meter (coin counter incremented on 0/1 edge)
if( (output_devices_ & CoinMeter) == 0 && (b & 0x01) != 0 )
coin_counter_++;
setOutputFlipFlop( CoinMeter, b & 0x01 );
break;
case 0x50c0:
// Watchdog reset
break;
default:
if( addr >= 0x5040 && addr < 0x5060 ) {
// Sound registers
//SOUND sound_chip_.setRegister( addr-0x5040, b );
}
else if( addr >= 0x5060 && addr < 0x5070 ) {
// Sprite coordinates, x/y pairs for 8 sprites
unsigned idx = (addr-0x5060) / 2;
if( addr & 1 ) {
sprites_[ idx ].y = 272 - b + 1;
}
else {
sprites_[ idx ].x = 240 - b - 1;
if( idx <= 2 ) {
// In Pacman the first few sprites must be further offset
// to the left to get a correct display (is this a hack?)
sprites_[ idx ].x -= 1;
}
}
}
break;
}
}
}
/*
For Z80 Environment: read from a port.
Note: all ports in Pacman are memory mapped so they are read with readByte().
*/
unsigned char readPort( unsigned port )
{
(void)port;
return 0;
}
/*
For Z80 Environment: write to a port.
*/
void writePort( unsigned addr, unsigned char b )
{
if( addr == 0 ) {
// Sets the interrupt vector for the next CPU interrupt
interrupt_vector_ = b;
}
}
void setOutputFlipFlop( unsigned char bit, unsigned char value )
{
if( value ) {
output_devices_ |= bit;
}
else {
output_devices_ &= ~bit;
}
}

View file

@ -0,0 +1,141 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Pacbox - a Pacman Emulator for Rockbox
*
* Based on PIE - Pacman Instructional Emulator
*
* Copyright (c) 1997-2003,2004 Alessandro Scotti
* http://www.ascotti.org/
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef _HARDWARE_H
#define _HARDWARE_H
extern unsigned char ram_[20*1024]; // ROM (16K) and RAM (4K)
extern unsigned char charset_rom_[4*1024]; // Character set ROM (4K)
extern unsigned char spriteset_rom_[4*1024]; // Sprite set ROM (4K)
extern unsigned char dirty_[1024];
extern unsigned char video_mem_[1024]; // Video memory (1K)
extern unsigned char color_mem_[1024]; // Color memory (1K)
extern unsigned char charmap_[256*8*8]; /* Character data for 256 8x8 characters */
extern unsigned char spritemap_[64*16*16]; /* Sprite data for 64 16x16 sprites */
extern unsigned char output_devices_; /* Output flip-flops set by the game program */
extern unsigned char interrupt_vector_;
extern unsigned coin_counter_;
extern unsigned char port1_;
extern unsigned char port2_;
extern unsigned char dip_switches_;
/* Output flip-flops */
enum {
FlipScreen = 0x01,
PlayerOneLight = 0x02,
PlayerTwoLight = 0x04,
InterruptEnabled = 0x08,
SoundEnabled = 0x10,
CoinLockout = 0x20,
CoinMeter = 0x40,
AuxBoardEnabled = 0x80
};
struct PacmanSprite
{
int mode; /** Display mode (normal or flipped) */
int x; /** X coordinate */
int y; /** Y coordinate */
int n; /** Shape (from 0 to 63) */
int color; /** Base color (0=not visible) */
};
/* Internal tables and structures for faster access to data */
extern struct PacmanSprite sprites_[8]; /* Sprites */
extern short vchar_to_i_[1024];
void writeByte(unsigned addr, unsigned char b);
unsigned char readPort( unsigned port );
void writePort( unsigned addr, unsigned char b );
void setOutputFlipFlop( unsigned char bit, unsigned char value );
/*
For Z80 Environment: read a byte from high memory addresses (i.e. the
memory-mapped registers)
*/
static inline unsigned char readByte( unsigned addr )
{
addr &= 0xFFFF;
if (addr < sizeof(ram_))
return ram_[addr];
// Address is not in RAM, check to see if it's a memory mapped register
switch( addr & 0xFFC0 ) {
// IN0
case 0x5000:
// bit 0 : up
// bit 1 : left
// bit 2 : right
// bit 3 : down
// bit 4 : switch: advance to next level
// bit 5 : coin 1
// bit 6 : coin 2
// bit 7 : credit (same as coin but coin counter is not incremented)
return port1_;
// IN1
case 0x5040:
// bit 0 : up (2nd player)
// bit 1 : left (2nd player)
// bit 2 : right (2nd player)
// bit 3 : down (2nd player)
// bit 4 : switch: rack test -> 0x10=off, 0=on
// bit 5 : start 1
// bit 6 : start 2
// bit 7 : cabinet -> 0x80=upright, 0x00=table
return port2_;
// DSW1
case 0x5080:
// bits 0,1 : coinage -> 0=free play, 1=1 coin/play, 2=1 coin/2 play, 3=2 coin/1 play
// bits 2,3 : lives -> 0x0=1, 0x4=2, 0x8=3, 0xC=5
// bits 4,5 : bonus life -> 0=10000, 0x10=15000, 0x20=20000, 0x30=none
// bit 6 : jumper pad: difficulty -> 0x40=normal, 0=hard
// bit 7 : jumper pad: ghost name -> 0x80=normal, 0=alternate
return dip_switches_;
// Watchdog reset
case 0x50C0:
break;
}
return 0xFF;
}
/* Reads a 16 bit word from memory at the specified address. */
static inline unsigned readWord( unsigned addr ) {
addr &= 0xFFFF;
if (addr < (sizeof(ram_)-1)) {
return ram_[addr] | ((ram_[addr+1]) << 8);
} else {
return readByte(addr) | (((unsigned)readByte(addr+1)) << 8);
}
}
/* Writes a 16 bit word to memory at the specified address. */
static inline void writeWord( unsigned addr, unsigned value ) {
writeByte( addr, value & 0xFF );
writeByte( addr+1, (value >> 8) & 0xFF );
}
#endif

View file

@ -0,0 +1,534 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Pacbox - a Pacman Emulator for Rockbox
*
* Based on PIE - Pacman Instructional Emulator
*
* Copyright (c) 1997-2003,2004 Alessandro Scotti
* http://www.ascotti.org/
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "plugin.h"
#include "arcade.h"
PLUGIN_HEADER
#ifdef USE_IRAM
extern char iramcopy[];
extern char iramstart[];
extern char iramend[];
extern char iedata[];
extern char iend[];
#endif
/* How many video frames (out of a possible 60) we display each second */
#define FPS 20
#if CONFIG_KEYPAD == IPOD_4G_PAD
#define PACMAN_UP BUTTON_RIGHT
#define PACMAN_DOWN BUTTON_LEFT
#define PACMAN_LEFT BUTTON_MENU
#define PACMAN_RIGHT BUTTON_PLAY
#define PACMAN_1UP BUTTON_SELECT
#define PACMAN_COIN BUTTON_SELECT
#elif CONFIG_KEYPAD == IRIVER_H100_PAD || CONFIG_KEYPAD == IRIVER_H300_PAD
#define PACMAN_UP BUTTON_RIGHT
#define PACMAN_DOWN BUTTON_LEFT
#define PACMAN_LEFT BUTTON_UP
#define PACMAN_RIGHT BUTTON_DOWN
#define PACMAN_1UP BUTTON_SELECT
#define PACMAN_2UP BUTTON_ON
#define PACMAN_COIN BUTTON_REC
#define PACMAN_MENU BUTTON_MODE
#elif CONFIG_KEYPAD == GIGABEAT_PAD
#define PACMAN_UP BUTTON_UP
#define PACMAN_DOWN BUTTON_DOWN
#define PACMAN_LEFT BUTTON_LEFT
#define PACMAN_RIGHT BUTTON_RIGHT
#define PACMAN_1UP BUTTON_SELECT
#define PACMAN_2UP BUTTON_POWER
#define PACMAN_COIN BUTTON_A
#define PACMAN_MENU BUTTON_MENU
#elif CONFIG_KEYPAD == IAUDIO_X5_PAD
#define PACMAN_UP BUTTON_RIGHT
#define PACMAN_DOWN BUTTON_LEFT
#define PACMAN_LEFT BUTTON_UP
#define PACMAN_RIGHT BUTTON_DOWN
#define PACMAN_1UP BUTTON_SELECT
#define PACMAN_2UP BUTTON_POWER
#define PACMAN_COIN BUTTON_REC
#define PACMAN_MENU BUTTON_PLAY
#endif
#if (LCD_HEIGHT >= 288)
#define XOFS ((LCD_WIDTH-224)/2)
#define YOFS ((LCD_HEIGHT-288)/2)
#elif (LCD_WIDTH >= 288)
#define XOFS ((LCD_WIDTH-288)/2)
#define YOFS ((LCD_HEIGHT-224)/2)
#elif (LCD_WIDTH >= 220)
#define XOFS ((LCD_WIDTH-(288*3/4))/2)
#define YOFS ((LCD_HEIGHT-(224*3/4))/2)
#elif (LCD_WIDTH >= 144)
#define XOFS ((LCD_WIDTH-288/2)/2)
#define YOFS ((LCD_HEIGHT-224/2)/2)
#endif
struct plugin_api* rb;
unsigned framesPerSecond = VideoFrequency;
unsigned long frame_counter = 0;
struct pacman_settings {
int difficulty;
int numlives;
int bonus;
int ghostnames;
int showfps;
};
struct pacman_settings settings;
bool loadFile( const char * name, unsigned char * buf, int len )
{
char filename[MAX_PATH];
rb->snprintf(filename,sizeof(filename),"/.rockbox/pacman/%s",name);
int fd = rb->open( filename, O_RDONLY);
if( fd < 0 ) {
return false;
}
int n = rb->read( fd, buf, len);
rb->close( fd );
if( n != len ) {
return false;
}
return true;
}
bool loadROMS( void )
{
bool romsLoaded = false;
romsLoaded = loadFile( "pacman.6e", ram_, 0x1000) &&
loadFile( "pacman.6f", ram_+0x1000, 0x1000) &&
loadFile( "pacman.6h", ram_+0x2000, 0x1000) &&
loadFile( "pacman.6j", ram_+0x3000, 0x1000) &&
loadFile( "pacman.5e", charset_rom_, 0x1000) &&
loadFile( "pacman.5f", spriteset_rom_, 0x1000);
if( romsLoaded ) {
decodeROMs();
reset_PacmanMachine();
}
return romsLoaded;
}
/* A buffer to render Pacman's 244x288 screen into */
unsigned char background[ScreenWidth*ScreenHeight] __attribute__ ((aligned (4)));
unsigned char video_buffer[ScreenWidth*ScreenHeight] __attribute__ ((aligned (4)));
long start_time;
long sleep_counter = 0;
long video_frames = 0;
int dipDifficulty[] = { DipDifficulty_Normal, DipDifficulty_Hard };
int dipLives[] = { DipLives_1, DipLives_2, DipLives_3, DipLives_5 };
int dipBonus[] = { DipBonus_10000, DipBonus_15000, DipBonus_20000, DipBonus_None };
int dipGhostNames[] = { DipGhostNames_Normal, DipGhostNames_Alternate };
int settings_to_dip(struct pacman_settings settings)
{
return ( DipPlay_OneCoinOneGame |
DipCabinet_Upright |
DipMode_Play |
DipRackAdvance_Off |
dipDifficulty[settings.difficulty] |
dipLives[settings.numlives] |
dipBonus[settings.bonus] |
dipGhostNames[settings.ghostnames]
);
}
int pacbox_menu_cb(int key, int m)
{
(void)m;
switch(key)
{
#ifdef MENU_ENTER2
case MENU_ENTER2:
#endif
case MENU_ENTER:
key = BUTTON_NONE; /* eat the downpress, next menu reacts on release */
break;
#ifdef MENU_ENTER2
case MENU_ENTER2 | BUTTON_REL:
#endif
case MENU_ENTER | BUTTON_REL:
key = MENU_ENTER; /* fake downpress, next menu doesn't like release */
break;
}
return key;
}
bool pacbox_menu(void)
{
int m;
int result;
int menu_quit=0;
int new_setting;
bool need_restart = false;
static const struct opt_items noyes[2] = {
{ "No", NULL },
{ "Yes", NULL },
};
static const struct opt_items difficulty_options[2] = {
{ "Normal", NULL },
{ "Harder", NULL },
};
static const struct opt_items numlives_options[4] = {
{ "1", NULL },
{ "2", NULL },
{ "3", NULL },
{ "5", NULL },
};
static const struct opt_items bonus_options[4] = {
{ "10000 points", NULL },
{ "15000 points", NULL },
{ "20000 points", NULL },
{ "No bonus", NULL },
};
static const struct opt_items ghostname_options[2] = {
{ "Normal", NULL },
{ "Alternate", NULL },
};
static const struct menu_item items[] = {
{ "Difficulty", NULL },
{ "Pacmen Per Game", NULL },
{ "Bonus Life", NULL },
{ "Ghost Names", NULL },
{ "Display FPS", NULL },
{ "Restart", NULL },
{ "Quit", NULL },
};
m = rb->menu_init(items, sizeof(items) / sizeof(*items),
pacbox_menu_cb, NULL, NULL, NULL);
rb->button_clear_queue();
while (!menu_quit) {
result=rb->menu_show(m);
switch(result)
{
case 0:
new_setting=settings.difficulty;
rb->set_option("Difficulty", &new_setting, INT,
difficulty_options , 2, NULL);
if (new_setting != settings.difficulty) {
settings.difficulty=new_setting;
need_restart=true;
}
break;
case 1:
new_setting=settings.numlives;
rb->set_option("Pacmen Per Game", &new_setting, INT,
numlives_options , 4, NULL);
if (new_setting != settings.numlives) {
settings.numlives=new_setting;
need_restart=true;
}
break;
case 2:
new_setting=settings.bonus;
rb->set_option("Bonus Life", &new_setting, INT,
bonus_options , 4, NULL);
if (new_setting != settings.bonus) {
settings.bonus=new_setting;
need_restart=true;
}
break;
case 3:
new_setting=settings.ghostnames;
rb->set_option("Ghost Names", &new_setting, INT,
ghostname_options , 2, NULL);
if (new_setting != settings.ghostnames) {
settings.ghostnames=new_setting;
need_restart=true;
}
break;
case 4: /* Show FPS */
rb->set_option("Display FPS",&settings.showfps,INT, noyes, 2, NULL);
break;
case 5: /* Restart */
need_restart=true;
menu_quit=1;
break;
default:
menu_quit=1;
break;
}
}
rb->menu_exit(m);
if (need_restart) {
init_PacmanMachine(settings_to_dip(settings));
}
/* Possible results:
exit game
restart game
usb connected
*/
return (result==6);
}
/*
Runs the game engine for one frame.
*/
int gameProc( void )
{
int x,y;
int fps;
char str[80];
int status;
long end_time;
unsigned char* vbuf = video_buffer;
fb_data* dst;
fb_data* next_dst;
/* Run the machine for one frame (1/60th second) */
run();
frame_counter++;
/* Check the button status */
status = rb->button_status();
#ifdef PACMAN_MENU
if (status & PACMAN_MENU) {
#else
if (rb->button_hold()) {
#endif
end_time = *rb->current_tick;
x = pacbox_menu();
rb->lcd_clear_display();
#ifdef HAVE_REMOTE_LCD
rb->lcd_remote_clear_display();
rb->lcd_remote_update();
#endif
if (x == 1) { return 1; }
start_time += *rb->current_tick-end_time;
}
setDeviceMode( Joy1_Left, (status & PACMAN_LEFT) ? DeviceOn : DeviceOff);
setDeviceMode( Joy1_Right, (status & PACMAN_RIGHT) ? DeviceOn : DeviceOff);
setDeviceMode( Joy1_Up, (status & PACMAN_UP) ? DeviceOn : DeviceOff);
setDeviceMode( Joy1_Down, (status & PACMAN_DOWN) ? DeviceOn : DeviceOff);
setDeviceMode( CoinSlot_1, (status & PACMAN_COIN) ? DeviceOn : DeviceOff);
setDeviceMode( Key_OnePlayer, (status & PACMAN_1UP) ? DeviceOn : DeviceOff);
#ifdef PACMAN_2UP
setDeviceMode( Key_TwoPlayers, (status & PACMAN_2UP) ? DeviceOn : DeviceOff);
#endif
/* We only update the screen every third frame - Pacman's native
framerate is 60fps, so we are attempting to display 20fps */
if( (frame_counter % (60/FPS)) == 0) {
video_frames++;
/* The following functions render the Pacman screen from the contents
of the video and color ram. We first update the background, and
then draw the Sprites on top.
Note that we only redraw the parts of the background that have
changed, which is why we need to keep a copy of the background without
the sprites on top. Even with the memcpy, this is faster than redrawing
the whole background.
*/
renderBackground( background );
rb->memcpy(video_buffer,background,sizeof(video_buffer));
renderSprites( video_buffer );
#ifdef HAVE_LCD_COLOR
#if (LCD_WIDTH >= 224) && (LCD_HEIGHT >= 288)
/* Native resolution = 224x288 */
(void)next_dst;
dst=&rb->lcd_framebuffer[YOFS*LCD_WIDTH+XOFS];
for (y=0;y<ScreenHeight;y++) {
for (x=0;x<ScreenWidth;x++) {
*(dst++) = palette[*(vbuf++)];
}
dst += XOFS*2;
}
#elif (LCD_WIDTH >= 288) && (LCD_HEIGHT >= 224)
/* Native resolution - rotated 90 degrees = 288x224 */
next_dst=&rb->lcd_framebuffer[YOFS*LCD_WIDTH+XOFS+ScreenHeight-1];
for( y=ScreenHeight-1; y>=0; y-- ) {
dst = (next_dst--);
for( x=0; x<ScreenWidth; x++ ) {
*dst = palette[*(vbuf++)];
dst+=LCD_WIDTH;
}
}
#elif (LCD_WIDTH >= 216) && (LCD_HEIGHT >= 168)
/* 0.75 scaling - display 3 out of 4 pixels = 216x168
Skipping pixel #2 out of 4 seems to give the most legible display
*/
next_dst=&rb->lcd_framebuffer[YOFS*LCD_WIDTH+XOFS+((ScreenHeight*3)/4)-1];
for (y=ScreenHeight-1;y >= 0; y--) {
if ((y & 3) != 1) {
dst = (next_dst--);
for (x=0;x<ScreenWidth;x++) {
if ((x & 3) == 1) { vbuf++; }
else {
*dst = palette[*(vbuf++)];
dst+=LCD_WIDTH;
}
}
} else {
vbuf+=ScreenWidth;
}
}
#elif (LCD_WIDTH >= 144) && (LCD_HEIGHT >= 112)
/* 0.5 scaling - display every other pixel = 144x112 */
next_dst=&rb->lcd_framebuffer[YOFS*LCD_WIDTH+XOFS+ScreenHeight/2-1];
for (y=(ScreenHeight/2)-1;y >= 0; y--) {
dst = (next_dst--);
for (x=0;x<ScreenWidth/2;x++) {
*dst = palette[*(vbuf)];
vbuf+=2;
dst+=LCD_WIDTH;
}
vbuf+=ScreenWidth;
}
#endif
#else /* Greyscale LCDs */
#if (LCD_WIDTH >= 144) && (LCD_HEIGHT >= 112)
#if LCD_PIXELFORMAT == VERTICAL_PACKING
/* 0.5 scaling - display every other pixel = 144x112 */
next_dst=&rb->lcd_framebuffer[YOFS/4*LCD_WIDTH+XOFS+ScreenHeight/2-1];
for (y=(ScreenHeight/2)-1;y >= 0; y--) {
dst = (next_dst--);
for (x=0;x<ScreenWidth/8;x++) {
*dst = (palette[*(vbuf+6)]<<6) | (palette[*(vbuf+4)] << 4) | (palette[*(vbuf+2)] << 2) | palette[*(vbuf)];
vbuf+=8;
dst+=LCD_WIDTH;
}
vbuf+=ScreenWidth;
}
#endif /* Vertical Packing */
#endif /* Size >= 144x112 */
#endif /* Not Colour */
if (settings.showfps) {
fps = (video_frames*HZ*100) / (*rb->current_tick-start_time);
rb->snprintf(str,sizeof(str),"%d.%02d / %d fps ",fps/100,fps%100,
FPS);
rb->lcd_putsxy(0,0,str);
}
rb->lcd_update();
#ifdef SIMULATOR
/* Keep the framerate at Pacman's 60fps */
end_time = start_time + (video_frames*HZ)/FPS;
while (TIME_BEFORE(*rb->current_tick,end_time)) {
rb->sleep(1);
}
#endif
}
return 0;
}
enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
{
(void)parameter;
int status;
rb = api;
#ifdef USE_IRAM
rb->memcpy(iramstart, iramcopy, iramend-iramstart);
rb->memset(iedata, 0, iend - iedata);
#endif
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
rb->cpu_boost(true);
#endif
rb->lcd_set_foreground(LCD_WHITE);
rb->lcd_set_background(LCD_BLACK);
rb->lcd_clear_display();
rb->lcd_update();
/* Set the default settings (we should load these from a file) */
settings.difficulty = 0; /* Normal */
settings.numlives = 2; /* 3 lives */
settings.bonus = 0; /* 10000 points */
settings.ghostnames = 0; /* Normal names */
settings.showfps = 0; /* Do not show FPS */
/* Initialise the hardware */
init_PacmanMachine(settings_to_dip(settings));
/* Load the romset */
if (loadROMS()) {
start_time = *rb->current_tick-1;
do {
status = gameProc();
} while (!status);
} else {
rb->splash(HZ*2,true,"No ROMs in /.rockbox/pacman/");
}
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
rb->cpu_boost(false);
#endif
return PLUGIN_OK;
}

View file

@ -0,0 +1,13 @@
Pacbox is based on PIE - the Pacman Instructional Emulator written by
Alessandro Scotti. PIE is a Pacman arcade machine emulator licensed
under the GNU GPL and is available from http://www.ascotti.org/
PIE is a Windows application written in C++ - all the Windows-specific
code was stripped out and the emulator converted to C for use in
Rockbox.
The version of PIE used as the basis of the port was v1.11
Dave Chapman
March 2006

8058
apps/plugins/pacbox/z80.c Normal file

File diff suppressed because it is too large Load diff

160
apps/plugins/pacbox/z80.h Normal file
View file

@ -0,0 +1,160 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Pacbox - a Pacman Emulator for Rockbox
*
* Based on PIE - Pacman Instructional Emulator
*
* Copyright (c) 1997-2003,2004 Alessandro Scotti
* http://www.ascotti.org/
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef Z80_H_
#define Z80_H_
/**
Environment for Z80 emulation.
This class implements all input/output functions for the Z80 emulator class,
that is it provides functions to access the system RAM, ROM and I/O ports.
An object of this class corresponds to a system that has no RAM, ROM or ports:
users of the Z80 emulator should provide the desired behaviour by writing a
descendant of this class.
@author Alessandro Scotti
@version 1.0
*/
/** Sets the CPU cycle counter to the specified value. */
void setCycles( unsigned value );
void onReturnFromInterrupt(void);
/**
Z80 software emulator.
@author Alessandro Scotti
@version 1.1
*/
/** CPU flags */
enum {
Carry = 0x01, // C
AddSub = 0x02, Subtraction = AddSub, // N
Parity = 0x04, Overflow = Parity, // P/V, same bit used for parity and overflow
Flag3 = 0x08, // Aka XF, not used
Halfcarry = 0x10, // H
Flag5 = 0x20, // Aka YF, not used
Zero = 0x40, // Z
Sign = 0x80 // S
};
/**
Constructor: creates a Z80 object with the specified environment.
*/
// Z80( Z80Environment & );
/**
Copy constructor: creates a copy of the specified Z80 object.
*/
// Z80( const Z80 & );
// /** Destructor. */
// virtual ~Z80() {
/**
Resets the CPU to its initial state.
The stack pointer (SP) is set to F000h, all other registers are cleared.
*/
void z80_reset(void);
/**
Runs the CPU for the specified number of cycles.
Note that the number of CPU cycles performed by this function may be
actually a little more than the value specified. If that happens then the
function returns the number of extra cycles executed.
@param cycles number of cycles the CPU must execute
@return the number of extra cycles executed by the last instruction
*/
unsigned z80_run( unsigned cycles );
/**
Executes one instruction.
*/
void z80_step(void);
/**
Invokes an interrupt.
If interrupts are enabled, the current program counter (PC) is saved on
the stack and assigned the specified address. When the interrupt handler
returns, execution resumes from the point where the interrupt occurred.
The actual interrupt address depends on the current interrupt mode and
on the interrupt type. For maskable interrupts, data is as follows:
- mode 0: data is an opcode that is executed (usually RST xxh);
- mode 1: data is ignored and a call is made to address 0x38;
- mode 2: a call is made to the 16 bit address given by (256*I + data).
*/
void z80_interrupt( unsigned char data );
/** Forces a non-maskable interrupt. */
void z80_nmi(void);
/**
Copies CPU register from one object to another.
Note that the environment is not copied, only registers.
*/
// Z80 & operator = ( const Z80 & );
/** Returns the size of the buffer needed to take a snapshot of the CPU. */
unsigned getSizeOfSnapshotBuffer(void);
/**
Takes a snapshot of the CPU.
A snapshot saves all of the CPU registers and internals. It can be
restored at any time to bring the CPU back to the exact status it
had when the snapshot was taken.
Note: the size of the snapshot buffer must be no less than the size
returned by the getSizeOfSnapshotBuffer() function.
@param buffer buffer where the snapshot data is stored
@return the number of bytes written into the buffer
*/
unsigned takeSnapshot( unsigned char * buffer );
/**
Restores a snapshot taken with takeSnapshot().
This function uses the data saved in the snapshot buffer to restore the
CPU status.
@param buffer buffer where the snapshot data is stored
@return the number of bytes read from the buffer
*/
unsigned restoreSnapshot( unsigned char * buffer );
#endif // Z80_H_

File diff suppressed because it is too large Load diff