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:
parent
1246668a78
commit
a814584c87
13 changed files with 11079 additions and 1 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
113
apps/plugins/pacbox/Makefile
Normal file
113
apps/plugins/pacbox/Makefile
Normal 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)
|
||||
|
||||
577
apps/plugins/pacbox/arcade.c
Normal file
577
apps/plugins/pacbox/arcade.c
Normal 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;
|
||||
}
|
||||
199
apps/plugins/pacbox/arcade.h
Normal file
199
apps/plugins/pacbox/arcade.h
Normal 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_
|
||||
197
apps/plugins/pacbox/hardware.c
Normal file
197
apps/plugins/pacbox/hardware.c
Normal 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;
|
||||
}
|
||||
}
|
||||
141
apps/plugins/pacbox/hardware.h
Normal file
141
apps/plugins/pacbox/hardware.h
Normal 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
|
||||
534
apps/plugins/pacbox/pacbox.c
Normal file
534
apps/plugins/pacbox/pacbox.c
Normal 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;
|
||||
}
|
||||
13
apps/plugins/pacbox/readme.txt
Normal file
13
apps/plugins/pacbox/readme.txt
Normal 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
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
160
apps/plugins/pacbox/z80.h
Normal 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_
|
||||
1062
apps/plugins/pacbox/z80_internal.h
Normal file
1062
apps/plugins/pacbox/z80_internal.h
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue